@fireproof/core 0.19.0-dev-publish → 0.19.0-dev-use-fix

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) 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.js +41 -122
  10. package/index.js.map +1 -1
  11. package/metafile-cjs.json +1 -1
  12. package/metafile-esm.json +1 -1
  13. package/package.json +1 -1
  14. package/{sqlite-data-store-RIH56645.js → sqlite-data-store-3ST7XOLX.js} +3 -3
  15. package/{sqlite-meta-store-6347MWOR.js → sqlite-meta-store-QOIMCSJ7.js} +3 -3
  16. package/{sqlite-wal-store-G5YGK77N.js → sqlite-wal-store-JFBQPOYT.js} +3 -3
  17. package/{store-file-D472VFCS.js → store-file-CSS5THFH.js} +2 -2
  18. package/{store-indexdb-FRX5PTKR.js → store-indexdb-DR4HELVP.js} +3 -3
  19. package/{store-sql-MDSU23Y7.js → store-sql-BG6SMGQJ.js} +5 -5
  20. package/tests/blockstore/loader.test.ts +265 -0
  21. package/tests/blockstore/store.test.ts +164 -0
  22. package/tests/blockstore/transaction.test.ts +121 -0
  23. package/tests/fireproof/config.test.ts +212 -0
  24. package/tests/fireproof/crdt.test.ts +434 -0
  25. package/tests/fireproof/database.test.ts +466 -0
  26. package/tests/fireproof/fireproof.test.ts +602 -0
  27. package/tests/fireproof/hello.test.ts +54 -0
  28. package/tests/fireproof/indexer.test.ts +389 -0
  29. package/tests/helpers.ts +81 -0
  30. package/tests/react/useFireproof.test.tsx +19 -0
  31. package/tests/www/gallery.html +132 -0
  32. package/tests/www/iife.html +42 -0
  33. package/tests/www/todo-aws.html +232 -0
  34. package/tests/www/todo-ipfs.html +213 -0
  35. package/tests/www/todo-local.html +214 -0
  36. package/tests/www/todo-netlify.html +227 -0
  37. package/tests/www/todo.html +236 -0
  38. package/chunk-UCMXU3DH.js.map +0 -1
  39. /package/{chunk-EVSZA26U.js.map → chunk-AZVWSRER.js.map} +0 -0
  40. /package/{chunk-5X6APJDY.js.map → chunk-ZHO4NMWL.js.map} +0 -0
  41. /package/{sqlite-data-store-RIH56645.js.map → sqlite-data-store-3ST7XOLX.js.map} +0 -0
  42. /package/{sqlite-meta-store-6347MWOR.js.map → sqlite-meta-store-QOIMCSJ7.js.map} +0 -0
  43. /package/{sqlite-wal-store-G5YGK77N.js.map → sqlite-wal-store-JFBQPOYT.js.map} +0 -0
  44. /package/{store-file-D472VFCS.js.map → store-file-CSS5THFH.js.map} +0 -0
  45. /package/{store-indexdb-FRX5PTKR.js.map → store-indexdb-DR4HELVP.js.map} +0 -0
  46. /package/{store-sql-MDSU23Y7.js.map → store-sql-BG6SMGQJ.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>