@fireproof/core 0.19.0-dev-publish → 0.19.0-dev-global

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. package/{chunk-EVSZA26U.js → chunk-AZVWSRER.js} +2 -2
  2. package/{chunk-UCMXU3DH.js → chunk-NZNG6TQT.js} +103 -1
  3. package/chunk-NZNG6TQT.js.map +1 -0
  4. package/{chunk-5X6APJDY.js → chunk-ZHO4NMWL.js} +2 -2
  5. package/index.cjs +122 -92
  6. package/index.cjs.map +1 -1
  7. package/index.d.cts +21 -1
  8. package/index.d.ts +21 -1
  9. package/index.global.js +24688 -0
  10. package/index.global.js.map +1 -0
  11. package/index.js +41 -122
  12. package/index.js.map +1 -1
  13. package/metafile-cjs.json +1 -1
  14. package/metafile-esm.json +1 -1
  15. package/metafile-iife.json +1 -0
  16. package/package.json +1 -1
  17. package/{sqlite-data-store-RIH56645.js → sqlite-data-store-3ST7XOLX.js} +3 -3
  18. package/{sqlite-meta-store-6347MWOR.js → sqlite-meta-store-QOIMCSJ7.js} +3 -3
  19. package/{sqlite-wal-store-G5YGK77N.js → sqlite-wal-store-JFBQPOYT.js} +3 -3
  20. package/{store-file-D472VFCS.js → store-file-CSS5THFH.js} +2 -2
  21. package/{store-indexdb-FRX5PTKR.js → store-indexdb-DR4HELVP.js} +3 -3
  22. package/{store-sql-MDSU23Y7.js → store-sql-BG6SMGQJ.js} +5 -5
  23. package/tests/blockstore/loader.test.ts +265 -0
  24. package/tests/blockstore/store.test.ts +164 -0
  25. package/tests/blockstore/transaction.test.ts +121 -0
  26. package/tests/fireproof/config.test.ts +212 -0
  27. package/tests/fireproof/crdt.test.ts +434 -0
  28. package/tests/fireproof/database.test.ts +466 -0
  29. package/tests/fireproof/fireproof.test.ts +602 -0
  30. package/tests/fireproof/hello.test.ts +54 -0
  31. package/tests/fireproof/indexer.test.ts +389 -0
  32. package/tests/helpers.ts +81 -0
  33. package/tests/react/useFireproof.test.tsx +19 -0
  34. package/tests/www/gallery.html +132 -0
  35. package/tests/www/iife.html +42 -0
  36. package/tests/www/todo-aws.html +232 -0
  37. package/tests/www/todo-ipfs.html +213 -0
  38. package/tests/www/todo-local.html +214 -0
  39. package/tests/www/todo-netlify.html +227 -0
  40. package/tests/www/todo.html +236 -0
  41. package/chunk-UCMXU3DH.js.map +0 -1
  42. /package/{chunk-EVSZA26U.js.map → chunk-AZVWSRER.js.map} +0 -0
  43. /package/{chunk-5X6APJDY.js.map → chunk-ZHO4NMWL.js.map} +0 -0
  44. /package/{sqlite-data-store-RIH56645.js.map → sqlite-data-store-3ST7XOLX.js.map} +0 -0
  45. /package/{sqlite-meta-store-6347MWOR.js.map → sqlite-meta-store-QOIMCSJ7.js.map} +0 -0
  46. /package/{sqlite-wal-store-G5YGK77N.js.map → sqlite-wal-store-JFBQPOYT.js.map} +0 -0
  47. /package/{store-file-D472VFCS.js.map → store-file-CSS5THFH.js.map} +0 -0
  48. /package/{store-indexdb-FRX5PTKR.js.map → store-indexdb-DR4HELVP.js.map} +0 -0
  49. /package/{store-sql-MDSU23Y7.js.map → store-sql-BG6SMGQJ.js.map} +0 -0
@@ -0,0 +1,466 @@
1
+ import { buildBlobFiles, FileWithCid } from "../helpers.js";
2
+ import { rt, bs, Database, DbResponse, DocFileMeta, DocWithId, DocFiles } from "@fireproof/core";
3
+
4
+ describe("basic Database", () => {
5
+ let db: Database;
6
+ afterEach(async () => {
7
+ await db.close();
8
+ await db.destroy();
9
+ });
10
+ beforeEach(async () => {
11
+ await rt.SysContainer.start();
12
+ db = new Database();
13
+ });
14
+ it("should put", async () => {
15
+ /** @type {Doc} */
16
+ const doc = { _id: "hello", value: "world" };
17
+ const ok = await db.put(doc);
18
+ expect(ok.id).toBe("hello");
19
+ });
20
+ it("get missing should throw", async () => {
21
+ const e = await db.get("missing").catch((e) => e);
22
+ expect(e.message).toMatch(/Not found/);
23
+ });
24
+ it("del missing should result in deleted state", async () => {
25
+ await db.del("missing");
26
+
27
+ const e = await db.get("missing").catch((e) => e);
28
+ expect(e.message).toMatch(/Not found/);
29
+ });
30
+ it("has no changes", async () => {
31
+ const { rows } = await db.changes([]);
32
+ expect(rows.length).toBe(0);
33
+ });
34
+ });
35
+
36
+ describe("basic Database with record", function () {
37
+ interface Doc {
38
+ readonly value: string;
39
+ }
40
+ let db: Database;
41
+ afterEach(async () => {
42
+ await db.close();
43
+ await db.destroy();
44
+ });
45
+ beforeEach(async function () {
46
+ await rt.SysContainer.start();
47
+ db = new Database();
48
+ const ok = await db.put<Doc>({ _id: "hello", value: "world" });
49
+ expect(ok.id).toBe("hello");
50
+ });
51
+ it("should get", async function () {
52
+ const doc = await db.get<Doc>("hello");
53
+ expect(doc).toBeTruthy();
54
+ expect(doc._id).toBe("hello");
55
+ expect(doc.value).toBe("world");
56
+ });
57
+ it("should update", async function () {
58
+ const ok = await db.put({ _id: "hello", value: "universe" });
59
+ expect(ok.id).toBe("hello");
60
+ const doc = await db.get<Doc>("hello");
61
+ expect(doc).toBeTruthy();
62
+ expect(doc._id).toBe("hello");
63
+ expect(doc.value).toBe("universe");
64
+ });
65
+ it("should del last record", async function () {
66
+ const ok = await db.del("hello");
67
+ expect(ok.id).toBe("hello");
68
+
69
+ const e = await db.get("hello").catch((e) => e);
70
+ expect(e.message).toMatch(/Not found/);
71
+ });
72
+ it("has changes", async function () {
73
+ const { rows } = await db.changes([]);
74
+ expect(rows.length).toBe(1);
75
+ expect(rows[0].key).toBe("hello");
76
+ expect(rows[0].value._id).toBe("hello");
77
+ });
78
+ it("is not persisted", async function () {
79
+ const db2 = new Database();
80
+ const { rows } = await db2.changes([]);
81
+ expect(rows.length).toBe(0);
82
+ const doc = await db2.get("hello").catch((e) => e);
83
+ expect(doc.message).toBeTruthy();
84
+ await db2.close();
85
+ await db2.destroy();
86
+ });
87
+ });
88
+
89
+ describe("named Database with record", function () {
90
+ interface Doc {
91
+ readonly value: string;
92
+ }
93
+ let db: Database;
94
+ afterEach(async () => {
95
+ await db.close();
96
+ await db.destroy();
97
+ });
98
+ beforeEach(async function () {
99
+ await rt.SysContainer.start();
100
+ db = new Database("test-db-name");
101
+ /** @type {Doc} */
102
+ const doc = { _id: "hello", value: "world" };
103
+ const ok = await db.put(doc);
104
+ expect(ok.id).toBe("hello");
105
+ });
106
+ it("should get", async function () {
107
+ const doc = await db.get<Doc>("hello");
108
+ expect(doc).toBeTruthy();
109
+ expect(doc._id).toBe("hello");
110
+ expect(doc.value).toBe("world");
111
+ });
112
+ it("should update", async function () {
113
+ const ok = await db.put({ _id: "hello", value: "universe" });
114
+ expect(ok.id).toBe("hello");
115
+ const doc = await db.get<Doc>("hello");
116
+ expect(doc).toBeTruthy();
117
+ expect(doc._id).toBe("hello");
118
+ expect(doc.value).toBe("universe");
119
+ });
120
+ it("should del last record", async function () {
121
+ const ok = await db.del("hello");
122
+ expect(ok.id).toBe("hello");
123
+
124
+ const e = await db.get("hello").catch((e) => e);
125
+ expect(e.message).toMatch(/Not found/);
126
+ });
127
+ it("has changes", async function () {
128
+ const { rows } = await db.changes([]);
129
+ expect(rows.length).toBe(1);
130
+ expect(rows[0].key).toBe("hello");
131
+ expect(rows[0].value._id).toBe("hello");
132
+ });
133
+ it("should have a key", async function () {
134
+ const { rows } = await db.changes([]);
135
+ expect(rows.length).toBe(1);
136
+ const blocks = db._crdt.blockstore as bs.EncryptedBlockstore;
137
+ const loader = blocks.loader;
138
+ expect(loader).toBeTruthy();
139
+ await loader.ready();
140
+ expect(loader.key?.length).toBe(64);
141
+ expect(loader.keyId?.length).toBe(64);
142
+ expect(loader.key).not.toBe(loader.keyId);
143
+ });
144
+ it("should work right with a sequence of changes", async function () {
145
+ const numDocs = 10;
146
+ for (let i = 0; i < numDocs; i++) {
147
+ const doc = { _id: `id-${i}`, hello: "world" };
148
+ const ok = await db.put(doc);
149
+ expect(ok.id).toBe(`id-${i}`);
150
+ }
151
+ const { rows } = await db.changes([]);
152
+ expect(rows.length).toBe(numDocs + 1);
153
+
154
+ const ok6 = await db.put({ _id: `id-${6}`, hello: "block" });
155
+ expect(ok6.id).toBe(`id-${6}`);
156
+
157
+ for (let i = 0; i < numDocs; i++) {
158
+ const id = `id-${i}`;
159
+ const doc = await db.get<{ hello: string }>(id);
160
+ expect(doc).toBeTruthy();
161
+ expect(doc._id).toBe(id);
162
+ expect(doc.hello.length).toBe(5);
163
+ }
164
+
165
+ const { rows: rows2 } = await db.changes([]);
166
+ expect(rows2.length).toBe(numDocs + 1);
167
+
168
+ const ok7 = await db.del(`id-${7}`);
169
+ expect(ok7.id).toBe(`id-${7}`);
170
+
171
+ const { rows: rows3 } = await db.changes([]);
172
+ expect(rows3.length).toBe(numDocs + 1);
173
+ expect(rows3[numDocs].key).toBe(`id-${7}`);
174
+ expect(rows3[numDocs].value._deleted).toBe(true);
175
+
176
+ // test limit
177
+ const { rows: rows4 } = await db.changes([], { limit: 5 });
178
+ expect(rows4.length).toBe(5);
179
+ });
180
+
181
+ it("should work right after compaction", async function () {
182
+ const numDocs = 10;
183
+ for (let i = 0; i < numDocs; i++) {
184
+ const doc = { _id: `id-${i}`, hello: "world" };
185
+ const ok = await db.put(doc);
186
+ expect(ok.id).toBe(`id-${i}`);
187
+ }
188
+ const { rows } = await db.changes([]);
189
+ expect(rows.length).toBe(numDocs + 1);
190
+
191
+ await db.compact();
192
+
193
+ const { rows: rows3 } = await db.changes([], { dirty: true });
194
+ expect(rows3.length).toBe(numDocs + 1);
195
+
196
+ const { rows: rows4 } = await db.changes([], { dirty: false });
197
+ expect(rows4.length).toBe(numDocs + 1);
198
+ });
199
+ });
200
+
201
+ // describe('basic Database parallel writes / public', function () {
202
+ // /** @type {Database} */
203
+ // let db
204
+ // const writes = []
205
+ // beforeEach(async function () {
206
+ // await resetDirectory(dataDir, 'test-parallel-writes')
207
+ // db = new Database('test-parallel-writes', { public: true })
208
+ // /** @type {Doc} */
209
+ // for (let i = 0; i < 10; i++) {
210
+ // const doc = { _id: `id-${i}`, hello: 'world' }
211
+ // writes.push(db.put(doc))
212
+ // }
213
+ // await Promise.all(writes)
214
+ // })
215
+
216
+ describe("basic Database parallel writes / public", function () {
217
+ let db: Database;
218
+ const writes: Promise<DbResponse>[] = [];
219
+ afterEach(async () => {
220
+ await db.close();
221
+ await db.destroy();
222
+ });
223
+ beforeEach(async function () {
224
+ await rt.SysContainer.start();
225
+ db = new Database("test-parallel-writes", { public: true });
226
+ for (let i = 0; i < 10; i++) {
227
+ const doc = { _id: `id-${i}`, hello: "world" };
228
+ writes.push(db.put(doc));
229
+ }
230
+ await Promise.all(writes);
231
+ });
232
+ it("should have one head", function () {
233
+ const crdt = db._crdt;
234
+ expect(crdt.clock.head.length).toBe(1);
235
+ });
236
+ it("should write all", async function () {
237
+ for (let i = 0; i < 10; i++) {
238
+ const id = `id-${i}`;
239
+ const doc = await db.get<{ hello: string }>(id);
240
+ expect(doc).toBeTruthy();
241
+ expect(doc._id).toBe(id);
242
+ expect(doc.hello).toBe("world");
243
+ }
244
+ });
245
+ it("should del all", async function () {
246
+ for (let i = 0; i < 10; i++) {
247
+ const id = `id-${i}`;
248
+ const ok = await db.del(id);
249
+ expect(ok.id).toBe(id);
250
+
251
+ const e = await db.get(id).catch((e) => e);
252
+ expect(e.message).toMatch(/Not found/);
253
+ }
254
+ });
255
+ it("should delete all in parallel", async function () {
256
+ const deletes: Promise<DbResponse>[] = [];
257
+ for (let i = 0; i < 10; i++) {
258
+ const id = `id-${i}`;
259
+ deletes.push(db.del(id));
260
+ }
261
+ await Promise.all(deletes);
262
+ for (let i = 0; i < 10; i++) {
263
+ const id = `id-${i}`;
264
+ const e = await db.get(id).catch((e) => e);
265
+ expect(e.message).toMatch(/Not found/);
266
+ }
267
+ });
268
+ it("has changes", async function () {
269
+ const { rows, clock } = await db.changes([]);
270
+ expect(clock[0]).toBe(db._crdt.clock.head[0]);
271
+ expect(rows.length).toBe(10);
272
+ // rows.sort((a, b) => a.key.localeCompare(b.key));
273
+ for (let i = 0; i < 10; i++) {
274
+ expect(rows[i].key).toBe("id-" + i);
275
+ expect(rows[i].clock).toBeTruthy();
276
+ }
277
+ });
278
+ it("should not have a key", async function () {
279
+ const { rows } = await db.changes([]);
280
+ expect(rows.length).toBe(10);
281
+ expect(db.opts.public).toBeTruthy();
282
+ expect(db._crdt.opts.public).toBeTruthy();
283
+ const blocks = db._crdt.blockstore as bs.EncryptedBlockstore;
284
+ const loader = blocks.loader;
285
+ expect(loader).toBeTruthy();
286
+ await loader.ready();
287
+ expect(loader.key).toBeUndefined();
288
+ expect(loader.keyId).toBeUndefined();
289
+ });
290
+ });
291
+
292
+ describe("basic Database with subscription", function () {
293
+ let db: Database;
294
+ let didRun: number;
295
+ let unsubscribe: () => void;
296
+ let lastDoc: DocWithId<NonNullable<unknown>>;
297
+ let waitForSub: Promise<void>;
298
+ afterEach(async () => {
299
+ await db.close();
300
+ await db.destroy();
301
+ });
302
+ beforeEach(async function () {
303
+ await rt.SysContainer.start();
304
+ db = new Database();
305
+ didRun = 0;
306
+ waitForSub = new Promise((resolve) => {
307
+ unsubscribe = db.subscribe((docs) => {
308
+ lastDoc = docs[0];
309
+ // lastDoc = {_id: "ok"};
310
+ didRun++;
311
+ resolve();
312
+ }, true);
313
+ });
314
+ });
315
+ it("should run on put", async function () {
316
+ const all = await db.allDocs();
317
+ expect(all.rows.length).toBe(0);
318
+ const doc = { _id: "hello", message: "world" };
319
+ expect(didRun).toBe(0);
320
+ const ok = await db.put(doc);
321
+ await waitForSub;
322
+ expect(didRun).toBeTruthy();
323
+ expect(lastDoc).toBeTruthy();
324
+ expect(lastDoc._id).toBe("hello");
325
+ expect(ok.id).toBe("hello");
326
+ expect(didRun).toBe(1);
327
+ });
328
+ it("should unsubscribe", async function () {
329
+ unsubscribe();
330
+ const doc = { _id: "hello", message: "again" };
331
+ const ok = await db.put(doc);
332
+ expect(ok.id).toBe("hello");
333
+ expect(didRun).toBe(0);
334
+ });
335
+ });
336
+
337
+ describe("basic Database with no update subscription", function () {
338
+ let db: Database;
339
+ let didRun: number;
340
+ let unsubscribe: () => void;
341
+ afterEach(async () => {
342
+ await db.close();
343
+ await db.destroy();
344
+ });
345
+ beforeEach(async function () {
346
+ await rt.SysContainer.start();
347
+ db = new Database();
348
+ didRun = 0;
349
+
350
+ unsubscribe = db.subscribe(() => {
351
+ didRun++;
352
+ });
353
+ });
354
+ it("should run on put", async function () {
355
+ const all = await db.allDocs();
356
+ expect(all.rows.length).toBe(0);
357
+ /** @type {Doc} */
358
+ const doc = { _id: "hello", message: "world" };
359
+ expect(didRun).toBe(0);
360
+ const ok = await db.put(doc);
361
+ expect(ok.id).toBe("hello");
362
+ expect(didRun).toBe(1);
363
+ });
364
+ it("should unsubscribe", async function () {
365
+ unsubscribe();
366
+ const doc = { _id: "hello", message: "again" };
367
+ const ok = await db.put(doc);
368
+ expect(ok.id).toBe("hello");
369
+ expect(didRun).toBe(0);
370
+ });
371
+ });
372
+
373
+ describe("database with files input", () => {
374
+ let db: Database;
375
+ let imagefiles: FileWithCid[] = [];
376
+ let result: DbResponse;
377
+
378
+ afterEach(async () => {
379
+ await db.close();
380
+ await db.destroy();
381
+ });
382
+ beforeEach(async function () {
383
+ await rt.SysContainer.start();
384
+ imagefiles = await buildBlobFiles();
385
+ db = new Database("fireproof-with-images");
386
+ const doc = {
387
+ _id: "images-main",
388
+ type: "files",
389
+ _files: {
390
+ one: imagefiles[0].file,
391
+ two: imagefiles[1].file,
392
+ },
393
+ };
394
+ result = await db.put(doc);
395
+ });
396
+
397
+ it("Should upload images", async function () {
398
+ expect(result.id).toBe("images-main");
399
+ });
400
+
401
+ it("Should fetch the images", async function () {
402
+ const doc = await db.get(result.id);
403
+ const files = doc._files as DocFiles;
404
+ expect(files).toBeTruthy();
405
+ const keys = Object.keys(files);
406
+ let fileMeta = files[keys[0]] as DocFileMeta;
407
+ expect(fileMeta).toBeTruthy();
408
+ expect(imagefiles[0].file.type).toBeTruthy();
409
+ expect(fileMeta.type).toBeTruthy();
410
+ expect(fileMeta.type).toBe(imagefiles[0].file.type);
411
+ expect(fileMeta.size).toBe(imagefiles[0].file.size);
412
+ expect(fileMeta.cid.toString()).toBe(imagefiles[0].cid);
413
+ expect(typeof fileMeta.file).toBe("function");
414
+ let file = (await fileMeta.file?.()) as File;
415
+
416
+ expect(file.type).toBe(imagefiles[0].file.type);
417
+ expect(file.size).toBe(imagefiles[0].file.size);
418
+ // expect(file.name).toBe('image.jpg') // see https://github.com/fireproof-storage/fireproof/issues/70
419
+
420
+ fileMeta = files[keys[1]] as DocFileMeta;
421
+ expect(fileMeta.type).toBe(imagefiles[1].file.type);
422
+ expect(fileMeta.size).toBe(imagefiles[1].file.size);
423
+ expect(fileMeta.cid.toString()).toBe(imagefiles[1].cid);
424
+ expect(typeof fileMeta.file).toBe("function");
425
+ file = (await fileMeta.file?.()) as File;
426
+
427
+ expect(file.type).toBe(imagefiles[1].file.type);
428
+ expect(file.size).toBe(imagefiles[1].file.size);
429
+ // expect(file.name).toBe('fireproof.png') // see https://github.com/fireproof-storage/fireproof/issues/70
430
+ });
431
+
432
+ it("should update the file document data without changing the files", async function () {
433
+ interface Doc {
434
+ type: string;
435
+ }
436
+ const doc = await db.get<Doc>(result.id);
437
+ let files = doc._files || {};
438
+ let keys = Object.keys(files);
439
+ let fileMeta = files[keys[0]] as DocFileMeta;
440
+ expect(fileMeta.type).toBe(imagefiles[0].file.type);
441
+ expect(fileMeta.size).toBe(imagefiles[0].file.size);
442
+ expect(fileMeta.cid.toString()).toBe(imagefiles[0].cid);
443
+ expect(typeof fileMeta.file).toBe("function");
444
+ let file = (await fileMeta.file?.()) as File;
445
+
446
+ expect(file.type).toBe(imagefiles[0].file.type);
447
+ expect(file.size).toBe(imagefiles[0].file.size);
448
+
449
+ doc.type = "images";
450
+ const r2 = await db.put(doc);
451
+ expect(r2.id).toBe("images-main");
452
+ const readDoc = await db.get<Doc>(r2.id);
453
+ expect(readDoc.type).toBe("images");
454
+ files = readDoc._files || {};
455
+ keys = Object.keys(files);
456
+ fileMeta = files[keys[0]] as DocFileMeta;
457
+ expect(fileMeta.type).toBe(imagefiles[0].file.type);
458
+ expect(fileMeta.size).toBe(imagefiles[0].file.size);
459
+ expect(fileMeta.cid.toString()).toBe(imagefiles[0].cid);
460
+ expect(typeof fileMeta.file).toBe("function");
461
+ file = (await fileMeta.file?.()) as File;
462
+
463
+ expect(file.type).toBe(imagefiles[0].file.type);
464
+ expect(file.size).toBe(imagefiles[0].file.size);
465
+ });
466
+ });