@fireproof/core 0.3.22 → 0.4.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/dist/blockstore.js +242 -0
- package/dist/clock.js +355 -0
- package/dist/crypto.js +59 -0
- package/dist/database.js +308 -0
- package/dist/db-index.js +314 -0
- package/dist/fireproof.js +83 -0
- package/dist/hooks/use-fireproof.js +100 -0
- package/dist/listener.js +110 -0
- package/dist/prolly.js +316 -0
- package/dist/sha1.js +74 -0
- package/dist/src/blockstore.js +242 -0
- package/dist/src/clock.js +355 -0
- package/dist/src/crypto.js +59 -0
- package/dist/src/database.js +312 -0
- package/dist/src/db-index.js +314 -0
- package/dist/src/fireproof.d.ts +319 -0
- package/dist/src/fireproof.js +38976 -0
- package/dist/src/fireproof.js.map +1 -0
- package/dist/src/fireproof.mjs +38972 -0
- package/dist/src/fireproof.mjs.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +19 -14
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.mjs +19 -14
- package/dist/src/index.mjs.map +1 -1
- package/dist/src/listener.js +108 -0
- package/dist/src/prolly.js +319 -0
- package/dist/src/sha1.js +74 -0
- package/dist/src/utils.js +16 -0
- package/dist/src/valet.js +262 -0
- package/dist/test/block.js +57 -0
- package/dist/test/clock.test.js +556 -0
- package/dist/test/db-index.test.js +231 -0
- package/dist/test/fireproof.test.js +444 -0
- package/dist/test/fulltext.test.js +61 -0
- package/dist/test/helpers.js +39 -0
- package/dist/test/hydrator.test.js +142 -0
- package/dist/test/listener.test.js +103 -0
- package/dist/test/prolly.test.js +162 -0
- package/dist/test/proofs.test.js +45 -0
- package/dist/test/reproduce-fixture-bug.test.js +57 -0
- package/dist/test/valet.test.js +56 -0
- package/dist/utils.js +16 -0
- package/dist/valet.js +262 -0
- package/hooks/use-fireproof.js +38 -63
- package/package.json +13 -14
- package/src/blockstore.js +8 -4
- package/src/database.js +338 -0
- package/src/db-index.js +3 -3
- package/src/fireproof.js +65 -322
- package/src/listener.js +10 -8
- package/src/prolly.js +10 -6
- package/src/utils.js +16 -0
- package/src/hydrator.js +0 -54
- package/src/index.js +0 -6
package/dist/utils.js
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
/* global localStorage */
|
2
|
+
let storageSupported = false;
|
3
|
+
try {
|
4
|
+
storageSupported = window.localStorage && true;
|
5
|
+
}
|
6
|
+
catch (e) { }
|
7
|
+
export function localGet(key) {
|
8
|
+
if (storageSupported) {
|
9
|
+
return localStorage && localStorage.getItem(key);
|
10
|
+
}
|
11
|
+
}
|
12
|
+
export function localSet(key, value) {
|
13
|
+
if (storageSupported) {
|
14
|
+
return localStorage && localStorage.setItem(key, value);
|
15
|
+
}
|
16
|
+
}
|
package/dist/valet.js
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
import { CarReader } from '@ipld/car';
|
2
|
+
import { CID } from 'multiformats/cid';
|
3
|
+
import { sha256 } from 'multiformats/hashes/sha2';
|
4
|
+
import * as CBW from '@ipld/car/buffer-writer';
|
5
|
+
import * as raw from 'multiformats/codecs/raw';
|
6
|
+
import * as Block from 'multiformats/block';
|
7
|
+
import * as dagcbor from '@ipld/dag-cbor';
|
8
|
+
import { openDB } from 'idb';
|
9
|
+
import cargoQueue from 'async/cargoQueue.js';
|
10
|
+
// @ts-ignore
|
11
|
+
import { bf } from 'prolly-trees/utils';
|
12
|
+
// @ts-ignore
|
13
|
+
import { nocache as cache } from 'prolly-trees/cache';
|
14
|
+
import { encrypt, decrypt } from './crypto.js';
|
15
|
+
import { Buffer } from 'buffer';
|
16
|
+
// @ts-ignore
|
17
|
+
import * as codec from 'encrypted-block';
|
18
|
+
import { rawSha1 as sha1sync } from './sha1.js';
|
19
|
+
const chunker = bf(3);
|
20
|
+
const NO_ENCRYPT = typeof process !== 'undefined' && !!process.env?.NO_ENCRYPT;
|
21
|
+
// ? process.env.NO_ENCRYPT : import.meta && import.meta.env.VITE_NO_ENCRYPT
|
22
|
+
export class Valet {
|
23
|
+
idb = null;
|
24
|
+
name = null;
|
25
|
+
uploadQueue = null;
|
26
|
+
alreadyEnqueued = new Set();
|
27
|
+
keyMaterial = null;
|
28
|
+
keyId = 'null';
|
29
|
+
/**
|
30
|
+
* Function installed by the database to upload car files
|
31
|
+
* @type {null|function(string, Uint8Array):Promise<void>}
|
32
|
+
*/
|
33
|
+
uploadFunction = null;
|
34
|
+
constructor(name = 'default', keyMaterial) {
|
35
|
+
this.name = name;
|
36
|
+
this.setKeyMaterial(keyMaterial);
|
37
|
+
this.uploadQueue = cargoQueue(async (tasks, callback) => {
|
38
|
+
console.log('queue worker', tasks.length, tasks.reduce((acc, t) => acc + t.value.length, 0));
|
39
|
+
if (this.uploadFunction) {
|
40
|
+
// todo we can coalesce these into a single car file
|
41
|
+
return await this.withDB(async (db) => {
|
42
|
+
for (const task of tasks) {
|
43
|
+
await this.uploadFunction(task.carCid, task.value);
|
44
|
+
// update the indexedb to mark this car as no longer pending
|
45
|
+
const carMeta = await db.get('cidToCar', task.carCid);
|
46
|
+
delete carMeta.pending;
|
47
|
+
await db.put('cidToCar', carMeta);
|
48
|
+
}
|
49
|
+
});
|
50
|
+
}
|
51
|
+
callback();
|
52
|
+
});
|
53
|
+
this.uploadQueue.drain(async () => {
|
54
|
+
return await this.withDB(async (db) => {
|
55
|
+
const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car);
|
56
|
+
for (const carKey of carKeys) {
|
57
|
+
await this.uploadFunction(carKey, await db.get('cars', carKey));
|
58
|
+
const carMeta = await db.get('cidToCar', carKey);
|
59
|
+
delete carMeta.pending;
|
60
|
+
await db.put('cidToCar', carMeta);
|
61
|
+
}
|
62
|
+
});
|
63
|
+
});
|
64
|
+
}
|
65
|
+
getKeyMaterial() {
|
66
|
+
return this.keyMaterial;
|
67
|
+
}
|
68
|
+
setKeyMaterial(km) {
|
69
|
+
if (km && !NO_ENCRYPT) {
|
70
|
+
const hex = Uint8Array.from(Buffer.from(km, 'hex'));
|
71
|
+
this.keyMaterial = km;
|
72
|
+
const hash = sha1sync(hex);
|
73
|
+
this.keyId = Buffer.from(hash).toString('hex');
|
74
|
+
}
|
75
|
+
else {
|
76
|
+
this.keyMaterial = null;
|
77
|
+
this.keyId = 'null';
|
78
|
+
}
|
79
|
+
// console.trace('keyId', this.name, this.keyId)
|
80
|
+
}
|
81
|
+
/**
|
82
|
+
* Group the blocks into a car and write it to the valet.
|
83
|
+
* @param {import('./blockstore.js').InnerBlockstore} innerBlockstore
|
84
|
+
* @param {Set<string>} cids
|
85
|
+
* @returns {Promise<void>}
|
86
|
+
* @memberof Valet
|
87
|
+
*/
|
88
|
+
async writeTransaction(innerBlockstore, cids) {
|
89
|
+
if (innerBlockstore.lastCid) {
|
90
|
+
if (this.keyMaterial) {
|
91
|
+
// console.log('encrypting car', innerBlockstore.label)
|
92
|
+
const newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this.keyMaterial);
|
93
|
+
await this.parkCar(newCar.cid.toString(), newCar.bytes, cids);
|
94
|
+
}
|
95
|
+
else {
|
96
|
+
const newCar = await blocksToCarBlock(innerBlockstore.lastCid, innerBlockstore);
|
97
|
+
await this.parkCar(newCar.cid.toString(), newCar.bytes, cids);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
withDB = async (dbWorkFun) => {
|
102
|
+
if (!this.idb) {
|
103
|
+
this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 2, {
|
104
|
+
upgrade(db, oldVersion, newVersion, transaction) {
|
105
|
+
if (oldVersion < 1) {
|
106
|
+
db.createObjectStore('cars'); // todo use database name
|
107
|
+
const cidToCar = db.createObjectStore('cidToCar', { keyPath: 'car' });
|
108
|
+
cidToCar.createIndex('cids', 'cids', { multiEntry: true });
|
109
|
+
}
|
110
|
+
if (oldVersion < 2) {
|
111
|
+
const cidToCar = transaction.objectStore('cidToCar');
|
112
|
+
cidToCar.createIndex('pending', 'pending');
|
113
|
+
}
|
114
|
+
}
|
115
|
+
});
|
116
|
+
}
|
117
|
+
return await dbWorkFun(this.idb);
|
118
|
+
};
|
119
|
+
/**
|
120
|
+
*
|
121
|
+
* @param {string} carCid
|
122
|
+
* @param {*} value
|
123
|
+
*/
|
124
|
+
async parkCar(carCid, value, cids) {
|
125
|
+
await this.withDB(async (db) => {
|
126
|
+
const tx = db.transaction(['cars', 'cidToCar'], 'readwrite');
|
127
|
+
await tx.objectStore('cars').put(value, carCid);
|
128
|
+
await tx.objectStore('cidToCar').put({ pending: 'y', car: carCid, cids: Array.from(cids) });
|
129
|
+
return await tx.done;
|
130
|
+
});
|
131
|
+
// upload to web3.storage if we have credentials
|
132
|
+
if (this.uploadFunction) {
|
133
|
+
if (this.alreadyEnqueued.has(carCid)) {
|
134
|
+
// console.log('already enqueued', carCid)
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
// don't await this, it will be done in the queue
|
138
|
+
// console.log('add to queue', carCid, value.length)
|
139
|
+
this.uploadQueue.push({ carCid, value });
|
140
|
+
this.alreadyEnqueued.add(carCid);
|
141
|
+
}
|
142
|
+
else {
|
143
|
+
// console.log('no upload function', carCid, value.length, this.uploadFunction)
|
144
|
+
}
|
145
|
+
}
|
146
|
+
remoteBlockFunction = null;
|
147
|
+
async getBlock(dataCID) {
|
148
|
+
return await this.withDB(async (db) => {
|
149
|
+
const tx = db.transaction(['cars', 'cidToCar'], 'readonly');
|
150
|
+
const indexResp = await tx.objectStore('cidToCar').index('cids').get(dataCID);
|
151
|
+
const carCid = indexResp?.car;
|
152
|
+
if (!carCid) {
|
153
|
+
throw new Error('Missing block: ' + dataCID);
|
154
|
+
}
|
155
|
+
const carBytes = await tx.objectStore('cars').get(carCid);
|
156
|
+
const reader = await CarReader.fromBytes(carBytes);
|
157
|
+
if (this.keyMaterial) {
|
158
|
+
const roots = await reader.getRoots();
|
159
|
+
const readerGetWithCodec = async (cid) => {
|
160
|
+
const got = await reader.get(cid);
|
161
|
+
// console.log('got.', cid.toString())
|
162
|
+
let useCodec = codec;
|
163
|
+
if (cid.toString().indexOf('bafy') === 0) {
|
164
|
+
useCodec = dagcbor;
|
165
|
+
}
|
166
|
+
const decoded = await Block.decode({
|
167
|
+
...got,
|
168
|
+
codec: useCodec,
|
169
|
+
hasher: sha256
|
170
|
+
});
|
171
|
+
// console.log('decoded', decoded.value)
|
172
|
+
return decoded;
|
173
|
+
};
|
174
|
+
const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
|
175
|
+
const block = blocks.find(b => b.cid.toString() === dataCID);
|
176
|
+
if (block) {
|
177
|
+
return block.bytes;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
else {
|
181
|
+
const gotBlock = await reader.get(CID.parse(dataCID));
|
182
|
+
if (gotBlock) {
|
183
|
+
return gotBlock.bytes;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
});
|
187
|
+
}
|
188
|
+
}
|
189
|
+
const blocksToCarBlock = async (lastCid, blocks) => {
|
190
|
+
let size = 0;
|
191
|
+
const headerSize = CBW.headerLength({ roots: [lastCid] });
|
192
|
+
size += headerSize;
|
193
|
+
if (!Array.isArray(blocks)) {
|
194
|
+
blocks = Array.from(blocks.entries());
|
195
|
+
}
|
196
|
+
for (const { cid, bytes } of blocks) {
|
197
|
+
size += CBW.blockLength({ cid, bytes });
|
198
|
+
}
|
199
|
+
const buffer = new Uint8Array(size);
|
200
|
+
const writer = await CBW.createWriter(buffer, { headerSize });
|
201
|
+
writer.addRoot(lastCid);
|
202
|
+
for (const { cid, bytes } of blocks) {
|
203
|
+
writer.write({ cid, bytes });
|
204
|
+
}
|
205
|
+
await writer.close();
|
206
|
+
return await Block.encode({ value: writer.bytes, hasher: sha256, codec: raw });
|
207
|
+
};
|
208
|
+
const blocksToEncryptedCarBlock = async (innerBlockStoreClockRootCid, blocks, keyMaterial) => {
|
209
|
+
const encryptionKey = Buffer.from(keyMaterial, 'hex');
|
210
|
+
const encryptedBlocks = [];
|
211
|
+
const theCids = [];
|
212
|
+
for (const { cid } of blocks.entries()) {
|
213
|
+
theCids.push(cid.toString());
|
214
|
+
}
|
215
|
+
let last;
|
216
|
+
for await (const block of encrypt({
|
217
|
+
cids: theCids,
|
218
|
+
get: async (cid) => blocks.get(cid),
|
219
|
+
key: encryptionKey,
|
220
|
+
hasher: sha256,
|
221
|
+
chunker,
|
222
|
+
cache,
|
223
|
+
// codec: dagcbor, // should be crypto?
|
224
|
+
root: innerBlockStoreClockRootCid
|
225
|
+
})) {
|
226
|
+
encryptedBlocks.push(block);
|
227
|
+
last = block;
|
228
|
+
}
|
229
|
+
// console.log('last', last.cid.toString(), 'for clock', innerBlockStoreClockRootCid.toString())
|
230
|
+
const encryptedCar = await blocksToCarBlock(last.cid, encryptedBlocks);
|
231
|
+
return encryptedCar;
|
232
|
+
};
|
233
|
+
// { root, get, key, cache, chunker, hasher }
|
234
|
+
const memoizeDecryptedCarBlocks = new Map();
|
235
|
+
const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
|
236
|
+
if (memoizeDecryptedCarBlocks.has(cid.toString())) {
|
237
|
+
return memoizeDecryptedCarBlocks.get(cid.toString());
|
238
|
+
}
|
239
|
+
else {
|
240
|
+
const blocksPromise = (async () => {
|
241
|
+
const decryptionKey = Buffer.from(keyMaterial, 'hex');
|
242
|
+
// console.log('decrypting', keyMaterial, cid.toString())
|
243
|
+
const cids = new Set();
|
244
|
+
const decryptedBlocks = [];
|
245
|
+
for await (const block of decrypt({
|
246
|
+
root: cid,
|
247
|
+
get,
|
248
|
+
key: decryptionKey,
|
249
|
+
chunker,
|
250
|
+
hasher: sha256,
|
251
|
+
cache
|
252
|
+
// codec: dagcbor
|
253
|
+
})) {
|
254
|
+
decryptedBlocks.push(block);
|
255
|
+
cids.add(block.cid.toString());
|
256
|
+
}
|
257
|
+
return { blocks: decryptedBlocks, cids };
|
258
|
+
})();
|
259
|
+
memoizeDecryptedCarBlocks.set(cid.toString(), blocksPromise);
|
260
|
+
return blocksPromise;
|
261
|
+
}
|
262
|
+
};
|
package/hooks/use-fireproof.js
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
/* global localStorage */
|
2
1
|
// @ts-ignore
|
3
2
|
import { useEffect, useState, createContext } from 'react'
|
4
|
-
import { Fireproof, Listener
|
3
|
+
import { Fireproof, Listener } from '../src/fireproof.js'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
/**
|
6
|
+
@typedef {Object} FireproofCtxValue
|
7
|
+
@property {Function} addSubscriber - A function to add a subscriber with a label and function.
|
8
|
+
@property {Fireproof} database - An instance of the Fireproof class.
|
9
|
+
@property {boolean} ready - A boolean indicating whether the database is ready.
|
10
|
+
@param {string} label - A label for the subscriber.
|
11
|
+
@param {Function} fn - A function to be added as a subscriber.
|
12
|
+
@returns {void}
|
13
|
+
*/
|
12
14
|
export const FireproofCtx = createContext({
|
13
15
|
addSubscriber: () => {},
|
14
16
|
database: null,
|
@@ -27,28 +29,24 @@ const initializeDatabase = name => {
|
|
27
29
|
}
|
28
30
|
|
29
31
|
/**
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
name
|
41
|
-
) {
|
32
|
+
|
33
|
+
@function useFireproof
|
34
|
+
React hook to initialize a Fireproof database, automatically saving and loading the clock.
|
35
|
+
You might need to import { nodePolyfills } from 'vite-plugin-node-polyfills' in your vite.config.ts
|
36
|
+
@param {string} name - The path to the database file
|
37
|
+
@param {function(database): void} [defineDatabaseFn] - Synchronous function that defines the database, run this before any async calls
|
38
|
+
@param {function(database): Promise<void>} [setupDatabaseFn] - Asynchronous function that sets up the database, run this to load fixture data etc
|
39
|
+
@returns {FireproofCtxValue} { addSubscriber, database, ready }
|
40
|
+
*/
|
41
|
+
export function useFireproof (name = 'useFireproof', defineDatabaseFn = () => {}, setupDatabaseFn = async () => {}) {
|
42
42
|
const [ready, setReady] = useState(false)
|
43
|
-
initializeDatabase(name
|
44
|
-
const localStorageKey = 'fp.' + database.name
|
43
|
+
initializeDatabase(name)
|
45
44
|
|
46
45
|
const addSubscriber = (label, fn) => {
|
47
46
|
inboundSubscriberQueue.set(label, fn)
|
48
47
|
}
|
49
48
|
|
50
49
|
const listenerCallback = async event => {
|
51
|
-
localSet(localStorageKey, JSON.stringify(database))
|
52
50
|
if (event._external) return
|
53
51
|
for (const [, fn] of inboundSubscriberQueue) fn()
|
54
52
|
}
|
@@ -59,31 +57,11 @@ export function useFireproof (
|
|
59
57
|
if (startedSetup) return
|
60
58
|
startedSetup = true
|
61
59
|
defineDatabaseFn(database) // define indexes before querying them
|
62
|
-
|
63
|
-
const fp = localGet(localStorageKey) // todo use db.name
|
64
|
-
if (fp) {
|
65
|
-
try {
|
66
|
-
const serialized = JSON.parse(fp)
|
67
|
-
// console.log('serialized', JSON.stringify(serialized.indexes.map(c => c.clock)))
|
68
|
-
console.log(`Loading previous database clock. (localStorage.removeItem('${localStorageKey}') to reset)`)
|
69
|
-
await Hydrator.fromJSON(serialized, database)
|
70
|
-
const changes = await database.changesSince()
|
71
|
-
if (changes.rows.length < 2) {
|
72
|
-
// console.log('Resetting database')
|
73
|
-
throw new Error('Resetting database')
|
74
|
-
}
|
75
|
-
} catch (e) {
|
76
|
-
console.error(`Error loading previous database clock. ${fp} Resetting.`, e)
|
77
|
-
await Hydrator.zoom(database, [])
|
78
|
-
await setupDatabaseFn(database)
|
79
|
-
localSet(localStorageKey, JSON.stringify(database))
|
80
|
-
}
|
81
|
-
} else {
|
60
|
+
if (database.clock.length === 0) {
|
82
61
|
await setupDatabaseFn(database)
|
83
|
-
localSet(localStorageKey, JSON.stringify(database))
|
84
62
|
}
|
85
63
|
setReady(true)
|
86
|
-
listener.on('*', listenerCallback)// hushed('*', listenerCallback, 250))
|
64
|
+
listener.on('*', listenerCallback) // hushed('*', listenerCallback, 250))
|
87
65
|
}
|
88
66
|
doSetup()
|
89
67
|
}, [ready])
|
@@ -91,10 +69,7 @@ export function useFireproof (
|
|
91
69
|
return {
|
92
70
|
addSubscriber,
|
93
71
|
database,
|
94
|
-
ready
|
95
|
-
persist: () => {
|
96
|
-
localSet(localStorageKey, JSON.stringify(database))
|
97
|
-
}
|
72
|
+
ready
|
98
73
|
}
|
99
74
|
}
|
100
75
|
|
@@ -114,20 +89,20 @@ export function useFireproof (
|
|
114
89
|
// (...args) =>
|
115
90
|
// husher(id, () => workFn(...args), ms)
|
116
91
|
|
117
|
-
let storageSupported = false
|
118
|
-
try {
|
119
|
-
|
120
|
-
} catch (e) {}
|
121
|
-
export function localGet (key) {
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
}
|
126
|
-
function localSet (key, value) {
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
}
|
92
|
+
// let storageSupported = false
|
93
|
+
// try {
|
94
|
+
// storageSupported = window.localStorage && true
|
95
|
+
// } catch (e) {}
|
96
|
+
// export function localGet (key) {
|
97
|
+
// if (storageSupported) {
|
98
|
+
// return localStorage && localStorage.getItem(key)
|
99
|
+
// }
|
100
|
+
// }
|
101
|
+
// function localSet (key, value) {
|
102
|
+
// if (storageSupported) {
|
103
|
+
// return localStorage && localStorage.setItem(key, value)
|
104
|
+
// }
|
105
|
+
// }
|
131
106
|
// function localRemove(key) {
|
132
107
|
// if (storageSupported) {
|
133
108
|
// return localStorage && localStorage.removeItem(key)
|
package/package.json
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fireproof/core",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"description": "Realtime database for IPFS",
|
5
|
-
"main": "dist/src/
|
6
|
-
"module": "dist/src/
|
7
|
-
"typings": "dist/src/
|
8
|
-
"types": "dist/src/
|
5
|
+
"main": "dist/src/fireproof.js",
|
6
|
+
"module": "dist/src/fireproof.mjs",
|
7
|
+
"typings": "dist/src/fireproof.d.ts",
|
8
|
+
"types": "dist/src/fireproof.d.ts",
|
9
9
|
"type": "module",
|
10
10
|
"scripts": {
|
11
11
|
"keygen": "node scripts/keygen.js",
|
@@ -14,11 +14,11 @@
|
|
14
14
|
"test:mocha": "mocha --reporter list test/*.test.js",
|
15
15
|
"test:watch": "npm run test:mocha -- -w --parallel",
|
16
16
|
"coverage": "c8 -r html -r text npm test",
|
17
|
-
"prepublishOnly": "cp ../../README.md .",
|
17
|
+
"prepublishOnly": "cp ../../README.md . && npm run build",
|
18
18
|
"postpublish": "rm README.md",
|
19
19
|
"lint": "standard",
|
20
20
|
"lint:fix": "standard --fix",
|
21
|
-
"
|
21
|
+
"tsc": "tsc --watch",
|
22
22
|
"build": "rollup -c"
|
23
23
|
},
|
24
24
|
"keywords": [
|
@@ -99,14 +99,13 @@
|
|
99
99
|
"homepage": "https://fireproof.storage",
|
100
100
|
"exports": {
|
101
101
|
".": {
|
102
|
-
"types": "./dist/src/
|
103
|
-
"import": "./dist/src/
|
104
|
-
"module": "./dist/src/
|
105
|
-
"default": "./dist/src/
|
106
|
-
"require": "./dist/src/
|
102
|
+
"types": "./dist/src/fireproof.d.ts",
|
103
|
+
"import": "./dist/src/fireproof.mjs",
|
104
|
+
"module": "./dist/src/fireproof.mjs",
|
105
|
+
"default": "./dist/src/fireproof.js",
|
106
|
+
"require": "./dist/src/fireproof.js"
|
107
107
|
},
|
108
|
-
"./use-fireproof": {
|
109
|
-
"types": "./dist/hooks/use-fireproof.d.ts",
|
108
|
+
"./hooks/use-fireproof": {
|
110
109
|
"import": "./hooks/use-fireproof.js"
|
111
110
|
},
|
112
111
|
"./package.json": "./package.json"
|
package/src/blockstore.js
CHANGED
@@ -40,7 +40,10 @@ export class TransactionBlockstore {
|
|
40
40
|
inflightTransactions = new Set()
|
41
41
|
|
42
42
|
constructor (name, encryptionKey) {
|
43
|
-
|
43
|
+
if (name) {
|
44
|
+
this.valet = new Valet(name, encryptionKey)
|
45
|
+
}
|
46
|
+
this.remoteBlockFunction = null
|
44
47
|
}
|
45
48
|
|
46
49
|
/**
|
@@ -73,6 +76,7 @@ export class TransactionBlockstore {
|
|
73
76
|
async committedGet (key) {
|
74
77
|
const old = this.committedBlocks.get(key)
|
75
78
|
if (old) return old
|
79
|
+
if (!this.valet) throw new Error('Missing block: ' + key)
|
76
80
|
const got = await this.valet.getBlock(key)
|
77
81
|
// console.log('committedGet: ' + key)
|
78
82
|
this.committedBlocks.set(key, got)
|
@@ -84,9 +88,9 @@ export class TransactionBlockstore {
|
|
84
88
|
}
|
85
89
|
|
86
90
|
async networkGet (key) {
|
87
|
-
if (this.
|
91
|
+
if (this.remoteBlockFunction) {
|
88
92
|
// todo why is this on valet?
|
89
|
-
const value = await husher(key, async () => await this.
|
93
|
+
const value = await husher(key, async () => await this.remoteBlockFunction(key))
|
90
94
|
if (value) {
|
91
95
|
// console.log('networkGot: ' + key, value.length)
|
92
96
|
doTransaction('networkGot: ' + key, this, async innerBlockstore => {
|
@@ -166,7 +170,7 @@ export class TransactionBlockstore {
|
|
166
170
|
cids.add(stringCid)
|
167
171
|
}
|
168
172
|
}
|
169
|
-
if (cids.size > 0) {
|
173
|
+
if (cids.size > 0 && this.valet) {
|
170
174
|
// console.log(innerBlockstore.label, 'committing', cids.size, 'blocks')
|
171
175
|
await this.valet.writeTransaction(innerBlockstore, cids)
|
172
176
|
}
|