tangled
alpha
login
or
join now
atscan.net
/
plcbundle-ref
5
fork
atom
PLC Bundle V1 Example Implementations
5
fork
atom
overview
issues
pulls
pipelines
fist commit
tree.fail
4 months ago
6f4d1ee4
+643
4 changed files
expand all
collapse all
unified
split
.gitignore
package.json
plcbundle.ts
pnpm-lock.yaml
+3
.gitignore
···
0
0
0
···
1
+
node_modules
2
+
.DS_Store
3
+
plc_bundles
+17
package.json
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
{
2
+
"name": "plcbundle-js",
3
+
"version": "1.0.0",
4
+
"description": "",
5
+
"main": "index.js",
6
+
"type": "module",
7
+
"scripts": {
8
+
"test": "echo \"Error: no test specified\" && exit 1"
9
+
},
10
+
"keywords": [],
11
+
"author": "",
12
+
"license": "ISC",
13
+
"dependencies": {
14
+
"@bokuweb/zstd-wasm": "^0.0.27",
15
+
"axios": "^1.13.0"
16
+
}
17
+
}
+411
plcbundle.ts
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
#!/usr/bin/env node
2
+
3
+
/**
4
+
* plcbundle.ts - Fetch from PLC Directory and create verifiable bundles
5
+
*/
6
+
7
+
import fs from 'fs/promises';
8
+
import path from 'path';
9
+
import crypto from 'crypto';
10
+
import { fileURLToPath } from 'url';
11
+
import { init, compress, decompress } from '@bokuweb/zstd-wasm';
12
+
import axios from 'axios';
13
+
14
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
+
16
+
const BUNDLE_SIZE = 10000;
17
+
const INDEX_FILE = 'plc_bundles.json';
18
+
const PLC_URL = 'https://plc.directory';
19
+
20
+
// ============================================================================
21
+
// Types
22
+
// ============================================================================
23
+
24
+
interface PLCOperation {
25
+
did: string;
26
+
cid: string;
27
+
createdAt: string;
28
+
operation: Record<string, any>;
29
+
nullified?: boolean | string;
30
+
_raw?: string;
31
+
}
32
+
33
+
interface BundleMetadata {
34
+
bundle_number: number;
35
+
start_time: string;
36
+
end_time: string;
37
+
operation_count: number;
38
+
did_count: number;
39
+
hash: string;
40
+
content_hash: string;
41
+
parent: string;
42
+
compressed_hash: string;
43
+
compressed_size: number;
44
+
uncompressed_size: number;
45
+
created_at: string;
46
+
}
47
+
48
+
interface Index {
49
+
version: string;
50
+
last_bundle: number;
51
+
updated_at: string;
52
+
total_size_bytes: number;
53
+
bundles: BundleMetadata[];
54
+
}
55
+
56
+
// Initialize zstd
57
+
await init();
58
+
59
+
// ============================================================================
60
+
// Index Management
61
+
// ============================================================================
62
+
63
+
const loadIndex = async (dir: string): Promise<Index> => {
64
+
try {
65
+
const data = await fs.readFile(path.join(dir, INDEX_FILE), 'utf8');
66
+
return JSON.parse(data);
67
+
} catch (err) {
68
+
return {
69
+
version: '1.0',
70
+
last_bundle: 0,
71
+
updated_at: new Date().toISOString(),
72
+
total_size_bytes: 0,
73
+
bundles: []
74
+
};
75
+
}
76
+
};
77
+
78
+
const saveIndex = async (dir: string, index: Index): Promise<void> => {
79
+
index.updated_at = new Date().toISOString();
80
+
const indexPath = path.join(dir, INDEX_FILE);
81
+
const tempPath = indexPath + '.tmp';
82
+
await fs.writeFile(tempPath, JSON.stringify(index, null, 2));
83
+
await fs.rename(tempPath, indexPath);
84
+
};
85
+
86
+
// ============================================================================
87
+
// Bundle Loading
88
+
// ============================================================================
89
+
90
+
const loadBundle = async (dir: string, bundleNumber: number): Promise<PLCOperation[]> => {
91
+
const filename = `${String(bundleNumber).padStart(6, '0')}.jsonl.zst`;
92
+
const filepath = path.join(dir, filename);
93
+
94
+
const compressed = await fs.readFile(filepath);
95
+
const decompressed = decompress(compressed);
96
+
const jsonl = Buffer.from(decompressed).toString('utf8');
97
+
98
+
const lines = jsonl.trim().split('\n').filter(l => l);
99
+
return lines.map(line => {
100
+
const op = JSON.parse(line) as PLCOperation;
101
+
op._raw = line;
102
+
return op;
103
+
});
104
+
};
105
+
106
+
// ============================================================================
107
+
// Boundary Handling
108
+
// ============================================================================
109
+
110
+
const getBoundaryCIDs = (operations: PLCOperation[]): Set<string> => {
111
+
if (operations.length === 0) return new Set();
112
+
113
+
const lastOp = operations[operations.length - 1];
114
+
const boundaryTime = lastOp.createdAt;
115
+
const cidSet = new Set<string>();
116
+
117
+
// Walk backwards from the end to find all operations with the same timestamp
118
+
for (let i = operations.length - 1; i >= 0; i--) {
119
+
if (operations[i].createdAt === boundaryTime) {
120
+
cidSet.add(operations[i].cid);
121
+
} else {
122
+
break;
123
+
}
124
+
}
125
+
126
+
return cidSet;
127
+
};
128
+
129
+
const stripBoundaryDuplicates = (
130
+
operations: PLCOperation[],
131
+
prevBoundaryCIDs: Set<string>
132
+
): PLCOperation[] => {
133
+
if (prevBoundaryCIDs.size === 0) return operations;
134
+
if (operations.length === 0) return operations;
135
+
136
+
const boundaryTime = operations[0].createdAt;
137
+
let startIdx = 0;
138
+
139
+
// Skip operations that are in the previous bundle's boundary
140
+
for (let i = 0; i < operations.length; i++) {
141
+
const op = operations[i];
142
+
143
+
// Stop if we've moved past the boundary timestamp
144
+
if (op.createdAt > boundaryTime) {
145
+
break;
146
+
}
147
+
148
+
// Skip if this CID was in the previous boundary
149
+
if (op.createdAt === boundaryTime && prevBoundaryCIDs.has(op.cid)) {
150
+
startIdx = i + 1;
151
+
continue;
152
+
}
153
+
154
+
break;
155
+
}
156
+
157
+
const stripped = operations.slice(startIdx);
158
+
if (startIdx > 0) {
159
+
console.log(` Stripped ${startIdx} boundary duplicates`);
160
+
}
161
+
return stripped;
162
+
};
163
+
164
+
// ============================================================================
165
+
// PLC Directory Client
166
+
// ============================================================================
167
+
168
+
const fetchOperations = async (after: string | null, count: number = 1000): Promise<PLCOperation[]> => {
169
+
const params: Record<string, any> = { count };
170
+
if (after) {
171
+
params.after = after;
172
+
}
173
+
174
+
const response = await axios.get<string>(`${PLC_URL}/export`, {
175
+
params,
176
+
responseType: 'text'
177
+
});
178
+
179
+
const lines = response.data.trim().split('\n').filter(l => l);
180
+
181
+
return lines.map(line => {
182
+
const op = JSON.parse(line) as PLCOperation;
183
+
op._raw = line; // Preserve exact JSON
184
+
return op;
185
+
});
186
+
};
187
+
188
+
// ============================================================================
189
+
// Bundle Operations
190
+
// ============================================================================
191
+
192
+
const serializeJSONL = (operations: PLCOperation[]): string => {
193
+
const lines = operations.map(op => {
194
+
const json = op._raw || JSON.stringify(op);
195
+
return json + '\n';
196
+
});
197
+
return lines.join('');
198
+
};
199
+
200
+
const sha256 = (data: Buffer | string): string => {
201
+
return crypto.createHash('sha256').update(data).digest('hex');
202
+
};
203
+
204
+
const calculateChainHash = (parent: string, contentHash: string): string => {
205
+
let data: string;
206
+
if (!parent || parent === '') {
207
+
data = `plcbundle:genesis:${contentHash}`;
208
+
} else {
209
+
data = `${parent}:${contentHash}`;
210
+
}
211
+
return sha256(data);
212
+
};
213
+
214
+
const extractUniqueDIDs = (operations: PLCOperation[]): number => {
215
+
const dids = new Set<string>();
216
+
operations.forEach(op => dids.add(op.did));
217
+
return dids.size;
218
+
};
219
+
220
+
const saveBundle = async (
221
+
dir: string,
222
+
bundleNumber: number,
223
+
operations: PLCOperation[],
224
+
parentHash: string
225
+
): Promise<BundleMetadata> => {
226
+
const filename = `${String(bundleNumber).padStart(6, '0')}.jsonl.zst`;
227
+
const filepath = path.join(dir, filename);
228
+
229
+
const jsonl = serializeJSONL(operations);
230
+
const uncompressedBuffer = Buffer.from(jsonl, 'utf8');
231
+
232
+
const contentHash = sha256(uncompressedBuffer);
233
+
const uncompressedSize = uncompressedBuffer.length;
234
+
235
+
const chainHash = calculateChainHash(parentHash, contentHash);
236
+
237
+
const compressed = compress(uncompressedBuffer, 3);
238
+
const compressedBuffer = Buffer.from(compressed);
239
+
const compressedHash = sha256(compressedBuffer);
240
+
const compressedSize = compressedBuffer.length;
241
+
242
+
await fs.writeFile(filepath, compressedBuffer);
243
+
244
+
const startTime = operations[0].createdAt;
245
+
const endTime = operations[operations.length - 1].createdAt;
246
+
const didCount = extractUniqueDIDs(operations);
247
+
248
+
return {
249
+
bundle_number: bundleNumber,
250
+
start_time: startTime,
251
+
end_time: endTime,
252
+
operation_count: operations.length,
253
+
did_count: didCount,
254
+
hash: chainHash,
255
+
content_hash: contentHash,
256
+
parent: parentHash || '',
257
+
compressed_hash: compressedHash,
258
+
compressed_size: compressedSize,
259
+
uncompressed_size: uncompressedSize,
260
+
created_at: new Date().toISOString()
261
+
};
262
+
};
263
+
264
+
// ============================================================================
265
+
// Main Logic
266
+
// ============================================================================
267
+
268
+
const run = async (): Promise<void> => {
269
+
const dir = process.argv[2] || './plc_bundles';
270
+
271
+
console.log('PLC Bundle Fetcher');
272
+
console.log('==================');
273
+
console.log();
274
+
console.log(`Directory: ${dir}`);
275
+
console.log(`Source: ${PLC_URL}`);
276
+
console.log();
277
+
278
+
await fs.mkdir(dir, { recursive: true });
279
+
280
+
const index = await loadIndex(dir);
281
+
282
+
let currentBundle = index.last_bundle + 1;
283
+
let cursor: string | null = null;
284
+
let parentHash = '';
285
+
let prevBoundaryCIDs = new Set<string>();
286
+
287
+
if (index.bundles.length > 0) {
288
+
const lastBundle = index.bundles[index.bundles.length - 1];
289
+
cursor = lastBundle.end_time;
290
+
parentHash = lastBundle.hash;
291
+
292
+
try {
293
+
const prevOps = await loadBundle(dir, lastBundle.bundle_number);
294
+
prevBoundaryCIDs = getBoundaryCIDs(prevOps);
295
+
console.log(`Loaded previous bundle boundary: ${prevBoundaryCIDs.size} CIDs`);
296
+
} catch (err) {
297
+
console.log(`Could not load previous bundle for boundary detection`);
298
+
}
299
+
300
+
console.log(`Resuming from bundle ${currentBundle}`);
301
+
console.log(`Last operation: ${cursor}`);
302
+
} else {
303
+
console.log('Starting from the beginning (genesis)');
304
+
}
305
+
306
+
console.log();
307
+
308
+
let mempool: PLCOperation[] = [];
309
+
const seenCIDs = new Set<string>(prevBoundaryCIDs);
310
+
let totalFetched = 0;
311
+
let totalBundles = 0;
312
+
313
+
while (true) {
314
+
try {
315
+
console.log(`Fetching operations (cursor: ${cursor || 'start'})...`);
316
+
const operations = await fetchOperations(cursor, 1000);
317
+
318
+
if (operations.length === 0) {
319
+
console.log('No more operations available');
320
+
break;
321
+
}
322
+
323
+
// Deduplicate
324
+
const uniqueOps = operations.filter(op => {
325
+
if (seenCIDs.has(op.cid)) {
326
+
return false;
327
+
}
328
+
seenCIDs.add(op.cid);
329
+
return true;
330
+
});
331
+
332
+
console.log(` Fetched ${operations.length} operations (${uniqueOps.length} unique)`);
333
+
totalFetched += uniqueOps.length;
334
+
335
+
mempool.push(...uniqueOps);
336
+
cursor = operations[operations.length - 1].createdAt;
337
+
338
+
while (mempool.length >= BUNDLE_SIZE) {
339
+
const bundleOps = mempool.splice(0, BUNDLE_SIZE);
340
+
341
+
console.log(`\nCreating bundle ${String(currentBundle).padStart(6, '0')}...`);
342
+
343
+
const metadata = await saveBundle(dir, currentBundle, bundleOps, parentHash);
344
+
345
+
index.bundles.push(metadata);
346
+
index.last_bundle = currentBundle;
347
+
index.total_size_bytes += metadata.compressed_size;
348
+
349
+
await saveIndex(dir, index);
350
+
351
+
console.log(` ✓ Bundle ${String(currentBundle).padStart(6, '0')}: ${metadata.operation_count} ops, ${metadata.did_count} DIDs`);
352
+
console.log(` Chain Hash: ${metadata.hash}`);
353
+
console.log(` Content Hash: ${metadata.content_hash}`);
354
+
console.log(` Size: ${(metadata.compressed_size / 1024).toFixed(1)} KB`);
355
+
356
+
// Get boundary CIDs for next bundle
357
+
prevBoundaryCIDs = getBoundaryCIDs(bundleOps);
358
+
console.log(` Boundary CIDs: ${prevBoundaryCIDs.size}`);
359
+
console.log();
360
+
361
+
parentHash = metadata.hash;
362
+
currentBundle++;
363
+
totalBundles++;
364
+
}
365
+
366
+
await new Promise(resolve => setTimeout(resolve, 100));
367
+
368
+
} catch (err: any) {
369
+
console.error(`Error: ${err.message}`);
370
+
371
+
if (err.response) {
372
+
console.error(`HTTP Status: ${err.response.status}`);
373
+
}
374
+
375
+
if (err.code === 'ECONNRESET' || err.code === 'ECONNABORTED') {
376
+
console.log('Connection error, retrying in 5 seconds...');
377
+
await new Promise(resolve => setTimeout(resolve, 5000));
378
+
continue;
379
+
}
380
+
381
+
break;
382
+
}
383
+
}
384
+
385
+
await saveIndex(dir, index);
386
+
387
+
console.log();
388
+
console.log('================');
389
+
console.log('Complete!');
390
+
console.log('================');
391
+
console.log(`Total operations fetched: ${totalFetched}`);
392
+
console.log(`Bundles created: ${totalBundles}`);
393
+
console.log(`Total bundles: ${index.bundles.length}`);
394
+
console.log(`Mempool: ${mempool.length} operations`);
395
+
console.log(`Total size: ${(index.total_size_bytes / 1024 / 1024).toFixed(1)} MB`);
396
+
397
+
if (mempool.length > 0) {
398
+
console.log();
399
+
console.log(`Note: ${mempool.length} operations in mempool`);
400
+
}
401
+
};
402
+
403
+
// ============================================================================
404
+
// Entry Point
405
+
// ============================================================================
406
+
407
+
run().catch(err => {
408
+
console.error('Fatal error:', err.message);
409
+
console.error(err.stack);
410
+
process.exit(1);
411
+
});
+212
pnpm-lock.yaml
···
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
lockfileVersion: '9.0'
2
+
3
+
settings:
4
+
autoInstallPeers: true
5
+
excludeLinksFromLockfile: false
6
+
7
+
importers:
8
+
9
+
.:
10
+
dependencies:
11
+
'@bokuweb/zstd-wasm':
12
+
specifier: ^0.0.27
13
+
version: 0.0.27
14
+
axios:
15
+
specifier: ^1.13.0
16
+
version: 1.13.0
17
+
18
+
packages:
19
+
20
+
'@bokuweb/zstd-wasm@0.0.27':
21
+
resolution: {integrity: sha512-GDm2uOTK3ESjnYmSeLQifJnBsRCWajKLvN32D2ZcQaaCIJI/Hse9s74f7APXjHit95S10UImsRGkTsbwHmrtmg==}
22
+
23
+
asynckit@0.4.0:
24
+
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
25
+
26
+
axios@1.13.0:
27
+
resolution: {integrity: sha512-zt40Pz4zcRXra9CVV31KeyofwiNvAbJ5B6YPz9pMJ+yOSLikvPT4Yi5LjfgjRa9CawVYBaD1JQzIVcIvBejKeA==}
28
+
29
+
call-bind-apply-helpers@1.0.2:
30
+
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
31
+
engines: {node: '>= 0.4'}
32
+
33
+
combined-stream@1.0.8:
34
+
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
35
+
engines: {node: '>= 0.8'}
36
+
37
+
delayed-stream@1.0.0:
38
+
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
39
+
engines: {node: '>=0.4.0'}
40
+
41
+
dunder-proto@1.0.1:
42
+
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
43
+
engines: {node: '>= 0.4'}
44
+
45
+
es-define-property@1.0.1:
46
+
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
47
+
engines: {node: '>= 0.4'}
48
+
49
+
es-errors@1.3.0:
50
+
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
51
+
engines: {node: '>= 0.4'}
52
+
53
+
es-object-atoms@1.1.1:
54
+
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
55
+
engines: {node: '>= 0.4'}
56
+
57
+
es-set-tostringtag@2.1.0:
58
+
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
59
+
engines: {node: '>= 0.4'}
60
+
61
+
follow-redirects@1.15.11:
62
+
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
63
+
engines: {node: '>=4.0'}
64
+
peerDependencies:
65
+
debug: '*'
66
+
peerDependenciesMeta:
67
+
debug:
68
+
optional: true
69
+
70
+
form-data@4.0.4:
71
+
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
72
+
engines: {node: '>= 6'}
73
+
74
+
function-bind@1.1.2:
75
+
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
76
+
77
+
get-intrinsic@1.3.0:
78
+
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
79
+
engines: {node: '>= 0.4'}
80
+
81
+
get-proto@1.0.1:
82
+
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
83
+
engines: {node: '>= 0.4'}
84
+
85
+
gopd@1.2.0:
86
+
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
87
+
engines: {node: '>= 0.4'}
88
+
89
+
has-symbols@1.1.0:
90
+
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
91
+
engines: {node: '>= 0.4'}
92
+
93
+
has-tostringtag@1.0.2:
94
+
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
95
+
engines: {node: '>= 0.4'}
96
+
97
+
hasown@2.0.2:
98
+
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
99
+
engines: {node: '>= 0.4'}
100
+
101
+
math-intrinsics@1.1.0:
102
+
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
103
+
engines: {node: '>= 0.4'}
104
+
105
+
mime-db@1.52.0:
106
+
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
107
+
engines: {node: '>= 0.6'}
108
+
109
+
mime-types@2.1.35:
110
+
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
111
+
engines: {node: '>= 0.6'}
112
+
113
+
proxy-from-env@1.1.0:
114
+
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
115
+
116
+
snapshots:
117
+
118
+
'@bokuweb/zstd-wasm@0.0.27': {}
119
+
120
+
asynckit@0.4.0: {}
121
+
122
+
axios@1.13.0:
123
+
dependencies:
124
+
follow-redirects: 1.15.11
125
+
form-data: 4.0.4
126
+
proxy-from-env: 1.1.0
127
+
transitivePeerDependencies:
128
+
- debug
129
+
130
+
call-bind-apply-helpers@1.0.2:
131
+
dependencies:
132
+
es-errors: 1.3.0
133
+
function-bind: 1.1.2
134
+
135
+
combined-stream@1.0.8:
136
+
dependencies:
137
+
delayed-stream: 1.0.0
138
+
139
+
delayed-stream@1.0.0: {}
140
+
141
+
dunder-proto@1.0.1:
142
+
dependencies:
143
+
call-bind-apply-helpers: 1.0.2
144
+
es-errors: 1.3.0
145
+
gopd: 1.2.0
146
+
147
+
es-define-property@1.0.1: {}
148
+
149
+
es-errors@1.3.0: {}
150
+
151
+
es-object-atoms@1.1.1:
152
+
dependencies:
153
+
es-errors: 1.3.0
154
+
155
+
es-set-tostringtag@2.1.0:
156
+
dependencies:
157
+
es-errors: 1.3.0
158
+
get-intrinsic: 1.3.0
159
+
has-tostringtag: 1.0.2
160
+
hasown: 2.0.2
161
+
162
+
follow-redirects@1.15.11: {}
163
+
164
+
form-data@4.0.4:
165
+
dependencies:
166
+
asynckit: 0.4.0
167
+
combined-stream: 1.0.8
168
+
es-set-tostringtag: 2.1.0
169
+
hasown: 2.0.2
170
+
mime-types: 2.1.35
171
+
172
+
function-bind@1.1.2: {}
173
+
174
+
get-intrinsic@1.3.0:
175
+
dependencies:
176
+
call-bind-apply-helpers: 1.0.2
177
+
es-define-property: 1.0.1
178
+
es-errors: 1.3.0
179
+
es-object-atoms: 1.1.1
180
+
function-bind: 1.1.2
181
+
get-proto: 1.0.1
182
+
gopd: 1.2.0
183
+
has-symbols: 1.1.0
184
+
hasown: 2.0.2
185
+
math-intrinsics: 1.1.0
186
+
187
+
get-proto@1.0.1:
188
+
dependencies:
189
+
dunder-proto: 1.0.1
190
+
es-object-atoms: 1.1.1
191
+
192
+
gopd@1.2.0: {}
193
+
194
+
has-symbols@1.1.0: {}
195
+
196
+
has-tostringtag@1.0.2:
197
+
dependencies:
198
+
has-symbols: 1.1.0
199
+
200
+
hasown@2.0.2:
201
+
dependencies:
202
+
function-bind: 1.1.2
203
+
204
+
math-intrinsics@1.1.0: {}
205
+
206
+
mime-db@1.52.0: {}
207
+
208
+
mime-types@2.1.35:
209
+
dependencies:
210
+
mime-db: 1.52.0
211
+
212
+
proxy-from-env@1.1.0: {}