Spaces:
Running
Running
Commit
·
e2a9158
1
Parent(s):
ec4ef43
copy from app in xet-core
Browse files- APP_README.md +98 -0
- index.html +0 -13
- package.json +27 -18
- pnpm-lock.yaml +964 -0
- public/vite.svg +0 -1
- src/App.svelte +0 -47
- src/app.css +0 -79
- src/app.d.ts +13 -0
- src/app.html +16 -0
- src/assets/svelte.svg +0 -1
- src/lib/Counter.svelte +0 -10
- src/lib/assets/favicon.svg +1 -0
- src/lib/components/ErrorDisplay.svelte +101 -0
- src/lib/components/FileUpload.svelte +241 -0
- src/lib/components/ShardViewer.svelte +543 -0
- src/lib/components/XorbViewer.svelte +273 -0
- src/lib/index.ts +1 -0
- src/lib/parsers.ts +412 -0
- src/lib/types.ts +119 -0
- src/main.ts +0 -9
- src/routes/+layout.svelte +11 -0
- src/routes/+page.svelte +305 -0
- src/vite-env.d.ts +0 -2
- static/robots.txt +3 -0
- svelte.config.js +17 -6
- tsconfig.app.json +0 -20
- tsconfig.json +17 -5
- tsconfig.node.json +0 -25
- vite.config.ts +4 -5
APP_README.md
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# XORB & Shard File Viewer
|
2 |
+
|
3 |
+
A static web application built with Svelte that allows you to upload and analyze XORB or Shard object files to view their metadata structure.
|
4 |
+
|
5 |
+
## Features
|
6 |
+
|
7 |
+
- **File Upload**: Drag & drop or click to upload XORB and Shard files
|
8 |
+
- **Automatic Detection**: Automatically detects file type based on binary structure
|
9 |
+
- **Comprehensive Metadata Display**: Shows detailed information about file contents
|
10 |
+
- **Responsive Design**: Works on desktop and mobile devices
|
11 |
+
- **Error Handling**: Provides clear error messages for invalid files
|
12 |
+
|
13 |
+
## Supported File Types
|
14 |
+
|
15 |
+
### 📦 XORB Files
|
16 |
+
|
17 |
+
XORB (Xet Orb) files contain collections of compressed chunks with metadata. The viewer displays:
|
18 |
+
|
19 |
+
- Chunk count and sizes
|
20 |
+
- Compression ratios
|
21 |
+
- Hash information
|
22 |
+
- Boundary offsets
|
23 |
+
- Individual chunk details
|
24 |
+
|
25 |
+
### 🗂️ Shard Files
|
26 |
+
|
27 |
+
MDB Shard files store file metadata and content-addressable storage information for efficient deduplication. The viewer shows:
|
28 |
+
|
29 |
+
- File information entries
|
30 |
+
- CAS (Content Addressable Storage) data
|
31 |
+
- Lookup tables
|
32 |
+
- Timestamps and security keys
|
33 |
+
- Header and footer details
|
34 |
+
|
35 |
+
## Development
|
36 |
+
|
37 |
+
### Prerequisites
|
38 |
+
|
39 |
+
- Node.js 18+
|
40 |
+
- pnpm (or npm/yarn)
|
41 |
+
|
42 |
+
### Setup
|
43 |
+
|
44 |
+
```bash
|
45 |
+
cd xorb-shard-viewer
|
46 |
+
pnpm install
|
47 |
+
pnpm run dev
|
48 |
+
```
|
49 |
+
|
50 |
+
The application will be available at `http://localhost:5173`
|
51 |
+
|
52 |
+
### Build for Production
|
53 |
+
|
54 |
+
```bash
|
55 |
+
pnpm run build
|
56 |
+
```
|
57 |
+
|
58 |
+
The static files will be generated in the `build` directory.
|
59 |
+
|
60 |
+
## File Format Support
|
61 |
+
|
62 |
+
The application implements binary parsers for:
|
63 |
+
|
64 |
+
- **XORB Format**: Based on the CAS object format with chunk compression and merkle hashing
|
65 |
+
- **Shard Format**: MDB shard file format v2 with header, footer, file info, and CAS info sections
|
66 |
+
|
67 |
+
## Architecture
|
68 |
+
|
69 |
+
- **Frontend**: Svelte + TypeScript
|
70 |
+
- **Parsing**: Custom binary parsers for both file formats
|
71 |
+
- **Styling**: Component-scoped CSS with responsive design
|
72 |
+
- **Type Safety**: Full TypeScript support with detailed type definitions
|
73 |
+
|
74 |
+
## Browser Compatibility
|
75 |
+
|
76 |
+
Works in all modern browsers that support:
|
77 |
+
|
78 |
+
- File API
|
79 |
+
- ArrayBuffer/Uint8Array
|
80 |
+
- ES2020+ features
|
81 |
+
|
82 |
+
## Security
|
83 |
+
|
84 |
+
- All file processing happens client-side
|
85 |
+
- No data is uploaded to any server
|
86 |
+
- Files are processed entirely in the browser's memory
|
87 |
+
|
88 |
+
## Contributing
|
89 |
+
|
90 |
+
1. Fork the repository
|
91 |
+
2. Create a feature branch
|
92 |
+
3. Make your changes
|
93 |
+
4. Test thoroughly
|
94 |
+
5. Submit a pull request
|
95 |
+
|
96 |
+
## License
|
97 |
+
|
98 |
+
See the parent repository's LICENSE file for licensing information.
|
index.html
DELETED
@@ -1,13 +0,0 @@
|
|
1 |
-
<!doctype html>
|
2 |
-
<html lang="en">
|
3 |
-
<head>
|
4 |
-
<meta charset="UTF-8" />
|
5 |
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
-
<title>Vite + Svelte + TS</title>
|
8 |
-
</head>
|
9 |
-
<body>
|
10 |
-
<div id="app"></div>
|
11 |
-
<script type="module" src="/src/main.ts"></script>
|
12 |
-
</body>
|
13 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
package.json
CHANGED
@@ -1,20 +1,29 @@
|
|
1 |
{
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
}
|
|
|
1 |
{
|
2 |
+
"name": "xorb-shard-viewer",
|
3 |
+
"private": true,
|
4 |
+
"version": "0.0.1",
|
5 |
+
"type": "module",
|
6 |
+
"scripts": {
|
7 |
+
"dev": "vite dev",
|
8 |
+
"build": "vite build",
|
9 |
+
"preview": "vite preview",
|
10 |
+
"prepare": "svelte-kit sync || echo ''",
|
11 |
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
12 |
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
13 |
+
},
|
14 |
+
"devDependencies": {
|
15 |
+
"@sveltejs/adapter-auto": "^6.0.0",
|
16 |
+
"@sveltejs/kit": "^2.22.0",
|
17 |
+
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
18 |
+
"svelte": "^5.0.0",
|
19 |
+
"svelte-check": "^4.0.0",
|
20 |
+
"typescript": "^5.0.0",
|
21 |
+
"vite": "^7.0.4"
|
22 |
+
},
|
23 |
+
"pnpm": {
|
24 |
+
"onlyBuiltDependencies": [
|
25 |
+
"esbuild"
|
26 |
+
]
|
27 |
+
},
|
28 |
+
"packageManager": "[email protected]+sha512.e519b9f7639869dc8d5c3c5dfef73b3f091094b0a006d7317353c72b124e80e1afd429732e28705ad6bfa1ee879c1fce46c128ccebd3192101f43dd67c667912"
|
29 |
}
|
pnpm-lock.yaml
ADDED
@@ -0,0 +1,964 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
lockfileVersion: '9.0'
|
2 |
+
|
3 |
+
settings:
|
4 |
+
autoInstallPeers: true
|
5 |
+
excludeLinksFromLockfile: false
|
6 |
+
|
7 |
+
importers:
|
8 |
+
|
9 |
+
.:
|
10 |
+
devDependencies:
|
11 |
+
'@sveltejs/adapter-auto':
|
12 |
+
specifier: ^6.0.0
|
13 |
+
version: 6.0.1(@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected]))
|
14 |
+
'@sveltejs/kit':
|
15 |
+
specifier: ^2.22.0
|
16 |
+
version: 2.27.0(@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected])
|
17 |
+
'@sveltejs/vite-plugin-svelte':
|
18 |
+
specifier: ^6.0.0
|
19 |
+
version: 6.1.0([email protected])([email protected])
|
20 |
+
svelte:
|
21 |
+
specifier: ^5.0.0
|
22 |
+
version: 5.37.3
|
23 |
+
svelte-check:
|
24 |
+
specifier: ^4.0.0
|
25 |
+
version: 4.3.1([email protected])([email protected])([email protected])
|
26 |
+
typescript:
|
27 |
+
specifier: ^5.0.0
|
28 |
+
version: 5.9.2
|
29 |
+
vite:
|
30 |
+
specifier: ^7.0.4
|
31 |
+
version: 7.0.6
|
32 |
+
|
33 |
+
packages:
|
34 |
+
|
35 |
+
'@ampproject/[email protected]':
|
36 |
+
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
37 |
+
engines: {node: '>=6.0.0'}
|
38 |
+
|
39 |
+
'@esbuild/[email protected]':
|
40 |
+
resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==}
|
41 |
+
engines: {node: '>=18'}
|
42 |
+
cpu: [ppc64]
|
43 |
+
os: [aix]
|
44 |
+
|
45 |
+
'@esbuild/[email protected]':
|
46 |
+
resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==}
|
47 |
+
engines: {node: '>=18'}
|
48 |
+
cpu: [arm64]
|
49 |
+
os: [android]
|
50 |
+
|
51 |
+
'@esbuild/[email protected]':
|
52 |
+
resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==}
|
53 |
+
engines: {node: '>=18'}
|
54 |
+
cpu: [arm]
|
55 |
+
os: [android]
|
56 |
+
|
57 |
+
'@esbuild/[email protected]':
|
58 |
+
resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==}
|
59 |
+
engines: {node: '>=18'}
|
60 |
+
cpu: [x64]
|
61 |
+
os: [android]
|
62 |
+
|
63 |
+
'@esbuild/[email protected]':
|
64 |
+
resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==}
|
65 |
+
engines: {node: '>=18'}
|
66 |
+
cpu: [arm64]
|
67 |
+
os: [darwin]
|
68 |
+
|
69 |
+
'@esbuild/[email protected]':
|
70 |
+
resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==}
|
71 |
+
engines: {node: '>=18'}
|
72 |
+
cpu: [x64]
|
73 |
+
os: [darwin]
|
74 |
+
|
75 |
+
'@esbuild/[email protected]':
|
76 |
+
resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==}
|
77 |
+
engines: {node: '>=18'}
|
78 |
+
cpu: [arm64]
|
79 |
+
os: [freebsd]
|
80 |
+
|
81 |
+
'@esbuild/[email protected]':
|
82 |
+
resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==}
|
83 |
+
engines: {node: '>=18'}
|
84 |
+
cpu: [x64]
|
85 |
+
os: [freebsd]
|
86 |
+
|
87 |
+
'@esbuild/[email protected]':
|
88 |
+
resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==}
|
89 |
+
engines: {node: '>=18'}
|
90 |
+
cpu: [arm64]
|
91 |
+
os: [linux]
|
92 |
+
|
93 |
+
'@esbuild/[email protected]':
|
94 |
+
resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==}
|
95 |
+
engines: {node: '>=18'}
|
96 |
+
cpu: [arm]
|
97 |
+
os: [linux]
|
98 |
+
|
99 |
+
'@esbuild/[email protected]':
|
100 |
+
resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==}
|
101 |
+
engines: {node: '>=18'}
|
102 |
+
cpu: [ia32]
|
103 |
+
os: [linux]
|
104 |
+
|
105 |
+
'@esbuild/[email protected]':
|
106 |
+
resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==}
|
107 |
+
engines: {node: '>=18'}
|
108 |
+
cpu: [loong64]
|
109 |
+
os: [linux]
|
110 |
+
|
111 |
+
'@esbuild/[email protected]':
|
112 |
+
resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==}
|
113 |
+
engines: {node: '>=18'}
|
114 |
+
cpu: [mips64el]
|
115 |
+
os: [linux]
|
116 |
+
|
117 |
+
'@esbuild/[email protected]':
|
118 |
+
resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==}
|
119 |
+
engines: {node: '>=18'}
|
120 |
+
cpu: [ppc64]
|
121 |
+
os: [linux]
|
122 |
+
|
123 |
+
'@esbuild/[email protected]':
|
124 |
+
resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==}
|
125 |
+
engines: {node: '>=18'}
|
126 |
+
cpu: [riscv64]
|
127 |
+
os: [linux]
|
128 |
+
|
129 |
+
'@esbuild/[email protected]':
|
130 |
+
resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==}
|
131 |
+
engines: {node: '>=18'}
|
132 |
+
cpu: [s390x]
|
133 |
+
os: [linux]
|
134 |
+
|
135 |
+
'@esbuild/[email protected]':
|
136 |
+
resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==}
|
137 |
+
engines: {node: '>=18'}
|
138 |
+
cpu: [x64]
|
139 |
+
os: [linux]
|
140 |
+
|
141 |
+
'@esbuild/[email protected]':
|
142 |
+
resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==}
|
143 |
+
engines: {node: '>=18'}
|
144 |
+
cpu: [arm64]
|
145 |
+
os: [netbsd]
|
146 |
+
|
147 |
+
'@esbuild/[email protected]':
|
148 |
+
resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==}
|
149 |
+
engines: {node: '>=18'}
|
150 |
+
cpu: [x64]
|
151 |
+
os: [netbsd]
|
152 |
+
|
153 |
+
'@esbuild/[email protected]':
|
154 |
+
resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==}
|
155 |
+
engines: {node: '>=18'}
|
156 |
+
cpu: [arm64]
|
157 |
+
os: [openbsd]
|
158 |
+
|
159 |
+
'@esbuild/[email protected]':
|
160 |
+
resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==}
|
161 |
+
engines: {node: '>=18'}
|
162 |
+
cpu: [x64]
|
163 |
+
os: [openbsd]
|
164 |
+
|
165 |
+
'@esbuild/[email protected]':
|
166 |
+
resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==}
|
167 |
+
engines: {node: '>=18'}
|
168 |
+
cpu: [arm64]
|
169 |
+
os: [openharmony]
|
170 |
+
|
171 |
+
'@esbuild/[email protected]':
|
172 |
+
resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==}
|
173 |
+
engines: {node: '>=18'}
|
174 |
+
cpu: [x64]
|
175 |
+
os: [sunos]
|
176 |
+
|
177 |
+
'@esbuild/[email protected]':
|
178 |
+
resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==}
|
179 |
+
engines: {node: '>=18'}
|
180 |
+
cpu: [arm64]
|
181 |
+
os: [win32]
|
182 |
+
|
183 |
+
'@esbuild/[email protected]':
|
184 |
+
resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==}
|
185 |
+
engines: {node: '>=18'}
|
186 |
+
cpu: [ia32]
|
187 |
+
os: [win32]
|
188 |
+
|
189 |
+
'@esbuild/[email protected]':
|
190 |
+
resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==}
|
191 |
+
engines: {node: '>=18'}
|
192 |
+
cpu: [x64]
|
193 |
+
os: [win32]
|
194 |
+
|
195 |
+
'@jridgewell/[email protected]':
|
196 |
+
resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
|
197 |
+
|
198 |
+
'@jridgewell/[email protected]':
|
199 |
+
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
200 |
+
engines: {node: '>=6.0.0'}
|
201 |
+
|
202 |
+
'@jridgewell/[email protected]':
|
203 |
+
resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
|
204 |
+
|
205 |
+
'@jridgewell/[email protected]':
|
206 |
+
resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
|
207 |
+
|
208 |
+
'@polka/[email protected]':
|
209 |
+
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
|
210 |
+
|
211 |
+
'@rollup/[email protected]':
|
212 |
+
resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==}
|
213 |
+
cpu: [arm]
|
214 |
+
os: [android]
|
215 |
+
|
216 |
+
'@rollup/[email protected]':
|
217 |
+
resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==}
|
218 |
+
cpu: [arm64]
|
219 |
+
os: [android]
|
220 |
+
|
221 |
+
'@rollup/[email protected]':
|
222 |
+
resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==}
|
223 |
+
cpu: [arm64]
|
224 |
+
os: [darwin]
|
225 |
+
|
226 |
+
'@rollup/[email protected]':
|
227 |
+
resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==}
|
228 |
+
cpu: [x64]
|
229 |
+
os: [darwin]
|
230 |
+
|
231 |
+
'@rollup/[email protected]':
|
232 |
+
resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==}
|
233 |
+
cpu: [arm64]
|
234 |
+
os: [freebsd]
|
235 |
+
|
236 |
+
'@rollup/[email protected]':
|
237 |
+
resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==}
|
238 |
+
cpu: [x64]
|
239 |
+
os: [freebsd]
|
240 |
+
|
241 |
+
'@rollup/[email protected]':
|
242 |
+
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
|
243 |
+
cpu: [arm]
|
244 |
+
os: [linux]
|
245 |
+
|
246 |
+
'@rollup/[email protected]':
|
247 |
+
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
|
248 |
+
cpu: [arm]
|
249 |
+
os: [linux]
|
250 |
+
|
251 |
+
'@rollup/[email protected]':
|
252 |
+
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
|
253 |
+
cpu: [arm64]
|
254 |
+
os: [linux]
|
255 |
+
|
256 |
+
'@rollup/[email protected]':
|
257 |
+
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
|
258 |
+
cpu: [arm64]
|
259 |
+
os: [linux]
|
260 |
+
|
261 |
+
'@rollup/[email protected]':
|
262 |
+
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
|
263 |
+
cpu: [loong64]
|
264 |
+
os: [linux]
|
265 |
+
|
266 |
+
'@rollup/[email protected]':
|
267 |
+
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
|
268 |
+
cpu: [ppc64]
|
269 |
+
os: [linux]
|
270 |
+
|
271 |
+
'@rollup/[email protected]':
|
272 |
+
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
|
273 |
+
cpu: [riscv64]
|
274 |
+
os: [linux]
|
275 |
+
|
276 |
+
'@rollup/[email protected]':
|
277 |
+
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
|
278 |
+
cpu: [riscv64]
|
279 |
+
os: [linux]
|
280 |
+
|
281 |
+
'@rollup/[email protected]':
|
282 |
+
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
|
283 |
+
cpu: [s390x]
|
284 |
+
os: [linux]
|
285 |
+
|
286 |
+
'@rollup/[email protected]':
|
287 |
+
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
|
288 |
+
cpu: [x64]
|
289 |
+
os: [linux]
|
290 |
+
|
291 |
+
'@rollup/[email protected]':
|
292 |
+
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
|
293 |
+
cpu: [x64]
|
294 |
+
os: [linux]
|
295 |
+
|
296 |
+
'@rollup/[email protected]':
|
297 |
+
resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
|
298 |
+
cpu: [arm64]
|
299 |
+
os: [win32]
|
300 |
+
|
301 |
+
'@rollup/[email protected]':
|
302 |
+
resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==}
|
303 |
+
cpu: [ia32]
|
304 |
+
os: [win32]
|
305 |
+
|
306 |
+
'@rollup/[email protected]':
|
307 |
+
resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==}
|
308 |
+
cpu: [x64]
|
309 |
+
os: [win32]
|
310 |
+
|
311 |
+
'@standard-schema/[email protected]':
|
312 |
+
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
|
313 |
+
|
314 |
+
'@sveltejs/[email protected]':
|
315 |
+
resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
|
316 |
+
peerDependencies:
|
317 |
+
acorn: ^8.9.0
|
318 |
+
|
319 |
+
'@sveltejs/[email protected]':
|
320 |
+
resolution: {integrity: sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==}
|
321 |
+
peerDependencies:
|
322 |
+
'@sveltejs/kit': ^2.0.0
|
323 |
+
|
324 |
+
'@sveltejs/[email protected]':
|
325 |
+
resolution: {integrity: sha512-pEX1Z2Km8tqmkni+ykIIou+ojp/7gb3M9tpllN5nDWNo9zlI0dI8/hDKFyBwQvb4jYR+EyLriFtrmgJ6GvbnBA==}
|
326 |
+
engines: {node: '>=18.13'}
|
327 |
+
hasBin: true
|
328 |
+
peerDependencies:
|
329 |
+
'@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0
|
330 |
+
svelte: ^4.0.0 || ^5.0.0-next.0
|
331 |
+
vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0
|
332 |
+
|
333 |
+
'@sveltejs/[email protected]':
|
334 |
+
resolution: {integrity: sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ==}
|
335 |
+
engines: {node: ^20.19 || ^22.12 || >=24}
|
336 |
+
peerDependencies:
|
337 |
+
'@sveltejs/vite-plugin-svelte': ^6.0.0-next.0
|
338 |
+
svelte: ^5.0.0
|
339 |
+
vite: ^6.3.0 || ^7.0.0
|
340 |
+
|
341 |
+
'@sveltejs/[email protected]':
|
342 |
+
resolution: {integrity: sha512-+U6lz1wvGEG/BvQyL4z/flyNdQ9xDNv5vrh+vWBWTHaebqT0c9RNggpZTo/XSPoHsSCWBlYaTlRX8pZ9GATXCw==}
|
343 |
+
engines: {node: ^20.19 || ^22.12 || >=24}
|
344 |
+
peerDependencies:
|
345 |
+
svelte: ^5.0.0
|
346 |
+
vite: ^6.3.0 || ^7.0.0
|
347 |
+
|
348 |
+
'@types/[email protected]':
|
349 |
+
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
350 |
+
|
351 |
+
'@types/[email protected]':
|
352 |
+
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
353 |
+
|
354 | |
355 |
+
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
|
356 |
+
engines: {node: '>=0.4.0'}
|
357 |
+
hasBin: true
|
358 |
+
|
359 | |
360 |
+
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
|
361 |
+
engines: {node: '>= 0.4'}
|
362 |
+
|
363 | |
364 |
+
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
|
365 |
+
engines: {node: '>= 0.4'}
|
366 |
+
|
367 | |
368 |
+
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
369 |
+
engines: {node: '>= 14.16.0'}
|
370 |
+
|
371 | |
372 |
+
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
373 |
+
engines: {node: '>=6'}
|
374 |
+
|
375 | |
376 |
+
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
377 |
+
engines: {node: '>= 0.6'}
|
378 |
+
|
379 | |
380 |
+
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
|
381 |
+
engines: {node: '>=6.0'}
|
382 |
+
peerDependencies:
|
383 |
+
supports-color: '*'
|
384 |
+
peerDependenciesMeta:
|
385 |
+
supports-color:
|
386 |
+
optional: true
|
387 |
+
|
388 | |
389 |
+
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
390 |
+
engines: {node: '>=0.10.0'}
|
391 |
+
|
392 | |
393 |
+
resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
|
394 |
+
|
395 | |
396 |
+
resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==}
|
397 |
+
engines: {node: '>=18'}
|
398 |
+
hasBin: true
|
399 |
+
|
400 | |
401 |
+
resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
|
402 |
+
|
403 | |
404 |
+
resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==}
|
405 |
+
|
406 | |
407 |
+
resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
|
408 |
+
peerDependencies:
|
409 |
+
picomatch: ^3 || ^4
|
410 |
+
peerDependenciesMeta:
|
411 |
+
picomatch:
|
412 |
+
optional: true
|
413 |
+
|
414 | |
415 |
+
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
416 |
+
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
417 |
+
os: [darwin]
|
418 |
+
|
419 | |
420 |
+
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
|
421 |
+
|
422 | |
423 |
+
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
424 |
+
engines: {node: '>=6'}
|
425 |
+
|
426 | |
427 |
+
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
|
428 |
+
|
429 | |
430 |
+
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
431 |
+
|
432 | |
433 |
+
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
434 |
+
engines: {node: '>=4'}
|
435 |
+
|
436 | |
437 |
+
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
|
438 |
+
engines: {node: '>=10'}
|
439 |
+
|
440 | |
441 |
+
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
442 |
+
|
443 | |
444 |
+
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
445 |
+
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
446 |
+
hasBin: true
|
447 |
+
|
448 | |
449 |
+
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
450 |
+
|
451 | |
452 |
+
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
453 |
+
engines: {node: '>=12'}
|
454 |
+
|
455 | |
456 |
+
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
457 |
+
engines: {node: ^10 || ^12 || >=14}
|
458 |
+
|
459 | |
460 |
+
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
461 |
+
engines: {node: '>= 14.18.0'}
|
462 |
+
|
463 | |
464 |
+
resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==}
|
465 |
+
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
466 |
+
hasBin: true
|
467 |
+
|
468 | |
469 |
+
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
470 |
+
engines: {node: '>=6'}
|
471 |
+
|
472 | |
473 |
+
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
474 |
+
|
475 | |
476 |
+
resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
|
477 |
+
engines: {node: '>=18'}
|
478 |
+
|
479 | |
480 |
+
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
481 |
+
engines: {node: '>=0.10.0'}
|
482 |
+
|
483 | |
484 |
+
resolution: {integrity: sha512-lkh8gff5gpHLjxIV+IaApMxQhTGnir2pNUAqcNgeKkvK5bT/30Ey/nzBxNLDlkztCH4dP7PixkMt9SWEKFPBWg==}
|
485 |
+
engines: {node: '>= 18.0.0'}
|
486 |
+
hasBin: true
|
487 |
+
peerDependencies:
|
488 |
+
svelte: ^4.0.0 || ^5.0.0-next.0
|
489 |
+
typescript: '>=5.0.0'
|
490 |
+
|
491 | |
492 |
+
resolution: {integrity: sha512-7t/ejshehHd+95z3Z7ebS7wsqHDQxi/8nBTuTRwpMgNegfRBfuitCSKTUDKIBOExqfT2+DhQ2VLG8Xn+cBXoaQ==}
|
493 |
+
engines: {node: '>=18'}
|
494 |
+
|
495 | |
496 |
+
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
|
497 |
+
engines: {node: '>=12.0.0'}
|
498 |
+
|
499 | |
500 |
+
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
501 |
+
engines: {node: '>=6'}
|
502 |
+
|
503 | |
504 |
+
resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
|
505 |
+
engines: {node: '>=14.17'}
|
506 |
+
hasBin: true
|
507 |
+
|
508 | |
509 |
+
resolution: {integrity: sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==}
|
510 |
+
engines: {node: ^20.19.0 || >=22.12.0}
|
511 |
+
hasBin: true
|
512 |
+
peerDependencies:
|
513 |
+
'@types/node': ^20.19.0 || >=22.12.0
|
514 |
+
jiti: '>=1.21.0'
|
515 |
+
less: ^4.0.0
|
516 |
+
lightningcss: ^1.21.0
|
517 |
+
sass: ^1.70.0
|
518 |
+
sass-embedded: ^1.70.0
|
519 |
+
stylus: '>=0.54.8'
|
520 |
+
sugarss: ^5.0.0
|
521 |
+
terser: ^5.16.0
|
522 |
+
tsx: ^4.8.1
|
523 |
+
yaml: ^2.4.2
|
524 |
+
peerDependenciesMeta:
|
525 |
+
'@types/node':
|
526 |
+
optional: true
|
527 |
+
jiti:
|
528 |
+
optional: true
|
529 |
+
less:
|
530 |
+
optional: true
|
531 |
+
lightningcss:
|
532 |
+
optional: true
|
533 |
+
sass:
|
534 |
+
optional: true
|
535 |
+
sass-embedded:
|
536 |
+
optional: true
|
537 |
+
stylus:
|
538 |
+
optional: true
|
539 |
+
sugarss:
|
540 |
+
optional: true
|
541 |
+
terser:
|
542 |
+
optional: true
|
543 |
+
tsx:
|
544 |
+
optional: true
|
545 |
+
yaml:
|
546 |
+
optional: true
|
547 |
+
|
548 | |
549 |
+
resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
|
550 |
+
peerDependencies:
|
551 |
+
vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
|
552 |
+
peerDependenciesMeta:
|
553 |
+
vite:
|
554 |
+
optional: true
|
555 |
+
|
556 | |
557 |
+
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
|
558 |
+
|
559 |
+
snapshots:
|
560 |
+
|
561 |
+
'@ampproject/[email protected]':
|
562 |
+
dependencies:
|
563 |
+
'@jridgewell/gen-mapping': 0.3.12
|
564 |
+
'@jridgewell/trace-mapping': 0.3.29
|
565 |
+
|
566 |
+
'@esbuild/[email protected]':
|
567 |
+
optional: true
|
568 |
+
|
569 |
+
'@esbuild/[email protected]':
|
570 |
+
optional: true
|
571 |
+
|
572 |
+
'@esbuild/[email protected]':
|
573 |
+
optional: true
|
574 |
+
|
575 |
+
'@esbuild/[email protected]':
|
576 |
+
optional: true
|
577 |
+
|
578 |
+
'@esbuild/[email protected]':
|
579 |
+
optional: true
|
580 |
+
|
581 |
+
'@esbuild/[email protected]':
|
582 |
+
optional: true
|
583 |
+
|
584 |
+
'@esbuild/[email protected]':
|
585 |
+
optional: true
|
586 |
+
|
587 |
+
'@esbuild/[email protected]':
|
588 |
+
optional: true
|
589 |
+
|
590 |
+
'@esbuild/[email protected]':
|
591 |
+
optional: true
|
592 |
+
|
593 |
+
'@esbuild/[email protected]':
|
594 |
+
optional: true
|
595 |
+
|
596 |
+
'@esbuild/[email protected]':
|
597 |
+
optional: true
|
598 |
+
|
599 |
+
'@esbuild/[email protected]':
|
600 |
+
optional: true
|
601 |
+
|
602 |
+
'@esbuild/[email protected]':
|
603 |
+
optional: true
|
604 |
+
|
605 |
+
'@esbuild/[email protected]':
|
606 |
+
optional: true
|
607 |
+
|
608 |
+
'@esbuild/[email protected]':
|
609 |
+
optional: true
|
610 |
+
|
611 |
+
'@esbuild/[email protected]':
|
612 |
+
optional: true
|
613 |
+
|
614 |
+
'@esbuild/[email protected]':
|
615 |
+
optional: true
|
616 |
+
|
617 |
+
'@esbuild/[email protected]':
|
618 |
+
optional: true
|
619 |
+
|
620 |
+
'@esbuild/[email protected]':
|
621 |
+
optional: true
|
622 |
+
|
623 |
+
'@esbuild/[email protected]':
|
624 |
+
optional: true
|
625 |
+
|
626 |
+
'@esbuild/[email protected]':
|
627 |
+
optional: true
|
628 |
+
|
629 |
+
'@esbuild/[email protected]':
|
630 |
+
optional: true
|
631 |
+
|
632 |
+
'@esbuild/[email protected]':
|
633 |
+
optional: true
|
634 |
+
|
635 |
+
'@esbuild/[email protected]':
|
636 |
+
optional: true
|
637 |
+
|
638 |
+
'@esbuild/[email protected]':
|
639 |
+
optional: true
|
640 |
+
|
641 |
+
'@esbuild/[email protected]':
|
642 |
+
optional: true
|
643 |
+
|
644 |
+
'@jridgewell/[email protected]':
|
645 |
+
dependencies:
|
646 |
+
'@jridgewell/sourcemap-codec': 1.5.4
|
647 |
+
'@jridgewell/trace-mapping': 0.3.29
|
648 |
+
|
649 |
+
'@jridgewell/[email protected]': {}
|
650 |
+
|
651 |
+
'@jridgewell/[email protected]': {}
|
652 |
+
|
653 |
+
'@jridgewell/[email protected]':
|
654 |
+
dependencies:
|
655 |
+
'@jridgewell/resolve-uri': 3.1.2
|
656 |
+
'@jridgewell/sourcemap-codec': 1.5.4
|
657 |
+
|
658 |
+
'@polka/[email protected]': {}
|
659 |
+
|
660 |
+
'@rollup/[email protected]':
|
661 |
+
optional: true
|
662 |
+
|
663 |
+
'@rollup/[email protected]':
|
664 |
+
optional: true
|
665 |
+
|
666 |
+
'@rollup/[email protected]':
|
667 |
+
optional: true
|
668 |
+
|
669 |
+
'@rollup/[email protected]':
|
670 |
+
optional: true
|
671 |
+
|
672 |
+
'@rollup/[email protected]':
|
673 |
+
optional: true
|
674 |
+
|
675 |
+
'@rollup/[email protected]':
|
676 |
+
optional: true
|
677 |
+
|
678 |
+
'@rollup/[email protected]':
|
679 |
+
optional: true
|
680 |
+
|
681 |
+
'@rollup/[email protected]':
|
682 |
+
optional: true
|
683 |
+
|
684 |
+
'@rollup/[email protected]':
|
685 |
+
optional: true
|
686 |
+
|
687 |
+
'@rollup/[email protected]':
|
688 |
+
optional: true
|
689 |
+
|
690 |
+
'@rollup/[email protected]':
|
691 |
+
optional: true
|
692 |
+
|
693 |
+
'@rollup/[email protected]':
|
694 |
+
optional: true
|
695 |
+
|
696 |
+
'@rollup/[email protected]':
|
697 |
+
optional: true
|
698 |
+
|
699 |
+
'@rollup/[email protected]':
|
700 |
+
optional: true
|
701 |
+
|
702 |
+
'@rollup/[email protected]':
|
703 |
+
optional: true
|
704 |
+
|
705 |
+
'@rollup/[email protected]':
|
706 |
+
optional: true
|
707 |
+
|
708 |
+
'@rollup/[email protected]':
|
709 |
+
optional: true
|
710 |
+
|
711 |
+
'@rollup/[email protected]':
|
712 |
+
optional: true
|
713 |
+
|
714 |
+
'@rollup/[email protected]':
|
715 |
+
optional: true
|
716 |
+
|
717 |
+
'@rollup/[email protected]':
|
718 |
+
optional: true
|
719 |
+
|
720 |
+
'@standard-schema/[email protected]': {}
|
721 |
+
|
722 |
+
'@sveltejs/[email protected]([email protected])':
|
723 |
+
dependencies:
|
724 |
+
acorn: 8.15.0
|
725 |
+
|
726 |
+
'@sveltejs/[email protected](@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected]))':
|
727 |
+
dependencies:
|
728 |
+
'@sveltejs/kit': 2.27.0(@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected])
|
729 |
+
|
730 |
+
'@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected])':
|
731 |
+
dependencies:
|
732 |
+
'@standard-schema/spec': 1.0.0
|
733 |
+
'@sveltejs/acorn-typescript': 1.0.5([email protected])
|
734 |
+
'@sveltejs/vite-plugin-svelte': 6.1.0([email protected])([email protected])
|
735 |
+
'@types/cookie': 0.6.0
|
736 |
+
acorn: 8.15.0
|
737 |
+
cookie: 0.6.0
|
738 |
+
devalue: 5.1.1
|
739 |
+
esm-env: 1.2.2
|
740 |
+
kleur: 4.1.5
|
741 |
+
magic-string: 0.30.17
|
742 |
+
mrmime: 2.0.1
|
743 |
+
sade: 1.8.1
|
744 |
+
set-cookie-parser: 2.7.1
|
745 |
+
sirv: 3.0.1
|
746 |
+
svelte: 5.37.3
|
747 |
+
vite: 7.0.6
|
748 |
+
|
749 |
+
'@sveltejs/[email protected](@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected])':
|
750 |
+
dependencies:
|
751 |
+
'@sveltejs/vite-plugin-svelte': 6.1.0([email protected])([email protected])
|
752 |
+
debug: 4.4.1
|
753 |
+
svelte: 5.37.3
|
754 |
+
vite: 7.0.6
|
755 |
+
transitivePeerDependencies:
|
756 |
+
- supports-color
|
757 |
+
|
758 |
+
'@sveltejs/[email protected]([email protected])([email protected])':
|
759 |
+
dependencies:
|
760 |
+
'@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/[email protected]([email protected])([email protected]))([email protected])([email protected])
|
761 |
+
debug: 4.4.1
|
762 |
+
deepmerge: 4.3.1
|
763 |
+
kleur: 4.1.5
|
764 |
+
magic-string: 0.30.17
|
765 |
+
svelte: 5.37.3
|
766 |
+
vite: 7.0.6
|
767 |
+
vitefu: 1.1.1([email protected])
|
768 |
+
transitivePeerDependencies:
|
769 |
+
- supports-color
|
770 |
+
|
771 |
+
'@types/[email protected]': {}
|
772 |
+
|
773 |
+
'@types/[email protected]': {}
|
774 |
+
|
775 |
+
[email protected]: {}
|
776 |
+
|
777 |
+
[email protected]: {}
|
778 |
+
|
779 |
+
[email protected]: {}
|
780 |
+
|
781 | |
782 |
+
dependencies:
|
783 |
+
readdirp: 4.1.2
|
784 |
+
|
785 |
+
[email protected]: {}
|
786 |
+
|
787 |
+
[email protected]: {}
|
788 |
+
|
789 | |
790 |
+
dependencies:
|
791 |
+
ms: 2.1.3
|
792 |
+
|
793 |
+
[email protected]: {}
|
794 |
+
|
795 |
+
[email protected]: {}
|
796 |
+
|
797 | |
798 |
+
optionalDependencies:
|
799 |
+
'@esbuild/aix-ppc64': 0.25.8
|
800 |
+
'@esbuild/android-arm': 0.25.8
|
801 |
+
'@esbuild/android-arm64': 0.25.8
|
802 |
+
'@esbuild/android-x64': 0.25.8
|
803 |
+
'@esbuild/darwin-arm64': 0.25.8
|
804 |
+
'@esbuild/darwin-x64': 0.25.8
|
805 |
+
'@esbuild/freebsd-arm64': 0.25.8
|
806 |
+
'@esbuild/freebsd-x64': 0.25.8
|
807 |
+
'@esbuild/linux-arm': 0.25.8
|
808 |
+
'@esbuild/linux-arm64': 0.25.8
|
809 |
+
'@esbuild/linux-ia32': 0.25.8
|
810 |
+
'@esbuild/linux-loong64': 0.25.8
|
811 |
+
'@esbuild/linux-mips64el': 0.25.8
|
812 |
+
'@esbuild/linux-ppc64': 0.25.8
|
813 |
+
'@esbuild/linux-riscv64': 0.25.8
|
814 |
+
'@esbuild/linux-s390x': 0.25.8
|
815 |
+
'@esbuild/linux-x64': 0.25.8
|
816 |
+
'@esbuild/netbsd-arm64': 0.25.8
|
817 |
+
'@esbuild/netbsd-x64': 0.25.8
|
818 |
+
'@esbuild/openbsd-arm64': 0.25.8
|
819 |
+
'@esbuild/openbsd-x64': 0.25.8
|
820 |
+
'@esbuild/openharmony-arm64': 0.25.8
|
821 |
+
'@esbuild/sunos-x64': 0.25.8
|
822 |
+
'@esbuild/win32-arm64': 0.25.8
|
823 |
+
'@esbuild/win32-ia32': 0.25.8
|
824 |
+
'@esbuild/win32-x64': 0.25.8
|
825 |
+
|
826 |
+
[email protected]: {}
|
827 |
+
|
828 | |
829 |
+
dependencies:
|
830 |
+
'@jridgewell/sourcemap-codec': 1.5.4
|
831 |
+
|
832 | |
833 |
+
optionalDependencies:
|
834 |
+
picomatch: 4.0.3
|
835 |
+
|
836 | |
837 |
+
optional: true
|
838 |
+
|
839 | |
840 |
+
dependencies:
|
841 |
+
'@types/estree': 1.0.8
|
842 |
+
|
843 |
+
[email protected]: {}
|
844 |
+
|
845 |
+
[email protected]: {}
|
846 |
+
|
847 | |
848 |
+
dependencies:
|
849 |
+
'@jridgewell/sourcemap-codec': 1.5.4
|
850 |
+
|
851 |
+
[email protected]: {}
|
852 |
+
|
853 |
+
[email protected]: {}
|
854 |
+
|
855 |
+
[email protected]: {}
|
856 |
+
|
857 |
+
[email protected]: {}
|
858 |
+
|
859 |
+
[email protected]: {}
|
860 |
+
|
861 |
+
[email protected]: {}
|
862 |
+
|
863 | |
864 |
+
dependencies:
|
865 |
+
nanoid: 3.3.11
|
866 |
+
picocolors: 1.1.1
|
867 |
+
source-map-js: 1.2.1
|
868 |
+
|
869 |
+
[email protected]: {}
|
870 |
+
|
871 | |
872 |
+
dependencies:
|
873 |
+
'@types/estree': 1.0.8
|
874 |
+
optionalDependencies:
|
875 |
+
'@rollup/rollup-android-arm-eabi': 4.46.2
|
876 |
+
'@rollup/rollup-android-arm64': 4.46.2
|
877 |
+
'@rollup/rollup-darwin-arm64': 4.46.2
|
878 |
+
'@rollup/rollup-darwin-x64': 4.46.2
|
879 |
+
'@rollup/rollup-freebsd-arm64': 4.46.2
|
880 |
+
'@rollup/rollup-freebsd-x64': 4.46.2
|
881 |
+
'@rollup/rollup-linux-arm-gnueabihf': 4.46.2
|
882 |
+
'@rollup/rollup-linux-arm-musleabihf': 4.46.2
|
883 |
+
'@rollup/rollup-linux-arm64-gnu': 4.46.2
|
884 |
+
'@rollup/rollup-linux-arm64-musl': 4.46.2
|
885 |
+
'@rollup/rollup-linux-loongarch64-gnu': 4.46.2
|
886 |
+
'@rollup/rollup-linux-ppc64-gnu': 4.46.2
|
887 |
+
'@rollup/rollup-linux-riscv64-gnu': 4.46.2
|
888 |
+
'@rollup/rollup-linux-riscv64-musl': 4.46.2
|
889 |
+
'@rollup/rollup-linux-s390x-gnu': 4.46.2
|
890 |
+
'@rollup/rollup-linux-x64-gnu': 4.46.2
|
891 |
+
'@rollup/rollup-linux-x64-musl': 4.46.2
|
892 |
+
'@rollup/rollup-win32-arm64-msvc': 4.46.2
|
893 |
+
'@rollup/rollup-win32-ia32-msvc': 4.46.2
|
894 |
+
'@rollup/rollup-win32-x64-msvc': 4.46.2
|
895 |
+
fsevents: 2.3.3
|
896 |
+
|
897 | |
898 |
+
dependencies:
|
899 |
+
mri: 1.2.0
|
900 |
+
|
901 |
+
[email protected]: {}
|
902 |
+
|
903 | |
904 |
+
dependencies:
|
905 |
+
'@polka/url': 1.0.0-next.29
|
906 |
+
mrmime: 2.0.1
|
907 |
+
totalist: 3.0.1
|
908 |
+
|
909 |
+
[email protected]: {}
|
910 |
+
|
911 | |
912 |
+
dependencies:
|
913 |
+
'@jridgewell/trace-mapping': 0.3.29
|
914 |
+
chokidar: 4.0.3
|
915 |
+
fdir: 6.4.6([email protected])
|
916 |
+
picocolors: 1.1.1
|
917 |
+
sade: 1.8.1
|
918 |
+
svelte: 5.37.3
|
919 |
+
typescript: 5.9.2
|
920 |
+
transitivePeerDependencies:
|
921 |
+
- picomatch
|
922 |
+
|
923 | |
924 |
+
dependencies:
|
925 |
+
'@ampproject/remapping': 2.3.0
|
926 |
+
'@jridgewell/sourcemap-codec': 1.5.4
|
927 |
+
'@sveltejs/acorn-typescript': 1.0.5([email protected])
|
928 |
+
'@types/estree': 1.0.8
|
929 |
+
acorn: 8.15.0
|
930 |
+
aria-query: 5.3.2
|
931 |
+
axobject-query: 4.1.0
|
932 |
+
clsx: 2.1.1
|
933 |
+
esm-env: 1.2.2
|
934 |
+
esrap: 2.1.0
|
935 |
+
is-reference: 3.0.3
|
936 |
+
locate-character: 3.0.0
|
937 |
+
magic-string: 0.30.17
|
938 |
+
zimmerframe: 1.1.2
|
939 |
+
|
940 | |
941 |
+
dependencies:
|
942 |
+
fdir: 6.4.6([email protected])
|
943 |
+
picomatch: 4.0.3
|
944 |
+
|
945 |
+
[email protected]: {}
|
946 |
+
|
947 |
+
[email protected]: {}
|
948 |
+
|
949 | |
950 |
+
dependencies:
|
951 |
+
esbuild: 0.25.8
|
952 |
+
fdir: 6.4.6([email protected])
|
953 |
+
picomatch: 4.0.3
|
954 |
+
postcss: 8.5.6
|
955 |
+
rollup: 4.46.2
|
956 |
+
tinyglobby: 0.2.14
|
957 |
+
optionalDependencies:
|
958 |
+
fsevents: 2.3.3
|
959 |
+
|
960 | |
961 |
+
optionalDependencies:
|
962 |
+
vite: 7.0.6
|
963 |
+
|
964 |
+
[email protected]: {}
|
public/vite.svg
DELETED
src/App.svelte
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
<script lang="ts">
|
2 |
-
import svelteLogo from './assets/svelte.svg'
|
3 |
-
import viteLogo from '/vite.svg'
|
4 |
-
import Counter from './lib/Counter.svelte'
|
5 |
-
</script>
|
6 |
-
|
7 |
-
<main>
|
8 |
-
<div>
|
9 |
-
<a href="https://vite.dev" target="_blank" rel="noreferrer">
|
10 |
-
<img src={viteLogo} class="logo" alt="Vite Logo" />
|
11 |
-
</a>
|
12 |
-
<a href="https://svelte.dev" target="_blank" rel="noreferrer">
|
13 |
-
<img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
|
14 |
-
</a>
|
15 |
-
</div>
|
16 |
-
<h1>Vite + Svelte</h1>
|
17 |
-
|
18 |
-
<div class="card">
|
19 |
-
<Counter />
|
20 |
-
</div>
|
21 |
-
|
22 |
-
<p>
|
23 |
-
Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank" rel="noreferrer">SvelteKit</a>, the official Svelte app framework powered by Vite!
|
24 |
-
</p>
|
25 |
-
|
26 |
-
<p class="read-the-docs">
|
27 |
-
Click on the Vite and Svelte logos to learn more
|
28 |
-
</p>
|
29 |
-
</main>
|
30 |
-
|
31 |
-
<style>
|
32 |
-
.logo {
|
33 |
-
height: 6em;
|
34 |
-
padding: 1.5em;
|
35 |
-
will-change: filter;
|
36 |
-
transition: filter 300ms;
|
37 |
-
}
|
38 |
-
.logo:hover {
|
39 |
-
filter: drop-shadow(0 0 2em #646cffaa);
|
40 |
-
}
|
41 |
-
.logo.svelte:hover {
|
42 |
-
filter: drop-shadow(0 0 2em #ff3e00aa);
|
43 |
-
}
|
44 |
-
.read-the-docs {
|
45 |
-
color: #888;
|
46 |
-
}
|
47 |
-
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app.css
DELETED
@@ -1,79 +0,0 @@
|
|
1 |
-
:root {
|
2 |
-
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
3 |
-
line-height: 1.5;
|
4 |
-
font-weight: 400;
|
5 |
-
|
6 |
-
color-scheme: light dark;
|
7 |
-
color: rgba(255, 255, 255, 0.87);
|
8 |
-
background-color: #242424;
|
9 |
-
|
10 |
-
font-synthesis: none;
|
11 |
-
text-rendering: optimizeLegibility;
|
12 |
-
-webkit-font-smoothing: antialiased;
|
13 |
-
-moz-osx-font-smoothing: grayscale;
|
14 |
-
}
|
15 |
-
|
16 |
-
a {
|
17 |
-
font-weight: 500;
|
18 |
-
color: #646cff;
|
19 |
-
text-decoration: inherit;
|
20 |
-
}
|
21 |
-
a:hover {
|
22 |
-
color: #535bf2;
|
23 |
-
}
|
24 |
-
|
25 |
-
body {
|
26 |
-
margin: 0;
|
27 |
-
display: flex;
|
28 |
-
place-items: center;
|
29 |
-
min-width: 320px;
|
30 |
-
min-height: 100vh;
|
31 |
-
}
|
32 |
-
|
33 |
-
h1 {
|
34 |
-
font-size: 3.2em;
|
35 |
-
line-height: 1.1;
|
36 |
-
}
|
37 |
-
|
38 |
-
.card {
|
39 |
-
padding: 2em;
|
40 |
-
}
|
41 |
-
|
42 |
-
#app {
|
43 |
-
max-width: 1280px;
|
44 |
-
margin: 0 auto;
|
45 |
-
padding: 2rem;
|
46 |
-
text-align: center;
|
47 |
-
}
|
48 |
-
|
49 |
-
button {
|
50 |
-
border-radius: 8px;
|
51 |
-
border: 1px solid transparent;
|
52 |
-
padding: 0.6em 1.2em;
|
53 |
-
font-size: 1em;
|
54 |
-
font-weight: 500;
|
55 |
-
font-family: inherit;
|
56 |
-
background-color: #1a1a1a;
|
57 |
-
cursor: pointer;
|
58 |
-
transition: border-color 0.25s;
|
59 |
-
}
|
60 |
-
button:hover {
|
61 |
-
border-color: #646cff;
|
62 |
-
}
|
63 |
-
button:focus,
|
64 |
-
button:focus-visible {
|
65 |
-
outline: 4px auto -webkit-focus-ring-color;
|
66 |
-
}
|
67 |
-
|
68 |
-
@media (prefers-color-scheme: light) {
|
69 |
-
:root {
|
70 |
-
color: #213547;
|
71 |
-
background-color: #ffffff;
|
72 |
-
}
|
73 |
-
a:hover {
|
74 |
-
color: #747bff;
|
75 |
-
}
|
76 |
-
button {
|
77 |
-
background-color: #f9f9f9;
|
78 |
-
}
|
79 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app.d.ts
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// See https://svelte.dev/docs/kit/types#app.d.ts
|
2 |
+
// for information about these interfaces
|
3 |
+
declare global {
|
4 |
+
namespace App {
|
5 |
+
// interface Error {}
|
6 |
+
// interface Locals {}
|
7 |
+
// interface PageData {}
|
8 |
+
// interface PageState {}
|
9 |
+
// interface Platform {}
|
10 |
+
}
|
11 |
+
}
|
12 |
+
|
13 |
+
export {};
|
src/app.html
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!doctype html>
|
2 |
+
<html lang="en">
|
3 |
+
|
4 |
+
<head>
|
5 |
+
<meta charset="utf-8" />
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
7 |
+
<title>XORB & Shard File Viewer</title>
|
8 |
+
<meta name="description" content="Parse and view metadata from XORB and Shard object files" />
|
9 |
+
%sveltekit.head%
|
10 |
+
</head>
|
11 |
+
|
12 |
+
<body data-sveltekit-preload-data="hover">
|
13 |
+
<div style="display: contents">%sveltekit.body%</div>
|
14 |
+
</body>
|
15 |
+
|
16 |
+
</html>
|
src/assets/svelte.svg
DELETED
src/lib/Counter.svelte
DELETED
@@ -1,10 +0,0 @@
|
|
1 |
-
<script lang="ts">
|
2 |
-
let count: number = $state(0)
|
3 |
-
const increment = () => {
|
4 |
-
count += 1
|
5 |
-
}
|
6 |
-
</script>
|
7 |
-
|
8 |
-
<button onclick={increment}>
|
9 |
-
count is {count}
|
10 |
-
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/assets/favicon.svg
ADDED
|
src/lib/components/ErrorDisplay.svelte
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
export let error: string;
|
3 |
+
export let filename: string = "";
|
4 |
+
</script>
|
5 |
+
|
6 |
+
<div class="error-container">
|
7 |
+
<div class="error-content">
|
8 |
+
<div class="error-icon">⚠️</div>
|
9 |
+
<h3>Error Parsing File</h3>
|
10 |
+
{#if filename}
|
11 |
+
<p class="filename">File: {filename}</p>
|
12 |
+
{/if}
|
13 |
+
<div class="error-message">
|
14 |
+
{error}
|
15 |
+
</div>
|
16 |
+
<div class="suggestions">
|
17 |
+
<h4>Suggestions:</h4>
|
18 |
+
<ul>
|
19 |
+
<li>Verify that the file is a valid XORB or Shard file</li>
|
20 |
+
<li>Check that the file is not corrupted</li>
|
21 |
+
<li>Ensure the file format matches the expected binary structure</li>
|
22 |
+
</ul>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
|
27 |
+
<style>
|
28 |
+
.error-container {
|
29 |
+
max-width: 600px;
|
30 |
+
margin: 20px auto;
|
31 |
+
padding: 20px;
|
32 |
+
}
|
33 |
+
|
34 |
+
.error-content {
|
35 |
+
background: #fee;
|
36 |
+
border: 1px solid #fcc;
|
37 |
+
border-radius: 8px;
|
38 |
+
padding: 30px;
|
39 |
+
text-align: center;
|
40 |
+
}
|
41 |
+
|
42 |
+
.error-icon {
|
43 |
+
font-size: 48px;
|
44 |
+
margin-bottom: 16px;
|
45 |
+
}
|
46 |
+
|
47 |
+
.error-content h3 {
|
48 |
+
margin: 0 0 16px 0;
|
49 |
+
color: #d32f2f;
|
50 |
+
font-size: 20px;
|
51 |
+
font-weight: 600;
|
52 |
+
}
|
53 |
+
|
54 |
+
.filename {
|
55 |
+
font-family: "Monaco", "Consolas", monospace;
|
56 |
+
background: #fff;
|
57 |
+
padding: 8px 12px;
|
58 |
+
border-radius: 4px;
|
59 |
+
margin: 0 0 20px 0;
|
60 |
+
color: #666;
|
61 |
+
border: 1px solid #eee;
|
62 |
+
}
|
63 |
+
|
64 |
+
.error-message {
|
65 |
+
background: #fff;
|
66 |
+
border: 1px solid #fcc;
|
67 |
+
border-radius: 4px;
|
68 |
+
padding: 16px;
|
69 |
+
margin: 20px 0;
|
70 |
+
font-family: "Monaco", "Consolas", monospace;
|
71 |
+
font-size: 14px;
|
72 |
+
color: #d32f2f;
|
73 |
+
text-align: left;
|
74 |
+
white-space: pre-wrap;
|
75 |
+
}
|
76 |
+
|
77 |
+
.suggestions {
|
78 |
+
text-align: left;
|
79 |
+
margin-top: 20px;
|
80 |
+
background: #fff9c4;
|
81 |
+
border: 1px solid #f7e97d;
|
82 |
+
border-radius: 4px;
|
83 |
+
padding: 16px;
|
84 |
+
}
|
85 |
+
|
86 |
+
.suggestions h4 {
|
87 |
+
margin: 0 0 12px 0;
|
88 |
+
color: #8d6e00;
|
89 |
+
font-size: 16px;
|
90 |
+
}
|
91 |
+
|
92 |
+
.suggestions ul {
|
93 |
+
margin: 0;
|
94 |
+
padding-left: 20px;
|
95 |
+
color: #8d6e00;
|
96 |
+
}
|
97 |
+
|
98 |
+
.suggestions li {
|
99 |
+
margin-bottom: 8px;
|
100 |
+
}
|
101 |
+
</style>
|
src/lib/components/FileUpload.svelte
ADDED
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { createEventDispatcher } from "svelte";
|
3 |
+
|
4 |
+
const dispatch = createEventDispatcher<{
|
5 |
+
fileSelected: { file: File; type: "xorb" | "shard" };
|
6 |
+
}>();
|
7 |
+
|
8 |
+
let xorbDragActive = false;
|
9 |
+
let shardDragActive = false;
|
10 |
+
let xorbFileInput: HTMLInputElement;
|
11 |
+
let shardFileInput: HTMLInputElement;
|
12 |
+
|
13 |
+
function handleDragOver(event: DragEvent, type: "xorb" | "shard") {
|
14 |
+
event.preventDefault();
|
15 |
+
if (type === "xorb") {
|
16 |
+
xorbDragActive = true;
|
17 |
+
} else {
|
18 |
+
shardDragActive = true;
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
function handleDragLeave(type: "xorb" | "shard") {
|
23 |
+
if (type === "xorb") {
|
24 |
+
xorbDragActive = false;
|
25 |
+
} else {
|
26 |
+
shardDragActive = false;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
function handleDrop(event: DragEvent, type: "xorb" | "shard") {
|
31 |
+
event.preventDefault();
|
32 |
+
if (type === "xorb") {
|
33 |
+
xorbDragActive = false;
|
34 |
+
} else {
|
35 |
+
shardDragActive = false;
|
36 |
+
}
|
37 |
+
|
38 |
+
const files = event.dataTransfer?.files;
|
39 |
+
if (files && files.length > 0) {
|
40 |
+
handleFile(files[0], type);
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
function handleFileInput(event: Event, type: "xorb" | "shard") {
|
45 |
+
const input = event.target as HTMLInputElement;
|
46 |
+
if (input.files && input.files.length > 0) {
|
47 |
+
handleFile(input.files[0], type);
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
function handleFile(file: File, type: "xorb" | "shard") {
|
52 |
+
dispatch("fileSelected", { file, type });
|
53 |
+
}
|
54 |
+
|
55 |
+
function openFileDialog(type: "xorb" | "shard") {
|
56 |
+
if (type === "xorb") {
|
57 |
+
xorbFileInput.click();
|
58 |
+
} else {
|
59 |
+
shardFileInput.click();
|
60 |
+
}
|
61 |
+
}
|
62 |
+
</script>
|
63 |
+
|
64 |
+
<div class="upload-container">
|
65 |
+
<div class="upload-areas">
|
66 |
+
<!-- XORB Upload Area -->
|
67 |
+
<div class="upload-section">
|
68 |
+
<h3>📦 Upload XORB File</h3>
|
69 |
+
<div
|
70 |
+
class="upload-area xorb-area"
|
71 |
+
class:drag-active={xorbDragActive}
|
72 |
+
on:dragover={(e) => handleDragOver(e, "xorb")}
|
73 |
+
on:dragleave={() => handleDragLeave("xorb")}
|
74 |
+
on:drop={(e) => handleDrop(e, "xorb")}
|
75 |
+
on:click={() => openFileDialog("xorb")}
|
76 |
+
on:keydown={(e) => e.key === "Enter" && openFileDialog("xorb")}
|
77 |
+
role="button"
|
78 |
+
tabindex="0"
|
79 |
+
>
|
80 |
+
<div class="upload-content">
|
81 |
+
<div class="upload-icon">📦</div>
|
82 |
+
<h4>Drop XORB file here</h4>
|
83 |
+
<p>or click to browse</p>
|
84 |
+
<span class="format-tag xorb-tag">XORB</span>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
</div>
|
88 |
+
|
89 |
+
<!-- Shard Upload Area -->
|
90 |
+
<div class="upload-section">
|
91 |
+
<h3>🗂️ Upload Shard File</h3>
|
92 |
+
<div
|
93 |
+
class="upload-area shard-area"
|
94 |
+
class:drag-active={shardDragActive}
|
95 |
+
on:dragover={(e) => handleDragOver(e, "shard")}
|
96 |
+
on:dragleave={() => handleDragLeave("shard")}
|
97 |
+
on:drop={(e) => handleDrop(e, "shard")}
|
98 |
+
on:click={() => openFileDialog("shard")}
|
99 |
+
on:keydown={(e) => e.key === "Enter" && openFileDialog("shard")}
|
100 |
+
role="button"
|
101 |
+
tabindex="0"
|
102 |
+
>
|
103 |
+
<div class="upload-content">
|
104 |
+
<div class="upload-icon">🗂️</div>
|
105 |
+
<h4>Drop Shard file here</h4>
|
106 |
+
<p>or click to browse</p>
|
107 |
+
<span class="format-tag shard-tag">SHARD</span>
|
108 |
+
</div>
|
109 |
+
</div>
|
110 |
+
</div>
|
111 |
+
</div>
|
112 |
+
|
113 |
+
<input
|
114 |
+
bind:this={xorbFileInput}
|
115 |
+
type="file"
|
116 |
+
on:change={(e) => handleFileInput(e, "xorb")}
|
117 |
+
style="display: none;"
|
118 |
+
/>
|
119 |
+
|
120 |
+
<input
|
121 |
+
bind:this={shardFileInput}
|
122 |
+
type="file"
|
123 |
+
on:change={(e) => handleFileInput(e, "shard")}
|
124 |
+
style="display: none;"
|
125 |
+
/>
|
126 |
+
</div>
|
127 |
+
|
128 |
+
<style>
|
129 |
+
.upload-container {
|
130 |
+
width: 100%;
|
131 |
+
max-width: 800px;
|
132 |
+
margin: 0 auto;
|
133 |
+
}
|
134 |
+
|
135 |
+
.upload-areas {
|
136 |
+
display: grid;
|
137 |
+
grid-template-columns: 1fr 1fr;
|
138 |
+
gap: 30px;
|
139 |
+
}
|
140 |
+
|
141 |
+
.upload-section {
|
142 |
+
text-align: center;
|
143 |
+
}
|
144 |
+
|
145 |
+
.upload-section h3 {
|
146 |
+
margin: 0 0 20px 0;
|
147 |
+
color: #2c3e50;
|
148 |
+
font-size: 18px;
|
149 |
+
font-weight: 600;
|
150 |
+
}
|
151 |
+
|
152 |
+
.upload-area {
|
153 |
+
border: 2px dashed #ccc;
|
154 |
+
border-radius: 8px;
|
155 |
+
padding: 30px 20px;
|
156 |
+
text-align: center;
|
157 |
+
cursor: pointer;
|
158 |
+
transition: all 0.3s ease;
|
159 |
+
background: #fafafa;
|
160 |
+
min-height: 200px;
|
161 |
+
display: flex;
|
162 |
+
align-items: center;
|
163 |
+
justify-content: center;
|
164 |
+
}
|
165 |
+
|
166 |
+
.xorb-area:hover {
|
167 |
+
border-color: #28a745;
|
168 |
+
background: #f0fff4;
|
169 |
+
}
|
170 |
+
|
171 |
+
.xorb-area.drag-active {
|
172 |
+
border-color: #28a745;
|
173 |
+
background: #e8f5e8;
|
174 |
+
transform: scale(1.02);
|
175 |
+
}
|
176 |
+
|
177 |
+
.shard-area:hover {
|
178 |
+
border-color: #007bff;
|
179 |
+
background: #f0f8ff;
|
180 |
+
}
|
181 |
+
|
182 |
+
.shard-area.drag-active {
|
183 |
+
border-color: #007bff;
|
184 |
+
background: #e3f2fd;
|
185 |
+
transform: scale(1.02);
|
186 |
+
}
|
187 |
+
|
188 |
+
.upload-content {
|
189 |
+
pointer-events: none;
|
190 |
+
}
|
191 |
+
|
192 |
+
.upload-icon {
|
193 |
+
font-size: 36px;
|
194 |
+
margin-bottom: 12px;
|
195 |
+
}
|
196 |
+
|
197 |
+
.upload-area h4 {
|
198 |
+
margin: 0 0 8px 0;
|
199 |
+
color: #333;
|
200 |
+
font-weight: 600;
|
201 |
+
font-size: 16px;
|
202 |
+
}
|
203 |
+
|
204 |
+
.upload-area p {
|
205 |
+
margin: 0 0 16px 0;
|
206 |
+
color: #666;
|
207 |
+
font-size: 14px;
|
208 |
+
}
|
209 |
+
|
210 |
+
.format-tag {
|
211 |
+
color: white;
|
212 |
+
padding: 4px 12px;
|
213 |
+
border-radius: 16px;
|
214 |
+
font-size: 12px;
|
215 |
+
font-weight: 600;
|
216 |
+
}
|
217 |
+
|
218 |
+
.xorb-tag {
|
219 |
+
background: #28a745;
|
220 |
+
}
|
221 |
+
|
222 |
+
.shard-tag {
|
223 |
+
background: #007bff;
|
224 |
+
}
|
225 |
+
|
226 |
+
@media (max-width: 768px) {
|
227 |
+
.upload-areas {
|
228 |
+
grid-template-columns: 1fr;
|
229 |
+
gap: 20px;
|
230 |
+
}
|
231 |
+
|
232 |
+
.upload-area {
|
233 |
+
padding: 20px 15px;
|
234 |
+
min-height: 150px;
|
235 |
+
}
|
236 |
+
|
237 |
+
.upload-icon {
|
238 |
+
font-size: 28px;
|
239 |
+
}
|
240 |
+
}
|
241 |
+
</style>
|
src/lib/components/ShardViewer.svelte
ADDED
@@ -0,0 +1,543 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import type { ShardData } from "../types.js";
|
3 |
+
import { formatBytes, formatHash, formatTimestamp } from "../parsers.js";
|
4 |
+
|
5 |
+
export let data: ShardData;
|
6 |
+
export let filename: string;
|
7 |
+
export let fileSize: number;
|
8 |
+
|
9 |
+
$: header = data.header;
|
10 |
+
$: footer = data.footer;
|
11 |
+
$: totalFiles = data.file_info.length;
|
12 |
+
$: totalXorbs = data.cas_info.length;
|
13 |
+
$: totalChunks = data.cas_info.reduce(
|
14 |
+
(sum, cas) => sum + cas.header.num_entries,
|
15 |
+
0
|
16 |
+
);
|
17 |
+
|
18 |
+
// Check verification and metadata status across all files
|
19 |
+
$: {
|
20 |
+
const filesWithVerification = data.file_info.filter(
|
21 |
+
(fileInfo) => fileInfo.header.file_flags & 0x80000000
|
22 |
+
).length;
|
23 |
+
const filesWithMetadata = data.file_info.filter(
|
24 |
+
(fileInfo) => fileInfo.header.file_flags & 0x40000000
|
25 |
+
).length;
|
26 |
+
|
27 |
+
verificationStatus =
|
28 |
+
filesWithVerification === totalFiles
|
29 |
+
? "✅"
|
30 |
+
: filesWithVerification === 0
|
31 |
+
? "❌"
|
32 |
+
: "❓";
|
33 |
+
|
34 |
+
metadataStatus =
|
35 |
+
filesWithMetadata === totalFiles
|
36 |
+
? "✅"
|
37 |
+
: filesWithMetadata === 0
|
38 |
+
? "❌"
|
39 |
+
: "❓";
|
40 |
+
}
|
41 |
+
|
42 |
+
let verificationStatus = "";
|
43 |
+
let metadataStatus = "";
|
44 |
+
$: totalStoredBytes = data.cas_info.reduce(
|
45 |
+
(sum, cas) => sum + cas.header.num_bytes_in_cas,
|
46 |
+
0
|
47 |
+
);
|
48 |
+
|
49 |
+
// Track which files are expanded
|
50 |
+
let expandedFiles = new Set<number>();
|
51 |
+
|
52 |
+
function toggleFileExpansion(fileIndex: number) {
|
53 |
+
if (expandedFiles.has(fileIndex)) {
|
54 |
+
expandedFiles.delete(fileIndex);
|
55 |
+
} else {
|
56 |
+
expandedFiles.add(fileIndex);
|
57 |
+
}
|
58 |
+
expandedFiles = expandedFiles; // Trigger reactivity
|
59 |
+
}
|
60 |
+
</script>
|
61 |
+
|
62 |
+
<div class="shard-viewer">
|
63 |
+
<div class="header">
|
64 |
+
<h2>🗂️ Shard File Analysis</h2>
|
65 |
+
<div class="file-info">
|
66 |
+
<span class="filename">{filename}</span>
|
67 |
+
<span class="file-size">{formatBytes(fileSize)}</span>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
|
71 |
+
<div class="metadata-grid">
|
72 |
+
<div class="metadata-section">
|
73 |
+
<h3>Header Information</h3>
|
74 |
+
<div class="metadata-item">
|
75 |
+
<span class="label">Version:</span>
|
76 |
+
<span class="value">{header.version}</span>
|
77 |
+
</div>
|
78 |
+
<div class="metadata-item">
|
79 |
+
<span class="label">Footer Size:</span>
|
80 |
+
<span class="value">{formatBytes(header.footer_size)}</span>
|
81 |
+
</div>
|
82 |
+
</div>
|
83 |
+
|
84 |
+
<div class="metadata-section">
|
85 |
+
<h3>Content Statistics</h3>
|
86 |
+
<div class="metadata-item">
|
87 |
+
<span class="label">Files:</span>
|
88 |
+
<span class="value">{totalFiles.toLocaleString()}</span>
|
89 |
+
</div>
|
90 |
+
<div class="metadata-item">
|
91 |
+
<span class="label">XORBs:</span>
|
92 |
+
<span class="value">{totalXorbs.toLocaleString()}</span>
|
93 |
+
</div>
|
94 |
+
<div class="metadata-item">
|
95 |
+
<span class="label">Total Chunks:</span>
|
96 |
+
<span class="value">{totalChunks.toLocaleString()}</span>
|
97 |
+
</div>
|
98 |
+
<div class="metadata-item">
|
99 |
+
<span class="label">Stored Bytes:</span>
|
100 |
+
<span class="value">{formatBytes(totalStoredBytes)}</span>
|
101 |
+
</div>
|
102 |
+
</div>
|
103 |
+
|
104 |
+
<div class="metadata-section">
|
105 |
+
<h3>Timestamps & Security</h3>
|
106 |
+
<div class="metadata-item">
|
107 |
+
<span class="label">Created:</span>
|
108 |
+
<span class="value"
|
109 |
+
>{formatTimestamp(footer.shard_creation_timestamp)}</span
|
110 |
+
>
|
111 |
+
</div>
|
112 |
+
<div class="metadata-item">
|
113 |
+
<span class="label">Key Expiry:</span>
|
114 |
+
<span class="value">{formatTimestamp(footer.shard_key_expiry)}</span>
|
115 |
+
</div>
|
116 |
+
<div class="metadata-item">
|
117 |
+
<span class="label">HMAC Key:</span>
|
118 |
+
<span class="value hash" title={formatHash(footer.chunk_hash_hmac_key)}>
|
119 |
+
{formatHash(footer.chunk_hash_hmac_key)}
|
120 |
+
</span>
|
121 |
+
</div>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
|
125 |
+
{#if data.file_info.length > 0}
|
126 |
+
<div class="file-details">
|
127 |
+
<h3>
|
128 |
+
File Information ({data.file_info.length} files) - Verification: {verificationStatus}
|
129 |
+
Metadata: {metadataStatus}
|
130 |
+
</h3>
|
131 |
+
<div class="table-container">
|
132 |
+
<table class="data-table">
|
133 |
+
<thead>
|
134 |
+
<tr>
|
135 |
+
<th>File Hash</th>
|
136 |
+
<th>Entries</th>
|
137 |
+
<th>Total Length</th>
|
138 |
+
<th>SHA256</th>
|
139 |
+
</tr>
|
140 |
+
</thead>
|
141 |
+
<tbody>
|
142 |
+
{#each data.file_info as fileInfo, fileIndex}
|
143 |
+
<tr
|
144 |
+
class="file-row"
|
145 |
+
class:expanded={expandedFiles.has(fileIndex)}
|
146 |
+
on:click={() => toggleFileExpansion(fileIndex)}
|
147 |
+
role="button"
|
148 |
+
tabindex="0"
|
149 |
+
on:keydown={(e) =>
|
150 |
+
e.key === "Enter" && toggleFileExpansion(fileIndex)}
|
151 |
+
>
|
152 |
+
<td class="hash" title={formatHash(fileInfo.header.file_hash)}>
|
153 |
+
<span class="expand-icon">
|
154 |
+
{expandedFiles.has(fileIndex) ? "▼" : "▶"}
|
155 |
+
</span>
|
156 |
+
{formatHash(fileInfo.header.file_hash)}
|
157 |
+
</td>
|
158 |
+
<td>{fileInfo.header.num_entries}</td>
|
159 |
+
<td>
|
160 |
+
{formatBytes(
|
161 |
+
fileInfo.entries.reduce(
|
162 |
+
(sum, entry) => sum + entry.unpacked_segment_bytes,
|
163 |
+
0
|
164 |
+
)
|
165 |
+
)}
|
166 |
+
</td>
|
167 |
+
<td>
|
168 |
+
{#if fileInfo.metadata_ext}
|
169 |
+
<span
|
170 |
+
class="hash"
|
171 |
+
title={formatHash(fileInfo.metadata_ext.sha256)}
|
172 |
+
>
|
173 |
+
{formatHash(fileInfo.metadata_ext.sha256)}
|
174 |
+
</span>
|
175 |
+
{:else}
|
176 |
+
<span class="no-data">—</span>
|
177 |
+
{/if}
|
178 |
+
</td>
|
179 |
+
</tr>
|
180 |
+
{#if expandedFiles.has(fileIndex)}
|
181 |
+
<tr class="file-details-row">
|
182 |
+
<td colspan="4">
|
183 |
+
<div class="file-entries-container">
|
184 |
+
<div class="entries-table-container">
|
185 |
+
<h4>Data Entries for File</h4>
|
186 |
+
<table class="entries-table">
|
187 |
+
<thead>
|
188 |
+
<tr>
|
189 |
+
<th>Entry #</th>
|
190 |
+
<th>CAS Hash</th>
|
191 |
+
<th>Chunk Range</th>
|
192 |
+
<th>Unpacked Size</th>
|
193 |
+
</tr>
|
194 |
+
</thead>
|
195 |
+
<tbody>
|
196 |
+
{#each fileInfo.entries as entry, entryIndex}
|
197 |
+
<tr>
|
198 |
+
<td>{entryIndex + 1}</td>
|
199 |
+
<td
|
200 |
+
class="hash"
|
201 |
+
title={formatHash(entry.cas_hash)}
|
202 |
+
>
|
203 |
+
{formatHash(entry.cas_hash)}
|
204 |
+
</td>
|
205 |
+
<td
|
206 |
+
>{entry.chunk_index_start} - {entry.chunk_index_end}</td
|
207 |
+
>
|
208 |
+
<td
|
209 |
+
>{formatBytes(
|
210 |
+
entry.unpacked_segment_bytes
|
211 |
+
)}</td
|
212 |
+
>
|
213 |
+
</tr>
|
214 |
+
{/each}
|
215 |
+
</tbody>
|
216 |
+
</table>
|
217 |
+
</div>
|
218 |
+
</div>
|
219 |
+
</td>
|
220 |
+
</tr>
|
221 |
+
{/if}
|
222 |
+
{/each}
|
223 |
+
</tbody>
|
224 |
+
</table>
|
225 |
+
</div>
|
226 |
+
</div>
|
227 |
+
{/if}
|
228 |
+
|
229 |
+
{#if data.cas_info.length > 0}
|
230 |
+
<div class="cas-details">
|
231 |
+
<h3>CAS Information ({data.cas_info.length} XORBs)</h3>
|
232 |
+
<div class="table-container">
|
233 |
+
<table class="data-table">
|
234 |
+
<thead>
|
235 |
+
<tr>
|
236 |
+
<th>CAS Hash</th>
|
237 |
+
<th>Chunks</th>
|
238 |
+
<th>Bytes in CAS</th>
|
239 |
+
<th>Bytes on Disk</th>
|
240 |
+
<th>Compression</th>
|
241 |
+
</tr>
|
242 |
+
</thead>
|
243 |
+
<tbody>
|
244 |
+
{#each data.cas_info as casInfo}
|
245 |
+
<tr>
|
246 |
+
<td class="hash" title={formatHash(casInfo.header.cas_hash)}>
|
247 |
+
{formatHash(casInfo.header.cas_hash)}
|
248 |
+
</td>
|
249 |
+
<td>{casInfo.header.num_entries}</td>
|
250 |
+
<td>{formatBytes(casInfo.header.num_bytes_in_cas)}</td>
|
251 |
+
<td>{formatBytes(casInfo.header.num_bytes_on_disk)}</td>
|
252 |
+
<td>
|
253 |
+
{casInfo.header.num_bytes_in_cas > 0
|
254 |
+
? (
|
255 |
+
(casInfo.header.num_bytes_on_disk /
|
256 |
+
casInfo.header.num_bytes_in_cas) *
|
257 |
+
100
|
258 |
+
).toFixed(1) + "%"
|
259 |
+
: "N/A"}
|
260 |
+
</td>
|
261 |
+
</tr>
|
262 |
+
{/each}
|
263 |
+
</tbody>
|
264 |
+
</table>
|
265 |
+
</div>
|
266 |
+
</div>
|
267 |
+
{/if}
|
268 |
+
</div>
|
269 |
+
|
270 |
+
<style>
|
271 |
+
.shard-viewer {
|
272 |
+
max-width: 1200px;
|
273 |
+
margin: 0 auto;
|
274 |
+
padding: 20px;
|
275 |
+
}
|
276 |
+
|
277 |
+
.header {
|
278 |
+
display: flex;
|
279 |
+
justify-content: space-between;
|
280 |
+
align-items: center;
|
281 |
+
margin-bottom: 30px;
|
282 |
+
padding-bottom: 20px;
|
283 |
+
border-bottom: 2px solid #eee;
|
284 |
+
}
|
285 |
+
|
286 |
+
.header h2 {
|
287 |
+
margin: 0;
|
288 |
+
color: #333;
|
289 |
+
font-size: 24px;
|
290 |
+
}
|
291 |
+
|
292 |
+
.file-info {
|
293 |
+
display: flex;
|
294 |
+
flex-direction: column;
|
295 |
+
align-items: flex-end;
|
296 |
+
gap: 4px;
|
297 |
+
}
|
298 |
+
|
299 |
+
.filename {
|
300 |
+
font-weight: 600;
|
301 |
+
color: #555;
|
302 |
+
}
|
303 |
+
|
304 |
+
.file-size {
|
305 |
+
font-size: 14px;
|
306 |
+
color: #888;
|
307 |
+
}
|
308 |
+
|
309 |
+
.metadata-grid {
|
310 |
+
display: grid;
|
311 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
312 |
+
gap: 20px;
|
313 |
+
margin-bottom: 30px;
|
314 |
+
}
|
315 |
+
|
316 |
+
.metadata-section {
|
317 |
+
background: #f8f9fa;
|
318 |
+
padding: 20px;
|
319 |
+
border-radius: 8px;
|
320 |
+
border: 1px solid #e9ecef;
|
321 |
+
}
|
322 |
+
|
323 |
+
.metadata-section h3 {
|
324 |
+
margin: 0 0 15px 0;
|
325 |
+
color: #495057;
|
326 |
+
font-size: 18px;
|
327 |
+
font-weight: 600;
|
328 |
+
}
|
329 |
+
|
330 |
+
.metadata-item {
|
331 |
+
display: flex;
|
332 |
+
justify-content: space-between;
|
333 |
+
align-items: center;
|
334 |
+
margin-bottom: 12px;
|
335 |
+
padding: 8px 0;
|
336 |
+
border-bottom: 1px solid #e9ecef;
|
337 |
+
}
|
338 |
+
|
339 |
+
.metadata-item:last-child {
|
340 |
+
border-bottom: none;
|
341 |
+
margin-bottom: 0;
|
342 |
+
}
|
343 |
+
|
344 |
+
.metadata-item .label {
|
345 |
+
font-weight: 500;
|
346 |
+
color: #6c757d;
|
347 |
+
margin-right: 10px;
|
348 |
+
}
|
349 |
+
|
350 |
+
.metadata-item .value {
|
351 |
+
font-family: "Monaco", "Consolas", monospace;
|
352 |
+
font-size: 14px;
|
353 |
+
color: #212529;
|
354 |
+
text-align: right;
|
355 |
+
}
|
356 |
+
|
357 |
+
.hash {
|
358 |
+
font-family: "Monaco", "Consolas", monospace;
|
359 |
+
background: #e9ecef;
|
360 |
+
padding: 2px 6px;
|
361 |
+
border-radius: 4px;
|
362 |
+
cursor: help;
|
363 |
+
font-size: 12px;
|
364 |
+
}
|
365 |
+
|
366 |
+
.file-details,
|
367 |
+
.cas-details {
|
368 |
+
margin-top: 30px;
|
369 |
+
}
|
370 |
+
|
371 |
+
.file-details h3,
|
372 |
+
.cas-details h3 {
|
373 |
+
margin: 0 0 20px 0;
|
374 |
+
color: #495057;
|
375 |
+
font-size: 18px;
|
376 |
+
font-weight: 600;
|
377 |
+
}
|
378 |
+
|
379 |
+
.table-container {
|
380 |
+
overflow-x: auto;
|
381 |
+
border-radius: 8px;
|
382 |
+
border: 1px solid #e9ecef;
|
383 |
+
}
|
384 |
+
|
385 |
+
.data-table {
|
386 |
+
width: 100%;
|
387 |
+
border-collapse: collapse;
|
388 |
+
background: white;
|
389 |
+
}
|
390 |
+
|
391 |
+
.data-table th,
|
392 |
+
.data-table td {
|
393 |
+
padding: 12px;
|
394 |
+
text-align: left;
|
395 |
+
border-bottom: 1px solid #e9ecef;
|
396 |
+
}
|
397 |
+
|
398 |
+
.data-table th {
|
399 |
+
background: #f8f9fa;
|
400 |
+
font-weight: 600;
|
401 |
+
color: #495057;
|
402 |
+
}
|
403 |
+
|
404 |
+
.data-table tr:hover {
|
405 |
+
background: #f8f9fa;
|
406 |
+
}
|
407 |
+
|
408 |
+
.no-data {
|
409 |
+
color: #999;
|
410 |
+
font-style: italic;
|
411 |
+
}
|
412 |
+
|
413 |
+
/* Expandable file rows */
|
414 |
+
.file-row {
|
415 |
+
cursor: pointer;
|
416 |
+
transition: background-color 0.2s ease;
|
417 |
+
}
|
418 |
+
|
419 |
+
.file-row:hover {
|
420 |
+
background-color: #f0f7ff !important;
|
421 |
+
}
|
422 |
+
|
423 |
+
.file-row.expanded {
|
424 |
+
background-color: #e3f2fd;
|
425 |
+
}
|
426 |
+
|
427 |
+
.expand-icon {
|
428 |
+
display: inline-block;
|
429 |
+
margin-right: 8px;
|
430 |
+
font-size: 12px;
|
431 |
+
width: 12px;
|
432 |
+
transition: transform 0.2s ease;
|
433 |
+
}
|
434 |
+
|
435 |
+
.file-details-row {
|
436 |
+
background-color: #f8f9fa;
|
437 |
+
}
|
438 |
+
|
439 |
+
.file-details-row td {
|
440 |
+
padding: 0;
|
441 |
+
}
|
442 |
+
|
443 |
+
.file-entries-container {
|
444 |
+
padding: 16px;
|
445 |
+
border-left: 3px solid #007bff;
|
446 |
+
margin-left: 12px;
|
447 |
+
max-height: 90vh;
|
448 |
+
overflow-y: auto;
|
449 |
+
overflow-x: hidden;
|
450 |
+
border-radius: 6px;
|
451 |
+
background-color: #f8f9fa;
|
452 |
+
}
|
453 |
+
|
454 |
+
/* Scrollbar styling for webkit browsers */
|
455 |
+
.file-entries-container::-webkit-scrollbar {
|
456 |
+
width: 6px;
|
457 |
+
}
|
458 |
+
|
459 |
+
.file-entries-container::-webkit-scrollbar-track {
|
460 |
+
background: #f1f1f1;
|
461 |
+
border-radius: 3px;
|
462 |
+
}
|
463 |
+
|
464 |
+
.file-entries-container::-webkit-scrollbar-thumb {
|
465 |
+
background: #c1c1c1;
|
466 |
+
border-radius: 3px;
|
467 |
+
}
|
468 |
+
|
469 |
+
.file-entries-container::-webkit-scrollbar-thumb:hover {
|
470 |
+
background: #a8a8a8;
|
471 |
+
}
|
472 |
+
|
473 |
+
.file-entries-container h4 {
|
474 |
+
margin: 0 0 12px 0;
|
475 |
+
color: #495057;
|
476 |
+
font-size: 14px;
|
477 |
+
font-weight: 600;
|
478 |
+
position: sticky;
|
479 |
+
top: 0;
|
480 |
+
background-color: #f8f9fa;
|
481 |
+
padding: 8px 0;
|
482 |
+
z-index: 1;
|
483 |
+
}
|
484 |
+
|
485 |
+
.entries-table-container {
|
486 |
+
overflow-x: auto;
|
487 |
+
border-radius: 6px;
|
488 |
+
border: 1px solid #dee2e6;
|
489 |
+
}
|
490 |
+
|
491 |
+
.entries-table {
|
492 |
+
width: 100%;
|
493 |
+
border-collapse: collapse;
|
494 |
+
background: white;
|
495 |
+
font-size: 13px;
|
496 |
+
}
|
497 |
+
|
498 |
+
.entries-table th,
|
499 |
+
.entries-table td {
|
500 |
+
padding: 8px 12px;
|
501 |
+
text-align: left;
|
502 |
+
border-bottom: 1px solid #dee2e6;
|
503 |
+
}
|
504 |
+
|
505 |
+
.entries-table th {
|
506 |
+
background: #f1f3f4;
|
507 |
+
font-weight: 600;
|
508 |
+
color: #495057;
|
509 |
+
font-size: 12px;
|
510 |
+
}
|
511 |
+
|
512 |
+
.entries-table tr:hover {
|
513 |
+
background: #f8f9fa;
|
514 |
+
}
|
515 |
+
|
516 |
+
.entries-table .hash {
|
517 |
+
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
|
518 |
+
font-size: 11px;
|
519 |
+
color: #6c757d;
|
520 |
+
}
|
521 |
+
|
522 |
+
@media (max-width: 768px) {
|
523 |
+
.header {
|
524 |
+
flex-direction: column;
|
525 |
+
align-items: flex-start;
|
526 |
+
gap: 10px;
|
527 |
+
}
|
528 |
+
|
529 |
+
.metadata-grid {
|
530 |
+
grid-template-columns: 1fr;
|
531 |
+
}
|
532 |
+
|
533 |
+
.metadata-item {
|
534 |
+
flex-direction: column;
|
535 |
+
align-items: flex-start;
|
536 |
+
gap: 4px;
|
537 |
+
}
|
538 |
+
|
539 |
+
.metadata-item .value {
|
540 |
+
text-align: left;
|
541 |
+
}
|
542 |
+
}
|
543 |
+
</style>
|
src/lib/components/XorbViewer.svelte
ADDED
@@ -0,0 +1,273 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import type { Chunk } from "../types.js";
|
3 |
+
import { formatBytes } from "../parsers.js";
|
4 |
+
|
5 |
+
export let data: Chunk[];
|
6 |
+
export let filename: string;
|
7 |
+
export let fileSize: number;
|
8 |
+
|
9 |
+
$: totalChunks = data.length;
|
10 |
+
$: totalCompressedSize = data.reduce(
|
11 |
+
(sum, chunk) => sum + chunk.header.compressed_size,
|
12 |
+
0
|
13 |
+
);
|
14 |
+
$: totalUncompressedSize = data.reduce(
|
15 |
+
(sum, chunk) => sum + chunk.header.uncompressed_size,
|
16 |
+
0
|
17 |
+
);
|
18 |
+
$: averageChunkSize =
|
19 |
+
totalChunks > 0 ? totalUncompressedSize / totalChunks : 0;
|
20 |
+
$: compressionRatio =
|
21 |
+
totalUncompressedSize > 0
|
22 |
+
? (totalCompressedSize / totalUncompressedSize) * 100
|
23 |
+
: 0;
|
24 |
+
|
25 |
+
function getCompressionTypeName(type: number): string {
|
26 |
+
switch (type) {
|
27 |
+
case 0:
|
28 |
+
return "None";
|
29 |
+
case 1:
|
30 |
+
return "LZ4";
|
31 |
+
case 2:
|
32 |
+
return "Zstd";
|
33 |
+
case 3:
|
34 |
+
return "Gzip";
|
35 |
+
default:
|
36 |
+
return `Unknown (${type})`;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
</script>
|
40 |
+
|
41 |
+
<div class="xorb-viewer">
|
42 |
+
<div class="header">
|
43 |
+
<h2>📦 XORB File Analysis</h2>
|
44 |
+
<div class="file-info">
|
45 |
+
<span class="filename">{filename}</span>
|
46 |
+
<span class="file-size">{formatBytes(fileSize)}</span>
|
47 |
+
</div>
|
48 |
+
</div>
|
49 |
+
|
50 |
+
<div class="metadata-grid">
|
51 |
+
<div class="metadata-section">
|
52 |
+
<h3>File Information</h3>
|
53 |
+
<div class="metadata-item">
|
54 |
+
<span class="label">File Size:</span>
|
55 |
+
<span class="value">{formatBytes(fileSize)}</span>
|
56 |
+
</div>
|
57 |
+
<div class="metadata-item">
|
58 |
+
<span class="label">Total Chunks:</span>
|
59 |
+
<span class="value">{totalChunks.toLocaleString()}</span>
|
60 |
+
</div>
|
61 |
+
</div>
|
62 |
+
|
63 |
+
<div class="metadata-section">
|
64 |
+
<h3>Compression Statistics</h3>
|
65 |
+
<div class="metadata-item">
|
66 |
+
<span class="label">Total Compressed Size:</span>
|
67 |
+
<span class="value">{formatBytes(totalCompressedSize)}</span>
|
68 |
+
</div>
|
69 |
+
<div class="metadata-item">
|
70 |
+
<span class="label">Total Uncompressed Size:</span>
|
71 |
+
<span class="value">{formatBytes(totalUncompressedSize)}</span>
|
72 |
+
</div>
|
73 |
+
<div class="metadata-item">
|
74 |
+
<span class="label">Overall Compression Ratio:</span>
|
75 |
+
<span class="value">{compressionRatio.toFixed(1)}%</span>
|
76 |
+
</div>
|
77 |
+
<div class="metadata-item">
|
78 |
+
<span class="label">Average Chunk Size:</span>
|
79 |
+
<span class="value">{formatBytes(averageChunkSize)}</span>
|
80 |
+
</div>
|
81 |
+
</div>
|
82 |
+
</div>
|
83 |
+
|
84 |
+
{#if data.length > 0}
|
85 |
+
<div class="chunk-details">
|
86 |
+
<h3>Chunk Headers ({data.length} chunks)</h3>
|
87 |
+
<div class="chunk-table-container">
|
88 |
+
<table class="chunk-table">
|
89 |
+
<thead>
|
90 |
+
<tr>
|
91 |
+
<th>Index</th>
|
92 |
+
<th>Version</th>
|
93 |
+
<th>Compression Type</th>
|
94 |
+
<th>Compressed Size</th>
|
95 |
+
<th>Uncompressed Size</th>
|
96 |
+
<th>Compression Ratio</th>
|
97 |
+
</tr>
|
98 |
+
</thead>
|
99 |
+
<tbody>
|
100 |
+
{#each data as chunk, i}
|
101 |
+
<tr>
|
102 |
+
<td>{i}</td>
|
103 |
+
<td>{chunk.header.version}</td>
|
104 |
+
<td>{getCompressionTypeName(chunk.header.compression_type)}</td>
|
105 |
+
<td>{formatBytes(chunk.header.compressed_size)}</td>
|
106 |
+
<td>{formatBytes(chunk.header.uncompressed_size)}</td>
|
107 |
+
<td>
|
108 |
+
{chunk.header.uncompressed_size > 0
|
109 |
+
? (
|
110 |
+
(chunk.header.compressed_size /
|
111 |
+
chunk.header.uncompressed_size) *
|
112 |
+
100
|
113 |
+
).toFixed(1) + "%"
|
114 |
+
: "N/A"}
|
115 |
+
</td>
|
116 |
+
</tr>
|
117 |
+
{/each}
|
118 |
+
</tbody>
|
119 |
+
</table>
|
120 |
+
</div>
|
121 |
+
</div>
|
122 |
+
{/if}
|
123 |
+
</div>
|
124 |
+
|
125 |
+
<style>
|
126 |
+
.xorb-viewer {
|
127 |
+
max-width: 1200px;
|
128 |
+
margin: 0 auto;
|
129 |
+
padding: 20px;
|
130 |
+
}
|
131 |
+
|
132 |
+
.header {
|
133 |
+
display: flex;
|
134 |
+
justify-content: space-between;
|
135 |
+
align-items: center;
|
136 |
+
margin-bottom: 30px;
|
137 |
+
padding-bottom: 20px;
|
138 |
+
border-bottom: 2px solid #eee;
|
139 |
+
}
|
140 |
+
|
141 |
+
.header h2 {
|
142 |
+
margin: 0;
|
143 |
+
color: #333;
|
144 |
+
font-size: 24px;
|
145 |
+
}
|
146 |
+
|
147 |
+
.file-info {
|
148 |
+
display: flex;
|
149 |
+
flex-direction: column;
|
150 |
+
align-items: flex-end;
|
151 |
+
gap: 4px;
|
152 |
+
}
|
153 |
+
|
154 |
+
.filename {
|
155 |
+
font-weight: 600;
|
156 |
+
color: #555;
|
157 |
+
}
|
158 |
+
|
159 |
+
.file-size {
|
160 |
+
font-size: 14px;
|
161 |
+
color: #888;
|
162 |
+
}
|
163 |
+
|
164 |
+
.metadata-grid {
|
165 |
+
display: grid;
|
166 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
167 |
+
gap: 20px;
|
168 |
+
margin-bottom: 30px;
|
169 |
+
}
|
170 |
+
|
171 |
+
.metadata-section {
|
172 |
+
background: #f8f9fa;
|
173 |
+
padding: 20px;
|
174 |
+
border-radius: 8px;
|
175 |
+
border: 1px solid #e9ecef;
|
176 |
+
}
|
177 |
+
|
178 |
+
.metadata-section h3 {
|
179 |
+
margin: 0 0 15px 0;
|
180 |
+
color: #495057;
|
181 |
+
font-size: 18px;
|
182 |
+
font-weight: 600;
|
183 |
+
}
|
184 |
+
|
185 |
+
.metadata-item {
|
186 |
+
display: flex;
|
187 |
+
justify-content: space-between;
|
188 |
+
align-items: center;
|
189 |
+
margin-bottom: 12px;
|
190 |
+
padding: 8px 0;
|
191 |
+
border-bottom: 1px solid #e9ecef;
|
192 |
+
}
|
193 |
+
|
194 |
+
.metadata-item:last-child {
|
195 |
+
border-bottom: none;
|
196 |
+
margin-bottom: 0;
|
197 |
+
}
|
198 |
+
|
199 |
+
.metadata-item .label {
|
200 |
+
font-weight: 500;
|
201 |
+
color: #6c757d;
|
202 |
+
margin-right: 10px;
|
203 |
+
}
|
204 |
+
|
205 |
+
.metadata-item .value {
|
206 |
+
font-family: "Monaco", "Consolas", monospace;
|
207 |
+
font-size: 14px;
|
208 |
+
color: #212529;
|
209 |
+
text-align: right;
|
210 |
+
}
|
211 |
+
|
212 |
+
.chunk-details {
|
213 |
+
margin-top: 30px;
|
214 |
+
}
|
215 |
+
|
216 |
+
.chunk-details h3 {
|
217 |
+
margin: 0 0 20px 0;
|
218 |
+
color: #495057;
|
219 |
+
font-size: 18px;
|
220 |
+
font-weight: 600;
|
221 |
+
}
|
222 |
+
|
223 |
+
.chunk-table-container {
|
224 |
+
overflow-x: auto;
|
225 |
+
border-radius: 8px;
|
226 |
+
border: 1px solid #e9ecef;
|
227 |
+
}
|
228 |
+
|
229 |
+
.chunk-table {
|
230 |
+
width: 100%;
|
231 |
+
border-collapse: collapse;
|
232 |
+
background: white;
|
233 |
+
}
|
234 |
+
|
235 |
+
.chunk-table th,
|
236 |
+
.chunk-table td {
|
237 |
+
padding: 12px;
|
238 |
+
text-align: left;
|
239 |
+
border-bottom: 1px solid #e9ecef;
|
240 |
+
}
|
241 |
+
|
242 |
+
.chunk-table th {
|
243 |
+
background: #f8f9fa;
|
244 |
+
font-weight: 600;
|
245 |
+
color: #495057;
|
246 |
+
}
|
247 |
+
|
248 |
+
.chunk-table tr:hover {
|
249 |
+
background: #f8f9fa;
|
250 |
+
}
|
251 |
+
|
252 |
+
@media (max-width: 768px) {
|
253 |
+
.header {
|
254 |
+
flex-direction: column;
|
255 |
+
align-items: flex-start;
|
256 |
+
gap: 10px;
|
257 |
+
}
|
258 |
+
|
259 |
+
.metadata-grid {
|
260 |
+
grid-template-columns: 1fr;
|
261 |
+
}
|
262 |
+
|
263 |
+
.metadata-item {
|
264 |
+
flex-direction: column;
|
265 |
+
align-items: flex-start;
|
266 |
+
gap: 4px;
|
267 |
+
}
|
268 |
+
|
269 |
+
.metadata-item .value {
|
270 |
+
text-align: left;
|
271 |
+
}
|
272 |
+
}
|
273 |
+
</style>
|
src/lib/index.ts
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
// place files you want to import through the `$lib` alias in this folder.
|
src/lib/parsers.ts
ADDED
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Binary parsers for xorb and shard files
|
2 |
+
|
3 |
+
import type {
|
4 |
+
ParsedFileMetadata,
|
5 |
+
Chunk,
|
6 |
+
ChunkHeader,
|
7 |
+
ShardData,
|
8 |
+
MerkleHash,
|
9 |
+
HMACKey,
|
10 |
+
MDBShardFileHeader,
|
11 |
+
MDBShardFileFooter,
|
12 |
+
FileDataSequenceHeader,
|
13 |
+
FileDataSequenceEntry,
|
14 |
+
FileVerificationEntry,
|
15 |
+
FileMetadataExt,
|
16 |
+
CASChunkSequenceHeader,
|
17 |
+
CASChunkSequenceEntry,
|
18 |
+
MDBFileInfo,
|
19 |
+
MDBCASInfo,
|
20 |
+
} from "./types.js";
|
21 |
+
import { MDB_SHARD_HEADER_TAG, XORB_IDENT } from "./types.js";
|
22 |
+
|
23 |
+
export class BinaryReader {
|
24 |
+
private data: Uint8Array;
|
25 |
+
private offset: number = 0;
|
26 |
+
|
27 |
+
constructor(data: Uint8Array) {
|
28 |
+
this.data = data;
|
29 |
+
}
|
30 |
+
|
31 |
+
readUint8(): number {
|
32 |
+
if (this.offset >= this.data.length) {
|
33 |
+
console.trace();
|
34 |
+
throw new Error("Unexpected end of data");
|
35 |
+
}
|
36 |
+
return this.data[this.offset++];
|
37 |
+
}
|
38 |
+
|
39 |
+
readUint32LE(): number {
|
40 |
+
if (this.offset + 4 > this.data.length) {
|
41 |
+
console.trace();
|
42 |
+
throw new Error("Unexpected end of data");
|
43 |
+
}
|
44 |
+
const result = new DataView(this.data.buffer).getUint32(this.offset, true);
|
45 |
+
this.offset += 4;
|
46 |
+
return result;
|
47 |
+
}
|
48 |
+
|
49 |
+
readUint64LE(): bigint {
|
50 |
+
if (this.offset + 8 > this.data.length) {
|
51 |
+
console.trace();
|
52 |
+
throw new Error("Unexpected end of data");
|
53 |
+
}
|
54 |
+
const result = new DataView(this.data.buffer).getBigUint64(
|
55 |
+
this.offset,
|
56 |
+
true
|
57 |
+
);
|
58 |
+
this.offset += 8;
|
59 |
+
return result;
|
60 |
+
}
|
61 |
+
|
62 |
+
readBytes(length: number): Uint8Array {
|
63 |
+
if (this.offset + length > this.data.length) {
|
64 |
+
console.trace();
|
65 |
+
throw new Error("Unexpected end of data");
|
66 |
+
}
|
67 |
+
const result = this.data.slice(this.offset, this.offset + length);
|
68 |
+
this.offset += length;
|
69 |
+
return result;
|
70 |
+
}
|
71 |
+
|
72 |
+
readHash(): MerkleHash {
|
73 |
+
return { data: this.readBytes(32) };
|
74 |
+
}
|
75 |
+
|
76 |
+
readHMACKey(): HMACKey {
|
77 |
+
return { data: this.readBytes(32) };
|
78 |
+
}
|
79 |
+
|
80 |
+
readString(length: number): string {
|
81 |
+
const bytes = this.readBytes(length);
|
82 |
+
return new TextDecoder().decode(bytes);
|
83 |
+
}
|
84 |
+
|
85 |
+
seek(position: number): void {
|
86 |
+
this.offset = position;
|
87 |
+
}
|
88 |
+
|
89 |
+
seekFromEnd(offsetFromEnd: number): void {
|
90 |
+
this.offset = this.data.length - offsetFromEnd;
|
91 |
+
}
|
92 |
+
|
93 |
+
get position(): number {
|
94 |
+
return this.offset;
|
95 |
+
}
|
96 |
+
|
97 |
+
get remaining(): number {
|
98 |
+
return this.data.length - this.offset;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
|
102 |
+
function arraysEqual(a: Uint8Array, b: Uint8Array): boolean {
|
103 |
+
if (a.length !== b.length) return false;
|
104 |
+
for (let i = 0; i < a.length; i++) {
|
105 |
+
if (a[i] !== b[i]) return false;
|
106 |
+
}
|
107 |
+
return true;
|
108 |
+
}
|
109 |
+
|
110 |
+
function isBookendHash(hash: MerkleHash): boolean {
|
111 |
+
// Bookend hash is all 0xFF bytes
|
112 |
+
return hash.data.every((byte) => byte === 0xff);
|
113 |
+
}
|
114 |
+
|
115 |
+
function reorderHash(hash: MerkleHash): Array<number> {
|
116 |
+
const data = new Array(32);
|
117 |
+
let start = 0;
|
118 |
+
for (let i = 0; i < 32; i++) {
|
119 |
+
if (i % 8 === 0) {
|
120 |
+
start += 8;
|
121 |
+
}
|
122 |
+
data.push(hash.data[start - (i % 8) - 1]);
|
123 |
+
}
|
124 |
+
return data;
|
125 |
+
}
|
126 |
+
|
127 |
+
function formatHash(hash: MerkleHash): string {
|
128 |
+
return reorderHash(hash)
|
129 |
+
.map((b) => b.toString(16).padStart(2, "0"))
|
130 |
+
.join("");
|
131 |
+
}
|
132 |
+
|
133 |
+
// File type detection removed - type is now specified by user selection
|
134 |
+
|
135 |
+
function parseXorbFile(data: Uint8Array): Chunk[] {
|
136 |
+
const reader = new BinaryReader(data);
|
137 |
+
|
138 |
+
const chunks: Chunk[] = [];
|
139 |
+
|
140 |
+
while (reader.remaining > 0) {
|
141 |
+
// Check if we have enough bytes for a header
|
142 |
+
if (reader.remaining < 8) {
|
143 |
+
console.error("Unexpected end of data parsing xorb file");
|
144 |
+
break;
|
145 |
+
}
|
146 |
+
|
147 |
+
const header_bytes = reader.readBytes(8);
|
148 |
+
let is_xorb_ident = true;
|
149 |
+
// Urgh how do I compare two Uint8Arrays?
|
150 |
+
for (let i = 0; i < 7; i++) {
|
151 |
+
if (header_bytes[i] !== XORB_IDENT[i]) {
|
152 |
+
is_xorb_ident = false;
|
153 |
+
break;
|
154 |
+
}
|
155 |
+
}
|
156 |
+
if (is_xorb_ident) {
|
157 |
+
// reached optional xorb footer, skip rest
|
158 |
+
break;
|
159 |
+
}
|
160 |
+
|
161 |
+
const header = new DataView(header_bytes.buffer);
|
162 |
+
|
163 |
+
const version = header.getUint8(0);
|
164 |
+
const compressed_size =
|
165 |
+
header.getUint8(1) |
|
166 |
+
(header.getUint8(2) << 8) |
|
167 |
+
(header.getUint8(3) << 16);
|
168 |
+
const compression_type = header.getUint8(4);
|
169 |
+
const uncompressed_size =
|
170 |
+
header.getUint8(5) |
|
171 |
+
(header.getUint8(6) << 8) |
|
172 |
+
(header.getUint8(7) << 16);
|
173 |
+
|
174 |
+
const chunkHeader: ChunkHeader = {
|
175 |
+
version,
|
176 |
+
compressed_size,
|
177 |
+
compression_type,
|
178 |
+
uncompressed_size,
|
179 |
+
};
|
180 |
+
|
181 |
+
const compressed_data = reader.readBytes(compressed_size);
|
182 |
+
|
183 |
+
chunks.push({ header: chunkHeader, compressed_data });
|
184 |
+
}
|
185 |
+
|
186 |
+
return chunks;
|
187 |
+
}
|
188 |
+
|
189 |
+
function parseShardFile(data: Uint8Array): ShardData {
|
190 |
+
const reader = new BinaryReader(data);
|
191 |
+
|
192 |
+
// Parse header
|
193 |
+
const tag = reader.readBytes(32);
|
194 |
+
if (!arraysEqual(tag, MDB_SHARD_HEADER_TAG)) {
|
195 |
+
throw new Error("Invalid shard file header tag");
|
196 |
+
}
|
197 |
+
|
198 |
+
const header: MDBShardFileHeader = {
|
199 |
+
tag,
|
200 |
+
version: Number(reader.readUint64LE()),
|
201 |
+
footer_size: Number(reader.readUint64LE()),
|
202 |
+
};
|
203 |
+
|
204 |
+
if (header.version !== 2) {
|
205 |
+
throw new Error(`Unsupported shard header version: ${header.version}`);
|
206 |
+
}
|
207 |
+
|
208 |
+
// Parse footer (from end of file)
|
209 |
+
reader.seekFromEnd(header.footer_size);
|
210 |
+
const version = Number(reader.readUint64LE());
|
211 |
+
const file_info_offset = Number(reader.readUint64LE());
|
212 |
+
const cas_info_offset = Number(reader.readUint64LE());
|
213 |
+
|
214 |
+
// Skip first buffer (48 bytes)
|
215 |
+
reader.readBytes(48);
|
216 |
+
|
217 |
+
const chunk_hash_hmac_key = reader.readHMACKey();
|
218 |
+
const shard_creation_timestamp = Number(reader.readUint64LE());
|
219 |
+
const shard_key_expiry = Number(reader.readUint64LE());
|
220 |
+
|
221 |
+
// Skip second buffer (72 bytes)
|
222 |
+
reader.readBytes(72);
|
223 |
+
|
224 |
+
const footer_offset = Number(reader.readUint64LE());
|
225 |
+
|
226 |
+
const footer: MDBShardFileFooter = {
|
227 |
+
version,
|
228 |
+
file_info_offset,
|
229 |
+
cas_info_offset,
|
230 |
+
chunk_hash_hmac_key,
|
231 |
+
shard_creation_timestamp,
|
232 |
+
shard_key_expiry,
|
233 |
+
footer_offset,
|
234 |
+
};
|
235 |
+
|
236 |
+
if (footer.version !== 1) {
|
237 |
+
throw new Error(`Unsupported shard footer version: ${footer.version}`);
|
238 |
+
}
|
239 |
+
|
240 |
+
// Parse file info section
|
241 |
+
const file_info: MDBFileInfo[] = [];
|
242 |
+
reader.seek(footer.file_info_offset);
|
243 |
+
|
244 |
+
while (reader.position < footer.cas_info_offset) {
|
245 |
+
const pos = reader.position;
|
246 |
+
const file_hash = reader.readHash();
|
247 |
+
|
248 |
+
// Check for bookend
|
249 |
+
if (isBookendHash(file_hash)) {
|
250 |
+
reader.readBytes(16); // unused
|
251 |
+
break;
|
252 |
+
}
|
253 |
+
|
254 |
+
const file_flags = reader.readUint32LE();
|
255 |
+
const num_entries = reader.readUint32LE();
|
256 |
+
const _unused = reader.readBytes(8);
|
257 |
+
|
258 |
+
const header: FileDataSequenceHeader = {
|
259 |
+
file_hash,
|
260 |
+
file_flags,
|
261 |
+
num_entries,
|
262 |
+
_unused,
|
263 |
+
};
|
264 |
+
|
265 |
+
// Read entries
|
266 |
+
const entries: FileDataSequenceEntry[] = [];
|
267 |
+
for (let i = 0; i < num_entries; i++) {
|
268 |
+
const cas_hash = reader.readHash();
|
269 |
+
const cas_flags = reader.readUint32LE();
|
270 |
+
const unpacked_segment_bytes = reader.readUint32LE();
|
271 |
+
const chunk_index_start = reader.readUint32LE();
|
272 |
+
const chunk_index_end = reader.readUint32LE();
|
273 |
+
entries.push({
|
274 |
+
cas_hash,
|
275 |
+
cas_flags,
|
276 |
+
unpacked_segment_bytes,
|
277 |
+
chunk_index_start,
|
278 |
+
chunk_index_end,
|
279 |
+
});
|
280 |
+
}
|
281 |
+
|
282 |
+
// Read verification entries if present
|
283 |
+
let verification_entries: FileVerificationEntry[] | undefined;
|
284 |
+
if (file_flags & 0x80000000) {
|
285 |
+
verification_entries = [];
|
286 |
+
for (let i = 0; i < num_entries; i++) {
|
287 |
+
verification_entries.push({
|
288 |
+
chunk_hash: reader.readHash(),
|
289 |
+
_unused: reader.readBytes(16),
|
290 |
+
});
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
+
// Read metadata extension if present
|
295 |
+
let metadata_ext: FileMetadataExt | undefined;
|
296 |
+
if (file_flags & 0x40000000) {
|
297 |
+
metadata_ext = {
|
298 |
+
sha256: reader.readHash(),
|
299 |
+
_unused: reader.readBytes(16),
|
300 |
+
};
|
301 |
+
}
|
302 |
+
|
303 |
+
file_info.push({
|
304 |
+
header,
|
305 |
+
entries,
|
306 |
+
verification_entries,
|
307 |
+
metadata_ext,
|
308 |
+
});
|
309 |
+
}
|
310 |
+
|
311 |
+
// Parse CAS info section
|
312 |
+
const cas_info: MDBCASInfo[] = [];
|
313 |
+
reader.seek(footer.cas_info_offset);
|
314 |
+
|
315 |
+
while (reader.position < footer.footer_offset) {
|
316 |
+
const cas_hash = reader.readHash();
|
317 |
+
|
318 |
+
// Check for bookend
|
319 |
+
if (isBookendHash(cas_hash)) {
|
320 |
+
break;
|
321 |
+
}
|
322 |
+
|
323 |
+
const cas_flags = reader.readUint32LE();
|
324 |
+
const num_entries = reader.readUint32LE();
|
325 |
+
const num_bytes_in_cas = reader.readUint32LE();
|
326 |
+
const num_bytes_on_disk = reader.readUint32LE();
|
327 |
+
|
328 |
+
const header: CASChunkSequenceHeader = {
|
329 |
+
cas_hash,
|
330 |
+
cas_flags,
|
331 |
+
num_entries,
|
332 |
+
num_bytes_in_cas,
|
333 |
+
num_bytes_on_disk,
|
334 |
+
};
|
335 |
+
|
336 |
+
// Read entries
|
337 |
+
const entries: CASChunkSequenceEntry[] = [];
|
338 |
+
for (let i = 0; i < num_entries; i++) {
|
339 |
+
entries.push({
|
340 |
+
chunk_hash: reader.readHash(),
|
341 |
+
chunk_byte_range_start: reader.readUint32LE(),
|
342 |
+
unpacked_segment_bytes: reader.readUint32LE(),
|
343 |
+
_unused: Number(reader.readUint64LE()),
|
344 |
+
});
|
345 |
+
}
|
346 |
+
|
347 |
+
cas_info.push({
|
348 |
+
header,
|
349 |
+
entries,
|
350 |
+
});
|
351 |
+
}
|
352 |
+
|
353 |
+
return {
|
354 |
+
header,
|
355 |
+
footer,
|
356 |
+
file_info,
|
357 |
+
cas_info,
|
358 |
+
};
|
359 |
+
}
|
360 |
+
|
361 |
+
export async function parseFile(
|
362 |
+
file: File,
|
363 |
+
fileType: "xorb" | "shard"
|
364 |
+
): Promise<ParsedFileMetadata> {
|
365 |
+
try {
|
366 |
+
const arrayBuffer = await file.arrayBuffer();
|
367 |
+
const data = new Uint8Array(arrayBuffer);
|
368 |
+
|
369 |
+
let parsedData: Chunk[] | ShardData;
|
370 |
+
|
371 |
+
if (fileType === "xorb") {
|
372 |
+
parsedData = parseXorbFile(data);
|
373 |
+
} else {
|
374 |
+
parsedData = parseShardFile(data);
|
375 |
+
}
|
376 |
+
|
377 |
+
return {
|
378 |
+
type: fileType,
|
379 |
+
filename: file.name,
|
380 |
+
fileSize: file.size,
|
381 |
+
data: parsedData,
|
382 |
+
};
|
383 |
+
} catch (error) {
|
384 |
+
return {
|
385 |
+
type: fileType,
|
386 |
+
filename: file.name,
|
387 |
+
fileSize: file.size,
|
388 |
+
data: [] as any,
|
389 |
+
error: error instanceof Error ? error.message : "Unknown error occurred",
|
390 |
+
};
|
391 |
+
}
|
392 |
+
}
|
393 |
+
|
394 |
+
// Helper functions for displaying data
|
395 |
+
export function formatBytes(bytes: number): string {
|
396 |
+
if (bytes === 0) return "0 B";
|
397 |
+
const k = 1000;
|
398 |
+
const sizes = ["B", "KB", "MB", "GB"];
|
399 |
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
400 |
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
401 |
+
}
|
402 |
+
|
403 |
+
export function formatTimestamp(timestamp: number): string {
|
404 |
+
return new Date(timestamp * 1000).toISOString();
|
405 |
+
}
|
406 |
+
|
407 |
+
export function formatHashShort(hash: MerkleHash): string {
|
408 |
+
const fullHash = formatHash(hash);
|
409 |
+
return fullHash.substring(0, 16) + "...";
|
410 |
+
}
|
411 |
+
|
412 |
+
export { formatHash };
|
src/lib/types.ts
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Type definitions for xorb and shard file formats
|
2 |
+
|
3 |
+
export interface MerkleHash {
|
4 |
+
data: Uint8Array; // 32 bytes
|
5 |
+
}
|
6 |
+
|
7 |
+
export interface HMACKey {
|
8 |
+
data: Uint8Array; // 32 bytes
|
9 |
+
}
|
10 |
+
|
11 |
+
// === XORB Types ===
|
12 |
+
|
13 |
+
export interface ChunkHeader {
|
14 |
+
version: number;
|
15 |
+
compressed_size: number;
|
16 |
+
compression_type: number;
|
17 |
+
uncompressed_size: number;
|
18 |
+
}
|
19 |
+
|
20 |
+
export interface Chunk {
|
21 |
+
header: ChunkHeader;
|
22 |
+
compressed_data: Uint8Array;
|
23 |
+
}
|
24 |
+
|
25 |
+
// === SHARD Types ===
|
26 |
+
|
27 |
+
export interface MDBShardFileHeader {
|
28 |
+
tag: Uint8Array; // 32 bytes magic number
|
29 |
+
version: number;
|
30 |
+
footer_size: number;
|
31 |
+
}
|
32 |
+
|
33 |
+
export interface MDBShardFileFooter {
|
34 |
+
version: number;
|
35 |
+
file_info_offset: number;
|
36 |
+
cas_info_offset: number;
|
37 |
+
chunk_hash_hmac_key: HMACKey;
|
38 |
+
shard_creation_timestamp: number;
|
39 |
+
shard_key_expiry: number;
|
40 |
+
footer_offset: number;
|
41 |
+
}
|
42 |
+
|
43 |
+
export interface FileDataSequenceHeader {
|
44 |
+
file_hash: MerkleHash;
|
45 |
+
file_flags: number;
|
46 |
+
num_entries: number;
|
47 |
+
_unused: Uint8Array;
|
48 |
+
}
|
49 |
+
|
50 |
+
export interface FileDataSequenceEntry {
|
51 |
+
cas_hash: MerkleHash;
|
52 |
+
cas_flags: number;
|
53 |
+
unpacked_segment_bytes: number;
|
54 |
+
chunk_index_start: number;
|
55 |
+
chunk_index_end: number;
|
56 |
+
}
|
57 |
+
|
58 |
+
export interface FileVerificationEntry {
|
59 |
+
chunk_hash: MerkleHash;
|
60 |
+
_unused: Uint8Array;
|
61 |
+
}
|
62 |
+
|
63 |
+
export interface FileMetadataExt {
|
64 |
+
sha256: MerkleHash;
|
65 |
+
_unused: Uint8Array;
|
66 |
+
}
|
67 |
+
|
68 |
+
export interface CASChunkSequenceHeader {
|
69 |
+
cas_hash: MerkleHash;
|
70 |
+
cas_flags: number;
|
71 |
+
num_entries: number;
|
72 |
+
num_bytes_in_cas: number;
|
73 |
+
num_bytes_on_disk: number;
|
74 |
+
}
|
75 |
+
|
76 |
+
export interface CASChunkSequenceEntry {
|
77 |
+
chunk_hash: MerkleHash;
|
78 |
+
chunk_byte_range_start: number;
|
79 |
+
unpacked_segment_bytes: number;
|
80 |
+
_unused: number;
|
81 |
+
}
|
82 |
+
|
83 |
+
export interface MDBFileInfo {
|
84 |
+
header: FileDataSequenceHeader;
|
85 |
+
entries: FileDataSequenceEntry[];
|
86 |
+
verification_entries?: FileVerificationEntry[];
|
87 |
+
metadata_ext?: FileMetadataExt;
|
88 |
+
}
|
89 |
+
|
90 |
+
export interface MDBCASInfo {
|
91 |
+
header: CASChunkSequenceHeader;
|
92 |
+
entries: CASChunkSequenceEntry[];
|
93 |
+
}
|
94 |
+
|
95 |
+
export interface ShardData {
|
96 |
+
header: MDBShardFileHeader;
|
97 |
+
footer: MDBShardFileFooter;
|
98 |
+
file_info: MDBFileInfo[];
|
99 |
+
cas_info: MDBCASInfo[];
|
100 |
+
}
|
101 |
+
|
102 |
+
// === Parsed Metadata for Display ===
|
103 |
+
|
104 |
+
export interface ParsedFileMetadata {
|
105 |
+
type: "xorb" | "shard";
|
106 |
+
filename: string;
|
107 |
+
fileSize: number;
|
108 |
+
data: Chunk[] | ShardData;
|
109 |
+
error?: string;
|
110 |
+
}
|
111 |
+
|
112 |
+
// File type detection
|
113 |
+
export const MDB_SHARD_HEADER_TAG = new Uint8Array([
|
114 |
+
0x48, 0x46, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74,
|
115 |
+
0x61, 0x00, 0x55, 0x69, 0x67, 0x45, 0x6a, 0x7b, 0x81, 0x57, 0x83, 0xa5, 0xbd,
|
116 |
+
0xd9, 0x5c, 0xcd, 0xd1, 0x4a, 0xa9,
|
117 |
+
]);
|
118 |
+
|
119 |
+
export const XORB_IDENT = new Uint8Array([88, 69, 84, 66, 76, 79, 66]);
|
src/main.ts
DELETED
@@ -1,9 +0,0 @@
|
|
1 |
-
import { mount } from 'svelte'
|
2 |
-
import './app.css'
|
3 |
-
import App from './App.svelte'
|
4 |
-
|
5 |
-
const app = mount(App, {
|
6 |
-
target: document.getElementById('app')!,
|
7 |
-
})
|
8 |
-
|
9 |
-
export default app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/routes/+layout.svelte
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import favicon from '$lib/assets/favicon.svg';
|
3 |
+
|
4 |
+
let { children } = $props();
|
5 |
+
</script>
|
6 |
+
|
7 |
+
<svelte:head>
|
8 |
+
<link rel="icon" href={favicon} />
|
9 |
+
</svelte:head>
|
10 |
+
|
11 |
+
{@render children?.()}
|
src/routes/+page.svelte
ADDED
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import FileUpload from "$lib/components/FileUpload.svelte";
|
3 |
+
import XorbViewer from "$lib/components/XorbViewer.svelte";
|
4 |
+
import ShardViewer from "$lib/components/ShardViewer.svelte";
|
5 |
+
import ErrorDisplay from "$lib/components/ErrorDisplay.svelte";
|
6 |
+
import { parseFile } from "$lib/parsers.js";
|
7 |
+
import type { ParsedFileMetadata, Chunk, ShardData } from "$lib/types.js";
|
8 |
+
|
9 |
+
let parsedData: ParsedFileMetadata | null = null;
|
10 |
+
let loading = false;
|
11 |
+
|
12 |
+
async function handleFileSelected(
|
13 |
+
event: CustomEvent<{ file: File; type: "xorb" | "shard" }>
|
14 |
+
) {
|
15 |
+
loading = true;
|
16 |
+
parsedData = null;
|
17 |
+
|
18 |
+
try {
|
19 |
+
const { file, type } = event.detail;
|
20 |
+
const result = await parseFile(file, type);
|
21 |
+
parsedData = result;
|
22 |
+
} catch (error) {
|
23 |
+
parsedData = {
|
24 |
+
type: event.detail.type,
|
25 |
+
filename: event.detail.file.name,
|
26 |
+
fileSize: event.detail.file.size,
|
27 |
+
data: {} as any,
|
28 |
+
error:
|
29 |
+
error instanceof Error ? error.message : "Unknown error occurred",
|
30 |
+
};
|
31 |
+
} finally {
|
32 |
+
loading = false;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
function resetView() {
|
37 |
+
parsedData = null;
|
38 |
+
loading = false;
|
39 |
+
}
|
40 |
+
</script>
|
41 |
+
|
42 |
+
<svelte:head>
|
43 |
+
<title>XORB & Shard File Viewer</title>
|
44 |
+
<meta
|
45 |
+
name="description"
|
46 |
+
content="Parse and view metadata from XORB and Shard object files"
|
47 |
+
/>
|
48 |
+
</svelte:head>
|
49 |
+
|
50 |
+
<main>
|
51 |
+
<div class="container">
|
52 |
+
<header>
|
53 |
+
<h1>🔍 XORB & Shard File Viewer</h1>
|
54 |
+
<p>
|
55 |
+
Upload and analyze XORB or Shard object files to view their metadata
|
56 |
+
structure
|
57 |
+
</p>
|
58 |
+
{#if parsedData}
|
59 |
+
<button class="reset-btn" on:click={resetView}>
|
60 |
+
← Upload New File
|
61 |
+
</button>
|
62 |
+
{/if}
|
63 |
+
</header>
|
64 |
+
|
65 |
+
{#if loading}
|
66 |
+
<div class="loading">
|
67 |
+
<div class="spinner"></div>
|
68 |
+
<p>Parsing file...</p>
|
69 |
+
</div>
|
70 |
+
{:else if parsedData}
|
71 |
+
{#if parsedData.error}
|
72 |
+
<ErrorDisplay error={parsedData.error} filename={parsedData.filename} />
|
73 |
+
{:else if parsedData.type === "xorb"}
|
74 |
+
<XorbViewer
|
75 |
+
data={parsedData.data as Chunk[]}
|
76 |
+
filename={parsedData.filename}
|
77 |
+
fileSize={parsedData.fileSize}
|
78 |
+
/>
|
79 |
+
{:else if parsedData.type === "shard"}
|
80 |
+
<ShardViewer
|
81 |
+
data={parsedData.data as ShardData}
|
82 |
+
filename={parsedData.filename}
|
83 |
+
fileSize={parsedData.fileSize}
|
84 |
+
/>
|
85 |
+
{/if}
|
86 |
+
{:else}
|
87 |
+
<FileUpload on:fileSelected={handleFileSelected} />
|
88 |
+
|
89 |
+
<div class="info-section">
|
90 |
+
<h2>Supported File Types</h2>
|
91 |
+
<div class="file-types">
|
92 |
+
<div class="file-type">
|
93 |
+
<h3>📦 XORB Files</h3>
|
94 |
+
<p>
|
95 |
+
XORB (Xet Orb) files contain collections of compressed chunks with
|
96 |
+
metadata. The viewer will display chunk information, compression
|
97 |
+
statistics, and structural details.
|
98 |
+
</p>
|
99 |
+
<ul>
|
100 |
+
<li>Chunk count and sizes</li>
|
101 |
+
<li>Compression ratios</li>
|
102 |
+
<li>Hash information</li>
|
103 |
+
<li>Boundary offsets</li>
|
104 |
+
</ul>
|
105 |
+
</div>
|
106 |
+
|
107 |
+
<div class="file-type">
|
108 |
+
<h3>🗂️ Shard Files</h3>
|
109 |
+
<p>
|
110 |
+
MDB Shard files store file metadata and content-addressable
|
111 |
+
storage information for efficient deduplication. The viewer shows
|
112 |
+
file and CAS details.
|
113 |
+
</p>
|
114 |
+
<ul>
|
115 |
+
<li>File information entries</li>
|
116 |
+
<li>CAS (Content Addressable Storage) data</li>
|
117 |
+
<li>Lookup tables</li>
|
118 |
+
<li>Timestamps and security keys</li>
|
119 |
+
</ul>
|
120 |
+
</div>
|
121 |
+
</div>
|
122 |
+
</div>
|
123 |
+
{/if}
|
124 |
+
</div>
|
125 |
+
</main>
|
126 |
+
|
127 |
+
<style>
|
128 |
+
:global(body) {
|
129 |
+
margin: 0;
|
130 |
+
padding: 0;
|
131 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
132 |
+
sans-serif;
|
133 |
+
background: #f5f7fa;
|
134 |
+
color: #333;
|
135 |
+
line-height: 1.6;
|
136 |
+
}
|
137 |
+
|
138 |
+
:global(*) {
|
139 |
+
box-sizing: border-box;
|
140 |
+
}
|
141 |
+
|
142 |
+
main {
|
143 |
+
min-height: 100vh;
|
144 |
+
padding: 20px;
|
145 |
+
}
|
146 |
+
|
147 |
+
.container {
|
148 |
+
max-width: 1200px;
|
149 |
+
margin: 0 auto;
|
150 |
+
}
|
151 |
+
|
152 |
+
header {
|
153 |
+
text-align: center;
|
154 |
+
margin-bottom: 40px;
|
155 |
+
position: relative;
|
156 |
+
}
|
157 |
+
|
158 |
+
header h1 {
|
159 |
+
font-size: 36px;
|
160 |
+
margin: 0 0 16px 0;
|
161 |
+
color: #2c3e50;
|
162 |
+
font-weight: 700;
|
163 |
+
}
|
164 |
+
|
165 |
+
header p {
|
166 |
+
font-size: 18px;
|
167 |
+
color: #6c757d;
|
168 |
+
margin: 0;
|
169 |
+
}
|
170 |
+
|
171 |
+
.reset-btn {
|
172 |
+
position: absolute;
|
173 |
+
left: 0;
|
174 |
+
top: 50%;
|
175 |
+
transform: translateY(-50%);
|
176 |
+
background: #007bff;
|
177 |
+
color: white;
|
178 |
+
border: none;
|
179 |
+
padding: 10px 20px;
|
180 |
+
border-radius: 6px;
|
181 |
+
cursor: pointer;
|
182 |
+
font-size: 14px;
|
183 |
+
font-weight: 500;
|
184 |
+
transition: background-color 0.2s;
|
185 |
+
}
|
186 |
+
|
187 |
+
.reset-btn:hover {
|
188 |
+
background: #0056b3;
|
189 |
+
}
|
190 |
+
|
191 |
+
.loading {
|
192 |
+
text-align: center;
|
193 |
+
padding: 60px 20px;
|
194 |
+
}
|
195 |
+
|
196 |
+
.spinner {
|
197 |
+
width: 40px;
|
198 |
+
height: 40px;
|
199 |
+
border: 4px solid #f3f3f3;
|
200 |
+
border-top: 4px solid #007bff;
|
201 |
+
border-radius: 50%;
|
202 |
+
animation: spin 1s linear infinite;
|
203 |
+
margin: 0 auto 20px;
|
204 |
+
}
|
205 |
+
|
206 |
+
@keyframes spin {
|
207 |
+
0% {
|
208 |
+
transform: rotate(0deg);
|
209 |
+
}
|
210 |
+
100% {
|
211 |
+
transform: rotate(360deg);
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
.loading p {
|
216 |
+
color: #6c757d;
|
217 |
+
font-size: 16px;
|
218 |
+
margin: 0;
|
219 |
+
}
|
220 |
+
|
221 |
+
.info-section {
|
222 |
+
margin-top: 60px;
|
223 |
+
text-align: center;
|
224 |
+
}
|
225 |
+
|
226 |
+
.info-section h2 {
|
227 |
+
font-size: 24px;
|
228 |
+
color: #2c3e50;
|
229 |
+
margin: 0 0 30px 0;
|
230 |
+
}
|
231 |
+
|
232 |
+
.file-types {
|
233 |
+
display: grid;
|
234 |
+
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
235 |
+
gap: 30px;
|
236 |
+
margin-top: 30px;
|
237 |
+
}
|
238 |
+
|
239 |
+
.file-type {
|
240 |
+
background: white;
|
241 |
+
padding: 30px;
|
242 |
+
border-radius: 12px;
|
243 |
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
244 |
+
text-align: left;
|
245 |
+
}
|
246 |
+
|
247 |
+
.file-type h3 {
|
248 |
+
font-size: 20px;
|
249 |
+
margin: 0 0 16px 0;
|
250 |
+
color: #2c3e50;
|
251 |
+
}
|
252 |
+
|
253 |
+
.file-type p {
|
254 |
+
color: #6c757d;
|
255 |
+
margin: 0 0 20px 0;
|
256 |
+
line-height: 1.6;
|
257 |
+
}
|
258 |
+
|
259 |
+
.file-type ul {
|
260 |
+
list-style: none;
|
261 |
+
padding: 0;
|
262 |
+
margin: 0;
|
263 |
+
}
|
264 |
+
|
265 |
+
.file-type li {
|
266 |
+
padding: 8px 0;
|
267 |
+
border-bottom: 1px solid #eee;
|
268 |
+
color: #495057;
|
269 |
+
}
|
270 |
+
|
271 |
+
.file-type li:before {
|
272 |
+
content: "✓";
|
273 |
+
color: #28a745;
|
274 |
+
font-weight: bold;
|
275 |
+
margin-right: 8px;
|
276 |
+
}
|
277 |
+
|
278 |
+
.file-type li:last-child {
|
279 |
+
border-bottom: none;
|
280 |
+
}
|
281 |
+
|
282 |
+
@media (max-width: 768px) {
|
283 |
+
header h1 {
|
284 |
+
font-size: 28px;
|
285 |
+
}
|
286 |
+
|
287 |
+
header p {
|
288 |
+
font-size: 16px;
|
289 |
+
}
|
290 |
+
|
291 |
+
.reset-btn {
|
292 |
+
position: static;
|
293 |
+
transform: none;
|
294 |
+
margin-top: 20px;
|
295 |
+
}
|
296 |
+
|
297 |
+
.file-types {
|
298 |
+
grid-template-columns: 1fr;
|
299 |
+
}
|
300 |
+
|
301 |
+
.file-type {
|
302 |
+
padding: 20px;
|
303 |
+
}
|
304 |
+
}
|
305 |
+
</style>
|
src/vite-env.d.ts
DELETED
@@ -1,2 +0,0 @@
|
|
1 |
-
/// <reference types="svelte" />
|
2 |
-
/// <reference types="vite/client" />
|
|
|
|
|
|
static/robots.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
# allow crawling everything by default
|
2 |
+
User-agent: *
|
3 |
+
Disallow:
|
svelte.config.js
CHANGED
@@ -1,7 +1,18 @@
|
|
1 |
-
import
|
|
|
2 |
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import adapter from '@sveltejs/adapter-auto';
|
2 |
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
3 |
|
4 |
+
/** @type {import('@sveltejs/kit').Config} */
|
5 |
+
const config = {
|
6 |
+
// Consult https://svelte.dev/docs/kit/integrations
|
7 |
+
// for more information about preprocessors
|
8 |
+
preprocess: vitePreprocess(),
|
9 |
+
|
10 |
+
kit: {
|
11 |
+
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
12 |
+
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
13 |
+
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
|
14 |
+
adapter: adapter()
|
15 |
+
}
|
16 |
+
};
|
17 |
+
|
18 |
+
export default config;
|
tsconfig.app.json
DELETED
@@ -1,20 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"extends": "@tsconfig/svelte/tsconfig.json",
|
3 |
-
"compilerOptions": {
|
4 |
-
"target": "ESNext",
|
5 |
-
"useDefineForClassFields": true,
|
6 |
-
"module": "ESNext",
|
7 |
-
"resolveJsonModule": true,
|
8 |
-
/**
|
9 |
-
* Typecheck JS in `.svelte` and `.js` files by default.
|
10 |
-
* Disable checkJs if you'd like to use dynamic types in JS.
|
11 |
-
* Note that setting allowJs false does not prevent the use
|
12 |
-
* of JS in `.svelte` files.
|
13 |
-
*/
|
14 |
-
"allowJs": true,
|
15 |
-
"checkJs": true,
|
16 |
-
"isolatedModules": true,
|
17 |
-
"moduleDetection": "force"
|
18 |
-
},
|
19 |
-
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
|
20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tsconfig.json
CHANGED
@@ -1,7 +1,19 @@
|
|
1 |
{
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
|
|
1 |
{
|
2 |
+
"extends": "./.svelte-kit/tsconfig.json",
|
3 |
+
"compilerOptions": {
|
4 |
+
"allowJs": true,
|
5 |
+
"checkJs": true,
|
6 |
+
"esModuleInterop": true,
|
7 |
+
"forceConsistentCasingInFileNames": true,
|
8 |
+
"resolveJsonModule": true,
|
9 |
+
"skipLibCheck": true,
|
10 |
+
"sourceMap": true,
|
11 |
+
"strict": true,
|
12 |
+
"moduleResolution": "bundler"
|
13 |
+
}
|
14 |
+
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
15 |
+
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
16 |
+
//
|
17 |
+
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
18 |
+
// from the referenced tsconfig.json - TypeScript does not merge them in
|
19 |
}
|
tsconfig.node.json
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"compilerOptions": {
|
3 |
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
4 |
-
"target": "ES2022",
|
5 |
-
"lib": ["ES2023"],
|
6 |
-
"module": "ESNext",
|
7 |
-
"skipLibCheck": true,
|
8 |
-
|
9 |
-
/* Bundler mode */
|
10 |
-
"moduleResolution": "bundler",
|
11 |
-
"allowImportingTsExtensions": true,
|
12 |
-
"verbatimModuleSyntax": true,
|
13 |
-
"moduleDetection": "force",
|
14 |
-
"noEmit": true,
|
15 |
-
|
16 |
-
/* Linting */
|
17 |
-
"strict": true,
|
18 |
-
"noUnusedLocals": true,
|
19 |
-
"noUnusedParameters": true,
|
20 |
-
"erasableSyntaxOnly": true,
|
21 |
-
"noFallthroughCasesInSwitch": true,
|
22 |
-
"noUncheckedSideEffectImports": true
|
23 |
-
},
|
24 |
-
"include": ["vite.config.ts"]
|
25 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vite.config.ts
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
-
import {
|
2 |
-
import {
|
3 |
|
4 |
-
// https://vite.dev/config/
|
5 |
export default defineConfig({
|
6 |
-
|
7 |
-
})
|
|
|
1 |
+
import { sveltekit } from '@sveltejs/kit/vite';
|
2 |
+
import { defineConfig } from 'vite';
|
3 |
|
|
|
4 |
export default defineConfig({
|
5 |
+
plugins: [sveltekit()]
|
6 |
+
});
|