@fireproof/core 0.19.5-dev → 0.19.8-dev-alldocs

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.
Files changed (55) hide show
  1. package/{chunk-QHSXUST7.js → chunk-5UFCF36O.js} +3 -3
  2. package/{chunk-HCXR2M5B.js → chunk-DG6XSV44.js} +175 -7
  3. package/chunk-DG6XSV44.js.map +1 -0
  4. package/{chunk-H3A2HMMM.js → chunk-OWQAHX2V.js} +2 -2
  5. package/chunk-OWQAHX2V.js.map +1 -0
  6. package/{chunk-7OGPZSGT.js → chunk-PRQHQG4I.js} +2 -2
  7. package/index.cjs +248 -191
  8. package/index.cjs.map +1 -1
  9. package/index.d.cts +174 -68
  10. package/index.d.ts +174 -68
  11. package/index.global.js +24688 -0
  12. package/index.global.js.map +1 -0
  13. package/index.js +60 -127
  14. package/index.js.map +1 -1
  15. package/metafile-cjs.json +1 -1
  16. package/metafile-esm.json +1 -1
  17. package/metafile-iife.json +1 -0
  18. package/{node-sys-container-E7LADX2Z.js → node-sys-container-TTGEC66A.js} +2 -2
  19. package/package.json +1 -1
  20. package/{sqlite-data-store-YS4U7AQ4.js → sqlite-data-store-MA55LVQE.js} +4 -4
  21. package/{sqlite-meta-store-FJZSZG4R.js → sqlite-meta-store-UNQKVYRM.js} +4 -4
  22. package/{sqlite-wal-store-6JZ4URNS.js → sqlite-wal-store-KVUOC4PO.js} +4 -4
  23. package/{store-file-HMHPQTUV.js → store-file-WD746RSY.js} +3 -3
  24. package/{store-indexdb-MRVZG4OG.js → store-indexdb-NG45BU3Q.js} +4 -4
  25. package/{store-sql-5XMJ5OWJ.js → store-sql-QVFNIGND.js} +7 -69
  26. package/store-sql-QVFNIGND.js.map +1 -0
  27. package/tests/blockstore/loader.test.ts +265 -0
  28. package/tests/blockstore/store.test.ts +164 -0
  29. package/tests/blockstore/transaction.test.ts +121 -0
  30. package/tests/fireproof/config.test.ts +212 -0
  31. package/tests/fireproof/crdt.test.ts +434 -0
  32. package/tests/fireproof/database.test.ts +466 -0
  33. package/tests/fireproof/fireproof.test.ts +602 -0
  34. package/tests/fireproof/hello.test.ts +54 -0
  35. package/tests/fireproof/indexer.test.ts +389 -0
  36. package/tests/helpers.ts +81 -0
  37. package/tests/react/useFireproof.test.tsx +19 -0
  38. package/tests/www/gallery.html +132 -0
  39. package/tests/www/iife.html +42 -0
  40. package/tests/www/todo-aws.html +232 -0
  41. package/tests/www/todo-ipfs.html +213 -0
  42. package/tests/www/todo-local.html +214 -0
  43. package/tests/www/todo-netlify.html +227 -0
  44. package/tests/www/todo.html +236 -0
  45. package/chunk-H3A2HMMM.js.map +0 -1
  46. package/chunk-HCXR2M5B.js.map +0 -1
  47. package/store-sql-5XMJ5OWJ.js.map +0 -1
  48. /package/{chunk-QHSXUST7.js.map → chunk-5UFCF36O.js.map} +0 -0
  49. /package/{chunk-7OGPZSGT.js.map → chunk-PRQHQG4I.js.map} +0 -0
  50. /package/{node-sys-container-E7LADX2Z.js.map → node-sys-container-TTGEC66A.js.map} +0 -0
  51. /package/{sqlite-data-store-YS4U7AQ4.js.map → sqlite-data-store-MA55LVQE.js.map} +0 -0
  52. /package/{sqlite-meta-store-FJZSZG4R.js.map → sqlite-meta-store-UNQKVYRM.js.map} +0 -0
  53. /package/{sqlite-wal-store-6JZ4URNS.js.map → sqlite-wal-store-KVUOC4PO.js.map} +0 -0
  54. /package/{store-file-HMHPQTUV.js.map → store-file-WD746RSY.js.map} +0 -0
  55. /package/{store-indexdb-MRVZG4OG.js.map → store-indexdb-NG45BU3Q.js.map} +0 -0
@@ -0,0 +1,389 @@
1
+ import { itSkip } from "../helpers.js";
2
+
3
+ import { rt, Index, index, Database, CRDT, IndexRows } from "@fireproof/core";
4
+
5
+ interface TestType {
6
+ readonly title: string;
7
+ readonly score: number;
8
+ }
9
+
10
+ describe("basic Index", () => {
11
+ let db: Database<TestType>;
12
+ let indexer: Index<string, TestType>;
13
+ let didMap: boolean;
14
+ afterEach(async function () {
15
+ await db.close();
16
+ await db.destroy();
17
+ await indexer.close();
18
+ await indexer.destroy();
19
+ });
20
+ beforeEach(async function () {
21
+ await rt.SysContainer.start();
22
+ db = new Database("test-indexer");
23
+ await db.put({ title: "amazing" });
24
+ await db.put({ title: "creative" });
25
+ await db.put({ title: "bazillas" });
26
+ indexer = new Index<string, TestType>(db._crdt, "hello", (doc) => {
27
+ didMap = true;
28
+ return doc.title;
29
+ });
30
+ await indexer.ready();
31
+ });
32
+ it("should have properties", function () {
33
+ expect(indexer.crdt).toBe(db._crdt);
34
+ expect(indexer.crdt.name).toBe("test-indexer");
35
+ expect(indexer.name).toBe("hello");
36
+ expect(indexer.mapFn).toBeTruthy();
37
+ });
38
+ it("should call the map function on first query", async function () {
39
+ didMap = false;
40
+ await indexer.query();
41
+ expect(didMap).toBeTruthy();
42
+ });
43
+ it("should not call the map function on second query", async function () {
44
+ await indexer.query();
45
+ didMap = false;
46
+ await indexer.query();
47
+ expect(didMap).toBeFalsy();
48
+ });
49
+ it("should get results", async function () {
50
+ const result = await indexer.query();
51
+ expect(result).toBeTruthy();
52
+ expect(result.rows).toBeTruthy();
53
+ expect(result.rows.length).toBe(3);
54
+ });
55
+ it("should be in order", async function () {
56
+ const { rows } = await indexer.query();
57
+ expect(rows[0].key).toBe("amazing");
58
+ });
59
+ it("should work with limit", async function () {
60
+ const { rows } = await indexer.query({ limit: 1 });
61
+ expect(rows.length).toBe(1);
62
+ });
63
+ it("should work with descending", async function () {
64
+ const { rows } = await indexer.query({ descending: true });
65
+ expect(rows[0].key).toBe("creative");
66
+ });
67
+ it("should range query all", async function () {
68
+ const { rows } = await indexer.query({ range: ["a", "z"] });
69
+ expect(rows.length).toBe(3);
70
+ expect(rows[0].key).toBe("amazing");
71
+ });
72
+ it("should range query all twice", async function () {
73
+ const { rows } = await indexer.query({ range: ["a", "z"] });
74
+ expect(rows.length).toBe(3);
75
+ expect(rows[0].key).toBe("amazing");
76
+ const { rows: rows2 } = await indexer.query({ range: ["a", "z"] });
77
+ expect(rows2.length).toBe(3);
78
+ expect(rows2[0].key).toBe("amazing");
79
+ });
80
+ it("should range query", async function () {
81
+ const { rows } = await indexer.query({ range: ["b", "d"] });
82
+ expect(rows[0].key).toBe("bazillas");
83
+ });
84
+ it("should key query", async function () {
85
+ const { rows } = await indexer.query({ key: "bazillas" });
86
+ expect(rows.length).toBe(1);
87
+ });
88
+ it("should include docs", async function () {
89
+ const { rows } = await indexer.query({ includeDocs: true });
90
+ expect(rows[0]).toBeTruthy();
91
+ expect(rows[0].id).toBeTruthy();
92
+ expect(rows[0].doc).toBeTruthy();
93
+ expect(rows[0].doc?._id).toBe(rows[0].id);
94
+ });
95
+ });
96
+
97
+ describe("Index query with compound key", function () {
98
+ let db: Database<TestType>;
99
+ let indexer: Index<[string, number], TestType>;
100
+ afterEach(async function () {
101
+ await db.close();
102
+ await db.destroy();
103
+ await indexer.close();
104
+ await indexer.destroy();
105
+ });
106
+ beforeEach(async function () {
107
+ await rt.SysContainer.start();
108
+ db = new Database("test-indexer");
109
+ await db.put({ title: "amazing", score: 1 });
110
+ await db.put({ title: "creative", score: 2 });
111
+ await db.put({ title: "creative", score: 20 });
112
+ await db.put({ title: "bazillas", score: 3 });
113
+ indexer = new Index<[string, number], TestType>(db._crdt, "hello", (doc) => {
114
+ return [doc.title, doc.score];
115
+ });
116
+ await indexer.ready();
117
+ });
118
+ it("should prefix query", async function () {
119
+ const { rows } = await indexer.query({ prefix: "creative" });
120
+ expect(rows.length).toBe(2);
121
+ expect(rows[0].key).toEqual(["creative", 2]);
122
+ expect(rows[1].key).toEqual(["creative", 20]);
123
+ });
124
+ });
125
+
126
+ describe("basic Index with map fun", function () {
127
+ let db: Database<TestType>;
128
+ let indexer: Index<string, TestType>;
129
+ afterEach(async function () {
130
+ await db.close();
131
+ await db.destroy();
132
+ await indexer.close();
133
+ await indexer.destroy();
134
+ });
135
+ beforeEach(async function () {
136
+ await rt.SysContainer.start();
137
+ db = new Database("test-indexer");
138
+ await db.put({ title: "amazing" });
139
+ await db.put({ title: "creative" });
140
+ await db.put({ title: "bazillas" });
141
+ indexer = new Index<string, TestType>(db._crdt, "hello", (doc, map) => {
142
+ map(doc.title);
143
+ });
144
+ await indexer.ready();
145
+ });
146
+ it("should get results", async function () {
147
+ const result = await indexer.query();
148
+ expect(result).toBeTruthy();
149
+ expect(result.rows).toBeTruthy();
150
+ expect(result.rows.length).toBe(3);
151
+ expect(result.rows[0].key).toBe("amazing");
152
+ });
153
+ });
154
+
155
+ describe("basic Index with map fun with value", function () {
156
+ let db: Database<TestType>;
157
+ let indexer: Index<string, TestType, number>;
158
+ afterEach(async function () {
159
+ await db.close();
160
+ await db.destroy();
161
+ });
162
+ beforeEach(async function () {
163
+ await rt.SysContainer.start();
164
+ db = new Database("test-indexer");
165
+ await db.put({ title: "amazing" });
166
+ await db.put({ title: "creative" });
167
+ await db.put({ title: "bazillas" });
168
+ indexer = new Index<string, TestType, number>(db._crdt, "hello", (doc, map) => {
169
+ map(doc.title, doc.title.length);
170
+ });
171
+ });
172
+ it("should get results", async function () {
173
+ const result = await indexer.query();
174
+ expect(result).toBeTruthy();
175
+ expect(result.rows).toBeTruthy();
176
+ expect(result.rows.length).toBe(3);
177
+ expect(result.rows[0].key).toBe("amazing");
178
+ // @jchris why is this not a object?
179
+ expect(result.rows[0].value).toBe(7);
180
+ });
181
+ it("should include docs", async function () {
182
+ const { rows } = await indexer.query({ includeDocs: true });
183
+ expect(rows[0].doc).toBeTruthy();
184
+ expect(rows[0].doc?._id).toBe(rows[0].id);
185
+ expect(rows.length).toBe(3);
186
+ expect(rows[0].key).toBe("amazing");
187
+ // @jchris why is this not a object?
188
+ expect(rows[0].value).toBe(7);
189
+ });
190
+ });
191
+
192
+ describe("Index query with map and compound key", function () {
193
+ let db: Database<TestType>;
194
+ let indexer: Index<[string, number], TestType>;
195
+ afterEach(async function () {
196
+ await db.close();
197
+ await db.destroy();
198
+ await indexer.close();
199
+ await indexer.destroy();
200
+ });
201
+ beforeEach(async function () {
202
+ await rt.SysContainer.start();
203
+ db = new Database("test-indexer");
204
+ await db.put({ title: "amazing", score: 1 });
205
+ await db.put({ title: "creative", score: 2 });
206
+ await db.put({ title: "creative", score: 20 });
207
+ await db.put({ title: "bazillas", score: 3 });
208
+ indexer = new Index<[string, number], TestType>(db._crdt, "hello", (doc, emit) => {
209
+ emit([doc.title, doc.score]);
210
+ });
211
+ await indexer.ready();
212
+ });
213
+ it("should prefix query", async function () {
214
+ const { rows } = await indexer.query({ prefix: "creative" });
215
+ expect(rows.length).toBe(2);
216
+ expect(rows[0].key).toEqual(["creative", 2]);
217
+ expect(rows[1].key).toEqual(["creative", 20]);
218
+ });
219
+ });
220
+
221
+ describe("basic Index with string fun", function () {
222
+ let db: Database<TestType>;
223
+ let indexer: Index<string, TestType>;
224
+ afterEach(async function () {
225
+ await db.close();
226
+ await db.destroy();
227
+ await indexer.close();
228
+ await indexer.destroy();
229
+ });
230
+ beforeEach(async function () {
231
+ await rt.SysContainer.start();
232
+ db = new Database("test-indexer");
233
+ await db.put({ title: "amazing" });
234
+ await db.put({ title: "creative" });
235
+ await db.put({ title: "bazillas" });
236
+ indexer = new Index(db._crdt, "title");
237
+ await indexer.ready();
238
+ });
239
+ it("should get results", async function () {
240
+ const result = await indexer.query();
241
+ expect(result).toBeTruthy();
242
+ expect(result.rows).toBeTruthy();
243
+ expect(result.rows.length).toBe(3);
244
+ });
245
+ it("should include docs", async function () {
246
+ const { rows } = await indexer.query();
247
+ expect(rows.length).toBeTruthy();
248
+ expect(rows[0].doc).toBeTruthy();
249
+ });
250
+ });
251
+
252
+ describe("basic Index upon cold start", function () {
253
+ interface TestType {
254
+ title: string;
255
+ score?: number;
256
+ }
257
+ let crdt: CRDT<TestType>;
258
+ let indexer: Index<string, TestType>;
259
+ let didMap: number;
260
+ let mapFn: (doc: TestType) => string;
261
+ let result: IndexRows<string, TestType>;
262
+ // result, mapFn;
263
+ afterEach(async function () {
264
+ await crdt.close();
265
+ await crdt.destroy();
266
+ await indexer.close();
267
+ await indexer.destroy();
268
+ });
269
+ beforeEach(async function () {
270
+ await rt.SysContainer.start();
271
+ // db = database()
272
+ crdt = new CRDT<TestType>("test-indexer-cold", { persistIndexes: true });
273
+ await crdt.bulk([
274
+ { id: "abc1", value: { title: "amazing" } },
275
+ { id: "abc2", value: { title: "creative" } },
276
+ { id: "abc3", value: { title: "bazillas" } },
277
+ ]);
278
+ didMap = 0;
279
+ mapFn = (doc) => {
280
+ didMap++;
281
+ return doc.title;
282
+ };
283
+ indexer = await index<string, TestType>({ _crdt: crdt }, "hello", mapFn);
284
+ await indexer.ready();
285
+ // new Index(db._crdt.indexBlockstore, db._crdt, 'hello', mapFn)
286
+ result = await indexer.query();
287
+ expect(indexer.indexHead).toEqual(crdt.clock.head);
288
+ });
289
+ it("should call map on first query", function () {
290
+ expect(didMap).toBeTruthy();
291
+ expect(didMap).toEqual(3);
292
+ });
293
+ it("should get results on first query", function () {
294
+ expect(result).toBeTruthy();
295
+ expect(result.rows).toBeTruthy();
296
+ expect(result.rows.length).toEqual(3);
297
+ });
298
+ it("should work on cold load", async function () {
299
+ const crdt2 = new CRDT<TestType>("test-indexer-cold", { persistIndexes: true });
300
+ await crdt2.ready();
301
+ const { result, head } = await crdt2.changes();
302
+ expect(result).toBeTruthy();
303
+ await crdt2.ready();
304
+ const indexer2 = await index<string, TestType>({ _crdt: crdt2 }, "hello", mapFn);
305
+ await indexer2.ready();
306
+ const result2 = await indexer2.query();
307
+ expect(indexer2.indexHead).toEqual(head);
308
+ expect(result2).toBeTruthy();
309
+ expect(result2.rows.length).toEqual(3);
310
+ expect(indexer2.indexHead).toEqual(head);
311
+ });
312
+ itSkip("should not rerun the map function on seen changes", async function () {
313
+ didMap = 0;
314
+ const crdt2 = new CRDT<TestType>("test-indexer-cold", { persistIndexes: true });
315
+ const indexer2 = await index({ _crdt: crdt2 }, "hello", mapFn);
316
+ const { result, head } = await crdt2.changes([]);
317
+ expect(result.length).toEqual(3);
318
+ expect(head.length).toEqual(1);
319
+ const { result: ch2, head: h2 } = await crdt2.changes(head);
320
+ expect(ch2.length).toEqual(0);
321
+ expect(h2.length).toEqual(1);
322
+ expect(h2).toEqual(head);
323
+ const result2 = await indexer2.query();
324
+ expect(indexer2.indexHead).toEqual(head);
325
+ expect(result2).toBeTruthy();
326
+ expect(result2.rows.length).toEqual(3);
327
+ expect(didMap).toEqual(0);
328
+ await crdt2.bulk([{ id: "abc4", value: { title: "despicable", score: 0 } }]);
329
+
330
+ const { result: ch3, head: h3 } = await crdt2.changes(head);
331
+ expect(ch3.length).toEqual(1);
332
+ expect(h3.length).toEqual(1);
333
+ const result3 = await indexer2.query();
334
+ expect(result3).toBeTruthy();
335
+ expect(result3.rows.length).toEqual(4);
336
+ expect(didMap).toEqual(1);
337
+ });
338
+ it("should ignore meta when map function definiton changes", async function () {
339
+ const crdt2 = new CRDT<TestType>("test-indexer-cold");
340
+ const result = await index<string, TestType>({ _crdt: crdt2 }, "hello", (doc) =>
341
+ doc.title.split("").reverse().join(""),
342
+ ).query();
343
+ expect(result.rows.length).toEqual(3);
344
+ expect(result.rows[0].key).toEqual("evitaerc"); // creative
345
+ });
346
+ });
347
+
348
+ describe("basic Index with no data", function () {
349
+ let db: Database<TestType>;
350
+ let indexer: Index<string, TestType>;
351
+ let didMap: boolean;
352
+ afterEach(async function () {
353
+ await db.close();
354
+ await db.destroy();
355
+ await indexer.close();
356
+ await indexer.destroy();
357
+ });
358
+ beforeEach(async function () {
359
+ await rt.SysContainer.start();
360
+ db = new Database("test-indexer");
361
+ indexer = new Index<string, TestType>(db._crdt, "hello", (doc) => {
362
+ didMap = true;
363
+ return doc.title;
364
+ });
365
+ await indexer.ready();
366
+ });
367
+ it("should have properties", function () {
368
+ expect(indexer.crdt).toEqual(db._crdt);
369
+ expect(indexer.name).toEqual("hello");
370
+ expect(indexer.mapFn).toBeTruthy();
371
+ });
372
+ it("should not call the map function on first query", async function () {
373
+ didMap = false;
374
+ await indexer.query();
375
+ expect(didMap).toBeFalsy();
376
+ });
377
+ it("should not call the map function on second query", async function () {
378
+ await indexer.query();
379
+ didMap = false;
380
+ await indexer.query();
381
+ expect(didMap).toBeFalsy();
382
+ });
383
+ it("should get results", async function () {
384
+ const result = await indexer.query();
385
+ expect(result).toBeTruthy();
386
+ expect(result.rows).toBeTruthy();
387
+ expect(result.rows.length).toEqual(0);
388
+ });
389
+ });
@@ -0,0 +1,81 @@
1
+ import { rt } from "@fireproof/core";
2
+
3
+ const dataDir = rt.dataDir;
4
+ export { dataDir };
5
+
6
+ export function sleep(ms: number) {
7
+ return new Promise((resolve) => setTimeout(resolve, ms));
8
+ }
9
+
10
+ export function itSkip(value: string, fn: () => unknown, options?: number) {
11
+ if (typeof it !== "function") {
12
+ return;
13
+ }
14
+ const mit = it as unknown as { skip: (value: string, fn: () => unknown, options?: unknown) => unknown };
15
+ if (mit && typeof mit.skip === "function") {
16
+ mit.skip(value, fn, options);
17
+ return;
18
+ }
19
+ console.warn("itSkip of " + value);
20
+ }
21
+
22
+ //
23
+
24
+ // // Function to copy a directory
25
+ // export async function copyDirectory(source: string, destination: string) {
26
+ // // Ensure the destination directory exists
27
+ // await rt.SysContainer.mkdir(destination, { recursive: true });
28
+
29
+ // // Read the source directory
30
+ // const entries = await SysContainer.readdirent(source, { withFileTypes: true });
31
+
32
+ // // Iterate through each entry in the directory
33
+ // for (const entry of entries) {
34
+ // const sourcePath = SysContainer.join(source, entry.name);
35
+ // const destinationPath = SysContainer.join(destination, entry.name);
36
+
37
+ // if (entry.isDirectory()) {
38
+ // // If the entry is a directory, copy it recursively
39
+ // await copyDirectory(sourcePath, destinationPath);
40
+ // } else if (entry.isFile()) {
41
+ // // If the entry is a file, copy it
42
+ // await SysContainer.copyFile(sourcePath, destinationPath);
43
+ // }
44
+ // }
45
+ // }
46
+
47
+ // export function getDirectoryName(url: string) {
48
+ // let path: string;
49
+ // try {
50
+ // path = SysContainer.fileURLToPath(url);
51
+ // } catch (e) {
52
+ // path = url;
53
+ // }
54
+ // if (process && typeof process.cwd === "function") {
55
+ // const cwd = process.cwd();
56
+ // if (cwd.endsWith("dist/esm")) {
57
+ // path = "../../" + path;
58
+ // }
59
+ // }
60
+ // const dir_name = SysContainer.dirname(path);
61
+ // return dir_name;
62
+ // }
63
+
64
+ async function toFileWithCid(buffer: Uint8Array, name: string, opts: FilePropertyBag): Promise<FileWithCid> {
65
+ return {
66
+ file: new File([new Blob([buffer])], name, opts),
67
+ cid: (await rt.files.encodeFile(new File([new Blob([buffer])], name, opts))).cid.toString(),
68
+ };
69
+ }
70
+
71
+ export interface FileWithCid {
72
+ file: File;
73
+ cid: string;
74
+ }
75
+ export async function buildBlobFiles(): Promise<FileWithCid[]> {
76
+ const cp = rt.crypto.toCryptoOpts();
77
+ return [
78
+ await toFileWithCid(cp.randomBytes(Math.random() * 51283), `image.jpg`, { type: "image/jpeg" }),
79
+ await toFileWithCid(cp.randomBytes(Math.random() * 51283), `fireproof.png`, { type: "image/png" }),
80
+ ];
81
+ }
@@ -0,0 +1,19 @@
1
+ import { renderHook } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { useFireproof } from "use-fireproof";
5
+
6
+ describe("HOOK: useFireproof", () => {
7
+ it("should be defined", () => {
8
+ expect(useFireproof).toBeDefined();
9
+ });
10
+
11
+ it("renders the hook correctly and checks types", () => {
12
+ renderHook(() => {
13
+ const { database, useLiveQuery, useDocument } = useFireproof("dbname");
14
+ expect(typeof useLiveQuery).toBe("function");
15
+ expect(typeof useDocument).toBe("function");
16
+ expect(database?.constructor.name).toBe("Database");
17
+ });
18
+ });
19
+ });
@@ -0,0 +1,132 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Fireproof Uploads</title>
7
+ <script src="./fireproof.iife.js?cache=94"></script>
8
+ <script type="text/javascript">
9
+ function testApp() {
10
+ const { fireproof, connect } = Fireproof;
11
+ let dbName;
12
+ let db;
13
+ let cx;
14
+
15
+ let dbUnsubscribe = false;
16
+
17
+ function setupDb(name) {
18
+ if (dbUnsubscribe) {
19
+ dbUnsubscribe();
20
+ }
21
+ dbName = name;
22
+ db = fireproof(name);
23
+ window.db = db;
24
+
25
+ cx = db.connect("jchris+files-30@fireproof.storage", "todo-test");
26
+ window.cx = cx;
27
+
28
+ dbUnsubscribe = db.subscribe(redraw);
29
+ return db;
30
+ }
31
+
32
+ let doing;
33
+ const redraw = async () => {
34
+ if (doing) {
35
+ return doing;
36
+ }
37
+ doing = draw().finally(() => (doing = null));
38
+ return doing;
39
+ };
40
+
41
+ const draw = async () => {
42
+ const result = await db.query("_id", { descending: true, limit: 10 });
43
+ document.querySelector("ul").innerHTML = "";
44
+ for (const row of result.rows) {
45
+ const doc = row.doc;
46
+ if (doc._publicFiles) {
47
+ const li = document.querySelector("ul").appendChild(document.createElement("li"));
48
+ li.appendChild(document.createElement("span")).innerText = row.key;
49
+ li.appendChild(document.createElement("br"));
50
+ for (const file of Object.keys(doc._publicFiles)) {
51
+ (async () => {
52
+ const meta = doc._publicFiles[file];
53
+ if (meta.file && /image/.test(meta.type)) {
54
+ const src = URL.createObjectURL(await meta.file());
55
+ const img = document.createElement("img");
56
+ img.src = src;
57
+ img.height = 100;
58
+ img.onload = () => {
59
+ URL.revokeObjectURL(img.src);
60
+ };
61
+
62
+ console.log("url", meta.url);
63
+ li.appendChild(img);
64
+ }
65
+ })();
66
+ }
67
+ }
68
+ }
69
+ };
70
+
71
+ async function changeList(e) {
72
+ e.preventDefault();
73
+ const input = document.querySelector("#list");
74
+ dbName = input.value;
75
+ history.pushState(null, "", location.pathname + "?db=" + encodeURIComponent(dbName));
76
+ setupDb(dbName);
77
+
78
+ redraw();
79
+ }
80
+ window.changeList = changeList;
81
+
82
+ async function openDashboard(e) {
83
+ db.openDashboard();
84
+ }
85
+ window.openDashboard = openDashboard;
86
+
87
+ function handleFiles() {
88
+ const fileList = this.files;
89
+ const doc = {
90
+ _publicFiles: {},
91
+ };
92
+ for (const file of fileList) {
93
+ doc._publicFiles[file.name] = file;
94
+ }
95
+ const ok = db.put(doc);
96
+ }
97
+
98
+ async function initialize() {
99
+ ps = new URLSearchParams(location.search);
100
+ const listQ = ps.get("db");
101
+ setupDb(listQ || "hello-world");
102
+ const input = document.querySelector("#list");
103
+ input.value = dbName;
104
+
105
+ const inputElement = document.getElementById("files-up");
106
+ inputElement.addEventListener("change", handleFiles, false);
107
+ db.subscribe(draw);
108
+ draw();
109
+ }
110
+
111
+ window.onload = initialize;
112
+ }
113
+ testApp();
114
+ </script>
115
+ </head>
116
+
117
+ <body>
118
+ List:
119
+ <input title="gallery" type="text" name="list" id="list" />
120
+ <button onclick="changeList(event)">Change Gallery</button>
121
+ <button onclick="openDashboard(event)">🔥 Import to Dashboard</button>
122
+ <h3>Files</h3>
123
+ <p>
124
+ Data is stored locally and encrypted before upload to S3. This is a demo so the encryption key is not managed securely. Read
125
+ more about <a href="https://use-fireproof.com/docs/database-api/replication">Fireproof replication options.</a> You can also
126
+ see a demo without images but <a href="https://fireproof.storage/s3up-test.html">with compaction and refresh buttons.</a>
127
+ </p>
128
+ <label for="files-up"><strong>Drop files:</strong></label>
129
+ <input accept="image/*" title="save to Fireproof" type="file" id="files-up" multiple />
130
+ <ul></ul>
131
+ </body>
132
+ </html>
@@ -0,0 +1,42 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Fireproof Test</title>
7
+ <script src="./fireproof.iife.js"></script>
8
+ <script type="text/javascript">
9
+ function testApp() {
10
+ const db = Fireproof.fireproof("iife-test", { persistIndexes: true });
11
+
12
+ const draw = async () => {
13
+ const result = await db.query("sort", { includeDocs: true });
14
+ document.querySelector("ul").innerHTML = "";
15
+ for (const row of result.rows) {
16
+ document.querySelector("ul").appendChild(document.createElement("li")).innerText = JSON.stringify(row.doc);
17
+ }
18
+ };
19
+
20
+ async function initialize() {
21
+ console.log("initialize");
22
+ db.subscribe(draw);
23
+ draw();
24
+ }
25
+
26
+ async function onButtonClick(e) {
27
+ e.preventDefault();
28
+ console.log("put");
29
+ const ok = await db.put({ sort: Math.random(), test: "test" });
30
+ console.log("ok", ok.id);
31
+ }
32
+ window.onButtonClick = onButtonClick;
33
+ window.onload = initialize;
34
+ }
35
+ testApp();
36
+ </script>
37
+ </head>
38
+ <body>
39
+ <button onclick="onButtonClick(event)">Click to Run</button>
40
+ <ul></ul>
41
+ </body>
42
+ </html>