@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.
- package/{chunk-EVSZA26U.js → chunk-AZVWSRER.js} +2 -2
- package/{chunk-UCMXU3DH.js → chunk-NZNG6TQT.js} +103 -1
- package/chunk-NZNG6TQT.js.map +1 -0
- package/{chunk-5X6APJDY.js → chunk-ZHO4NMWL.js} +2 -2
- package/index.cjs +122 -92
- package/index.cjs.map +1 -1
- package/index.d.cts +21 -1
- package/index.d.ts +21 -1
- package/index.js +41 -122
- package/index.js.map +1 -1
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/package.json +1 -1
- package/{sqlite-data-store-RIH56645.js → sqlite-data-store-3ST7XOLX.js} +3 -3
- package/{sqlite-meta-store-6347MWOR.js → sqlite-meta-store-QOIMCSJ7.js} +3 -3
- package/{sqlite-wal-store-G5YGK77N.js → sqlite-wal-store-JFBQPOYT.js} +3 -3
- package/{store-file-D472VFCS.js → store-file-CSS5THFH.js} +2 -2
- package/{store-indexdb-FRX5PTKR.js → store-indexdb-DR4HELVP.js} +3 -3
- package/{store-sql-MDSU23Y7.js → store-sql-BG6SMGQJ.js} +5 -5
- package/tests/blockstore/loader.test.ts +265 -0
- package/tests/blockstore/store.test.ts +164 -0
- package/tests/blockstore/transaction.test.ts +121 -0
- package/tests/fireproof/config.test.ts +212 -0
- package/tests/fireproof/crdt.test.ts +434 -0
- package/tests/fireproof/database.test.ts +466 -0
- package/tests/fireproof/fireproof.test.ts +602 -0
- package/tests/fireproof/hello.test.ts +54 -0
- package/tests/fireproof/indexer.test.ts +389 -0
- package/tests/helpers.ts +81 -0
- package/tests/react/useFireproof.test.tsx +19 -0
- package/tests/www/gallery.html +132 -0
- package/tests/www/iife.html +42 -0
- package/tests/www/todo-aws.html +232 -0
- package/tests/www/todo-ipfs.html +213 -0
- package/tests/www/todo-local.html +214 -0
- package/tests/www/todo-netlify.html +227 -0
- package/tests/www/todo.html +236 -0
- package/chunk-UCMXU3DH.js.map +0 -1
- /package/{chunk-EVSZA26U.js.map → chunk-AZVWSRER.js.map} +0 -0
- /package/{chunk-5X6APJDY.js.map → chunk-ZHO4NMWL.js.map} +0 -0
- /package/{sqlite-data-store-RIH56645.js.map → sqlite-data-store-3ST7XOLX.js.map} +0 -0
- /package/{sqlite-meta-store-6347MWOR.js.map → sqlite-meta-store-QOIMCSJ7.js.map} +0 -0
- /package/{sqlite-wal-store-G5YGK77N.js.map → sqlite-wal-store-JFBQPOYT.js.map} +0 -0
- /package/{store-file-D472VFCS.js.map → store-file-CSS5THFH.js.map} +0 -0
- /package/{store-indexdb-FRX5PTKR.js.map → store-indexdb-DR4HELVP.js.map} +0 -0
- /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
|
+
});
|
package/tests/helpers.ts
ADDED
@@ -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>
|