zen-fs-config 0.5.21 → 0.5.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/README.zh-CN.md +22 -0
- package/dist/index.d.mts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +172 -30
- package/dist/index.mjs +172 -30
- package/dist/zen-fs-config.js +28472 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -26,6 +26,28 @@ npm install zen-fs-config @zenfs/core @zenfs/dom zen-fs-sync
|
|
|
26
26
|
|
|
27
27
|
> `@zenfs/dom` provides the IndexedDB backend (required in browser environments). `zen-fs-cache` is an optional dependency for remote request caching.
|
|
28
28
|
|
|
29
|
+
## Usage via `<script>` tag (no build step)
|
|
30
|
+
|
|
31
|
+
A self-contained browser bundle is published at `dist/zen-fs-config.js`. It bundles **all** dependencies (`@zenfs/core`, `@zenfs/dom`, `zen-fs-sync`, `zen-fs-cache`) and exposes the library on the global `window.ZenFSConfig`. No npm install, no bundler — just drop it into any HTML page:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script src="https://unpkg.com/zen-fs-config/dist/zen-fs-config.js"></script>
|
|
35
|
+
<script>
|
|
36
|
+
(async () => {
|
|
37
|
+
const { createConfigRepo } = window.ZenFSConfig;
|
|
38
|
+
|
|
39
|
+
// IndexedDB primary backend is created automatically
|
|
40
|
+
const repo = await createConfigRepo('my-app');
|
|
41
|
+
|
|
42
|
+
repo.setConfig('greeting.json', { msg: 'hello' });
|
|
43
|
+
const cfg = await repo.getConfig('greeting.json');
|
|
44
|
+
console.log(cfg); // { msg: 'hello' }
|
|
45
|
+
})();
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
> The browser bundle includes a pure-JS SHA-256 fallback, so version tracking works even in non-secure contexts (plain HTTP) where `crypto.subtle` is unavailable.
|
|
50
|
+
|
|
29
51
|
## Quick Start
|
|
30
52
|
|
|
31
53
|
### 1. Initialize (zero-configuration)
|
package/README.zh-CN.md
CHANGED
|
@@ -14,6 +14,28 @@ npm install zen-fs-config @zenfs/core @zenfs/dom zen-fs-sync
|
|
|
14
14
|
|
|
15
15
|
> `@zenfs/dom` 提供 IndexedDB 后端(浏览器环境必需)。`zen-fs-cache` 为可选依赖。
|
|
16
16
|
|
|
17
|
+
## 通过 `<script>` 标签直接使用(无需构建)
|
|
18
|
+
|
|
19
|
+
包内置了一个自包含的浏览器构建 `dist/zen-fs-config.js`,它把**所有**依赖(`@zenfs/core`、`@zenfs/dom`、`zen-fs-sync`、`zen-fs-cache`)打包在一起,并将库挂载到全局变量 `window.ZenFSConfig`。无需 npm install、无需打包工具,直接放入任意 HTML 页面即可:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<script src="https://unpkg.com/zen-fs-config/dist/zen-fs-config.js"></script>
|
|
23
|
+
<script>
|
|
24
|
+
(async () => {
|
|
25
|
+
const { createConfigRepo } = window.ZenFSConfig;
|
|
26
|
+
|
|
27
|
+
// 自动创建 IndexedDB 主后端
|
|
28
|
+
const repo = await createConfigRepo('my-app');
|
|
29
|
+
|
|
30
|
+
repo.setConfig('greeting.json', { msg: 'hello' });
|
|
31
|
+
const cfg = await repo.getConfig('greeting.json');
|
|
32
|
+
console.log(cfg); // { msg: 'hello' }
|
|
33
|
+
})();
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> 浏览器构建包含纯 JS 实现的 SHA-256 回退,因此即使在 `crypto.subtle` 不可用的非安全上下文(普通 HTTP)中,版本追踪也能正常工作。
|
|
38
|
+
|
|
17
39
|
## 快速开始
|
|
18
40
|
|
|
19
41
|
### 1. 初始化(零参数)
|
package/dist/index.d.mts
CHANGED
|
@@ -349,8 +349,12 @@ declare function createSerializerChain(custom?: ConfigSerializer): PathAwareSeri
|
|
|
349
349
|
/**
|
|
350
350
|
* Map a config key to a file path.
|
|
351
351
|
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
352
|
+
* Always returns a path with a leading `/` so that callers can safely
|
|
353
|
+
* concatenate it with a directory prefix (e.g. `/${appId}${filePath}`).
|
|
354
|
+
*
|
|
355
|
+
* - `db/host` → `/db/host.json` (append .json if no extension)
|
|
356
|
+
* - `/readme.md` → `/readme.md` (preserve existing extension)
|
|
357
|
+
* - `notes` → `/notes.json`
|
|
354
358
|
*/
|
|
355
359
|
declare function configKeyToFilePath(configPath: string): string;
|
|
356
360
|
/**
|
|
@@ -758,6 +762,11 @@ declare function versionPathFor(configFilePath: string): string | null;
|
|
|
758
762
|
/**
|
|
759
763
|
* Compute SHA-256 hash of a Uint8Array.
|
|
760
764
|
* Returns "sha256:" prefix + hex digest.
|
|
765
|
+
*
|
|
766
|
+
* Priority:
|
|
767
|
+
* 1. Web Crypto (crypto.subtle) — secure contexts (HTTPS, localhost)
|
|
768
|
+
* 2. Node.js crypto — server-side
|
|
769
|
+
* 3. Pure-JS fallback — non-secure browser contexts (HTTP, some WebViews)
|
|
761
770
|
*/
|
|
762
771
|
declare function sha256(data: Uint8Array): Promise<string>;
|
|
763
772
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -349,8 +349,12 @@ declare function createSerializerChain(custom?: ConfigSerializer): PathAwareSeri
|
|
|
349
349
|
/**
|
|
350
350
|
* Map a config key to a file path.
|
|
351
351
|
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
352
|
+
* Always returns a path with a leading `/` so that callers can safely
|
|
353
|
+
* concatenate it with a directory prefix (e.g. `/${appId}${filePath}`).
|
|
354
|
+
*
|
|
355
|
+
* - `db/host` → `/db/host.json` (append .json if no extension)
|
|
356
|
+
* - `/readme.md` → `/readme.md` (preserve existing extension)
|
|
357
|
+
* - `notes` → `/notes.json`
|
|
354
358
|
*/
|
|
355
359
|
declare function configKeyToFilePath(configPath: string): string;
|
|
356
360
|
/**
|
|
@@ -758,6 +762,11 @@ declare function versionPathFor(configFilePath: string): string | null;
|
|
|
758
762
|
/**
|
|
759
763
|
* Compute SHA-256 hash of a Uint8Array.
|
|
760
764
|
* Returns "sha256:" prefix + hex digest.
|
|
765
|
+
*
|
|
766
|
+
* Priority:
|
|
767
|
+
* 1. Web Crypto (crypto.subtle) — secure contexts (HTTPS, localhost)
|
|
768
|
+
* 2. Node.js crypto — server-side
|
|
769
|
+
* 3. Pure-JS fallback — non-secure browser contexts (HTTP, some WebViews)
|
|
761
770
|
*/
|
|
762
771
|
declare function sha256(data: Uint8Array): Promise<string>;
|
|
763
772
|
/**
|
package/dist/index.js
CHANGED
|
@@ -144,9 +144,11 @@ function createSerializerChain(custom) {
|
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
function configKeyToFilePath(configPath) {
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
147
|
+
let p = configPath;
|
|
148
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
149
|
+
const ext = getExtension(p);
|
|
150
|
+
if (ext !== "") return p;
|
|
151
|
+
return p.endsWith("/") ? p : `${p}.json`;
|
|
150
152
|
}
|
|
151
153
|
function getExtension(path) {
|
|
152
154
|
const lastSlash = path.lastIndexOf("/");
|
|
@@ -262,6 +264,20 @@ async function ensureParentDir(absolutePath) {
|
|
|
262
264
|
}
|
|
263
265
|
|
|
264
266
|
// src/adapters.ts
|
|
267
|
+
function toUint8Array(data) {
|
|
268
|
+
if (data instanceof Uint8Array) return data;
|
|
269
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
270
|
+
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
271
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
|
|
272
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
273
|
+
}
|
|
274
|
+
return new Uint8Array(data);
|
|
275
|
+
}
|
|
276
|
+
function toString(data, encoding) {
|
|
277
|
+
if (typeof data === "string") return data;
|
|
278
|
+
const bytes = toUint8Array(data);
|
|
279
|
+
return new TextDecoder().decode(bytes);
|
|
280
|
+
}
|
|
265
281
|
function backendToSyncableFS(backend, name) {
|
|
266
282
|
const syncable = {
|
|
267
283
|
async readdir(path) {
|
|
@@ -270,15 +286,9 @@ function backendToSyncableFS(backend, name) {
|
|
|
270
286
|
async readFile(path, encoding) {
|
|
271
287
|
const result = await backend.readFile(path, encoding);
|
|
272
288
|
if (encoding) {
|
|
273
|
-
|
|
274
|
-
if (result instanceof Uint8Array) return new TextDecoder().decode(result);
|
|
275
|
-
if (Buffer.isBuffer(result)) return result.toString(encoding);
|
|
276
|
-
return String(result);
|
|
289
|
+
return toString(result, encoding);
|
|
277
290
|
}
|
|
278
|
-
|
|
279
|
-
if (result instanceof Uint8Array) return Buffer.from(result);
|
|
280
|
-
if (Buffer.isBuffer(result)) return result;
|
|
281
|
-
return Buffer.from(String(result));
|
|
291
|
+
return toUint8Array(result);
|
|
282
292
|
},
|
|
283
293
|
async writeFile(path, data) {
|
|
284
294
|
return backend.writeFile(path, data);
|
|
@@ -499,20 +509,150 @@ function versionPathFor(configFilePath) {
|
|
|
499
509
|
const versionFileName = fileName.startsWith(".") ? `${fileName}.version` : `.${fileName}.version`;
|
|
500
510
|
return dir ? `${dir}/${versionFileName}` : versionFileName;
|
|
501
511
|
}
|
|
512
|
+
function sha256PureJS(data) {
|
|
513
|
+
const K = new Uint32Array([
|
|
514
|
+
1116352408,
|
|
515
|
+
1899447441,
|
|
516
|
+
3049323471,
|
|
517
|
+
3921009573,
|
|
518
|
+
961987163,
|
|
519
|
+
1508970993,
|
|
520
|
+
2453635748,
|
|
521
|
+
2870763221,
|
|
522
|
+
3624381080,
|
|
523
|
+
310598401,
|
|
524
|
+
607225278,
|
|
525
|
+
1426881987,
|
|
526
|
+
1925078388,
|
|
527
|
+
2162078206,
|
|
528
|
+
2614888103,
|
|
529
|
+
3248222580,
|
|
530
|
+
3835390401,
|
|
531
|
+
4022224774,
|
|
532
|
+
264347078,
|
|
533
|
+
604807628,
|
|
534
|
+
770255983,
|
|
535
|
+
1249150122,
|
|
536
|
+
1555081692,
|
|
537
|
+
1996064986,
|
|
538
|
+
2554220882,
|
|
539
|
+
2821834349,
|
|
540
|
+
2952996808,
|
|
541
|
+
3210313671,
|
|
542
|
+
3336571891,
|
|
543
|
+
3584528711,
|
|
544
|
+
113926993,
|
|
545
|
+
338241895,
|
|
546
|
+
666307205,
|
|
547
|
+
773529912,
|
|
548
|
+
1294757372,
|
|
549
|
+
1396182291,
|
|
550
|
+
1695183700,
|
|
551
|
+
1986661051,
|
|
552
|
+
2177026350,
|
|
553
|
+
2456956037,
|
|
554
|
+
2730485921,
|
|
555
|
+
2820302411,
|
|
556
|
+
3259730800,
|
|
557
|
+
3345764771,
|
|
558
|
+
3516065817,
|
|
559
|
+
3600352804,
|
|
560
|
+
4094571909,
|
|
561
|
+
275423344,
|
|
562
|
+
430227734,
|
|
563
|
+
506948616,
|
|
564
|
+
659060556,
|
|
565
|
+
883997877,
|
|
566
|
+
958139571,
|
|
567
|
+
1322822218,
|
|
568
|
+
1537002063,
|
|
569
|
+
1747873779,
|
|
570
|
+
1955562222,
|
|
571
|
+
2024104815,
|
|
572
|
+
2227730452,
|
|
573
|
+
2361852424,
|
|
574
|
+
2428436474,
|
|
575
|
+
2756734187,
|
|
576
|
+
3204031479,
|
|
577
|
+
3329325298
|
|
578
|
+
]);
|
|
579
|
+
const H = new Uint32Array([
|
|
580
|
+
1779033703,
|
|
581
|
+
3144134277,
|
|
582
|
+
1013904242,
|
|
583
|
+
2773480762,
|
|
584
|
+
1359893119,
|
|
585
|
+
2600822924,
|
|
586
|
+
528734635,
|
|
587
|
+
1541459225
|
|
588
|
+
]);
|
|
589
|
+
const len = data.length;
|
|
590
|
+
const bitLen = len * 8;
|
|
591
|
+
const padLen = (len + 8 >> 6 << 6) + 64;
|
|
592
|
+
const buf = new Uint8Array(padLen);
|
|
593
|
+
buf.set(data);
|
|
594
|
+
buf[len] = 128;
|
|
595
|
+
const dv = new DataView(buf.buffer);
|
|
596
|
+
dv.setUint32(padLen - 4, bitLen >>> 0, false);
|
|
597
|
+
dv.setUint32(padLen - 8, Math.floor(bitLen / 4294967296) >>> 0, false);
|
|
598
|
+
const W = new Uint32Array(64);
|
|
599
|
+
for (let i = 0; i < padLen; i += 64) {
|
|
600
|
+
for (let t = 0; t < 16; t++) {
|
|
601
|
+
W[t] = dv.getUint32(i + t * 4, false);
|
|
602
|
+
}
|
|
603
|
+
for (let t = 16; t < 64; t++) {
|
|
604
|
+
const s0 = (W[t - 15] >>> 7 | W[t - 15] << 25) ^ (W[t - 15] >>> 18 | W[t - 15] << 14) ^ W[t - 15] >>> 3;
|
|
605
|
+
const s1 = (W[t - 2] >>> 17 | W[t - 2] << 15) ^ (W[t - 2] >>> 19 | W[t - 2] << 13) ^ W[t - 2] >>> 10;
|
|
606
|
+
W[t] = W[t - 16] + s0 + W[t - 7] + s1 >>> 0;
|
|
607
|
+
}
|
|
608
|
+
let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4], f = H[5], g = H[6], h = H[7];
|
|
609
|
+
for (let t = 0; t < 64; t++) {
|
|
610
|
+
const S1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
|
|
611
|
+
const ch = e & f ^ ~e & g;
|
|
612
|
+
const temp1 = h + S1 + ch + K[t] + W[t] >>> 0;
|
|
613
|
+
const S0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
|
|
614
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
615
|
+
const temp2 = S0 + maj >>> 0;
|
|
616
|
+
h = g;
|
|
617
|
+
g = f;
|
|
618
|
+
f = e;
|
|
619
|
+
e = d + temp1 >>> 0;
|
|
620
|
+
d = c;
|
|
621
|
+
c = b;
|
|
622
|
+
b = a;
|
|
623
|
+
a = temp1 + temp2 >>> 0;
|
|
624
|
+
}
|
|
625
|
+
H[0] = H[0] + a >>> 0;
|
|
626
|
+
H[1] = H[1] + b >>> 0;
|
|
627
|
+
H[2] = H[2] + c >>> 0;
|
|
628
|
+
H[3] = H[3] + d >>> 0;
|
|
629
|
+
H[4] = H[4] + e >>> 0;
|
|
630
|
+
H[5] = H[5] + f >>> 0;
|
|
631
|
+
H[6] = H[6] + g >>> 0;
|
|
632
|
+
H[7] = H[7] + h >>> 0;
|
|
633
|
+
}
|
|
634
|
+
const out = new Uint8Array(32);
|
|
635
|
+
const outDv = new DataView(out.buffer);
|
|
636
|
+
for (let i = 0; i < 8; i++) outDv.setUint32(i * 4, H[i], false);
|
|
637
|
+
return out;
|
|
638
|
+
}
|
|
502
639
|
async function sha256(data) {
|
|
503
640
|
const buffer = data.byteLength === data.buffer.byteLength ? data.buffer : data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
504
|
-
|
|
505
|
-
|
|
641
|
+
const webCrypto = globalThis.crypto;
|
|
642
|
+
if (webCrypto && typeof webCrypto.subtle?.digest === "function") {
|
|
643
|
+
const hashBuffer = await webCrypto.subtle.digest("SHA-256", buffer);
|
|
506
644
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
507
|
-
const
|
|
508
|
-
return `sha256:${
|
|
645
|
+
const hex2 = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
646
|
+
return `sha256:${hex2}`;
|
|
509
647
|
}
|
|
510
648
|
if (typeof globalThis.window === "undefined") {
|
|
511
649
|
const nodeCrypto = await new Function("return import('node:crypto')")();
|
|
512
650
|
const hash = nodeCrypto.createHash("sha256").update(Buffer.from(buffer)).digest("hex");
|
|
513
651
|
return `sha256:${hash}`;
|
|
514
652
|
}
|
|
515
|
-
|
|
653
|
+
const digest = sha256PureJS(data);
|
|
654
|
+
const hex = Array.from(digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
655
|
+
return `sha256:${hex}`;
|
|
516
656
|
}
|
|
517
657
|
async function readVersion(fs, versionFilePath) {
|
|
518
658
|
try {
|
|
@@ -553,7 +693,7 @@ async function verifyOrRepairVersion(fs, configFilePath, author) {
|
|
|
553
693
|
data = new TextEncoder().encode(content);
|
|
554
694
|
} else if (content instanceof Uint8Array) {
|
|
555
695
|
data = content;
|
|
556
|
-
} else if (Buffer.isBuffer(content)) {
|
|
696
|
+
} else if (typeof Buffer !== "undefined" && Buffer.isBuffer(content)) {
|
|
557
697
|
data = new Uint8Array(content.buffer, content.byteOffset, content.byteLength);
|
|
558
698
|
} else {
|
|
559
699
|
data = new Uint8Array(content);
|
|
@@ -704,7 +844,7 @@ var ConfigRepo = class {
|
|
|
704
844
|
const fullPath = `${NODES_DIR}/${nodeId}${filePath}`;
|
|
705
845
|
try {
|
|
706
846
|
const raw = await this.cachedFS.readFile(fullPath);
|
|
707
|
-
return this.serializer.deserialize(
|
|
847
|
+
return this.serializer.deserialize(toUint8Array2(raw), fullPath);
|
|
708
848
|
} catch {
|
|
709
849
|
throw new Error(`Node config not found: ${nodeId}${path}`);
|
|
710
850
|
}
|
|
@@ -781,7 +921,7 @@ var ConfigRepo = class {
|
|
|
781
921
|
const fullPath = `${NODES_DIR}/${nodeId}${filePath}`;
|
|
782
922
|
try {
|
|
783
923
|
const raw = await this.cachedFS.readFile(fullPath);
|
|
784
|
-
return this.serializer.deserialize(
|
|
924
|
+
return this.serializer.deserialize(toUint8Array2(raw), fullPath);
|
|
785
925
|
} catch {
|
|
786
926
|
throw new Error(`Node config not found: ${nodeId}${path}`);
|
|
787
927
|
}
|
|
@@ -875,7 +1015,7 @@ var ConfigRepo = class {
|
|
|
875
1015
|
if (!entry.endsWith(".json")) continue;
|
|
876
1016
|
try {
|
|
877
1017
|
const raw = await this.cachedFS.readFile(`${DELETIONS_DIR}/${entry}`);
|
|
878
|
-
const data = JSON.parse(new TextDecoder().decode(
|
|
1018
|
+
const data = JSON.parse(new TextDecoder().decode(toUint8Array2(raw)));
|
|
879
1019
|
tombstones.push(data);
|
|
880
1020
|
} catch {
|
|
881
1021
|
}
|
|
@@ -1118,7 +1258,7 @@ var ConfigRepo = class {
|
|
|
1118
1258
|
try {
|
|
1119
1259
|
const raw = await this.cachedFS.readFile(metaPath);
|
|
1120
1260
|
const archive = JSON.parse(
|
|
1121
|
-
new TextDecoder().decode(
|
|
1261
|
+
new TextDecoder().decode(toUint8Array2(raw))
|
|
1122
1262
|
);
|
|
1123
1263
|
const configPath = archive.conflictPath;
|
|
1124
1264
|
const bytes = this.serializer.serialize(mergedContent, configPath);
|
|
@@ -1154,7 +1294,7 @@ var ConfigRepo = class {
|
|
|
1154
1294
|
try {
|
|
1155
1295
|
const raw = await this.cachedFS.readFile(metaPath);
|
|
1156
1296
|
const archive = JSON.parse(
|
|
1157
|
-
new TextDecoder().decode(
|
|
1297
|
+
new TextDecoder().decode(toUint8Array2(raw))
|
|
1158
1298
|
);
|
|
1159
1299
|
archives.push(archive);
|
|
1160
1300
|
} catch {
|
|
@@ -1169,7 +1309,7 @@ var ConfigRepo = class {
|
|
|
1169
1309
|
const conflictDir = `${CONFLICTS_DIR}/${conflictId}`.replace(/\/meta\.json$/, "");
|
|
1170
1310
|
const filePath = `${conflictDir}/${fileType}`;
|
|
1171
1311
|
const raw = await this.cachedFS.readFile(filePath);
|
|
1172
|
-
return new TextDecoder().decode(
|
|
1312
|
+
return new TextDecoder().decode(toUint8Array2(raw));
|
|
1173
1313
|
}
|
|
1174
1314
|
// -----------------------------------------------------------------------
|
|
1175
1315
|
// IConfigRepo — Lifecycle
|
|
@@ -1300,7 +1440,7 @@ var ConfigRepo = class {
|
|
|
1300
1440
|
files.map(async (filePath) => {
|
|
1301
1441
|
try {
|
|
1302
1442
|
const raw = await this.cachedFS.readFile(filePath);
|
|
1303
|
-
const data = this.serializer.deserialize(
|
|
1443
|
+
const data = this.serializer.deserialize(toUint8Array2(raw), filePath);
|
|
1304
1444
|
return { filePath, data };
|
|
1305
1445
|
} catch {
|
|
1306
1446
|
return null;
|
|
@@ -1430,7 +1570,7 @@ var ConfigRepo = class {
|
|
|
1430
1570
|
async readMetaFile(path) {
|
|
1431
1571
|
try {
|
|
1432
1572
|
const raw = await this.cachedFS.readFile(path);
|
|
1433
|
-
return JSON.parse(new TextDecoder().decode(
|
|
1573
|
+
return JSON.parse(new TextDecoder().decode(toUint8Array2(raw)));
|
|
1434
1574
|
} catch {
|
|
1435
1575
|
return null;
|
|
1436
1576
|
}
|
|
@@ -1458,7 +1598,7 @@ var ConfigRepo = class {
|
|
|
1458
1598
|
const filePath = `${BACKENDS_DIR}/${entry}`;
|
|
1459
1599
|
try {
|
|
1460
1600
|
const raw = await this.cachedFS.readFile(filePath);
|
|
1461
|
-
const desc = JSON.parse(new TextDecoder().decode(
|
|
1601
|
+
const desc = JSON.parse(new TextDecoder().decode(toUint8Array2(raw)));
|
|
1462
1602
|
if (desc.id && desc.type) {
|
|
1463
1603
|
let mtime = 0;
|
|
1464
1604
|
try {
|
|
@@ -1793,7 +1933,7 @@ var ConfigRepo = class {
|
|
|
1793
1933
|
const descPath = this.appDataGroupFilePath(id);
|
|
1794
1934
|
try {
|
|
1795
1935
|
const raw = await this.cachedFS.readFile(descPath);
|
|
1796
|
-
const descriptor = JSON.parse(new TextDecoder().decode(
|
|
1936
|
+
const descriptor = JSON.parse(new TextDecoder().decode(toUint8Array2(raw)));
|
|
1797
1937
|
const group = new AppDataGroupImpl(
|
|
1798
1938
|
id,
|
|
1799
1939
|
this.appId,
|
|
@@ -1817,7 +1957,7 @@ var ConfigRepo = class {
|
|
|
1817
1957
|
if (!entry.endsWith(".json")) continue;
|
|
1818
1958
|
try {
|
|
1819
1959
|
const raw = await this.cachedFS.readFile(`${dir}/${entry}`);
|
|
1820
|
-
const desc = JSON.parse(new TextDecoder().decode(
|
|
1960
|
+
const desc = JSON.parse(new TextDecoder().decode(toUint8Array2(raw)));
|
|
1821
1961
|
if (desc.id && desc.groupType === "data-sync") {
|
|
1822
1962
|
descriptors.push(desc);
|
|
1823
1963
|
}
|
|
@@ -1983,11 +2123,13 @@ var AppDataGroupImpl = class {
|
|
|
1983
2123
|
this.dataBackends.clear();
|
|
1984
2124
|
}
|
|
1985
2125
|
};
|
|
1986
|
-
function
|
|
2126
|
+
function toUint8Array2(raw) {
|
|
1987
2127
|
if (raw instanceof ArrayBuffer) return new Uint8Array(raw);
|
|
1988
2128
|
if (raw instanceof Uint8Array) return raw;
|
|
1989
2129
|
if (typeof raw === "string") return new TextEncoder().encode(raw);
|
|
1990
|
-
if (Buffer.isBuffer(raw))
|
|
2130
|
+
if (typeof Buffer !== "undefined" && Buffer.isBuffer(raw)) {
|
|
2131
|
+
return new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
2132
|
+
}
|
|
1991
2133
|
return new Uint8Array(raw);
|
|
1992
2134
|
}
|
|
1993
2135
|
async function createConfigRepo(appId, options = {}) {
|