@fireproof/core 0.19.8-dev-global → 0.19.9-dev-frag

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. package/README.md +7 -0
  2. package/chunk-7EWIAXTM.js +7 -0
  3. package/chunk-7EWIAXTM.js.map +1 -0
  4. package/chunk-JO5AVWG7.js +67 -0
  5. package/chunk-JO5AVWG7.js.map +1 -0
  6. package/chunk-PB4BKL4O.js +7 -0
  7. package/chunk-PB4BKL4O.js.map +1 -0
  8. package/chunk-YS4GL6OK.js +266 -0
  9. package/chunk-YS4GL6OK.js.map +1 -0
  10. package/{store-indexdb-WLRSICCB.js → gateway-IZRHJWPE.js} +48 -80
  11. package/gateway-IZRHJWPE.js.map +1 -0
  12. package/gateway-YSNUK2L3.js +145 -0
  13. package/gateway-YSNUK2L3.js.map +1 -0
  14. package/index.cjs +2132 -1783
  15. package/index.cjs.map +1 -1
  16. package/index.d.cts +613 -513
  17. package/index.d.ts +613 -513
  18. package/index.global.js +19366 -20107
  19. package/index.global.js.map +1 -1
  20. package/index.js +1512 -1022
  21. package/index.js.map +1 -1
  22. package/key-bag-file-NMEBFSPM.js +54 -0
  23. package/key-bag-file-NMEBFSPM.js.map +1 -0
  24. package/key-bag-indexdb-X5V6GNBZ.js +50 -0
  25. package/key-bag-indexdb-X5V6GNBZ.js.map +1 -0
  26. package/mem-filesystem-B6C6QOIP.js +41 -0
  27. package/mem-filesystem-B6C6QOIP.js.map +1 -0
  28. package/metafile-cjs.json +1 -1
  29. package/metafile-esm.json +1 -1
  30. package/metafile-iife.json +1 -1
  31. package/node-filesystem-5JLBSHKQ.js +41 -0
  32. package/node-filesystem-5JLBSHKQ.js.map +1 -0
  33. package/package.json +8 -7
  34. package/tests/blockstore/fragment-gateway.test.ts +107 -0
  35. package/tests/blockstore/keyed-crypto.test.ts +302 -0
  36. package/tests/blockstore/loader.test.ts +24 -19
  37. package/tests/blockstore/store.test.ts +34 -28
  38. package/tests/blockstore/transaction.test.ts +19 -15
  39. package/tests/fireproof/config.test.ts +94 -78
  40. package/tests/fireproof/crdt.test.ts +34 -28
  41. package/tests/fireproof/database.test.ts +22 -14
  42. package/tests/fireproof/fireproof.test.fixture.ts +133 -0
  43. package/tests/fireproof/fireproof.test.ts +331 -219
  44. package/tests/fireproof/hello.test.ts +6 -4
  45. package/tests/fireproof/indexer.test.ts +34 -27
  46. package/tests/fireproof/utils.test.ts +65 -0
  47. package/tests/helpers.ts +25 -57
  48. package/utils-IZPK4QS7.js +14 -0
  49. package/utils-IZPK4QS7.js.map +1 -0
  50. package/chunk-BNL4PVBF.js +0 -314
  51. package/chunk-BNL4PVBF.js.map +0 -1
  52. package/chunk-JW2QT6BF.js +0 -184
  53. package/chunk-JW2QT6BF.js.map +0 -1
  54. package/node-sys-container-MIEX6ELJ.js +0 -29
  55. package/node-sys-container-MIEX6ELJ.js.map +0 -1
  56. package/store-file-VJ6BI4II.js +0 -191
  57. package/store-file-VJ6BI4II.js.map +0 -1
  58. package/store-indexdb-WLRSICCB.js.map +0 -1
@@ -0,0 +1,41 @@
1
+ import {
2
+ toArrayBuffer
3
+ } from "./chunk-JO5AVWG7.js";
4
+ import "./chunk-YS4GL6OK.js";
5
+
6
+ // src/runtime/gateways/file/node-filesystem.ts
7
+ var NodeFileSystem = class {
8
+ async start() {
9
+ this.fs = await import("fs/promises");
10
+ return this;
11
+ }
12
+ async mkdir(path, options) {
13
+ return this.fs?.mkdir(path, options);
14
+ }
15
+ async readdir(path, options) {
16
+ return this.fs?.readdir(path, options);
17
+ }
18
+ async rm(path, options) {
19
+ return this.fs?.rm(path, options);
20
+ }
21
+ async copyFile(source, destination) {
22
+ return this.fs?.copyFile(source, destination);
23
+ }
24
+ async readfile(path, options) {
25
+ const ret = await this.fs?.readFile(path, options);
26
+ return toArrayBuffer(ret);
27
+ }
28
+ stat(path) {
29
+ return this.fs?.stat(path);
30
+ }
31
+ async unlink(path) {
32
+ return this.fs?.unlink(path);
33
+ }
34
+ async writefile(path, data) {
35
+ return this.fs?.writeFile(path, Buffer.from(data));
36
+ }
37
+ };
38
+ export {
39
+ NodeFileSystem
40
+ };
41
+ //# sourceMappingURL=node-filesystem-5JLBSHKQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/runtime/gateways/file/node-filesystem.ts"],"sourcesContent":["import type { PathLike, MakeDirectoryOptions, Stats, ObjectEncodingOptions } from \"fs\";\nimport type { mkdir, readdir, rm, copyFile, readFile, stat, unlink, writeFile } from \"fs/promises\";\nimport { toArrayBuffer } from \"./utils.js\";\nimport { SysFileSystem } from \"../../../types.js\";\n\nexport class NodeFileSystem implements SysFileSystem {\n fs?: {\n mkdir: typeof mkdir;\n readdir: typeof readdir;\n rm: typeof rm;\n copyFile: typeof copyFile;\n readFile: typeof readFile;\n stat: typeof stat;\n unlink: typeof unlink;\n writeFile: typeof writeFile;\n };\n\n async start(): Promise<SysFileSystem> {\n this.fs = await import(\"fs/promises\");\n return this;\n }\n async mkdir(path: PathLike, options?: { recursive: boolean }): Promise<string | undefined> {\n return this.fs?.mkdir(path, options);\n }\n async readdir(path: PathLike, options?: ObjectEncodingOptions): Promise<string[]> {\n return this.fs?.readdir(path, options) as Promise<string[]>;\n }\n async rm(path: PathLike, options?: MakeDirectoryOptions & { recursive: boolean }): Promise<void> {\n return this.fs?.rm(path, options);\n }\n async copyFile(source: PathLike, destination: PathLike): Promise<void> {\n return this.fs?.copyFile(source, destination);\n }\n async readfile(path: PathLike, options?: { encoding: BufferEncoding; flag?: string }): Promise<Uint8Array> {\n const ret = (await this.fs?.readFile(path, options)) as Buffer;\n return toArrayBuffer(ret);\n }\n stat(path: PathLike): Promise<Stats> {\n return this.fs?.stat(path) as Promise<Stats>;\n }\n async unlink(path: PathLike): Promise<void> {\n return this.fs?.unlink(path);\n }\n async writefile(path: PathLike, data: Uint8Array | string): Promise<void> {\n return this.fs?.writeFile(path, Buffer.from(data));\n }\n}\n\n// import { type NodeMap, join } from \"../../sys-container.js\";\n// import type { ObjectEncodingOptions, PathLike } from \"fs\";\n// import * as fs from \"fs/promises\";\n// import * as path from \"path\";\n// import * as os from \"os\";\n// import * as url from \"url\";\n// import { toArrayBuffer } from \"./utils.js\";\n\n// export async function createNodeSysContainer(): Promise<NodeMap> {\n// // const nodePath = \"node:path\";\n// // const nodeOS = \"node:os\";\n// // const nodeURL = \"node:url\";\n// // const nodeFS = \"node:fs\";\n// // const fs = (await import(\"node:fs\")).promises;\n// // const assert = \"assert\";\n// // const path = await import(\"node:path\");\n// return {\n// state: \"node\",\n// ...path,\n// // ...(await import(\"node:os\")),\n// // ...(await import(\"node:url\")),\n// ...os,\n// ...url,\n// ...fs,\n// join,\n// stat: fs.stat as NodeMap[\"stat\"],\n// readdir: fs.readdir as NodeMap[\"readdir\"],\n// readfile: async (path: PathLike, options?: ObjectEncodingOptions): Promise<Uint8Array> => {\n// const rs = await fs.readFile(path, options);\n// return toArrayBuffer(rs);\n// },\n// writefile: fs.writeFile as NodeMap[\"writefile\"],\n// };\n// }\n"],"mappings":";;;;;;AAKO,IAAM,iBAAN,MAA8C;AAAA,EAYnD,MAAM,QAAgC;AACpC,SAAK,KAAK,MAAM,OAAO,aAAa;AACpC,WAAO;AAAA,EACT;AAAA,EACA,MAAM,MAAM,MAAgB,SAA+D;AACzF,WAAO,KAAK,IAAI,MAAM,MAAM,OAAO;AAAA,EACrC;AAAA,EACA,MAAM,QAAQ,MAAgB,SAAoD;AAChF,WAAO,KAAK,IAAI,QAAQ,MAAM,OAAO;AAAA,EACvC;AAAA,EACA,MAAM,GAAG,MAAgB,SAAwE;AAC/F,WAAO,KAAK,IAAI,GAAG,MAAM,OAAO;AAAA,EAClC;AAAA,EACA,MAAM,SAAS,QAAkB,aAAsC;AACrE,WAAO,KAAK,IAAI,SAAS,QAAQ,WAAW;AAAA,EAC9C;AAAA,EACA,MAAM,SAAS,MAAgB,SAA4E;AACzG,UAAM,MAAO,MAAM,KAAK,IAAI,SAAS,MAAM,OAAO;AAClD,WAAO,cAAc,GAAG;AAAA,EAC1B;AAAA,EACA,KAAK,MAAgC;AACnC,WAAO,KAAK,IAAI,KAAK,IAAI;AAAA,EAC3B;AAAA,EACA,MAAM,OAAO,MAA+B;AAC1C,WAAO,KAAK,IAAI,OAAO,IAAI;AAAA,EAC7B;AAAA,EACA,MAAM,UAAU,MAAgB,MAA0C;AACxE,WAAO,KAAK,IAAI,UAAU,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,EACnD;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.19.8-dev-global",
3
+ "version": "0.19.9-dev-frag",
4
4
  "description": "Live database for the web.",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -46,17 +46,18 @@
46
46
  "react": ">=18.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "react": "^18.3.1",
50
- "@adviser/cement": "^0.2.2",
49
+ "@adviser/cement": "^0.2.22",
50
+ "@ipld/unixfs": "^3.0.0",
51
+ "@ipld/car": "^5.3.2",
52
+ "@web3-storage/pail": "^0.6.0",
53
+ "cborg": "^4.2.3",
51
54
  "charwise": "^3.0.1",
52
55
  "prolly-trees": "^1.0.4",
53
56
  "idb": "^8.0.0",
54
57
  "ipfs-unixfs-exporter": "^13.5.0",
55
- "uuidv7": "^1.0.0",
58
+ "memfs": "^4.11.0",
56
59
  "p-limit": "^6.1.0",
57
- "@web3-storage/pail": "^0.6.0",
58
- "@ipld/unixfs": "^3.0.0",
59
- "@ipld/car": "^5.3.2"
60
+ "react": "^18.3.1"
60
61
  },
61
62
  "scripts": {}
62
63
  }
@@ -0,0 +1,107 @@
1
+ import { Result, URI } from "@adviser/cement";
2
+ import { mockSuperThis } from "../helpers";
3
+ import { bs } from "@fireproof/core";
4
+
5
+ class TraceGateway implements bs.Gateway {
6
+ readonly buildUrlFn = vitest.fn();
7
+
8
+ readonly fragSize: number;
9
+ constructor(fragSize = 0) {
10
+ this.fragSize = fragSize;
11
+ }
12
+
13
+ buildUrl(baseUrl: URI, key: string): Promise<Result<URI>> {
14
+ this.buildUrlFn(baseUrl, key);
15
+ return Promise.resolve(Result.Ok(baseUrl.build().setParam("key", key).URI()));
16
+ }
17
+ readonly startFn = vitest.fn();
18
+ start(baseUrl: URI): Promise<Result<URI>> {
19
+ this.startFn(baseUrl);
20
+ const burl = baseUrl.build();
21
+ if (this.fragSize) {
22
+ burl.setParam("fragSize", this.fragSize.toString());
23
+ }
24
+ return Promise.resolve(Result.Ok(burl.URI()));
25
+ }
26
+ readonly closeFn = vitest.fn();
27
+ close(baseUrl: URI): Promise<bs.VoidResult> {
28
+ this.closeFn(baseUrl);
29
+ return Promise.resolve(Result.Ok(undefined));
30
+ }
31
+ readonly destroyFn = vitest.fn();
32
+ destroy(baseUrl: URI): Promise<bs.VoidResult> {
33
+ this.destroyFn(baseUrl);
34
+ return Promise.resolve(Result.Ok(undefined));
35
+ }
36
+ readonly getFn = vitest.fn();
37
+ putCalls = 0;
38
+ async get(url: URI): Promise<Result<Uint8Array>> {
39
+ const idx = this.putCalls++;
40
+ this.getFn(url);
41
+ return Result.Ok(this.putFn.mock.calls[idx][1]);
42
+ }
43
+ readonly putFn = vitest.fn();
44
+ async put(url: URI, data: Uint8Array): Promise<Result<void>> {
45
+ this.putFn(url, data);
46
+ return Result.Ok(undefined);
47
+ }
48
+ readonly deleteFn = vitest.fn();
49
+ async delete(url: URI): Promise<Result<void>> {
50
+ this.deleteFn(url);
51
+ return Result.Ok(undefined);
52
+ }
53
+ }
54
+
55
+ describe("FragmentGateway", () => {
56
+ const sthis = mockSuperThis();
57
+ it("passthrough", async () => {
58
+ const innerGW = new TraceGateway();
59
+ const fgw = new bs.FragmentGateway(sthis, innerGW);
60
+ const url = URI.from("http://example.com?key=3333");
61
+
62
+ expect(await fgw.put(url, new Uint8Array([1, 2, 3, 4]))).toEqual(Result.Ok(undefined));
63
+ expect(innerGW.putFn).toHaveBeenCalledWith(url, new Uint8Array([1, 2, 3, 4]));
64
+
65
+ expect(await fgw.get(url)).toEqual(Result.Ok(new Uint8Array([1, 2, 3, 4])));
66
+ expect(innerGW.getFn).toHaveBeenCalledWith(url);
67
+ });
68
+
69
+ function slice(total: number, headerSize: number, fragSize: number): { len?: string; ofs: string }[] {
70
+ const res = [];
71
+ for (let ofs = 0; ofs < total; ofs += fragSize - headerSize) {
72
+ res.push({ len: total.toString(), ofs: ofs.toString() });
73
+ }
74
+ return res;
75
+ }
76
+
77
+ it("enable frag", async () => {
78
+ const innerGW = new TraceGateway(128);
79
+ const fgw = new bs.FragmentGateway(sthis, innerGW);
80
+ const url = (await fgw.start(URI.from("http://example.com?key=3333"))).Ok();
81
+ const buf = new Uint8Array(1024).fill(1).map((_, i) => i);
82
+
83
+ expect(await fgw.put(url, buf)).toEqual(Result.Ok(undefined));
84
+
85
+ const ref = slice(1024, fgw.headerSize, 128);
86
+
87
+ expect(
88
+ innerGW.putFn.mock.calls.map((i) => {
89
+ return {
90
+ len: i[0].getParam("len"),
91
+ ofs: i[0].getParam("ofs"),
92
+ };
93
+ }),
94
+ ).toEqual(ref);
95
+
96
+ expect((await fgw.get(url)).Ok()).toEqual(buf);
97
+ ref[0].len = undefined;
98
+ expect(
99
+ innerGW.getFn.mock.calls.map((i) => {
100
+ return {
101
+ len: i[0].getParam("len"),
102
+ ofs: i[0].getParam("ofs"),
103
+ };
104
+ }),
105
+ ).toEqual(ref);
106
+ });
107
+ });
@@ -0,0 +1,302 @@
1
+ import { bs, rt } from "@fireproof/core";
2
+ import { BuildURI, Logger, MockLogger, runtimeFn, toCryptoRuntime, URI } from "@adviser/cement";
3
+ import { base58btc } from "multiformats/bases/base58";
4
+ import { sha256 as hasher } from "multiformats/hashes/sha2";
5
+ import * as dagCodec from "@ipld/dag-cbor";
6
+ import { mockSuperThis } from "../helpers";
7
+
8
+ describe("KeyBag", () => {
9
+ let url: URI;
10
+ const sthis = mockSuperThis();
11
+ beforeAll(async () => {
12
+ await sthis.start();
13
+ if (runtimeFn().isBrowser) {
14
+ url = URI.from("indexdb://fp-keybag");
15
+ } else {
16
+ url = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
17
+ }
18
+ });
19
+ it("default-path", async () => {
20
+ const old = sthis.env.get("FP_KEYBAG_URL");
21
+ sthis.env.delete("FP_KEYBAG_URL");
22
+ const kb = await rt.kb.getKeyBag(sthis);
23
+ if (runtimeFn().isBrowser) {
24
+ expect(kb.rt.url.toString()).toBe(`indexdb://fp-keybag`);
25
+ } else {
26
+ expect(kb.rt.url.toString()).toBe(`file://${sthis.env.get("HOME")}/.fireproof/keybag`);
27
+ }
28
+ sthis.env.set("FP_KEYBAG_URL", old);
29
+ });
30
+ it("from env", async () => {
31
+ const old = sthis.env.get("FP_KEYBAG_URL");
32
+ sthis.env.set("FP_KEYBAG_URL", url.toString());
33
+ const kb = await rt.kb.getKeyBag(sthis);
34
+ expect(kb.rt.url.toString()).toBe(url.toString());
35
+ sthis.env.set("FP_KEYBAG_URL", old);
36
+ });
37
+ it("simple add", async () => {
38
+ const kb = await rt.kb.getKeyBag(sthis, {
39
+ url: url.toString(),
40
+ crypto: toCryptoRuntime({
41
+ randomBytes: (size) => new Uint8Array(size).map((_, i) => i),
42
+ }),
43
+ });
44
+ const name = "setkey" + Math.random();
45
+ expect((await kb.getNamedKey(name, true)).isErr()).toBeTruthy();
46
+
47
+ const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
48
+ const res = await kb.setNamedKey(name, key);
49
+ expect(res.isOk()).toBeTruthy();
50
+ expect((await kb.getNamedKey(name, true)).Ok()).toEqual(res.Ok());
51
+
52
+ const name2 = "implicit";
53
+ const created = await kb.getNamedKey(name2);
54
+ expect(created.isOk()).toBeTruthy();
55
+
56
+ expect((await kb.getNamedKey(name2)).Ok()).toEqual(created.Ok());
57
+
58
+ let diskBag: rt.kb.KeyItem;
59
+ let diskBag2: rt.kb.KeyItem;
60
+ const provider = await kb.rt.getBag();
61
+ if (runtimeFn().isBrowser) {
62
+ const p = provider as rt.kb.KeyBagProviderIndexDB;
63
+ diskBag = await p._prepare().then((db) => db.get("bag", name));
64
+ diskBag2 = await p._prepare().then((db) => db.get("bag", name2));
65
+ } else {
66
+ const p = provider as rt.kb.KeyBagProviderFile;
67
+ const { sysFS } = await p._prepare(name);
68
+
69
+ diskBag = await sysFS.readfile((await p._prepare(name)).fName).then((data) => {
70
+ return JSON.parse(new TextDecoder().decode(data)) as rt.kb.KeyItem;
71
+ });
72
+ diskBag2 = await sysFS.readfile((await p._prepare(name2)).fName).then((data) => {
73
+ return JSON.parse(new TextDecoder().decode(data)) as rt.kb.KeyItem;
74
+ });
75
+ }
76
+ expect(await kb.toKeyWithFingerPrint(diskBag.key)).toEqual(res);
77
+ expect(await kb.toKeyWithFingerPrint(diskBag2.key)).toEqual(created);
78
+ const algo = {
79
+ name: "AES-GCM",
80
+ iv: kb.rt.crypto.randomBytes(12),
81
+ tagLength: 128,
82
+ };
83
+ const data = kb.rt.crypto.randomBytes(122);
84
+ expect(await kb.rt.crypto.encrypt(algo, res.Ok().key, data)).toEqual(await kb.rt.crypto.encrypt(algo, created.Ok().key, data));
85
+ expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(diskBag.key), data)).toEqual(
86
+ await kb.rt.crypto.encrypt(algo, created.Ok().key, data),
87
+ );
88
+ expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(diskBag2.key), data)).toEqual(
89
+ await kb.rt.crypto.encrypt(algo, created.Ok().key, data),
90
+ );
91
+ });
92
+ });
93
+
94
+ describe("KeyedCryptoStore", () => {
95
+ let kb: rt.kb.KeyBag;
96
+ let logger: Logger;
97
+ let baseUrl: URI;
98
+ const sthis = mockSuperThis();
99
+ beforeEach(async () => {
100
+ await sthis.start();
101
+ logger = MockLogger().logger;
102
+ let kbUrl: URI;
103
+ if (runtimeFn().isBrowser) {
104
+ kbUrl = URI.from("indexdb://fp-keybag");
105
+ baseUrl = URI.from("indexdb://fp-keyed-crypto-store");
106
+ } else {
107
+ kbUrl = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
108
+ baseUrl = URI.merge("file://./dist/tests/keyed-crypto-store", sthis.env.get("FP_STORAGE_URL"));
109
+ }
110
+ kb = await rt.kb.getKeyBag(sthis, {
111
+ url: kbUrl,
112
+ });
113
+ });
114
+ it("no crypto", async () => {
115
+ const loader = {
116
+ sthis,
117
+ name: "test",
118
+ ebOpts: {
119
+ keyBag: {
120
+ keyRuntime: kb.rt,
121
+ },
122
+ store: {
123
+ stores: {
124
+ base: baseUrl.build().setParam("storekey", "insecure"),
125
+ },
126
+ },
127
+ },
128
+ } as unknown as bs.Loadable;
129
+ const strt = bs.toStoreRuntime({}, sthis);
130
+
131
+ for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
132
+ const store = await pstore;
133
+ // await store.start();
134
+ const kc = await store.keyedCrypto();
135
+ expect(kc.constructor.name).toBe("noCrypto");
136
+ // expect(kc.isEncrypting).toBe(false);
137
+ }
138
+ });
139
+
140
+ it("create key", async () => {
141
+ const loader = {
142
+ sthis,
143
+ name: "test",
144
+ ebOpts: {
145
+ keyBag: {
146
+ keyRuntime: kb.rt,
147
+ },
148
+ store: {
149
+ stores: {
150
+ base: baseUrl,
151
+ },
152
+ },
153
+ },
154
+ } as unknown as bs.Loadable;
155
+ const strt = bs.toStoreRuntime({}, sthis);
156
+ for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
157
+ const store = await bs.ensureStart(await pstore, logger);
158
+ const kc = await store.keyedCrypto();
159
+ expect(kc.constructor.name).toBe("keyedCrypto");
160
+ // expect(kc.isEncrypting).toBe(true);
161
+ expect(store.url().getParam("storekey")).toBe(`@test:${store.url().getParam("store")}@`);
162
+ }
163
+ });
164
+
165
+ it("key ref keybag", async () => {
166
+ const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
167
+ const genKey = await kb.setNamedKey("@heute@", key);
168
+ const loader = {
169
+ sthis,
170
+ name: "test",
171
+ ebOpts: {
172
+ keyBag: {
173
+ keyRuntime: kb.rt,
174
+ },
175
+ store: {
176
+ stores: {
177
+ base: baseUrl.build().setParam("storekey", "@heute@").URI(),
178
+ },
179
+ },
180
+ },
181
+ } as unknown as bs.Loadable;
182
+ const strt = bs.toStoreRuntime({}, sthis);
183
+ for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
184
+ const store = await pstore;
185
+ // await store.start();
186
+ expect(store.url().getParam("storekey")).toBe(`@heute@`);
187
+ const kc = await store.keyedCrypto();
188
+ expect(kc.constructor.name).toBe("keyedCrypto");
189
+ const testData = kb.rt.crypto.randomBytes(1024);
190
+ const iv = kb.rt.crypto.randomBytes(12);
191
+ const blk = await kc._encrypt({ bytes: testData, iv });
192
+ expect(blk).not.toEqual(testData);
193
+ const fpkey = genKey.Ok();
194
+ expect(fpkey.fingerPrint).toEqual(await kc.fingerPrint());
195
+ const dec = new Uint8Array(await kc.crypto.decrypt(kc.algo(iv), fpkey.key, blk));
196
+ expect(dec).toEqual(testData);
197
+ }
198
+ });
199
+
200
+ it("key", async () => {
201
+ const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
202
+ const loader = {
203
+ sthis,
204
+ name: "test",
205
+ ebOpts: {
206
+ keyBag: {
207
+ keyRuntime: kb.rt,
208
+ },
209
+ store: {
210
+ stores: {
211
+ base: BuildURI.from(baseUrl).setParam("storekey", key),
212
+ },
213
+ },
214
+ },
215
+ } as unknown as bs.Loadable;
216
+ const strt = bs.toStoreRuntime({}, sthis);
217
+ for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
218
+ const store = await pstore;
219
+ // await store.start();
220
+ expect(store.url().getParam("storekey")).toBe(key);
221
+ const kc = await store.keyedCrypto();
222
+ expect(kc.constructor.name).toBe("keyedCrypto");
223
+ const testData = kb.rt.crypto.randomBytes(1024);
224
+ const iv = kb.rt.crypto.randomBytes(12);
225
+ const blk = await kc._encrypt({ bytes: testData, iv });
226
+ expect(blk).not.toEqual(testData);
227
+ const dec = await kc._decrypt({ bytes: blk, iv });
228
+ expect(dec).toEqual(testData);
229
+ }
230
+ });
231
+ });
232
+
233
+ describe("KeyedCrypto", () => {
234
+ let kb: rt.kb.KeyBag;
235
+ let kycr: bs.KeyedCrypto;
236
+ let keyStr: string;
237
+ const sthis = mockSuperThis();
238
+ beforeEach(async () => {
239
+ let url: URI;
240
+ if (runtimeFn().isBrowser) {
241
+ url = URI.from("indexdb://fp-keybag");
242
+ } else {
243
+ url = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
244
+ }
245
+ kb = await rt.kb.getKeyBag(sthis, {
246
+ url,
247
+ });
248
+ keyStr = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
249
+ kycr = await rt.kc.keyedCryptoFactory(URI.from(`test://bla?storekey=${keyStr}`), kb, sthis);
250
+ });
251
+ it("codec explict iv", async () => {
252
+ const testData = kb.rt.crypto.randomBytes(1024);
253
+ const iv = kb.rt.crypto.randomBytes(12);
254
+ const codec = kycr.codec(iv, { noIVVerify: true });
255
+ const blk = (await codec.encode(testData)) as Uint8Array;
256
+ const myDec = await rt.mf.block.decode<bs.IvKeyIdData, number, number>({ bytes: blk, hasher, codec: dagCodec });
257
+ expect(myDec.value.iv).toEqual(iv);
258
+ expect(base58btc.encode(myDec.value.keyId)).toEqual(await kycr.fingerPrint());
259
+ const dec = await codec.decode(blk);
260
+ expect(dec).toEqual(testData);
261
+ });
262
+
263
+ it("codec implict iv", async () => {
264
+ const testData = kb.rt.crypto.randomBytes(1024);
265
+ const codec = kycr.codec();
266
+ const blk = await codec.encode(testData);
267
+ expect(blk.length).toBeGreaterThanOrEqual(12 + testData.length);
268
+ const dec = await codec.decode(blk);
269
+ expect(dec).toEqual(testData);
270
+ });
271
+
272
+ it("codec implict iv same for multiple clients", async () => {
273
+ const testData = kb.rt.crypto.randomBytes(1024);
274
+ const codec = kycr.codec();
275
+ const blk = await codec.encode(testData);
276
+ const blk2 = await codec.encode(testData);
277
+ expect(blk).toEqual(blk2);
278
+ });
279
+ });
280
+
281
+ // describe("KeyedCryptoStore RunLength", () => {
282
+ // const logger = MockLogger().logger;
283
+ // it("de/encode", () => {
284
+ // for (const data of [
285
+ // new Uint8Array(),
286
+ // new Uint8Array(10).fill(10),
287
+ // new Uint8Array(127).fill(127),
288
+ // new Uint8Array(128).fill(128),
289
+ // new Uint8Array(1024).fill(17),
290
+ // ]) {
291
+ // const res = rt.kc.encodeRunLength(data, logger);
292
+ // expect(res.length).toBeLessThanOrEqual(data.length + (data.length > 127 ? 4 : 1));
293
+ // for (let ofs = 0; ofs < 1024; ofs += 61) {
294
+ // const ofsRes = new Uint8Array([...new Uint8Array(ofs).fill(23), ...res]);
295
+ // const dec = rt.kc.decodeRunLength(ofsRes, ofs, logger);
296
+ // expect(dec.data).toEqual(data);
297
+ // expect(dec.data.length).toBe(data.length);
298
+ // expect(dec.next).toBe(ofs + data.length + (data.length > 127 ? 4 : 1));
299
+ // }
300
+ // }
301
+ // });
302
+ // });
@@ -1,18 +1,20 @@
1
1
  import * as codec from "@ipld/dag-cbor";
2
2
  import { sha256 as hasher } from "multiformats/hashes/sha2";
3
3
  import { BlockView } from "multiformats";
4
- import { encode } from "multiformats/block";
5
4
  import { CID } from "multiformats/cid";
6
5
  import { MemoryBlockstore } from "@web3-storage/pail/block";
7
- import { CRDTMeta, IndexTransactionMeta, bs, rt } from "@fireproof/core";
6
+ import { CRDTMeta, IndexTransactionMeta, SuperThis, bs, rt } from "@fireproof/core";
7
+ import { mockSuperThis } from "../helpers";
8
8
 
9
9
  class MyMemoryBlockStore extends bs.EncryptedBlockstore {
10
10
  readonly memblock = new MemoryBlockstore();
11
- constructor() {
11
+ loader: bs.Loader;
12
+ constructor(sthis: SuperThis) {
12
13
  const ebOpts = {
13
14
  name: "MyMemoryBlockStore",
14
15
  };
15
- super(ebOpts);
16
+ super(sthis, ebOpts);
17
+ this.loader = new bs.Loader("MyMemoryBlockStore", {}, sthis);
16
18
  }
17
19
  ready(): Promise<void> {
18
20
  return Promise.resolve();
@@ -20,7 +22,6 @@ class MyMemoryBlockStore extends bs.EncryptedBlockstore {
20
22
  close(): Promise<void> {
21
23
  return this.loader.close();
22
24
  }
23
- loader = new bs.Loader("MyMemoryBlockStore", {});
24
25
  readonly transactions = new Set<bs.CarTransaction>();
25
26
  // readonly lastTxMeta?: TransactionMeta;
26
27
  readonly compacting: boolean = false;
@@ -50,6 +51,7 @@ describe("basic Loader simple", function () {
50
51
  let loader: bs.Loader;
51
52
  let block: BlockView;
52
53
  let t: bs.CarTransaction;
54
+ const sthis = mockSuperThis();
53
55
 
54
56
  afterEach(async function () {
55
57
  await loader.close();
@@ -58,12 +60,12 @@ describe("basic Loader simple", function () {
58
60
 
59
61
  beforeEach(async function () {
60
62
  const testDbName = "test-loader-commit";
61
- await rt.SysContainer.start();
62
- const mockM = new MyMemoryBlockStore();
63
+ await sthis.start();
64
+ const mockM = new MyMemoryBlockStore(sthis);
63
65
  t = new bs.CarTransaction(mockM as bs.EncryptedBlockstore);
64
- loader = new bs.Loader(testDbName, { public: true });
66
+ loader = new bs.Loader(testDbName, { public: true }, sthis);
65
67
  await loader.ready();
66
- block = await encode({
68
+ block = await rt.mf.block.encode({
67
69
  value: { hello: "world" },
68
70
  hasher,
69
71
  codec,
@@ -97,17 +99,19 @@ describe("basic Loader with two commits", function () {
97
99
  let carCid: bs.CarGroup;
98
100
  let carCid0: bs.CarGroup;
99
101
 
102
+ const sthis = mockSuperThis();
103
+
100
104
  afterEach(async function () {
101
105
  await loader.close();
102
106
  await loader.destroy();
103
107
  });
104
108
 
105
109
  beforeEach(async function () {
106
- await rt.SysContainer.start();
107
- const mockM = new MyMemoryBlockStore();
110
+ await sthis.start();
111
+ const mockM = new MyMemoryBlockStore(sthis);
108
112
  t = new bs.CarTransaction(mockM);
109
- loader = new bs.Loader("test-loader-two-commit", { public: true });
110
- block = await encode({
113
+ loader = new bs.Loader("test-loader-two-commit", { public: true }, sthis);
114
+ block = await rt.mf.block.encode({
111
115
  value: { hello: "world" },
112
116
  hasher,
113
117
  codec,
@@ -115,7 +119,7 @@ describe("basic Loader with two commits", function () {
115
119
  await t.put(block.cid, block.bytes);
116
120
  carCid0 = await loader.commit(t, { head: [block.cid] });
117
121
 
118
- block2 = await encode({
122
+ block2 = await rt.mf.block.encode({
119
123
  value: { hello: "universe" },
120
124
  hasher,
121
125
  codec,
@@ -123,14 +127,14 @@ describe("basic Loader with two commits", function () {
123
127
  await t.put(block2.cid, block2.bytes);
124
128
  carCid = await loader.commit(t, { head: [block2.cid] });
125
129
 
126
- block3 = await encode({
130
+ block3 = await rt.mf.block.encode({
127
131
  value: { hello: "multiverse" },
128
132
  hasher,
129
133
  codec,
130
134
  });
131
135
  await t.put(block3.cid, block3.bytes);
132
136
 
133
- block4 = await encode({
137
+ block4 = await rt.mf.block.encode({
134
138
  value: { hello: "megaverse" },
135
139
  hasher,
136
140
  codec,
@@ -197,6 +201,7 @@ describe("basic Loader with index commits", function () {
197
201
  let indexerResult: IndexTransactionMeta;
198
202
  let cid: CID;
199
203
  // let indexMap: Map<string, CID>;
204
+ const sthis = mockSuperThis();
200
205
 
201
206
  afterEach(async function () {
202
207
  await ib.close();
@@ -205,10 +210,10 @@ describe("basic Loader with index commits", function () {
205
210
 
206
211
  beforeEach(async function () {
207
212
  const name = "test-loader-index" + Math.random();
208
- await rt.SysContainer.start();
213
+ await sthis.start();
209
214
  // t = new CarTransaction()
210
- ib = new bs.EncryptedBlockstore({ name });
211
- block = await encode({
215
+ ib = new bs.EncryptedBlockstore(sthis, { name });
216
+ block = await rt.mf.block.encode({
212
217
  value: { hello: "world" },
213
218
  hasher,
214
219
  codec,