@fireproof/core 0.20.0-dev-preview-40 → 0.20.0-dev-preview-50
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 +6 -4
- package/deno/index.js +2 -2
- package/deno/index.js.map +1 -1
- package/deno.json +3 -2
- package/index.cjs +955 -599
- package/index.cjs.map +1 -1
- package/index.d.cts +334 -127
- package/index.d.ts +334 -127
- package/index.js +939 -582
- package/index.js.map +1 -1
- package/indexeddb/index.cjs.map +1 -1
- package/indexeddb/index.js.map +1 -1
- package/indexeddb/metafile-cjs.json +1 -1
- package/indexeddb/metafile-esm.json +1 -1
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/package.json +7 -5
- package/react/index.cjs +17 -9
- package/react/index.cjs.map +1 -1
- package/react/index.d.cts +5 -4
- package/react/index.d.ts +5 -4
- package/react/index.js +17 -9
- package/react/index.js.map +1 -1
- package/react/metafile-cjs.json +1 -1
- package/react/metafile-esm.json +1 -1
- package/tests/blockstore/interceptor-gateway.test.ts +15 -1
- package/tests/blockstore/keyed-crypto-indexeddb-file.test.ts +8 -18
- package/tests/blockstore/keyed-crypto.test.ts +31 -53
- package/tests/blockstore/loader.test.ts +21 -19
- package/tests/blockstore/store.test.ts +52 -56
- package/tests/blockstore/transaction.test.ts +13 -11
- package/tests/fireproof/all-gateway.test.ts +53 -50
- package/tests/fireproof/attachable.test.ts +356 -0
- package/tests/fireproof/crdt.test.ts +100 -60
- package/tests/fireproof/database.test.ts +95 -54
- package/tests/fireproof/fireproof.test.ts +58 -55
- package/tests/fireproof/hello.test.ts +4 -4
- package/tests/fireproof/indexer.test.ts +44 -44
- package/tests/fireproof/stable-cid.test.ts +69 -0
- package/tests/fireproof/utils.test.ts +21 -10
- package/tests/gateway/file/loader-config.test.ts +25 -25
- package/tests/gateway/fp-envelope-serialize.test.ts +8 -8
- package/tests/gateway/indexeddb/loader-config.test.ts +6 -6
- package/tests/helpers.ts +81 -2
- package/tests/react/useFireproof.test.tsx +59 -17
@@ -7,7 +7,7 @@ describe("storage-content", () => {
|
|
7
7
|
const sthis = mockSuperThis();
|
8
8
|
it("car", async () => {
|
9
9
|
const raw = new Uint8Array([55, 56, 57]);
|
10
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
10
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=car&suffix=.car").URI(), Result.Ok(raw));
|
11
11
|
expect(res.isOk()).toBeTruthy();
|
12
12
|
expect(res.unwrap().type).toEqual(bs.FPEnvelopeTypes.CAR);
|
13
13
|
expect(res.unwrap().payload).toEqual(raw);
|
@@ -15,7 +15,7 @@ describe("storage-content", () => {
|
|
15
15
|
|
16
16
|
it("file", async () => {
|
17
17
|
const raw = new Uint8Array([55, 56, 57]);
|
18
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
18
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=file").URI(), Result.Ok(raw));
|
19
19
|
expect(res.isOk()).toBeTruthy();
|
20
20
|
expect(res.unwrap().type).toEqual(bs.FPEnvelopeTypes.FILE);
|
21
21
|
expect(res.unwrap().payload).toEqual(raw);
|
@@ -167,7 +167,7 @@ describe("de-serialize", () => {
|
|
167
167
|
|
168
168
|
it("coerce into fpDeserialize Result", async () => {
|
169
169
|
const raw = new Uint8Array([55, 56, 57]);
|
170
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
170
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=car&suffix=.car").URI(), Result.Ok(raw));
|
171
171
|
expect(res.isOk()).toBeTruthy();
|
172
172
|
expect(res.unwrap().type).toEqual(bs.FPEnvelopeTypes.CAR);
|
173
173
|
expect(res.unwrap().payload).toEqual(raw);
|
@@ -175,7 +175,7 @@ describe("de-serialize", () => {
|
|
175
175
|
|
176
176
|
it("coerce into fpDeserialize Promise", async () => {
|
177
177
|
const raw = new Uint8Array([55, 56, 57]);
|
178
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
178
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=car&suffix=.car").URI(), Promise.resolve(raw));
|
179
179
|
expect(res.isOk()).toBeTruthy();
|
180
180
|
expect(res.unwrap().type).toEqual(bs.FPEnvelopeTypes.CAR);
|
181
181
|
expect(res.unwrap().payload).toEqual(raw);
|
@@ -185,7 +185,7 @@ describe("de-serialize", () => {
|
|
185
185
|
const raw = new Uint8Array([55, 56, 57]);
|
186
186
|
const res = await rt.gw.fpDeserialize(
|
187
187
|
sthis,
|
188
|
-
BuildURI.from("http://x.com?store=
|
188
|
+
BuildURI.from("http://x.com?store=car&suffix=.car").URI(),
|
189
189
|
Promise.resolve(Result.Ok(raw)),
|
190
190
|
);
|
191
191
|
expect(res.isOk()).toBeTruthy();
|
@@ -195,21 +195,21 @@ describe("de-serialize", () => {
|
|
195
195
|
|
196
196
|
it("coerce into fpDeserialize Promise Result.Err", async () => {
|
197
197
|
const raw = Promise.resolve(Result.Err<Uint8Array>("error"));
|
198
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
198
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=car&suffix=.car").URI(), raw);
|
199
199
|
expect(res.isErr()).toBeTruthy();
|
200
200
|
expect(res.unwrap_err().message).toEqual("error");
|
201
201
|
});
|
202
202
|
|
203
203
|
it("coerce into fpDeserialize Promise.reject", async () => {
|
204
204
|
const raw = Promise.reject(new Error("error"));
|
205
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
205
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=car&suffix=.car").URI(), raw);
|
206
206
|
expect(res.isErr()).toBeTruthy();
|
207
207
|
expect(res.unwrap_err().message).toEqual("error");
|
208
208
|
});
|
209
209
|
|
210
210
|
it("coerce into fpDeserialize Result.Err", async () => {
|
211
211
|
const raw = Result.Err<Uint8Array>("error");
|
212
|
-
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=
|
212
|
+
const res = await rt.gw.fpDeserialize(sthis, BuildURI.from("http://x.com?store=car&suffix=.car").URI(), raw);
|
213
213
|
expect(res.isErr()).toBeTruthy();
|
214
214
|
expect(res.unwrap_err().message).toEqual("error");
|
215
215
|
});
|
@@ -16,13 +16,13 @@ describe("fireproof config indexeddb", () => {
|
|
16
16
|
await db.put({ name: "my-app" });
|
17
17
|
expect(db.ledger.name).toBe(my_app());
|
18
18
|
|
19
|
-
const fileStore = await db.ledger.crdt.blockstore.loader.
|
19
|
+
const fileStore = await db.ledger.crdt.blockstore.loader.attachedStores.local().active.file;
|
20
20
|
expect(fileStore?.url().asObj()).toEqual({
|
21
21
|
pathname: "fp",
|
22
22
|
protocol: "indexeddb:",
|
23
23
|
searchParams: {
|
24
24
|
name: "my-app",
|
25
|
-
store: "
|
25
|
+
store: "file",
|
26
26
|
runtime: "browser",
|
27
27
|
storekey: "@my-app-data@",
|
28
28
|
urlGen: "default",
|
@@ -31,13 +31,13 @@ describe("fireproof config indexeddb", () => {
|
|
31
31
|
style: "path",
|
32
32
|
});
|
33
33
|
|
34
|
-
const dataStore = await db.ledger.crdt.blockstore.loader.
|
34
|
+
const dataStore = await db.ledger.crdt.blockstore.loader.attachedStores.local().active.car;
|
35
35
|
expect(dataStore?.url().asObj()).toEqual({
|
36
36
|
pathname: "fp",
|
37
37
|
protocol: "indexeddb:",
|
38
38
|
searchParams: {
|
39
39
|
name: "my-app",
|
40
|
-
store: "
|
40
|
+
store: "car",
|
41
41
|
runtime: "browser",
|
42
42
|
storekey: "@my-app-data@",
|
43
43
|
suffix: ".car",
|
@@ -46,7 +46,7 @@ describe("fireproof config indexeddb", () => {
|
|
46
46
|
},
|
47
47
|
style: "path",
|
48
48
|
});
|
49
|
-
const metaStore = await db.ledger.crdt.blockstore.loader.
|
49
|
+
const metaStore = await db.ledger.crdt.blockstore.loader.attachedStores.local().active.meta;
|
50
50
|
expect(metaStore?.url().asObj()).toEqual({
|
51
51
|
pathname: "fp",
|
52
52
|
protocol: "indexeddb:",
|
@@ -60,7 +60,7 @@ describe("fireproof config indexeddb", () => {
|
|
60
60
|
},
|
61
61
|
style: "path",
|
62
62
|
});
|
63
|
-
const WALStore = await db.ledger.crdt.blockstore.loader.
|
63
|
+
const WALStore = await db.ledger.crdt.blockstore.loader.attachedStores.local().active.wal;
|
64
64
|
expect(WALStore?.url().asObj()).toEqual({
|
65
65
|
pathname: "fp",
|
66
66
|
protocol: "indexeddb:",
|
package/tests/helpers.ts
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
import { BuildURI, MockLogger, runtimeFn, toCryptoRuntime, URI, utils, LogCollector } from "@adviser/cement";
|
2
|
-
import {
|
2
|
+
import {
|
3
|
+
ensureSuperThis,
|
4
|
+
rt,
|
5
|
+
SuperThis,
|
6
|
+
SuperThisOpts,
|
7
|
+
bs,
|
8
|
+
PARAM,
|
9
|
+
Attachable,
|
10
|
+
Attached,
|
11
|
+
CarTransaction,
|
12
|
+
Falsy,
|
13
|
+
} from "@fireproof/core";
|
3
14
|
import { CID } from "multiformats";
|
4
15
|
import { sha256 } from "multiformats/hashes/sha2";
|
5
16
|
import * as json from "multiformats/codecs/json";
|
@@ -67,7 +78,7 @@ export function simpleBlockOpts(sthis: SuperThis, name?: string) {
|
|
67
78
|
file: url,
|
68
79
|
wal: url,
|
69
80
|
meta: url,
|
70
|
-
|
81
|
+
car: url,
|
71
82
|
},
|
72
83
|
};
|
73
84
|
}
|
@@ -77,3 +88,71 @@ export async function simpleCID(sthis: SuperThis) {
|
|
77
88
|
const hash = await sha256.digest(bytes);
|
78
89
|
return CID.create(1, json.code, hash);
|
79
90
|
}
|
91
|
+
|
92
|
+
class MockLoader implements bs.Loadable {
|
93
|
+
readonly sthis: SuperThis;
|
94
|
+
readonly ebOpts: bs.BlockstoreRuntime;
|
95
|
+
readonly carLog: bs.CarLog;
|
96
|
+
readonly attachedStores: bs.AttachedStores;
|
97
|
+
readonly taskManager: bs.TaskManager;
|
98
|
+
|
99
|
+
constructor(sthis: SuperThis) {
|
100
|
+
this.sthis = sthis;
|
101
|
+
this.ebOpts = {} as bs.BlockstoreRuntime;
|
102
|
+
this.carLog = new bs.CarLog();
|
103
|
+
this.taskManager = new bs.TaskManager(sthis, () => Promise.resolve(), {
|
104
|
+
removeAfter: 3,
|
105
|
+
retryTimeout: 50,
|
106
|
+
});
|
107
|
+
this.attachedStores = new bs.AttachedRemotesImpl(this);
|
108
|
+
}
|
109
|
+
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
111
|
+
attach(attached: Attachable): Promise<Attached> {
|
112
|
+
throw new Error("Method not implemented.");
|
113
|
+
}
|
114
|
+
ready(): Promise<void> {
|
115
|
+
throw new Error("Method not implemented.");
|
116
|
+
}
|
117
|
+
close(): Promise<void> {
|
118
|
+
throw new Error("Method not implemented.");
|
119
|
+
}
|
120
|
+
keyBag(): Promise<rt.KeyBag> {
|
121
|
+
return rt.kb.getKeyBag(this.sthis, {});
|
122
|
+
}
|
123
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
124
|
+
handleDbMetasFromStore(metas: bs.DbMeta[], store: bs.ActiveStore): Promise<void> {
|
125
|
+
// throw new Error("Method not implemented.");
|
126
|
+
return Promise.resolve();
|
127
|
+
}
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
129
|
+
commit<T = unknown>(t: CarTransaction, done: T, opts: bs.CommitOpts): Promise<bs.CarGroup> {
|
130
|
+
throw new Error("Method not implemented.");
|
131
|
+
}
|
132
|
+
destroy(): Promise<void> {
|
133
|
+
throw new Error("Method not implemented.");
|
134
|
+
}
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
136
|
+
getBlock(cid: bs.AnyLink, store: bs.ActiveStore): Promise<bs.AnyBlock | Falsy> {
|
137
|
+
throw new Error("Method not implemented.");
|
138
|
+
}
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
140
|
+
loadFileCar(cid: bs.AnyLink, store: bs.ActiveStore): Promise<bs.CarCacheItem> {
|
141
|
+
throw new Error("Method not implemented.");
|
142
|
+
}
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
144
|
+
loadCar(cid: bs.AnyLink, store: bs.ActiveStore): Promise<bs.CarCacheItem> {
|
145
|
+
throw new Error("Method not implemented.");
|
146
|
+
}
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
148
|
+
commitFiles(t: CarTransaction, done: bs.TransactionMeta): Promise<bs.CarGroup> {
|
149
|
+
throw new Error("Method not implemented.");
|
150
|
+
}
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
152
|
+
entries(cache?: boolean): AsyncIterableIterator<bs.AnyBlock> {
|
153
|
+
throw new Error("Method not implemented.");
|
154
|
+
}
|
155
|
+
}
|
156
|
+
export function mockLoader(sthis: SuperThis): bs.Loadable {
|
157
|
+
return new MockLoader(sthis);
|
158
|
+
}
|
@@ -2,7 +2,7 @@ import { renderHook, waitFor } from "@testing-library/react";
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
3
3
|
|
4
4
|
import { Database, fireproof, useFireproof } from "use-fireproof";
|
5
|
-
import { LiveQueryResult, UseDocumentResult } from "
|
5
|
+
import { LiveQueryResult, UseDocumentResult } from "use-fireproof";
|
6
6
|
|
7
7
|
describe("HOOK: useFireproof", () => {
|
8
8
|
it("should be defined", () => {
|
@@ -20,24 +20,20 @@ describe("HOOK: useFireproof", () => {
|
|
20
20
|
});
|
21
21
|
|
22
22
|
describe("HOOK: useFireproof useLiveQuery has results", () => {
|
23
|
-
const dbName = "
|
23
|
+
const dbName = "useLiveQueryHasResults";
|
24
24
|
let db: Database,
|
25
25
|
query: LiveQueryResult<{ foo: string }, string>,
|
26
26
|
database: ReturnType<typeof useFireproof>["database"],
|
27
27
|
useLiveQuery: ReturnType<typeof useFireproof>["useLiveQuery"];
|
28
28
|
|
29
|
+
let cnt = 0;
|
30
|
+
|
29
31
|
beforeEach(async () => {
|
30
32
|
db = fireproof(dbName);
|
31
|
-
await db.put({ foo: "aha" });
|
32
|
-
await db.put({ foo: "bar" });
|
33
|
-
await db.put({ foo: "caz" });
|
34
|
-
|
35
|
-
renderHook(() => {
|
36
|
-
const result = useFireproof(dbName);
|
37
|
-
database = result.database;
|
38
|
-
useLiveQuery = result.useLiveQuery;
|
39
|
-
query = useLiveQuery<{ foo: string }>("foo");
|
40
|
-
});
|
33
|
+
await db.put({ foo: "aha", cnt });
|
34
|
+
await db.put({ foo: "bar", cnt });
|
35
|
+
await db.put({ foo: "caz", cnt });
|
36
|
+
cnt++;
|
41
37
|
});
|
42
38
|
|
43
39
|
it("should have setup data", async () => {
|
@@ -49,19 +45,29 @@ describe("HOOK: useFireproof useLiveQuery has results", () => {
|
|
49
45
|
});
|
50
46
|
|
51
47
|
it("queries correctly", async () => {
|
48
|
+
renderHook(() => {
|
49
|
+
const result = useFireproof(dbName);
|
50
|
+
database = result.database;
|
51
|
+
useLiveQuery = result.useLiveQuery;
|
52
|
+
query = useLiveQuery<{ foo: string }>("foo");
|
53
|
+
});
|
54
|
+
|
52
55
|
await waitFor(() => {
|
56
|
+
// act(() => {
|
57
|
+
// expect(query.rows).toBe([]);
|
53
58
|
expect(query.rows.length).toBe(3);
|
54
59
|
expect(query.rows[0].doc?.foo).toBe("aha");
|
55
60
|
expect(query.rows[1].doc?.foo).toBe("bar");
|
56
61
|
expect(query.rows[2].doc?.foo).toBe("caz");
|
62
|
+
// });
|
57
63
|
});
|
58
64
|
});
|
59
65
|
|
60
66
|
afterEach(async () => {
|
61
67
|
await db.close();
|
62
68
|
await db.destroy();
|
63
|
-
await database
|
64
|
-
await database
|
69
|
+
await database?.close();
|
70
|
+
await database?.destroy();
|
65
71
|
});
|
66
72
|
});
|
67
73
|
|
@@ -269,9 +275,8 @@ describe("HOOK: useFireproof useDocument has results reset sync", () => {
|
|
269
275
|
|
270
276
|
const allDocs = await db.allDocs<{ input: string }>();
|
271
277
|
expect(allDocs.rows.length).toBe(3);
|
272
|
-
|
273
|
-
expect(
|
274
|
-
expect(allDocs.rows[2].value.input).toBe("fresh");
|
278
|
+
const inputs = allDocs.rows.map((r) => r.value.input);
|
279
|
+
expect(inputs).toEqual(expect.arrayContaining(["first", "new", "fresh"]));
|
275
280
|
});
|
276
281
|
|
277
282
|
afterEach(async () => {
|
@@ -511,3 +516,40 @@ describe("HOOK: useFireproof race condition: calling save() without await overwr
|
|
511
516
|
await db.destroy();
|
512
517
|
});
|
513
518
|
});
|
519
|
+
|
520
|
+
describe("useFireproo calling submit()", () => {
|
521
|
+
const dbName = "submitDb";
|
522
|
+
let db: Database, docResult: UseDocumentResult<{ input: string }>;
|
523
|
+
|
524
|
+
beforeEach(async () => {
|
525
|
+
db = fireproof(dbName);
|
526
|
+
|
527
|
+
// Render a new hook instance
|
528
|
+
renderHook(() => {
|
529
|
+
const { useDocument } = useFireproof(dbName);
|
530
|
+
docResult = useDocument<{ input: string }>({ input: "" });
|
531
|
+
});
|
532
|
+
});
|
533
|
+
|
534
|
+
it("demonstrates that calling docResult.save() and docResult.reset() in the same tick can overwrite reset", async () => {
|
535
|
+
// Merge some changes into doc
|
536
|
+
docResult.merge({ input: "some data" });
|
537
|
+
|
538
|
+
docResult.submit();
|
539
|
+
|
540
|
+
// Let the async subscription produce a new doc in case the doc is reloaded with an _id
|
541
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
542
|
+
|
543
|
+
// If the reset worked, doc._id should STILL be undefined.
|
544
|
+
// If the subscription wins, doc._id will be defined => test fails.
|
545
|
+
await waitFor(() => {
|
546
|
+
expect(docResult.doc._id).toBeUndefined();
|
547
|
+
expect(docResult.doc.input).toBe("");
|
548
|
+
});
|
549
|
+
});
|
550
|
+
|
551
|
+
afterEach(async () => {
|
552
|
+
await db.close();
|
553
|
+
await db.destroy();
|
554
|
+
});
|
555
|
+
});
|