@fireproof/core 0.6.4 → 0.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{src/blockstore.js → blockstore.js} +7 -3
- package/dist/{src/database.js → database.js} +74 -48
- package/dist/{src/db-index.js → db-index.js} +13 -2
- package/dist/fireproof.js +92 -0
- package/dist/import.js +29 -0
- package/dist/loader.js +23 -0
- package/dist/{src/prolly.js → prolly.js} +1 -0
- package/dist/src/fireproof.d.ts +138 -137
- package/dist/src/fireproof.js +18183 -11479
- package/dist/src/fireproof.js.map +1 -1
- package/dist/src/fireproof.mjs +18184 -11479
- package/dist/src/fireproof.mjs.map +1 -1
- package/dist/storage/base.js +348 -0
- package/dist/storage/browser.js +61 -0
- package/dist/storage/filesystem.js +65 -0
- package/dist/storage/rest.js +58 -0
- package/dist/storage/ucan.js +0 -0
- package/dist/{src/sync.js → sync.js} +1 -1
- package/dist/valet.js +200 -0
- package/package.json +4 -5
- package/src/blockstore.js +6 -3
- package/src/database.js +80 -52
- package/src/db-index.js +12 -2
- package/src/fireproof.js +41 -30
- package/src/import.js +34 -0
- package/src/loader.js +26 -0
- package/src/prolly.js +2 -0
- package/src/storage/base.js +371 -0
- package/src/storage/browser.js +67 -0
- package/src/storage/filesystem.js +70 -0
- package/src/storage/rest.js +60 -0
- package/src/storage/ucan.js +0 -0
- package/src/sync.js +1 -1
- package/src/valet.js +57 -359
- package/dist/hooks/use-fireproof.js +0 -150
- package/dist/src/crypto-poly.js +0 -4
- package/dist/src/link.js +0 -1
- package/dist/src/loader.js +0 -131
- package/dist/src/valet.js +0 -476
- package/hooks/use-fireproof.js +0 -173
- package/src/listener.js +0 -119
- package/src/utils.js +0 -16
- /package/dist/{src/clock.js → clock.js} +0 -0
- /package/dist/{src/crypto.js → crypto.js} +0 -0
- /package/dist/{src/listener.js → listener.js} +0 -0
- /package/dist/{src/sha1.js → sha1.js} +0 -0
- /package/dist/{src/utils.js → utils.js} +0 -0
package/README.md
CHANGED
@@ -38,14 +38,14 @@ With Fireproof, you **build first** and connect it to your cloud of choice when
|
|
38
38
|
```js
|
39
39
|
const completedTodos = useLiveQuery((doc) => doc.completed, { key: true })
|
40
40
|
```
|
41
|
-
This is the README for the core database technology. [The `useFireproof` hook documentation has features and a getting started guide](https://github.com/fireproof-storage/fireproof/blob/main/packages/react/README.md), like `
|
41
|
+
This is the README for the core database technology. [The `useFireproof` hook documentation has features and a getting started guide](https://github.com/fireproof-storage/fireproof/blob/main/packages/react/README.md), like `useDocument` and database setup helpers. Don't forget to star 🌟 this repo on the way over.
|
42
42
|
|
43
43
|
## AI Assistant Quick Start
|
44
44
|
|
45
45
|
Because Fireproof is designed around the mantra of build-first, it's ideal for AI-assisted app development as you can get an app up and running before even considering the cloud. If you are using GPT-3.5, GPT-4, or Bard, you can [easily enable the AI to write React apps using Fireproof](https://hackernoon.com/get-chatgpt-to-focus-on-coding-on-the-right-apis-with-gptdoc-strings). Paste this line of code into your prompt, along with a detailed description of the app to build:
|
46
46
|
|
47
47
|
```
|
48
|
-
Fireproof/React/Usage: import { useFireproof } from '@fireproof/react'; function App() { const { useLiveQuery,
|
48
|
+
Fireproof/React/Usage: import { useFireproof } from '@fireproof/react'; function App() { const { useLiveQuery, useDocument, database } = useFireproof(); const result = useLiveQuery(doc => doc.word, { limit: 10 }); const [{ count }, saveCountDocument] = useDocument({_id: 'count', count: 0}); return (<><p>{count} changes</p><input type='text' onChange={() => saveCountDocument({count: count + 1})} onSubmit={e => database.put({word: e.target.value})} /><ul>{result.map(row => (<li key={row.id}>{row.key}</li>))}</ul></>)}
|
49
49
|
```
|
50
50
|
|
51
51
|
Here are some examples that worked for us:
|
@@ -31,9 +31,13 @@ export class TransactionBlockstore {
|
|
31
31
|
instanceId = 'blkz.' + Math.random().toString(36).substring(2, 4);
|
32
32
|
inflightTransactions = new Set();
|
33
33
|
syncs = new Set();
|
34
|
-
constructor(name,
|
34
|
+
constructor(name, config) {
|
35
35
|
if (name) {
|
36
|
-
this.valet = new Valet(name,
|
36
|
+
this.valet = new Valet(name, config);
|
37
|
+
this.ready = this.valet.ready;
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
this.ready = Promise.resolve();
|
37
41
|
}
|
38
42
|
this.remoteBlockFunction = null;
|
39
43
|
}
|
@@ -47,7 +51,7 @@ export class TransactionBlockstore {
|
|
47
51
|
const key = cid.toString();
|
48
52
|
// it is safe to read from the in-flight transactions becauase they are immutable
|
49
53
|
const bytes = await Promise.any([this.transactionsGet(key), this.committedGet(key)]).catch(e => {
|
50
|
-
|
54
|
+
console.log('get error', cid.toString(), e);
|
51
55
|
return this.networkGet(key);
|
52
56
|
});
|
53
57
|
if (!bytes)
|
@@ -2,8 +2,8 @@
|
|
2
2
|
import { visMerkleClock, visMerkleTree, vis, put, get, getAll, eventsSince } from './prolly.js';
|
3
3
|
import { doTransaction, TransactionBlockstore } from './blockstore.js';
|
4
4
|
import charwise from 'charwise';
|
5
|
-
import { localSet } from './utils.js';
|
6
5
|
import { CID } from 'multiformats';
|
6
|
+
import { DbIndex as Index } from './db-index.js';
|
7
7
|
// TypeScript Types
|
8
8
|
// eslint-disable-next-line no-unused-vars
|
9
9
|
// import { CID } from 'multiformats/dist/types/src/cid.js'
|
@@ -27,13 +27,49 @@ export class Database {
|
|
27
27
|
indexes = new Map();
|
28
28
|
rootCache = null;
|
29
29
|
eventsCache = new Map();
|
30
|
-
constructor(name,
|
30
|
+
constructor(name, config = {}) {
|
31
31
|
this.name = name;
|
32
|
+
this.clock = [];
|
32
33
|
this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`;
|
33
|
-
this.blocks = new TransactionBlockstore(name, config
|
34
|
-
this.indexBlocks = new TransactionBlockstore(name + '.indexes', config.
|
35
|
-
this.clock = clock;
|
34
|
+
this.blocks = new TransactionBlockstore(name, config);
|
35
|
+
this.indexBlocks = new TransactionBlockstore(name ? name + '.indexes' : null, { primary: config.index });
|
36
36
|
this.config = config;
|
37
|
+
// todo we can wait for index blocks elsewhere
|
38
|
+
this.ready = Promise.all([this.blocks.ready, this.indexBlocks.ready]).then(([blocksReady, indexReady]) => {
|
39
|
+
const clock = new Set();
|
40
|
+
// console.log('blocksReady', blocksReady)
|
41
|
+
if (!blocksReady) {
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
for (const headers of blocksReady) {
|
45
|
+
for (const [, header] of Object.entries(headers)) {
|
46
|
+
if (!header)
|
47
|
+
continue;
|
48
|
+
for (const cid of header.clock) {
|
49
|
+
clock.add(cid);
|
50
|
+
}
|
51
|
+
if (header.index) {
|
52
|
+
this.indexBlocks.valet.primary.setCarCidMapCarCid(header.index.car);
|
53
|
+
this.indexBlocks.valet.primary.setKeyMaterial(header.index.key);
|
54
|
+
}
|
55
|
+
if (header.indexes) {
|
56
|
+
for (const { name, code, clock: { byId, byKey, db } } of header.indexes) {
|
57
|
+
// console.log('index', name, code, { byId, byKey }, db, header.indexes)
|
58
|
+
Index.fromJSON(this, {
|
59
|
+
clock: {
|
60
|
+
byId: byId ? parseCID(byId) : null,
|
61
|
+
byKey: byKey ? parseCID(byKey) : null,
|
62
|
+
db: (db && db.length > 0) ? db.map(c => parseCID(c)) : null
|
63
|
+
},
|
64
|
+
code,
|
65
|
+
name
|
66
|
+
});
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
this.clock = [...clock];
|
72
|
+
});
|
37
73
|
}
|
38
74
|
/**
|
39
75
|
* Renders the Fireproof instance as a JSON object.
|
@@ -42,12 +78,16 @@ export class Database {
|
|
42
78
|
* @instance
|
43
79
|
*/
|
44
80
|
toJSON() {
|
81
|
+
return this.blocks.valet ? this.blocks.valet.primary.prepareHeader(this.toHeader(), false) : this.toHeader(); // omg
|
82
|
+
}
|
83
|
+
toHeader() {
|
45
84
|
return {
|
46
85
|
clock: this.clockToJSON(),
|
47
86
|
name: this.name,
|
48
|
-
|
49
|
-
|
50
|
-
|
87
|
+
index: {
|
88
|
+
key: this.indexBlocks.valet?.primary.keyMaterial,
|
89
|
+
car: this.indexBlocks.valet?.primary.valetRootCarCid?.toString()
|
90
|
+
},
|
51
91
|
indexes: [...this.indexes.values()].map(index => index.toJSON())
|
52
92
|
};
|
53
93
|
}
|
@@ -60,25 +100,12 @@ export class Database {
|
|
60
100
|
clockToJSON(clock = null) {
|
61
101
|
return (clock || this.clock).map(cid => cid.toString());
|
62
102
|
}
|
63
|
-
hydrate({ clock, name, key, car, indexCar }) {
|
64
|
-
this.name = name;
|
65
|
-
this.clock = clock;
|
66
|
-
this.blocks.valet?.setKeyMaterial(key);
|
67
|
-
this.blocks.valet?.setRootCarCid(car); // maybe
|
68
|
-
this.indexBlocks.valet?.setKeyMaterial(key);
|
69
|
-
this.indexBlocks.valet?.setRootCarCid(indexCar); // maybe
|
70
|
-
// this.indexBlocks = null
|
71
|
-
}
|
72
103
|
maybeSaveClock() {
|
73
104
|
if (this.name && this.blocks.valet) {
|
74
|
-
|
105
|
+
this.blocks.valet.saveHeader(this.toHeader());
|
75
106
|
}
|
76
107
|
}
|
77
108
|
index(name) {
|
78
|
-
// iterate over the indexes and gather any with the same name
|
79
|
-
// if there are more than one, throw an error
|
80
|
-
// if there is one, return it
|
81
|
-
// if there are none, return null
|
82
109
|
const indexes = [...this.indexes.values()].filter(index => index.name === name);
|
83
110
|
if (indexes.length > 1) {
|
84
111
|
throw new Error(`Multiple indexes found with name ${name}`);
|
@@ -93,12 +120,9 @@ export class Database {
|
|
93
120
|
* @instance
|
94
121
|
*/
|
95
122
|
async notifyReset() {
|
123
|
+
await this.ready;
|
96
124
|
await this.notifyListeners({ _reset: true, _clock: this.clockToJSON() });
|
97
125
|
}
|
98
|
-
// used be indexes etc to notify database listeners of new availability
|
99
|
-
// async notifyExternal (source = 'unknown') {
|
100
|
-
// // await this.notifyListeners({ _external: source, _clock: this.clockToJSON() })
|
101
|
-
// }
|
102
126
|
/**
|
103
127
|
* Returns the changes made to the Fireproof instance since the specified event.
|
104
128
|
* @function changesSince
|
@@ -108,6 +132,7 @@ export class Database {
|
|
108
132
|
* @instance
|
109
133
|
*/
|
110
134
|
async changesSince(aClock) {
|
135
|
+
await this.ready;
|
111
136
|
// console.log('events for', this.instanceId, aClock?.constructor.name)
|
112
137
|
// console.log('changesSince', this.instanceId, this.clockToJSON(aClock), this.clockToJSON())
|
113
138
|
let rows, dataCIDs, clockCIDs;
|
@@ -151,6 +176,7 @@ export class Database {
|
|
151
176
|
};
|
152
177
|
}
|
153
178
|
async allDocuments() {
|
179
|
+
await this.ready;
|
154
180
|
const allResp = await getAll(this.blocks, this.clock, this.rootCache);
|
155
181
|
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs };
|
156
182
|
const rows = allResp.result
|
@@ -163,6 +189,7 @@ export class Database {
|
|
163
189
|
};
|
164
190
|
}
|
165
191
|
async allCIDs() {
|
192
|
+
await this.ready;
|
166
193
|
const allResp = await getAll(this.blocks, this.clock, this.rootCache, true);
|
167
194
|
this.rootCache = { root: allResp.root, clockCIDs: allResp.clockCIDs };
|
168
195
|
// console.log('allcids', allResp.cids, allResp.clockCIDs)
|
@@ -172,29 +199,13 @@ export class Database {
|
|
172
199
|
return [...cids, ...clockCids]; // clock CID last -- need to handle multiple entry clocks
|
173
200
|
}
|
174
201
|
async allStoredCIDs() {
|
202
|
+
await this.ready;
|
175
203
|
const allCIDs = [];
|
176
204
|
for await (const { cid } of this.blocks.entries()) {
|
177
205
|
allCIDs.push(cid);
|
178
206
|
}
|
179
207
|
return allCIDs;
|
180
208
|
}
|
181
|
-
/**
|
182
|
-
* Runs validation on the specified document using the Fireproof instance's configuration. Throws an error if the document is invalid.
|
183
|
-
*
|
184
|
-
* @param {Object} doc - The document to validate.
|
185
|
-
* @returns {Promise<void>}
|
186
|
-
* @throws {Error} - Throws an error if the document is invalid.
|
187
|
-
* @memberof Fireproof
|
188
|
-
* @instance
|
189
|
-
*/
|
190
|
-
async runValidation(doc) {
|
191
|
-
if (this.config && this.config.validateChange) {
|
192
|
-
const oldDoc = await this.get(doc._id)
|
193
|
-
.then(doc => doc)
|
194
|
-
.catch(() => ({}));
|
195
|
-
this.config.validateChange(doc, oldDoc, this.authCtx);
|
196
|
-
}
|
197
|
-
}
|
198
209
|
/**
|
199
210
|
* Retrieves the document with the specified ID from the database
|
200
211
|
*
|
@@ -205,6 +216,7 @@ export class Database {
|
|
205
216
|
* @instance
|
206
217
|
*/
|
207
218
|
async get(key, opts = {}) {
|
219
|
+
await this.ready;
|
208
220
|
const clock = opts.clock || this.clock;
|
209
221
|
const resp = await get(this.blocks, clock, charwise.encode(key), this.rootCache);
|
210
222
|
this.rootCache = { root: resp.root, clockCIDs: resp.clockCIDs };
|
@@ -239,6 +251,7 @@ export class Database {
|
|
239
251
|
* @instance
|
240
252
|
*/
|
241
253
|
async put({ _id, _proof, ...doc }) {
|
254
|
+
await this.ready;
|
242
255
|
const id = _id || 'f' + Math.random().toString(36).slice(2);
|
243
256
|
await this.runValidation({ _id: id, ...doc });
|
244
257
|
return await this.putToProllyTree({ key: id, value: doc }, doc._clock);
|
@@ -251,6 +264,7 @@ export class Database {
|
|
251
264
|
* @instance
|
252
265
|
*/
|
253
266
|
async del(docOrId) {
|
267
|
+
await this.ready;
|
254
268
|
let id;
|
255
269
|
let clock = null;
|
256
270
|
if (docOrId._id) {
|
@@ -265,6 +279,23 @@ export class Database {
|
|
265
279
|
// this tombstone is temporary until we can get the prolly tree to delete
|
266
280
|
// return await this.putToProllyTree({ key: id, value: null }, clock)
|
267
281
|
}
|
282
|
+
/**
|
283
|
+
* Runs validation on the specified document using the Fireproof instance's configuration. Throws an error if the document is invalid.
|
284
|
+
*
|
285
|
+
* @param {Object} doc - The document to validate.
|
286
|
+
* @returns {Promise<void>}
|
287
|
+
* @throws {Error} - Throws an error if the document is invalid.
|
288
|
+
* @memberof Fireproof
|
289
|
+
* @instance
|
290
|
+
*/
|
291
|
+
async runValidation(doc) {
|
292
|
+
if (this.config && this.config.validateChange) {
|
293
|
+
const oldDoc = await this.get(doc._id)
|
294
|
+
.then(doc => doc)
|
295
|
+
.catch(() => ({}));
|
296
|
+
this.config.validateChange(doc, oldDoc, this.authCtx);
|
297
|
+
}
|
298
|
+
}
|
268
299
|
/**
|
269
300
|
* Updates the underlying storage with the specified event.
|
270
301
|
* @private
|
@@ -364,11 +395,6 @@ export class Database {
|
|
364
395
|
await listener(changes);
|
365
396
|
}
|
366
397
|
}
|
367
|
-
setCarUploader(carUploaderFn) {
|
368
|
-
// console.log('registering car uploader')
|
369
|
-
// https://en.wikipedia.org/wiki/Law_of_Demeter - this is a violation of the law of demeter
|
370
|
-
this.blocks.valet.uploadFunction = carUploaderFn;
|
371
|
-
}
|
372
398
|
setRemoteBlockReader(remoteBlockReaderFn) {
|
373
399
|
this.blocks.remoteBlockFunction = remoteBlockReaderFn;
|
374
400
|
}
|
@@ -127,13 +127,23 @@ export class DbIndex {
|
|
127
127
|
applyMapFn(mapFn, name) {
|
128
128
|
if (typeof mapFn === 'string') {
|
129
129
|
this.mapFnString = mapFn;
|
130
|
+
// make a regex that matches strings that only have letters, numbers, and spaces
|
131
|
+
const regex = /^[a-zA-Z0-9 ]+$/;
|
132
|
+
// if the string matches the regex, make a function that returns the value at that key
|
133
|
+
if (regex.test(mapFn)) {
|
134
|
+
this.mapFn = (doc, emit) => {
|
135
|
+
if (doc[mapFn])
|
136
|
+
emit(doc[mapFn]);
|
137
|
+
};
|
138
|
+
this.includeDocsDefault = true;
|
139
|
+
}
|
130
140
|
}
|
131
141
|
else {
|
132
142
|
this.mapFn = mapFn;
|
133
143
|
this.mapFnString = mapFn.toString();
|
134
144
|
}
|
135
145
|
const matches = /=>\s*(.*)/.exec(this.mapFnString);
|
136
|
-
this.includeDocsDefault = matches && matches.length > 0;
|
146
|
+
this.includeDocsDefault = this.includeDocsDefault || (matches && matches.length > 0);
|
137
147
|
this.name = name || this.makeName();
|
138
148
|
}
|
139
149
|
makeName() {
|
@@ -226,6 +236,7 @@ export class DbIndex {
|
|
226
236
|
* @returns
|
227
237
|
*/
|
228
238
|
async applyQuery(resp, query) {
|
239
|
+
// console.log('applyQuery', resp, query)
|
229
240
|
if (query.descending) {
|
230
241
|
resp.result = resp.result.reverse();
|
231
242
|
}
|
@@ -261,7 +272,7 @@ export class DbIndex {
|
|
261
272
|
}
|
262
273
|
else if (query.key) {
|
263
274
|
const encodedKey = charwise.encode(query.key);
|
264
|
-
return await this.applyQuery(this.indexByKey.root.get(encodedKey), query);
|
275
|
+
return await this.applyQuery(await this.indexByKey.root.get(encodedKey), query);
|
265
276
|
}
|
266
277
|
else {
|
267
278
|
const { result, ...all } = await this.indexByKey.root.getAllEntries();
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import { Database, parseCID } from './database.js';
|
2
|
+
import { DbIndex as Index } from './db-index.js';
|
3
|
+
import { Sync } from './sync.js';
|
4
|
+
export { Index, Database, Sync };
|
5
|
+
class Fireproof {
|
6
|
+
/**
|
7
|
+
* @function storage
|
8
|
+
* @memberof Fireproof
|
9
|
+
* Creates a new Fireproof instance with default storage settings
|
10
|
+
* Most apps should use this and not worry about the details.
|
11
|
+
* @static
|
12
|
+
* @returns {Database|Promise<Database>} - a new Fireproof instance or a promise for remote loaders
|
13
|
+
*/
|
14
|
+
static storage = (name = null, opts = {}) => {
|
15
|
+
if (!name) {
|
16
|
+
return new Database(null, opts);
|
17
|
+
}
|
18
|
+
else {
|
19
|
+
// const primaryLoader = Loader.appropriate(name, opts.primary, { key: null })
|
20
|
+
// const secondaryLoader = opts.secondary ? Loader.appropriate(name, opts.secondary, { key: null }) : null
|
21
|
+
const db = new Database(name, opts);
|
22
|
+
return db;
|
23
|
+
// const loaders = [pr]
|
24
|
+
// todo we need branch names here
|
25
|
+
// console.log('storage', name, opts, primaryLoader, secondaryLoader)
|
26
|
+
}
|
27
|
+
};
|
28
|
+
// static fromConfig (name, primary, secondary, opts = {}) {
|
29
|
+
// console.log('fromConfig', name, primary, secondary, opts)
|
30
|
+
// let clock = []
|
31
|
+
// if (primary && primary.clock) {
|
32
|
+
// clock = clock.concat(primary.clock)
|
33
|
+
// }
|
34
|
+
// if (secondary && secondary.clock) {
|
35
|
+
// clock = clock.concat(secondary.clock)
|
36
|
+
// }
|
37
|
+
// const mergedClock = [...new Set(clock)].map(c => parseCID(c))
|
38
|
+
// opts.primaryHeader = primary
|
39
|
+
// opts.secondaryHeader = secondary
|
40
|
+
// opts.index = primary ? primary.index : {}
|
41
|
+
// const fp = new Database(name, mergedClock, opts)
|
42
|
+
// return Fireproof.fromJSON(primary, secondary, fp)
|
43
|
+
// }
|
44
|
+
static fromJSON(primary, secondary, database) {
|
45
|
+
const json = primary && primary.indexes ? primary : secondary;
|
46
|
+
if (json.indexes) {
|
47
|
+
for (const { name, code, clock: { byId, byKey, db } } of json.indexes) {
|
48
|
+
Index.fromJSON(database, {
|
49
|
+
clock: {
|
50
|
+
byId: byId ? parseCID(byId) : null,
|
51
|
+
byKey: byKey ? parseCID(byKey) : null,
|
52
|
+
db: (db && db.length > 0) ? db.map(c => parseCID(c)) : null
|
53
|
+
},
|
54
|
+
code,
|
55
|
+
name
|
56
|
+
});
|
57
|
+
}
|
58
|
+
}
|
59
|
+
return database;
|
60
|
+
}
|
61
|
+
static snapshot(database, clock) {
|
62
|
+
const definition = database.toJSON();
|
63
|
+
if (clock) {
|
64
|
+
definition.clock = clock.map(c => parseCID(c));
|
65
|
+
definition.indexes.forEach(index => {
|
66
|
+
index.clock.byId = null;
|
67
|
+
index.clock.byKey = null;
|
68
|
+
index.clock.db = null;
|
69
|
+
});
|
70
|
+
}
|
71
|
+
const withBlocks = new Database(database.name);
|
72
|
+
withBlocks.blocks = database.blocks;
|
73
|
+
withBlocks.clock = definition.clock;
|
74
|
+
const snappedDb = Fireproof.fromJSON(definition, null, withBlocks);
|
75
|
+
[...database.indexes.values()].forEach(index => {
|
76
|
+
snappedDb.indexes.get(index.mapFnString).mapFn = index.mapFn;
|
77
|
+
});
|
78
|
+
return snappedDb;
|
79
|
+
}
|
80
|
+
static async zoom(database, clock) {
|
81
|
+
;
|
82
|
+
[...database.indexes.values()].forEach(index => {
|
83
|
+
index.indexById = { root: null, cid: null };
|
84
|
+
index.indexByKey = { root: null, cid: null };
|
85
|
+
index.dbHead = null;
|
86
|
+
});
|
87
|
+
database.clock = clock.map(c => parseCID(c));
|
88
|
+
await database.notifyReset(); // hmm... indexes should listen to this? might be more complex than worth it. so far this is the only caller
|
89
|
+
return database;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
export { Fireproof };
|
package/dist/import.js
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
import { createReadStream } from 'fs';
|
2
|
+
import { join } from 'path';
|
3
|
+
import { parse } from '@jsonlines/core';
|
4
|
+
import cargoQueue from 'async/cargoQueue.js';
|
5
|
+
// todo maybe this goes in a utils package for tree-shaking?
|
6
|
+
async function loadData(database, filename) {
|
7
|
+
const fullFilePath = join(process.cwd(), filename);
|
8
|
+
const readableStream = createReadStream(fullFilePath);
|
9
|
+
const parseStream = parse();
|
10
|
+
readableStream.pipe(parseStream);
|
11
|
+
const saveQueue = cargoQueue(async (tasks, callback) => {
|
12
|
+
for (const t of tasks) {
|
13
|
+
await database.put(t);
|
14
|
+
}
|
15
|
+
callback();
|
16
|
+
});
|
17
|
+
parseStream.on('data', async (data) => {
|
18
|
+
saveQueue.push(data);
|
19
|
+
});
|
20
|
+
let res;
|
21
|
+
const p = new Promise((resolve, reject) => {
|
22
|
+
res = resolve;
|
23
|
+
});
|
24
|
+
saveQueue.drain(async (x) => {
|
25
|
+
res();
|
26
|
+
});
|
27
|
+
return p;
|
28
|
+
}
|
29
|
+
export { loadData };
|
package/dist/loader.js
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
import { Browser } from './storage/browser.js';
|
2
|
+
import { Filesystem } from './storage/filesystem.js';
|
3
|
+
import { Rest } from './storage/rest.js';
|
4
|
+
const FORCE_IDB = typeof process !== 'undefined' && !!process.env?.FORCE_IDB;
|
5
|
+
/* global window */
|
6
|
+
export const Loader = {
|
7
|
+
appropriate: (name, config = {}) => {
|
8
|
+
let isBrowser = false;
|
9
|
+
try {
|
10
|
+
isBrowser = window.localStorage && true;
|
11
|
+
}
|
12
|
+
catch (e) { }
|
13
|
+
if (config.type === 'rest') {
|
14
|
+
return new Rest(name, config);
|
15
|
+
}
|
16
|
+
if (FORCE_IDB || isBrowser) {
|
17
|
+
return new Browser(name, config);
|
18
|
+
}
|
19
|
+
else {
|
20
|
+
return new Filesystem(name, config);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
};
|
@@ -8,6 +8,7 @@ import { nocache as cache } from 'prolly-trees/cache';
|
|
8
8
|
import { CIDCounter, bf, simpleCompare as compare } from 'prolly-trees/utils';
|
9
9
|
import * as codec from '@ipld/dag-cbor';
|
10
10
|
import { sha256 as hasher } from 'multiformats/hashes/sha2';
|
11
|
+
// import { blake2b256 as hasher } from '@multiformats/blake2/blake2b'
|
11
12
|
import { doTransaction } from './blockstore.js';
|
12
13
|
import { create as createBlock } from 'multiformats/block';
|
13
14
|
const blockOpts = { cache, chunker: bf(30), codec, hasher, compare };
|