@fireproof/core 0.19.8-dev-global → 0.19.9-dev-frag
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 +7 -0
- package/chunk-7EWIAXTM.js +7 -0
- package/chunk-7EWIAXTM.js.map +1 -0
- package/chunk-JO5AVWG7.js +67 -0
- package/chunk-JO5AVWG7.js.map +1 -0
- package/chunk-PB4BKL4O.js +7 -0
- package/chunk-PB4BKL4O.js.map +1 -0
- package/chunk-YS4GL6OK.js +266 -0
- package/chunk-YS4GL6OK.js.map +1 -0
- package/{store-indexdb-WLRSICCB.js → gateway-IZRHJWPE.js} +48 -80
- package/gateway-IZRHJWPE.js.map +1 -0
- package/gateway-YSNUK2L3.js +145 -0
- package/gateway-YSNUK2L3.js.map +1 -0
- package/index.cjs +2132 -1783
- package/index.cjs.map +1 -1
- package/index.d.cts +613 -513
- package/index.d.ts +613 -513
- package/index.global.js +19366 -20107
- package/index.global.js.map +1 -1
- package/index.js +1512 -1022
- package/index.js.map +1 -1
- package/key-bag-file-NMEBFSPM.js +54 -0
- package/key-bag-file-NMEBFSPM.js.map +1 -0
- package/key-bag-indexdb-X5V6GNBZ.js +50 -0
- package/key-bag-indexdb-X5V6GNBZ.js.map +1 -0
- package/mem-filesystem-B6C6QOIP.js +41 -0
- package/mem-filesystem-B6C6QOIP.js.map +1 -0
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/metafile-iife.json +1 -1
- package/node-filesystem-5JLBSHKQ.js +41 -0
- package/node-filesystem-5JLBSHKQ.js.map +1 -0
- package/package.json +8 -7
- package/tests/blockstore/fragment-gateway.test.ts +107 -0
- package/tests/blockstore/keyed-crypto.test.ts +302 -0
- package/tests/blockstore/loader.test.ts +24 -19
- package/tests/blockstore/store.test.ts +34 -28
- package/tests/blockstore/transaction.test.ts +19 -15
- package/tests/fireproof/config.test.ts +94 -78
- package/tests/fireproof/crdt.test.ts +34 -28
- package/tests/fireproof/database.test.ts +22 -14
- package/tests/fireproof/fireproof.test.fixture.ts +133 -0
- package/tests/fireproof/fireproof.test.ts +331 -219
- package/tests/fireproof/hello.test.ts +6 -4
- package/tests/fireproof/indexer.test.ts +34 -27
- package/tests/fireproof/utils.test.ts +65 -0
- package/tests/helpers.ts +25 -57
- package/utils-IZPK4QS7.js +14 -0
- package/utils-IZPK4QS7.js.map +1 -0
- package/chunk-BNL4PVBF.js +0 -314
- package/chunk-BNL4PVBF.js.map +0 -1
- package/chunk-JW2QT6BF.js +0 -184
- package/chunk-JW2QT6BF.js.map +0 -1
- package/node-sys-container-MIEX6ELJ.js +0 -29
- package/node-sys-container-MIEX6ELJ.js.map +0 -1
- package/store-file-VJ6BI4II.js +0 -191
- package/store-file-VJ6BI4II.js.map +0 -1
- package/store-indexdb-WLRSICCB.js.map +0 -1
package/index.js
CHANGED
@@ -1,29 +1,33 @@
|
|
1
|
+
import {
|
2
|
+
FILESTORE_VERSION
|
3
|
+
} from "./chunk-7EWIAXTM.js";
|
4
|
+
import {
|
5
|
+
getFileName,
|
6
|
+
getFileSystem,
|
7
|
+
getPath,
|
8
|
+
toArrayBuffer
|
9
|
+
} from "./chunk-JO5AVWG7.js";
|
10
|
+
import {
|
11
|
+
INDEXDB_VERSION
|
12
|
+
} from "./chunk-PB4BKL4O.js";
|
1
13
|
import {
|
2
14
|
NotFoundError,
|
3
15
|
Result,
|
16
|
+
UInt8ArrayEqual,
|
17
|
+
__export,
|
4
18
|
dataDir,
|
5
|
-
decodeFile,
|
6
|
-
encodeFile,
|
7
19
|
ensureLogger,
|
20
|
+
ensureSuperLog,
|
21
|
+
ensureSuperThis,
|
8
22
|
exception2Result,
|
9
23
|
exceptionWrapper,
|
10
24
|
getKey,
|
11
25
|
getName,
|
12
26
|
getStore,
|
13
|
-
isNotFoundError
|
14
|
-
|
15
|
-
toCryptoOpts
|
16
|
-
} from "./chunk-BNL4PVBF.js";
|
17
|
-
import {
|
18
|
-
SysContainer,
|
19
|
-
__export,
|
20
|
-
falsyToUndef,
|
21
|
-
isFalsy,
|
22
|
-
throwFalsy
|
23
|
-
} from "./chunk-JW2QT6BF.js";
|
27
|
+
isNotFoundError
|
28
|
+
} from "./chunk-YS4GL6OK.js";
|
24
29
|
|
25
30
|
// src/database.ts
|
26
|
-
import { uuidv7 } from "uuidv7";
|
27
31
|
import { ResolveOnce as ResolveOnce5 } from "@adviser/cement";
|
28
32
|
|
29
33
|
// src/write-queue.ts
|
@@ -69,11 +73,81 @@ function writeQueue(worker, payload = Infinity, unbounded = false) {
|
|
69
73
|
// src/crdt.ts
|
70
74
|
import { ResolveOnce as ResolveOnce4 } from "@adviser/cement";
|
71
75
|
|
76
|
+
// src/runtime/wait-pr-multiformats/block.ts
|
77
|
+
var block_exports = {};
|
78
|
+
__export(block_exports, {
|
79
|
+
Block: () => Block,
|
80
|
+
create: () => create,
|
81
|
+
createUnsafe: () => createUnsafe,
|
82
|
+
decode: () => decode,
|
83
|
+
encode: () => encode
|
84
|
+
});
|
85
|
+
import { bytes as binary, CID } from "multiformats";
|
86
|
+
import { Block as mfBlock } from "multiformats/block";
|
87
|
+
var Block = mfBlock;
|
88
|
+
async function decode({
|
89
|
+
bytes,
|
90
|
+
codec: codec3,
|
91
|
+
hasher: hasher7
|
92
|
+
}) {
|
93
|
+
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
94
|
+
if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
|
95
|
+
const value = await Promise.resolve(codec3.decode(bytes));
|
96
|
+
const hash = await hasher7.digest(bytes);
|
97
|
+
const cid = CID.create(1, codec3.code, hash);
|
98
|
+
return new mfBlock({ value, bytes, cid });
|
99
|
+
}
|
100
|
+
async function encode({
|
101
|
+
value,
|
102
|
+
codec: codec3,
|
103
|
+
hasher: hasher7
|
104
|
+
}) {
|
105
|
+
if (typeof value === "undefined") throw new Error('Missing required argument "value"');
|
106
|
+
if (codec3 == null || hasher7 == null) throw new Error("Missing required argument: codec or hasher");
|
107
|
+
const bytes = await Promise.resolve(codec3.encode(value));
|
108
|
+
const hash = await hasher7.digest(bytes);
|
109
|
+
const cid = CID.create(1, codec3.code, hash);
|
110
|
+
return new mfBlock({ value, bytes, cid });
|
111
|
+
}
|
112
|
+
async function create({
|
113
|
+
bytes,
|
114
|
+
cid,
|
115
|
+
hasher: hasher7,
|
116
|
+
codec: codec3
|
117
|
+
}) {
|
118
|
+
if (bytes == null) throw new Error('Missing required argument "bytes"');
|
119
|
+
if (hasher7 == null) throw new Error('Missing required argument "hasher"');
|
120
|
+
const value = await Promise.resolve(codec3.decode(bytes));
|
121
|
+
const hash = await hasher7.digest(bytes);
|
122
|
+
if (!binary.equals(cid.multihash.bytes, hash.bytes)) {
|
123
|
+
throw new Error("CID hash does not match bytes");
|
124
|
+
}
|
125
|
+
return createUnsafe({
|
126
|
+
bytes,
|
127
|
+
cid,
|
128
|
+
value,
|
129
|
+
codec: codec3
|
130
|
+
});
|
131
|
+
}
|
132
|
+
async function createUnsafe({
|
133
|
+
bytes,
|
134
|
+
cid,
|
135
|
+
value: maybeValue,
|
136
|
+
codec: codec3
|
137
|
+
}) {
|
138
|
+
const value = await Promise.resolve(maybeValue !== void 0 ? maybeValue : codec3?.decode(bytes));
|
139
|
+
if (value === void 0) throw new Error('Missing required argument, must either provide "value" or "codec"');
|
140
|
+
return new Block({
|
141
|
+
cid,
|
142
|
+
bytes,
|
143
|
+
value
|
144
|
+
});
|
145
|
+
}
|
146
|
+
|
72
147
|
// src/crdt-helpers.ts
|
73
|
-
import { encode as encode3, decode as decode3, Block as Block2 } from "multiformats/block";
|
74
148
|
import { parse as parse2 } from "multiformats/link";
|
75
|
-
import { sha256 as
|
76
|
-
import * as
|
149
|
+
import { sha256 as hasher5 } from "multiformats/hashes/sha2";
|
150
|
+
import * as codec from "@ipld/dag-cbor";
|
77
151
|
import { put, get, entries, root } from "@web3-storage/pail/crdt";
|
78
152
|
import { EventFetcher, vis } from "@web3-storage/pail/clock";
|
79
153
|
import * as Batch from "@web3-storage/pail/crdt/batch";
|
@@ -84,512 +158,145 @@ __export(blockstore_exports, {
|
|
84
158
|
BaseBlockstore: () => BaseBlockstore,
|
85
159
|
CarTransaction: () => CarTransaction,
|
86
160
|
CompactionFetcher: () => CompactionFetcher,
|
87
|
-
ConnectREST: () => ConnectREST,
|
88
161
|
ConnectionBase: () => ConnectionBase,
|
89
|
-
DataStore: () => DataStore,
|
90
162
|
EncryptedBlockstore: () => EncryptedBlockstore,
|
91
|
-
|
163
|
+
FragmentGateway: () => FragmentGateway,
|
92
164
|
Loader: () => Loader,
|
93
|
-
|
94
|
-
|
95
|
-
RemoteWAL: () => RemoteWAL,
|
96
|
-
isNotFoundError: () => isNotFoundError,
|
165
|
+
ensureStart: () => ensureStart,
|
166
|
+
getGatewayFromURL: () => getGatewayFromURL,
|
97
167
|
parseCarFile: () => parseCarFile,
|
98
168
|
registerStoreProtocol: () => registerStoreProtocol,
|
99
169
|
testStoreFactory: () => testStoreFactory,
|
100
|
-
|
101
|
-
|
170
|
+
toCIDBlock: () => toCIDBlock,
|
171
|
+
toStoreRuntime: () => toStoreRuntime
|
102
172
|
});
|
103
173
|
|
104
|
-
// src/blockstore/
|
105
|
-
|
106
|
-
|
174
|
+
// src/blockstore/types.ts
|
175
|
+
function toCIDBlock(block) {
|
176
|
+
return block;
|
177
|
+
}
|
107
178
|
|
108
|
-
// src/blockstore/
|
109
|
-
|
110
|
-
constructor(loader) {
|
111
|
-
this.eventsWeHandled = /* @__PURE__ */ new Set();
|
112
|
-
this.queue = [];
|
113
|
-
this.isProcessing = false;
|
114
|
-
this.loader = loader;
|
115
|
-
this.logger = ensureLogger(loader.logger, "TaskManager");
|
116
|
-
}
|
117
|
-
async handleEvent(eventBlock) {
|
118
|
-
const cid = eventBlock.cid.toString();
|
119
|
-
const parents = eventBlock.value.parents.map((cid2) => cid2.toString());
|
120
|
-
for (const parent of parents) {
|
121
|
-
this.eventsWeHandled.add(parent);
|
122
|
-
}
|
123
|
-
this.queue.push({ cid, eventBlock, retries: 0 });
|
124
|
-
this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
|
125
|
-
void this.processQueue();
|
126
|
-
}
|
127
|
-
async processQueue() {
|
128
|
-
if (this.isProcessing) return;
|
129
|
-
this.isProcessing = true;
|
130
|
-
const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
|
131
|
-
const first = filteredQueue[0];
|
132
|
-
if (!first) {
|
133
|
-
return;
|
134
|
-
}
|
135
|
-
try {
|
136
|
-
this.loader?.remoteMetaStore?.handleByteHeads([first.eventBlock.value.data.dbMeta]);
|
137
|
-
this.eventsWeHandled.add(first.cid);
|
138
|
-
this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
|
139
|
-
} catch (err) {
|
140
|
-
if (first.retries++ > 3) {
|
141
|
-
this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
|
142
|
-
this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
|
143
|
-
}
|
144
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
145
|
-
throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
|
146
|
-
} finally {
|
147
|
-
this.isProcessing = false;
|
148
|
-
if (this.queue.length > 0) {
|
149
|
-
void this.processQueue();
|
150
|
-
}
|
151
|
-
}
|
152
|
-
}
|
153
|
-
};
|
179
|
+
// src/blockstore/store-factory.ts
|
180
|
+
import { KeyedResolvOnce as KeyedResolvOnce2, URI as URI3 } from "@adviser/cement";
|
154
181
|
|
155
|
-
// src/
|
156
|
-
var
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
182
|
+
// src/runtime/files.ts
|
183
|
+
var files_exports = {};
|
184
|
+
__export(files_exports, {
|
185
|
+
decodeFile: () => decodeFile,
|
186
|
+
encodeFile: () => encodeFile
|
187
|
+
});
|
188
|
+
import * as UnixFS from "@ipld/unixfs";
|
189
|
+
import * as raw from "multiformats/codecs/raw";
|
190
|
+
import { withMaxChunkSize } from "@ipld/unixfs/file/chunker/fixed";
|
191
|
+
import { withWidth } from "@ipld/unixfs/file/layout/balanced";
|
192
|
+
import { exporter } from "ipfs-unixfs-exporter";
|
193
|
+
var queuingStrategy = UnixFS.withCapacity();
|
194
|
+
var settings = UnixFS.configure({
|
195
|
+
fileChunkEncoder: raw,
|
196
|
+
smallFileEncoder: raw,
|
197
|
+
chunker: withMaxChunkSize(1024 * 1024),
|
198
|
+
fileLayout: withWidth(1024)
|
199
|
+
});
|
200
|
+
async function collect(collectable) {
|
201
|
+
const chunks = [];
|
202
|
+
await collectable.pipeTo(
|
203
|
+
new WritableStream({
|
204
|
+
write(chunk) {
|
205
|
+
chunks.push(chunk);
|
206
|
+
}
|
207
|
+
})
|
208
|
+
);
|
209
|
+
return chunks;
|
210
|
+
}
|
211
|
+
async function encodeFile(blob) {
|
212
|
+
const readable = createFileEncoderStream(blob);
|
213
|
+
const blocks = await collect(readable);
|
214
|
+
return { cid: blocks.at(-1).cid, blocks };
|
215
|
+
}
|
216
|
+
async function decodeFile(blocks, cid, meta) {
|
217
|
+
const entry = await exporter(cid.toString(), blocks, { length: meta.size });
|
218
|
+
const chunks = [];
|
219
|
+
for await (const chunk of entry.content()) {
|
220
|
+
chunks.push(chunk);
|
221
|
+
}
|
222
|
+
return new File(chunks, entry.name, { type: meta.type, lastModified: 0 });
|
223
|
+
}
|
224
|
+
function createFileEncoderStream(blob) {
|
225
|
+
const { readable, writable } = new TransformStream({}, queuingStrategy);
|
226
|
+
const unixfsWriter = UnixFS.createWriter({ writable, settings });
|
227
|
+
const fileBuilder = new UnixFSFileBuilder("", blob);
|
228
|
+
void (async () => {
|
229
|
+
await fileBuilder.finalize(unixfsWriter);
|
230
|
+
await unixfsWriter.close();
|
231
|
+
})();
|
232
|
+
return readable;
|
233
|
+
}
|
234
|
+
var UnixFSFileBuilder = class {
|
235
|
+
#file;
|
236
|
+
constructor(name, file) {
|
237
|
+
this.name = name;
|
238
|
+
this.#file = file;
|
239
|
+
}
|
240
|
+
async finalize(writer) {
|
241
|
+
const unixfsFileWriter = UnixFS.createFileWriter(writer);
|
242
|
+
await this.#file.stream().pipeTo(
|
243
|
+
new WritableStream({
|
244
|
+
async write(chunk) {
|
245
|
+
await unixfsFileWriter.write(chunk);
|
246
|
+
}
|
247
|
+
})
|
196
248
|
);
|
197
|
-
await
|
198
|
-
return event;
|
199
|
-
}
|
200
|
-
async decodeEventBlock(bytes) {
|
201
|
-
const event = await decodeEventBlock(bytes);
|
202
|
-
return event;
|
203
|
-
}
|
204
|
-
// move this stuff to connect
|
205
|
-
// async getDashboardURL(compact = true) {
|
206
|
-
// const baseUrl = 'https://dashboard.fireproof.storage/'
|
207
|
-
// if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
|
208
|
-
// // if (compact) {
|
209
|
-
// // await this.compact()
|
210
|
-
// // }
|
211
|
-
// const currents = await this.loader?.metaStore?.load()
|
212
|
-
// if (!currents) throw new Error("Can't sync empty database: save data first")
|
213
|
-
// if (currents.length > 1)
|
214
|
-
// throw new Error("Can't sync database with split heads: make an update first")
|
215
|
-
// const current = currents[0]
|
216
|
-
// const params = {
|
217
|
-
// car: current.car.toString()
|
218
|
-
// }
|
219
|
-
// if (current.key) {
|
220
|
-
// // @ts-ignore
|
221
|
-
// params.key = current.key.toString()
|
222
|
-
// }
|
223
|
-
// // @ts-ignore
|
224
|
-
// if (this.name) {
|
225
|
-
// // @ts-ignore
|
226
|
-
// params.name = this.name
|
227
|
-
// }
|
228
|
-
// const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
|
229
|
-
// console.log('Import to dashboard: ' + url.toString())
|
230
|
-
// return url
|
231
|
-
// }
|
232
|
-
// openDashboard() {
|
233
|
-
// void this.getDashboardURL().then(url => {
|
234
|
-
// if (url) window.open(url.toString(), '_blank')
|
235
|
-
// })
|
236
|
-
// }
|
237
|
-
};
|
238
|
-
|
239
|
-
// src/blockstore/connect-rest.ts
|
240
|
-
var ConnectREST = class extends ConnectionBase {
|
241
|
-
constructor(base, logger) {
|
242
|
-
super(ensureLogger(logger, "ConnectREST"));
|
243
|
-
this.baseUrl = new URL(base);
|
244
|
-
}
|
245
|
-
async dataUpload(bytes, params) {
|
246
|
-
const carCid = params.car.toString();
|
247
|
-
const uploadURL = new URL(`/cars/${carCid}.car`, this.baseUrl);
|
248
|
-
const done = await fetch(uploadURL, { method: "PUT", body: bytes });
|
249
|
-
if (!done.ok) {
|
250
|
-
throw this.logger.Error().Msg("failed to upload data " + done.statusText);
|
251
|
-
}
|
252
|
-
}
|
253
|
-
async dataDownload(params) {
|
254
|
-
const { car } = params;
|
255
|
-
const fetchFromUrl = new URL(`/cars/${car.toString()}.car`, this.baseUrl);
|
256
|
-
const response = await fetch(fetchFromUrl);
|
257
|
-
if (!response.ok) {
|
258
|
-
return void 0;
|
259
|
-
}
|
260
|
-
const bytes = new Uint8Array(await response.arrayBuffer());
|
261
|
-
return bytes;
|
262
|
-
}
|
263
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
264
|
-
async metaUpload(bytes, params) {
|
265
|
-
return void 0;
|
266
|
-
}
|
267
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
268
|
-
async metaDownload(params) {
|
269
|
-
return [];
|
249
|
+
return await unixfsFileWriter.close();
|
270
250
|
}
|
271
251
|
};
|
272
252
|
|
273
|
-
// src/blockstore/store-factory.ts
|
274
|
-
import { KeyedResolvOnce } from "@adviser/cement";
|
275
|
-
|
276
253
|
// src/blockstore/store.ts
|
277
254
|
import pLimit2 from "p-limit";
|
278
255
|
import { format, parse } from "@ipld/dag-json";
|
279
|
-
import { ResolveOnce as ResolveOnce2, Result as
|
256
|
+
import { ResolveOnce as ResolveOnce2, Result as Result3 } from "@adviser/cement";
|
257
|
+
|
258
|
+
// src/types.ts
|
259
|
+
function isFalsy(value) {
|
260
|
+
return value === false && value === null && value === void 0;
|
261
|
+
}
|
262
|
+
function throwFalsy(value) {
|
263
|
+
if (isFalsy(value)) {
|
264
|
+
throw new Error("value is Falsy");
|
265
|
+
}
|
266
|
+
return value;
|
267
|
+
}
|
268
|
+
function falsyToUndef(value) {
|
269
|
+
if (isFalsy(value)) {
|
270
|
+
return void 0;
|
271
|
+
}
|
272
|
+
return value;
|
273
|
+
}
|
280
274
|
|
281
275
|
// src/blockstore/loader.ts
|
282
276
|
import pLimit from "p-limit";
|
283
277
|
import { CarReader } from "@ipld/car";
|
284
278
|
import { ResolveOnce } from "@adviser/cement";
|
285
279
|
|
286
|
-
// src/blockstore/types.ts
|
287
|
-
function toCIDBlock(block) {
|
288
|
-
return block;
|
289
|
-
}
|
290
|
-
|
291
280
|
// src/blockstore/loader-helpers.ts
|
292
|
-
import { encode, decode } from "multiformats/block";
|
293
281
|
import { sha256 as hasher } from "multiformats/hashes/sha2";
|
294
|
-
import * as
|
295
|
-
import * as CBW from "@ipld/car/buffer-writer";
|
296
|
-
import * as codec from "@ipld/dag-cbor";
|
297
|
-
async function encodeCarFile(roots, t) {
|
298
|
-
let size = 0;
|
299
|
-
const headerSize = CBW.headerLength({ roots });
|
300
|
-
size += headerSize;
|
301
|
-
for (const { cid, bytes } of t.entries()) {
|
302
|
-
size += CBW.blockLength({ cid, bytes });
|
303
|
-
}
|
304
|
-
const buffer = new Uint8Array(size);
|
305
|
-
const writer = CBW.createWriter(buffer, { headerSize });
|
306
|
-
for (const r of roots) {
|
307
|
-
writer.addRoot(r);
|
308
|
-
}
|
309
|
-
for (const { cid, bytes } of t.entries()) {
|
310
|
-
writer.write({ cid, bytes });
|
311
|
-
}
|
312
|
-
writer.close();
|
313
|
-
return await encode({ value: writer.bytes, hasher, codec: raw });
|
314
|
-
}
|
315
|
-
async function encodeCarHeader(fp) {
|
316
|
-
return await encode({
|
317
|
-
value: { fp },
|
318
|
-
hasher,
|
319
|
-
codec
|
320
|
-
});
|
321
|
-
}
|
282
|
+
import * as dagCodec from "@ipld/dag-cbor";
|
322
283
|
async function parseCarFile(reader, logger) {
|
323
284
|
const roots = await reader.getRoots();
|
324
285
|
const header = await reader.get(roots[0]);
|
325
286
|
if (!header) throw logger.Error().Msg("missing header block").AsError();
|
326
|
-
const
|
327
|
-
const fpvalue = value;
|
287
|
+
const dec = await decode({ bytes: header.bytes, hasher, codec: dagCodec });
|
288
|
+
const fpvalue = dec.value;
|
328
289
|
if (fpvalue && !fpvalue.fp) {
|
329
290
|
throw logger.Error().Msg("missing fp").AsError();
|
330
291
|
}
|
331
292
|
return fpvalue.fp;
|
332
293
|
}
|
333
294
|
|
334
|
-
// src/blockstore/encrypt-helpers.ts
|
335
|
-
import { sha256 } from "multiformats/hashes/sha2";
|
336
|
-
import { CID as CID2 } from "multiformats";
|
337
|
-
import { encode as encode2, decode as decode2, create as mfCreate } from "multiformats/block";
|
338
|
-
import * as dagcbor from "@ipld/dag-cbor";
|
339
|
-
import { MemoryBlockstore as MemoryBlockstore2 } from "@web3-storage/pail/block";
|
340
|
-
import { bf } from "prolly-trees/utils";
|
341
|
-
import { nocache as cache } from "prolly-trees/cache";
|
342
|
-
import { create, load } from "prolly-trees/cid-set";
|
343
|
-
|
344
|
-
// src/blockstore/encrypt-codec.ts
|
345
|
-
import { CID } from "multiformats";
|
346
|
-
function makeCodec(ilogger, crypto, randomBytes) {
|
347
|
-
const logger = ensureLogger(ilogger, "makeCodec");
|
348
|
-
const enc32 = (value) => {
|
349
|
-
value = +value;
|
350
|
-
const buff = new Uint8Array(4);
|
351
|
-
buff[3] = value >>> 24;
|
352
|
-
buff[2] = value >>> 16;
|
353
|
-
buff[1] = value >>> 8;
|
354
|
-
buff[0] = value & 255;
|
355
|
-
return buff;
|
356
|
-
};
|
357
|
-
const readUInt32LE = (buffer) => {
|
358
|
-
const offset = buffer.byteLength - 4;
|
359
|
-
return (buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16) + buffer[offset + 3] * 16777216;
|
360
|
-
};
|
361
|
-
const concat = (buffers) => {
|
362
|
-
const uint8Arrays = buffers.map((b) => b instanceof ArrayBuffer ? new Uint8Array(b) : b);
|
363
|
-
const totalLength = uint8Arrays.reduce((sum, arr) => sum + arr.length, 0);
|
364
|
-
const result = new Uint8Array(totalLength);
|
365
|
-
let offset = 0;
|
366
|
-
for (const arr of uint8Arrays) {
|
367
|
-
result.set(arr, offset);
|
368
|
-
offset += arr.length;
|
369
|
-
}
|
370
|
-
return result;
|
371
|
-
};
|
372
|
-
const encode4 = ({ iv, bytes }) => concat([iv, bytes]);
|
373
|
-
const decode4 = (bytes) => {
|
374
|
-
const iv = bytes.subarray(0, 12);
|
375
|
-
bytes = bytes.slice(12);
|
376
|
-
return { iv, bytes };
|
377
|
-
};
|
378
|
-
const code = 3145728 + 1337;
|
379
|
-
async function subtleKey(key) {
|
380
|
-
return await crypto.importKey(
|
381
|
-
"raw",
|
382
|
-
// raw or jwk
|
383
|
-
key,
|
384
|
-
// raw data
|
385
|
-
"AES-GCM",
|
386
|
-
false,
|
387
|
-
// extractable
|
388
|
-
["encrypt", "decrypt"]
|
389
|
-
);
|
390
|
-
}
|
391
|
-
const decrypt = async ({ key, value }) => {
|
392
|
-
const { bytes: inBytes, iv } = value;
|
393
|
-
const cryKey = await subtleKey(key);
|
394
|
-
const deBytes = await crypto.decrypt(
|
395
|
-
{
|
396
|
-
name: "AES-GCM",
|
397
|
-
iv,
|
398
|
-
tagLength: 128
|
399
|
-
},
|
400
|
-
cryKey,
|
401
|
-
inBytes
|
402
|
-
);
|
403
|
-
const bytes = new Uint8Array(deBytes);
|
404
|
-
const len = readUInt32LE(bytes.subarray(0, 4));
|
405
|
-
const cid = CID.decode(bytes.subarray(4, 4 + len));
|
406
|
-
return { cid, bytes: bytes.subarray(4 + len) };
|
407
|
-
};
|
408
|
-
const encrypt = async ({ key, cid, bytes }) => {
|
409
|
-
const len = enc32(cid.bytes.byteLength);
|
410
|
-
const iv = randomBytes(12);
|
411
|
-
const msg = concat([len, cid.bytes, bytes]);
|
412
|
-
try {
|
413
|
-
const cryKey = await subtleKey(key);
|
414
|
-
const deBytes = await crypto.encrypt(
|
415
|
-
{
|
416
|
-
name: "AES-GCM",
|
417
|
-
iv,
|
418
|
-
tagLength: 128
|
419
|
-
},
|
420
|
-
cryKey,
|
421
|
-
msg
|
422
|
-
);
|
423
|
-
bytes = new Uint8Array(deBytes);
|
424
|
-
} catch (e) {
|
425
|
-
throw logger.Error().Err(e).Msg("encrypt failed").AsError();
|
426
|
-
}
|
427
|
-
return { value: { bytes, iv } };
|
428
|
-
};
|
429
|
-
const cryptoFn = (key) => {
|
430
|
-
return { encrypt: (opts) => encrypt({ ...opts, key }), decrypt: (opts) => decrypt({ ...opts, key }) };
|
431
|
-
};
|
432
|
-
const name = "jchris@encrypted-block:aes-gcm";
|
433
|
-
return { encode: encode4, decode: decode4, code, name, encrypt, decrypt, crypto: cryptoFn };
|
434
|
-
}
|
435
|
-
|
436
|
-
// src/blockstore/encrypt-helpers.ts
|
437
|
-
function carLogIncludesGroup(list, cidMatch) {
|
438
|
-
return list.some((cid) => {
|
439
|
-
return cid.toString() === cidMatch.toString();
|
440
|
-
});
|
441
|
-
}
|
442
|
-
function makeEncDec(logger, crypto, randomBytes) {
|
443
|
-
const codec4 = makeCodec(logger, crypto, randomBytes);
|
444
|
-
const encrypt = async function* ({
|
445
|
-
get: get2,
|
446
|
-
cids,
|
447
|
-
hasher: hasher4,
|
448
|
-
key,
|
449
|
-
cache: cache3,
|
450
|
-
chunker: chunker2,
|
451
|
-
root: root3
|
452
|
-
}) {
|
453
|
-
const set = /* @__PURE__ */ new Set();
|
454
|
-
let eroot;
|
455
|
-
if (!carLogIncludesGroup(cids, root3)) cids.push(root3);
|
456
|
-
for (const cid of cids) {
|
457
|
-
const unencrypted = await get2(cid);
|
458
|
-
if (!unencrypted) throw logger.Error().Ref("cid", cid).Msg("missing cid block").AsError();
|
459
|
-
const encrypted = await codec4.encrypt({ ...unencrypted, key });
|
460
|
-
const block2 = await encode2({ ...encrypted, codec: codec4, hasher: hasher4 });
|
461
|
-
yield block2;
|
462
|
-
set.add(block2.cid.toString());
|
463
|
-
if (unencrypted.cid.equals(root3)) eroot = block2.cid;
|
464
|
-
}
|
465
|
-
if (!eroot) throw logger.Error().Msg("cids does not include root").AsError();
|
466
|
-
const list = [...set].map((s) => CID2.parse(s));
|
467
|
-
let last;
|
468
|
-
for await (const node of create({ list, get: get2, cache: cache3, chunker: chunker2, hasher: hasher4, codec: dagcbor })) {
|
469
|
-
const block2 = await node.block;
|
470
|
-
yield block2;
|
471
|
-
last = block2;
|
472
|
-
}
|
473
|
-
if (!last) throw logger.Error().Msg("missing last block").AsError();
|
474
|
-
const head = [eroot, last.cid];
|
475
|
-
const block = await encode2({ value: head, codec: dagcbor, hasher: hasher4 });
|
476
|
-
yield block;
|
477
|
-
};
|
478
|
-
const decrypt = async function* ({
|
479
|
-
root: root3,
|
480
|
-
get: get2,
|
481
|
-
key,
|
482
|
-
cache: cache3,
|
483
|
-
chunker: chunker2,
|
484
|
-
hasher: hasher4
|
485
|
-
}) {
|
486
|
-
const getWithDecode = async (cid) => get2(cid).then(async (block) => {
|
487
|
-
if (!block) return;
|
488
|
-
const decoded = await decode2({ ...block, codec: dagcbor, hasher: hasher4 });
|
489
|
-
return decoded;
|
490
|
-
});
|
491
|
-
const getWithDecrypt = async (cid) => get2(cid).then(async (block) => {
|
492
|
-
if (!block) return;
|
493
|
-
const decoded = await decode2({ ...block, codec: codec4, hasher: hasher4 });
|
494
|
-
return decoded;
|
495
|
-
});
|
496
|
-
const decodedRoot = await getWithDecode(root3);
|
497
|
-
if (!decodedRoot) throw logger.Error().Msg("missing root").AsError();
|
498
|
-
if (!decodedRoot.bytes) throw logger.Error().Msg("missing bytes").AsError();
|
499
|
-
const {
|
500
|
-
value: [eroot, tree]
|
501
|
-
} = decodedRoot;
|
502
|
-
const rootBlock = await get2(eroot);
|
503
|
-
if (!rootBlock) throw logger.Error().Msg("missing root block").AsError();
|
504
|
-
const cidset = await load({ cid: tree, get: getWithDecode, cache: cache3, chunker: chunker2, codec: codec4, hasher: hasher4 });
|
505
|
-
const { result: nodes } = await cidset.getAllEntries();
|
506
|
-
const unwrap = async (eblock) => {
|
507
|
-
if (!eblock) throw logger.Error().Msg("missing block").AsError();
|
508
|
-
if (!eblock.value) {
|
509
|
-
eblock = await decode2({ ...eblock, codec: codec4, hasher: hasher4 });
|
510
|
-
if (!eblock.value) throw logger.Error().Msg("missing value").AsError();
|
511
|
-
}
|
512
|
-
const { bytes, cid } = await codec4.decrypt({ ...eblock, key }).catch((e) => {
|
513
|
-
throw e;
|
514
|
-
});
|
515
|
-
const block = await mfCreate({ cid, bytes, hasher: hasher4, codec: codec4 });
|
516
|
-
return block;
|
517
|
-
};
|
518
|
-
const promises = [];
|
519
|
-
for (const { cid } of nodes) {
|
520
|
-
if (!rootBlock.cid.equals(cid)) promises.push(getWithDecrypt(cid).then(unwrap));
|
521
|
-
}
|
522
|
-
yield* promises;
|
523
|
-
yield unwrap(rootBlock);
|
524
|
-
};
|
525
|
-
return { encrypt, decrypt };
|
526
|
-
}
|
527
|
-
var chunker = bf(30);
|
528
|
-
function hexStringToUint8Array(hexString) {
|
529
|
-
const length = hexString.length;
|
530
|
-
const uint8Array = new Uint8Array(length / 2);
|
531
|
-
for (let i = 0; i < length; i += 2) {
|
532
|
-
uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
|
533
|
-
}
|
534
|
-
return uint8Array;
|
535
|
-
}
|
536
|
-
async function encryptedEncodeCarFile(logger, crypto, key, rootCid, t) {
|
537
|
-
const encryptionKey = hexStringToUint8Array(key);
|
538
|
-
const encryptedBlocks = new MemoryBlockstore2();
|
539
|
-
const cidsToEncrypt = [];
|
540
|
-
for (const { cid, bytes } of t.entries()) {
|
541
|
-
cidsToEncrypt.push(cid);
|
542
|
-
const g = await t.get(cid);
|
543
|
-
if (!g) throw logger.Error().Ref("cid", cid).Int("bytes", bytes.length).Msg("missing cid block").AsError();
|
544
|
-
}
|
545
|
-
let last = null;
|
546
|
-
const { encrypt } = makeEncDec(logger, crypto, crypto.randomBytes);
|
547
|
-
for await (const block of encrypt({
|
548
|
-
cids: cidsToEncrypt,
|
549
|
-
get: t.get.bind(t),
|
550
|
-
key: encryptionKey,
|
551
|
-
hasher: sha256,
|
552
|
-
chunker,
|
553
|
-
cache,
|
554
|
-
root: rootCid
|
555
|
-
})) {
|
556
|
-
await encryptedBlocks.put(block.cid, block.bytes);
|
557
|
-
last = block;
|
558
|
-
}
|
559
|
-
if (!last) throw logger.Error().Msg("no blocks encrypted").AsError();
|
560
|
-
const encryptedCar = await encodeCarFile([last.cid], encryptedBlocks);
|
561
|
-
return encryptedCar;
|
562
|
-
}
|
563
|
-
async function decodeEncryptedCar(logger, crypto, key, reader) {
|
564
|
-
const roots = await reader.getRoots();
|
565
|
-
const root3 = roots[0];
|
566
|
-
return await decodeCarBlocks(logger, crypto, root3, reader.get.bind(reader), key);
|
567
|
-
}
|
568
|
-
async function decodeCarBlocks(logger, crypto, root3, get2, keyMaterial) {
|
569
|
-
const decryptionKeyUint8 = hexStringToUint8Array(keyMaterial);
|
570
|
-
const decryptionKey = decryptionKeyUint8.buffer.slice(0, decryptionKeyUint8.byteLength);
|
571
|
-
const decryptedBlocks = new MemoryBlockstore2();
|
572
|
-
let last = null;
|
573
|
-
const { decrypt } = makeEncDec(logger, crypto, crypto.randomBytes);
|
574
|
-
for await (const block of decrypt({
|
575
|
-
root: root3,
|
576
|
-
get: get2,
|
577
|
-
key: decryptionKey,
|
578
|
-
hasher: sha256,
|
579
|
-
chunker,
|
580
|
-
cache
|
581
|
-
})) {
|
582
|
-
await decryptedBlocks.put(block.cid, block.bytes);
|
583
|
-
last = block;
|
584
|
-
}
|
585
|
-
if (!last) throw logger.Error().Msg("no blocks decrypted").AsError();
|
586
|
-
return { blocks: decryptedBlocks, root: last.cid };
|
587
|
-
}
|
588
|
-
|
589
295
|
// src/blockstore/transaction.ts
|
590
|
-
import { MemoryBlockstore
|
591
|
-
|
592
|
-
|
296
|
+
import { MemoryBlockstore } from "@web3-storage/pail/block";
|
297
|
+
import { toCryptoRuntime } from "@adviser/cement";
|
298
|
+
var CarTransaction = class extends MemoryBlockstore {
|
299
|
+
constructor(parent, opts = { add: true, noLoader: false }) {
|
593
300
|
super();
|
594
301
|
if (opts.add) {
|
595
302
|
parent.transactions.add(this);
|
@@ -603,8 +310,8 @@ var CarTransaction = class extends MemoryBlockstore3 {
|
|
603
310
|
return super.get(cid);
|
604
311
|
}
|
605
312
|
};
|
606
|
-
function defaultedBlockstoreRuntime(opts, component, ctx) {
|
607
|
-
const logger = ensureLogger(
|
313
|
+
function defaultedBlockstoreRuntime(sthis, opts, component, ctx) {
|
314
|
+
const logger = ensureLogger(sthis, component, ctx);
|
608
315
|
const store = opts.store || {};
|
609
316
|
return {
|
610
317
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
@@ -621,22 +328,24 @@ function defaultedBlockstoreRuntime(opts, component, ctx) {
|
|
621
328
|
threshold: 1e3 * 1e3,
|
622
329
|
...opts,
|
623
330
|
logger,
|
624
|
-
|
331
|
+
keyBag: opts.keyBag || {},
|
332
|
+
crypto: toCryptoRuntime(opts.crypto),
|
625
333
|
store,
|
626
|
-
storeRuntime: toStoreRuntime(store,
|
334
|
+
storeRuntime: toStoreRuntime(store, sthis)
|
627
335
|
};
|
628
336
|
}
|
629
|
-
|
337
|
+
function blockstoreFactory(sthis, opts) {
|
630
338
|
if (opts.name) {
|
631
|
-
return new EncryptedBlockstore(opts);
|
339
|
+
return new EncryptedBlockstore(sthis, opts);
|
632
340
|
} else {
|
633
341
|
return new BaseBlockstore(opts);
|
634
342
|
}
|
635
|
-
}
|
343
|
+
}
|
636
344
|
var BaseBlockstore = class {
|
637
345
|
constructor(ebOpts = {}) {
|
638
346
|
this.transactions = /* @__PURE__ */ new Set();
|
639
|
-
this.
|
347
|
+
this.sthis = ensureSuperThis(ebOpts);
|
348
|
+
this.ebOpts = defaultedBlockstoreRuntime(this.sthis, ebOpts, "BaseBlockstore");
|
640
349
|
this.logger = this.ebOpts.logger;
|
641
350
|
}
|
642
351
|
// ready: Promise<void>;
|
@@ -659,8 +368,8 @@ var BaseBlockstore = class {
|
|
659
368
|
throw this.logger.Error().Msg("use a transaction to put").AsError();
|
660
369
|
}
|
661
370
|
// TransactionMeta
|
662
|
-
async transaction(fn, _opts
|
663
|
-
const t = new CarTransaction(this);
|
371
|
+
async transaction(fn, _opts) {
|
372
|
+
const t = new CarTransaction(this, _opts);
|
664
373
|
const done = await fn(t);
|
665
374
|
this.lastTxMeta = done;
|
666
375
|
return { t, meta: done };
|
@@ -677,16 +386,16 @@ var BaseBlockstore = class {
|
|
677
386
|
}
|
678
387
|
};
|
679
388
|
var EncryptedBlockstore = class extends BaseBlockstore {
|
680
|
-
constructor(ebOpts) {
|
389
|
+
constructor(sthis, ebOpts) {
|
681
390
|
super(ebOpts);
|
682
391
|
this.compacting = false;
|
683
|
-
this.logger = ensureLogger(
|
392
|
+
this.logger = ensureLogger(this.sthis, "EncryptedBlockstore");
|
684
393
|
const { name } = ebOpts;
|
685
394
|
if (!name) {
|
686
395
|
throw this.logger.Error().Msg("name required").AsError();
|
687
396
|
}
|
688
397
|
this.name = name;
|
689
|
-
this.loader = new Loader(this.name, ebOpts);
|
398
|
+
this.loader = new Loader(this.name, ebOpts, sthis);
|
690
399
|
}
|
691
400
|
ready() {
|
692
401
|
return this.loader.ready();
|
@@ -717,10 +426,13 @@ var EncryptedBlockstore = class extends BaseBlockstore {
|
|
717
426
|
}
|
718
427
|
throw this.logger.Error().Msg("failed to commit car files").AsError();
|
719
428
|
}
|
720
|
-
async getFile(car, cid
|
429
|
+
async getFile(car, cid) {
|
721
430
|
await this.ready();
|
722
431
|
if (!this.loader) throw this.logger.Error().Msg("loader required to get file, database must be named").AsError();
|
723
|
-
const reader = await this.loader.loadFileCar(
|
432
|
+
const reader = await this.loader.loadFileCar(
|
433
|
+
car
|
434
|
+
/*, isPublic */
|
435
|
+
);
|
724
436
|
const block = await reader.get(cid);
|
725
437
|
if (!block) throw this.logger.Error().Str("cid", cid.toString()).Msg(`Missing block`).AsError();
|
726
438
|
return block.bytes;
|
@@ -776,10 +488,20 @@ var CompactionFetcher = class {
|
|
776
488
|
};
|
777
489
|
|
778
490
|
// src/blockstore/commit-queue.ts
|
491
|
+
import { Future } from "@adviser/cement";
|
779
492
|
var CommitQueue = class {
|
780
493
|
constructor() {
|
781
494
|
this.queue = [];
|
782
495
|
this.processing = false;
|
496
|
+
this._waitIdleItems = /* @__PURE__ */ new Set();
|
497
|
+
}
|
498
|
+
waitIdle() {
|
499
|
+
if (this.queue.length === 0 && !this.processing) {
|
500
|
+
return Promise.resolve();
|
501
|
+
}
|
502
|
+
const fn = new Future();
|
503
|
+
this._waitIdleItems.add(fn);
|
504
|
+
return fn.asPromise();
|
783
505
|
}
|
784
506
|
async enqueue(fn) {
|
785
507
|
return new Promise((resolve, reject) => {
|
@@ -804,20 +526,318 @@ var CommitQueue = class {
|
|
804
526
|
this.processing = true;
|
805
527
|
const queueFn = this.queue.shift();
|
806
528
|
if (queueFn) {
|
807
|
-
queueFn()
|
529
|
+
queueFn().finally(() => {
|
530
|
+
});
|
808
531
|
}
|
809
532
|
}
|
533
|
+
if (this.queue.length === 0 && !this.processing) {
|
534
|
+
const toResolve = Array.from(this._waitIdleItems);
|
535
|
+
this._waitIdleItems.clear();
|
536
|
+
toResolve.map((fn) => fn.resolve());
|
537
|
+
}
|
810
538
|
}
|
811
539
|
};
|
812
540
|
|
813
|
-
// src/
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
}
|
820
|
-
|
541
|
+
// src/runtime/key-bag.ts
|
542
|
+
var key_bag_exports = {};
|
543
|
+
__export(key_bag_exports, {
|
544
|
+
KeyBag: () => KeyBag,
|
545
|
+
getKeyBag: () => getKeyBag,
|
546
|
+
registerKeyBagProviderFactory: () => registerKeyBagProviderFactory
|
547
|
+
});
|
548
|
+
import {
|
549
|
+
KeyedResolvOnce,
|
550
|
+
ResolveSeq,
|
551
|
+
Result as Result2,
|
552
|
+
runtimeFn,
|
553
|
+
toCryptoRuntime as toCryptoRuntime2,
|
554
|
+
URI
|
555
|
+
} from "@adviser/cement";
|
556
|
+
import { base58btc } from "multiformats/bases/base58";
|
557
|
+
var KeyBag = class {
|
558
|
+
constructor(rt) {
|
559
|
+
this.rt = rt;
|
560
|
+
this._seq = new ResolveSeq();
|
561
|
+
this.logger = ensureLogger(rt.sthis, "KeyBag", {
|
562
|
+
id: rt.id()
|
563
|
+
});
|
564
|
+
this.logger.Debug().Msg("KeyBag created");
|
565
|
+
}
|
566
|
+
async subtleKey(key) {
|
567
|
+
return await this.rt.crypto.importKey(
|
568
|
+
"raw",
|
569
|
+
// raw or jwk
|
570
|
+
base58btc.decode(key),
|
571
|
+
// hexStringToUint8Array(key), // raw data
|
572
|
+
"AES-GCM",
|
573
|
+
false,
|
574
|
+
// extractable
|
575
|
+
["encrypt", "decrypt"]
|
576
|
+
);
|
577
|
+
}
|
578
|
+
async ensureKeyFromUrl(url, keyFactory) {
|
579
|
+
const storeKey = url.getParam("storekey");
|
580
|
+
if (storeKey === "insecure") {
|
581
|
+
return Result2.Ok(url);
|
582
|
+
}
|
583
|
+
if (!storeKey) {
|
584
|
+
const keyName = `@${keyFactory()}@`;
|
585
|
+
const ret = await this.getNamedKey(keyName);
|
586
|
+
if (ret.isErr()) {
|
587
|
+
return ret;
|
588
|
+
}
|
589
|
+
const urb = url.build().setParam("storekey", keyName);
|
590
|
+
return Result2.Ok(urb.URI());
|
591
|
+
}
|
592
|
+
if (storeKey.startsWith("@") && storeKey.endsWith("@")) {
|
593
|
+
const ret = await this.getNamedKey(storeKey);
|
594
|
+
if (ret.isErr()) {
|
595
|
+
return ret;
|
596
|
+
}
|
597
|
+
}
|
598
|
+
return Result2.Ok(url);
|
599
|
+
}
|
600
|
+
async toKeyWithFingerPrint(keyStr) {
|
601
|
+
const material = base58btc.decode(keyStr);
|
602
|
+
const key = await this.subtleKey(keyStr);
|
603
|
+
const fpr = await this.rt.crypto.digestSHA256(material);
|
604
|
+
return Result2.Ok({
|
605
|
+
key,
|
606
|
+
fingerPrint: base58btc.encode(new Uint8Array(fpr))
|
607
|
+
});
|
608
|
+
}
|
609
|
+
async setNamedKey(name, key) {
|
610
|
+
return this._seq.add(() => this._setNamedKey(name, key));
|
611
|
+
}
|
612
|
+
// avoid deadlock
|
613
|
+
async _setNamedKey(name, key) {
|
614
|
+
const item = {
|
615
|
+
name,
|
616
|
+
key
|
617
|
+
};
|
618
|
+
const bag = await this.rt.getBag();
|
619
|
+
this.logger.Debug().Str("name", name).Msg("setNamedKey");
|
620
|
+
await bag.set(name, item);
|
621
|
+
return await this.toKeyWithFingerPrint(item.key);
|
622
|
+
}
|
623
|
+
async getNamedKey(name, failIfNotFound = false) {
|
624
|
+
const id = this.rt.sthis.nextId(4).str;
|
625
|
+
return this._seq.add(async () => {
|
626
|
+
const bag = await this.rt.getBag();
|
627
|
+
const named = await bag.get(name);
|
628
|
+
if (named) {
|
629
|
+
const fpr = await this.toKeyWithFingerPrint(named.key);
|
630
|
+
this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", fpr).Msg("fingerPrint getNamedKey");
|
631
|
+
return fpr;
|
632
|
+
}
|
633
|
+
if (failIfNotFound) {
|
634
|
+
this.logger.Debug().Str("id", id).Str("name", name).Msg("failIfNotFound getNamedKey");
|
635
|
+
return Result2.Err(new Error(`Key not found: ${name}`));
|
636
|
+
}
|
637
|
+
const ret = await this._setNamedKey(name, base58btc.encode(this.rt.crypto.randomBytes(this.rt.keyLength)));
|
638
|
+
this.logger.Debug().Str("id", id).Str("name", name).Result("fpr", ret).Msg("createKey getNamedKey-post");
|
639
|
+
return ret;
|
640
|
+
});
|
641
|
+
}
|
642
|
+
};
|
643
|
+
var keyBagProviderFactories = new Map(
|
644
|
+
[
|
645
|
+
{
|
646
|
+
protocol: "file:",
|
647
|
+
factory: async (url, sthis) => {
|
648
|
+
const { KeyBagProviderFile } = await import("./key-bag-file-NMEBFSPM.js");
|
649
|
+
return new KeyBagProviderFile(url, sthis);
|
650
|
+
}
|
651
|
+
},
|
652
|
+
{
|
653
|
+
protocol: "indexdb:",
|
654
|
+
factory: async (url, sthis) => {
|
655
|
+
const { KeyBagProviderIndexDB } = await import("./key-bag-indexdb-X5V6GNBZ.js");
|
656
|
+
return new KeyBagProviderIndexDB(url, sthis);
|
657
|
+
}
|
658
|
+
}
|
659
|
+
].map((i) => [i.protocol, i])
|
660
|
+
);
|
661
|
+
function registerKeyBagProviderFactory(item) {
|
662
|
+
const protocol = item.protocol.endsWith(":") ? item.protocol : item.protocol + ":";
|
663
|
+
keyBagProviderFactories.set(protocol, {
|
664
|
+
...item,
|
665
|
+
protocol
|
666
|
+
});
|
667
|
+
}
|
668
|
+
function defaultKeyBagOpts(sthis, kbo) {
|
669
|
+
if (kbo.keyRuntime) {
|
670
|
+
return kbo.keyRuntime;
|
671
|
+
}
|
672
|
+
const logger = ensureLogger(sthis, "KeyBag");
|
673
|
+
let url;
|
674
|
+
if (kbo.url) {
|
675
|
+
url = URI.from(kbo.url);
|
676
|
+
logger.Debug().Url(url).Msg("from opts");
|
677
|
+
} else {
|
678
|
+
let bagFnameOrUrl = sthis.env.get("FP_KEYBAG_URL");
|
679
|
+
if (runtimeFn().isBrowser) {
|
680
|
+
url = URI.from(bagFnameOrUrl || "indexdb://fp-keybag");
|
681
|
+
} else {
|
682
|
+
if (!bagFnameOrUrl) {
|
683
|
+
const home = sthis.env.get("HOME");
|
684
|
+
bagFnameOrUrl = `${home}/.fireproof/keybag`;
|
685
|
+
url = URI.from(`file://${bagFnameOrUrl}`);
|
686
|
+
} else {
|
687
|
+
url = URI.from(bagFnameOrUrl);
|
688
|
+
}
|
689
|
+
}
|
690
|
+
logger.Debug().Url(url).Msg("from env");
|
691
|
+
}
|
692
|
+
let keyProviderFactory;
|
693
|
+
switch (url.protocol) {
|
694
|
+
case "file:":
|
695
|
+
keyProviderFactory = async () => {
|
696
|
+
const { KeyBagProviderFile } = await import("./key-bag-file-NMEBFSPM.js");
|
697
|
+
return new KeyBagProviderFile(url, sthis);
|
698
|
+
};
|
699
|
+
break;
|
700
|
+
case "indexdb:":
|
701
|
+
keyProviderFactory = async () => {
|
702
|
+
const { KeyBagProviderIndexDB } = await import("./key-bag-indexdb-X5V6GNBZ.js");
|
703
|
+
return new KeyBagProviderIndexDB(url, sthis);
|
704
|
+
};
|
705
|
+
break;
|
706
|
+
default:
|
707
|
+
throw logger.Error().Url(url).Msg("unsupported protocol").AsError();
|
708
|
+
}
|
709
|
+
if (url.hasParam("masterkey")) {
|
710
|
+
throw logger.Error().Url(url).Msg("masterkey is not supported").AsError();
|
711
|
+
}
|
712
|
+
return {
|
713
|
+
url,
|
714
|
+
crypto: kbo.crypto || toCryptoRuntime2({}),
|
715
|
+
sthis,
|
716
|
+
logger,
|
717
|
+
keyLength: kbo.keyLength || 16,
|
718
|
+
getBag: keyProviderFactory,
|
719
|
+
id: () => {
|
720
|
+
return url.toString();
|
721
|
+
}
|
722
|
+
};
|
723
|
+
}
|
724
|
+
var _keyBags = new KeyedResolvOnce();
|
725
|
+
async function getKeyBag(sthis, kbo = {}) {
|
726
|
+
await sthis.start();
|
727
|
+
const rt = defaultKeyBagOpts(sthis, kbo);
|
728
|
+
return _keyBags.get(rt.id()).once(async () => new KeyBag(rt));
|
729
|
+
}
|
730
|
+
|
731
|
+
// src/blockstore/commitor.ts
|
732
|
+
import * as CBW from "@ipld/car/buffer-writer";
|
733
|
+
import { sha256 as hasher2 } from "multiformats/hashes/sha2";
|
734
|
+
import * as dagCodec2 from "@ipld/dag-cbor";
|
735
|
+
async function encodeCarFile(roots, t, codec3) {
|
736
|
+
let size = 0;
|
737
|
+
const headerSize = CBW.headerLength({ roots });
|
738
|
+
size += headerSize;
|
739
|
+
for (const { cid, bytes } of t.entries()) {
|
740
|
+
size += CBW.blockLength({ cid, bytes });
|
741
|
+
}
|
742
|
+
const buffer = new Uint8Array(size);
|
743
|
+
const writer = CBW.createWriter(buffer, { headerSize });
|
744
|
+
for (const r of roots) {
|
745
|
+
writer.addRoot(r);
|
746
|
+
}
|
747
|
+
for (const { cid, bytes } of t.entries()) {
|
748
|
+
writer.write({ cid, bytes });
|
749
|
+
}
|
750
|
+
writer.close();
|
751
|
+
return await encode({ value: writer.bytes, hasher: hasher2, codec: codec3 });
|
752
|
+
}
|
753
|
+
async function createCarFile(encoder, cid, t) {
|
754
|
+
return encodeCarFile([cid], t, encoder);
|
755
|
+
}
|
756
|
+
async function commitFiles(fileStore, walStore, t, done) {
|
757
|
+
const { files: roots } = makeFileCarHeader(done);
|
758
|
+
const cids = [];
|
759
|
+
const codec3 = (await fileStore.keyedCrypto()).codec();
|
760
|
+
const cars = await prepareCarFilesFiles(codec3, roots, t);
|
761
|
+
for (const car of cars) {
|
762
|
+
const { cid, bytes } = car;
|
763
|
+
await fileStore.save({ cid, bytes });
|
764
|
+
await walStore.enqueueFile(
|
765
|
+
cid
|
766
|
+
/*, !!opts.public*/
|
767
|
+
);
|
768
|
+
cids.push(cid);
|
769
|
+
}
|
770
|
+
return cids;
|
771
|
+
}
|
772
|
+
function makeFileCarHeader(result) {
|
773
|
+
const files = [];
|
774
|
+
for (const [, meta] of Object.entries(result.files || {})) {
|
775
|
+
if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
|
776
|
+
files.push(meta.cid);
|
777
|
+
}
|
778
|
+
}
|
779
|
+
return { ...result, files };
|
780
|
+
}
|
781
|
+
async function prepareCarFilesFiles(encoder, roots, t) {
|
782
|
+
return [await encodeCarFile(roots, t, encoder)];
|
783
|
+
}
|
784
|
+
function makeCarHeader(meta, cars, compact = false) {
|
785
|
+
const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
|
786
|
+
return { ...coreHeader, meta };
|
787
|
+
}
|
788
|
+
async function encodeCarHeader(fp) {
|
789
|
+
return await encode({
|
790
|
+
value: { fp },
|
791
|
+
hasher: hasher2,
|
792
|
+
codec: dagCodec2
|
793
|
+
});
|
794
|
+
}
|
795
|
+
async function commit(params, t, done, opts = { noLoader: false, compact: false }) {
|
796
|
+
const fp = makeCarHeader(done, params.carLog, !!opts.compact);
|
797
|
+
const rootBlock = await encodeCarHeader(fp);
|
798
|
+
const cars = await prepareCarFiles(params.encoder, params.threshold, rootBlock, t);
|
799
|
+
const cids = [];
|
800
|
+
for (const car of cars) {
|
801
|
+
const { cid, bytes } = car;
|
802
|
+
await params.carStore.save({ cid, bytes });
|
803
|
+
cids.push(cid);
|
804
|
+
}
|
805
|
+
const newDbMeta = { cars: cids };
|
806
|
+
await params.WALStore.enqueue(newDbMeta, opts);
|
807
|
+
await params.metaStore.save(newDbMeta);
|
808
|
+
return { cgrp: cids, header: fp };
|
809
|
+
}
|
810
|
+
async function prepareCarFiles(encoder, threshold, rootBlock, t) {
|
811
|
+
const carFiles = [];
|
812
|
+
threshold = threshold || 1e3 * 1e3;
|
813
|
+
let clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
|
814
|
+
clonedt.putSync(rootBlock.cid, rootBlock.bytes);
|
815
|
+
let newsize = CBW.blockLength(toCIDBlock(rootBlock));
|
816
|
+
let cidRootBlock = rootBlock;
|
817
|
+
for (const { cid, bytes } of t.entries()) {
|
818
|
+
newsize += CBW.blockLength(toCIDBlock({ cid, bytes }));
|
819
|
+
if (newsize >= threshold) {
|
820
|
+
carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
|
821
|
+
clonedt = new CarTransaction(t.parent, { add: false, noLoader: false });
|
822
|
+
clonedt.putSync(cid, bytes);
|
823
|
+
cidRootBlock = { cid, bytes };
|
824
|
+
newsize = CBW.blockLength(toCIDBlock({ cid, bytes }));
|
825
|
+
} else {
|
826
|
+
clonedt.putSync(cid, bytes);
|
827
|
+
}
|
828
|
+
}
|
829
|
+
carFiles.push(await createCarFile(encoder, cidRootBlock.cid, clonedt));
|
830
|
+
return carFiles;
|
831
|
+
}
|
832
|
+
|
833
|
+
// src/blockstore/loader.ts
|
834
|
+
import { sha256 as hasher3 } from "multiformats/hashes/sha2";
|
835
|
+
function carLogIncludesGroup(list, cids) {
|
836
|
+
return list.some((arr) => {
|
837
|
+
return arr.toString() === cids.toString();
|
838
|
+
});
|
839
|
+
}
|
840
|
+
function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
|
821
841
|
const byString = /* @__PURE__ */ new Map();
|
822
842
|
for (const cid of list) {
|
823
843
|
if (remove.has(cid.toString())) continue;
|
@@ -825,17 +845,8 @@ function uniqueCids(list, remove = /* @__PURE__ */ new Set()) {
|
|
825
845
|
}
|
826
846
|
return [...byString.values()];
|
827
847
|
}
|
828
|
-
function toHexString(byteArray) {
|
829
|
-
return Array.from(byteArray).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
830
|
-
}
|
831
|
-
var Loadable = class {
|
832
|
-
constructor() {
|
833
|
-
this.name = "";
|
834
|
-
this.carLog = new Array();
|
835
|
-
}
|
836
|
-
};
|
837
848
|
var Loader = class {
|
838
|
-
constructor(name, ebOpts) {
|
849
|
+
constructor(name, ebOpts, sthis) {
|
839
850
|
this.commitQueue = new CommitQueue();
|
840
851
|
this.isCompacting = false;
|
841
852
|
this.carReaders = /* @__PURE__ */ new Map();
|
@@ -847,7 +858,9 @@ var Loader = class {
|
|
847
858
|
this.writeLimit = pLimit(1);
|
848
859
|
this.onceReady = new ResolveOnce();
|
849
860
|
this.name = name;
|
861
|
+
this.sthis = sthis;
|
850
862
|
this.ebOpts = defaultedBlockstoreRuntime(
|
863
|
+
sthis,
|
851
864
|
{
|
852
865
|
...ebOpts,
|
853
866
|
name
|
@@ -857,14 +870,17 @@ var Loader = class {
|
|
857
870
|
this.logger = this.ebOpts.logger;
|
858
871
|
}
|
859
872
|
// readonly id = uuidv4();
|
873
|
+
async keyBag() {
|
874
|
+
return getKeyBag(this.sthis, this.ebOpts.keyBag);
|
875
|
+
}
|
860
876
|
async carStore() {
|
861
877
|
return this.ebOpts.storeRuntime.makeDataStore(this);
|
862
878
|
}
|
863
879
|
async fileStore() {
|
864
880
|
return this.ebOpts.storeRuntime.makeDataStore(this);
|
865
881
|
}
|
866
|
-
async
|
867
|
-
return this.ebOpts.storeRuntime.
|
882
|
+
async WALStore() {
|
883
|
+
return this.ebOpts.storeRuntime.makeWALStore(this);
|
868
884
|
}
|
869
885
|
async metaStore() {
|
870
886
|
return this.ebOpts.storeRuntime.makeMetaStore(this);
|
@@ -878,11 +894,11 @@ var Loader = class {
|
|
878
894
|
});
|
879
895
|
}
|
880
896
|
async close() {
|
881
|
-
const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.
|
897
|
+
const toClose = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
|
882
898
|
await Promise.all(toClose.map((store) => store.close()));
|
883
899
|
}
|
884
900
|
async destroy() {
|
885
|
-
const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.
|
901
|
+
const toDestroy = await Promise.all([this.carStore(), this.metaStore(), this.fileStore(), this.WALStore()]);
|
886
902
|
await Promise.all(toDestroy.map((store) => store.destroy()));
|
887
903
|
}
|
888
904
|
// async snapToCar(carCid: AnyLink | string) {
|
@@ -896,6 +912,7 @@ var Loader = class {
|
|
896
912
|
// await this._applyCarHeader(carHeader, true)
|
897
913
|
// }
|
898
914
|
async handleDbMetasFromStore(metas) {
|
915
|
+
this.logger.Debug().Any("metas", metas).Msg("handleDbMetasFromStore");
|
899
916
|
for (const meta of metas) {
|
900
917
|
await this.writeLimit(async () => {
|
901
918
|
await this.mergeDbMetaIntoClock(meta);
|
@@ -908,10 +925,7 @@ var Loader = class {
|
|
908
925
|
}
|
909
926
|
if (this.seenMeta.has(meta.cars.toString())) return;
|
910
927
|
this.seenMeta.add(meta.cars.toString());
|
911
|
-
if (meta.
|
912
|
-
await this.setKey(meta.key);
|
913
|
-
}
|
914
|
-
if (carLogIncludesGroup2(this.carLog, meta.cars)) {
|
928
|
+
if (carLogIncludesGroup(this.carLog, meta.cars)) {
|
915
929
|
return;
|
916
930
|
}
|
917
931
|
const carHeader = await this.loadCarHeaderFromMeta(meta);
|
@@ -920,45 +934,59 @@ var Loader = class {
|
|
920
934
|
this.carLog = [...uniqueCids([meta.cars, ...this.carLog, ...carHeader.cars], this.seenCompacted)];
|
921
935
|
await this.ebOpts.applyMeta?.(carHeader.meta);
|
922
936
|
}
|
923
|
-
async ingestKeyFromMeta(meta) {
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
}
|
937
|
+
// protected async ingestKeyFromMeta(meta: DbMeta): Promise<void> {
|
938
|
+
// const { key } = meta;
|
939
|
+
// if (key) {
|
940
|
+
// await this.setKey(key);
|
941
|
+
// }
|
942
|
+
// }
|
929
943
|
async loadCarHeaderFromMeta({ cars: cids }) {
|
930
944
|
const reader = await this.loadCar(cids[0]);
|
931
945
|
return await parseCarFile(reader, this.logger);
|
932
946
|
}
|
933
|
-
async _getKey() {
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
}
|
943
|
-
// can these skip the queue? or have a file queue?
|
944
|
-
async _commitInternalFiles(t, done, opts = { noLoader: false, compact: false }) {
|
947
|
+
// async _getKey(): Promise<string | undefined> {
|
948
|
+
// if (this.key) return this.key;
|
949
|
+
// // generate a random key
|
950
|
+
// if (!this.ebOpts.public) {
|
951
|
+
// await this.setKey(toHexString(this.ebOpts.crypto.randomBytes(32)));
|
952
|
+
// }
|
953
|
+
// return this.key || undefined;
|
954
|
+
// }
|
955
|
+
async commitFiles(t, done) {
|
945
956
|
await this.ready();
|
946
|
-
const
|
947
|
-
const
|
948
|
-
|
949
|
-
for (const car of cars) {
|
950
|
-
const { cid, bytes } = car;
|
951
|
-
await (await this.fileStore()).save({ cid, bytes });
|
952
|
-
await (await this.remoteWAL()).enqueueFile(cid, !!opts.public);
|
953
|
-
cids.push(cid);
|
954
|
-
}
|
955
|
-
return cids;
|
957
|
+
const fstore = await this.fileStore();
|
958
|
+
const wstore = await this.WALStore();
|
959
|
+
return this.commitQueue.enqueue(() => commitFiles(fstore, wstore, t, done));
|
956
960
|
}
|
957
|
-
async loadFileCar(cid
|
958
|
-
return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore
|
961
|
+
async loadFileCar(cid) {
|
962
|
+
return await this.storesLoadCar(cid, await this.fileStore(), this.remoteFileStore);
|
959
963
|
}
|
960
964
|
async commit(t, done, opts = { noLoader: false, compact: false }) {
|
961
|
-
|
965
|
+
await this.ready();
|
966
|
+
const fstore = await this.fileStore();
|
967
|
+
const params = {
|
968
|
+
encoder: (await fstore.keyedCrypto()).codec(),
|
969
|
+
carLog: this.carLog,
|
970
|
+
carStore: fstore,
|
971
|
+
WALStore: await this.WALStore(),
|
972
|
+
metaStore: await this.metaStore()
|
973
|
+
};
|
974
|
+
return this.commitQueue.enqueue(async () => {
|
975
|
+
await this.cacheTransaction(t);
|
976
|
+
const ret = await commit(params, t, done, opts);
|
977
|
+
await this.updateCarLog(ret.cgrp, ret.header, !!opts.compact);
|
978
|
+
return ret.cgrp;
|
979
|
+
});
|
980
|
+
}
|
981
|
+
async updateCarLog(cids, fp, compact) {
|
982
|
+
if (compact) {
|
983
|
+
const previousCompactCid = fp.compact[fp.compact.length - 1];
|
984
|
+
fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
985
|
+
this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
|
986
|
+
await this.removeCidsForCompact(previousCompactCid[0]).catch((e) => e);
|
987
|
+
} else {
|
988
|
+
this.carLog.unshift(cids);
|
989
|
+
}
|
962
990
|
}
|
963
991
|
async cacheTransaction(t) {
|
964
992
|
for await (const block of t.entries()) {
|
@@ -978,79 +1006,6 @@ var Loader = class {
|
|
978
1006
|
}
|
979
1007
|
}
|
980
1008
|
}
|
981
|
-
async _commitInternal(t, done, opts = { noLoader: false, compact: false }) {
|
982
|
-
await this.ready();
|
983
|
-
const fp = this.makeCarHeader(done, this.carLog, !!opts.compact);
|
984
|
-
const rootBlock = await encodeCarHeader(fp);
|
985
|
-
const cars = await this.prepareCarFiles(rootBlock, t, !!opts.public);
|
986
|
-
const cids = [];
|
987
|
-
for (const car of cars) {
|
988
|
-
const { cid, bytes } = car;
|
989
|
-
await (await this.carStore()).save({ cid, bytes });
|
990
|
-
cids.push(cid);
|
991
|
-
}
|
992
|
-
await this.cacheTransaction(t);
|
993
|
-
const newDbMeta = { cars: cids, key: this.key || null };
|
994
|
-
await (await this.remoteWAL()).enqueue(newDbMeta, opts);
|
995
|
-
await (await this.metaStore()).save(newDbMeta);
|
996
|
-
await this.updateCarLog(cids, fp, !!opts.compact);
|
997
|
-
return cids;
|
998
|
-
}
|
999
|
-
async prepareCarFilesFiles(roots, t, isPublic) {
|
1000
|
-
const theKey = isPublic ? null : await this._getKey();
|
1001
|
-
const car = theKey && this.ebOpts.crypto ? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, roots[0], t) : await encodeCarFile(roots, t);
|
1002
|
-
return [car];
|
1003
|
-
}
|
1004
|
-
async prepareCarFiles(rootBlock, t, isPublic) {
|
1005
|
-
const theKey = isPublic ? void 0 : await this._getKey();
|
1006
|
-
const carFiles = [];
|
1007
|
-
const threshold = this.ebOpts.threshold || 1e3 * 1e3;
|
1008
|
-
let clonedt = new CarTransaction(t.parent, { add: false });
|
1009
|
-
clonedt.putSync(rootBlock.cid, rootBlock.bytes);
|
1010
|
-
let newsize = CBW2.blockLength(toCIDBlock(rootBlock));
|
1011
|
-
let cidRootBlock = rootBlock;
|
1012
|
-
for (const { cid, bytes } of t.entries()) {
|
1013
|
-
newsize += CBW2.blockLength(toCIDBlock({ cid, bytes }));
|
1014
|
-
if (newsize >= threshold) {
|
1015
|
-
carFiles.push(await this.createCarFile(theKey, cidRootBlock.cid, clonedt));
|
1016
|
-
clonedt = new CarTransaction(t.parent, { add: false });
|
1017
|
-
clonedt.putSync(cid, bytes);
|
1018
|
-
cidRootBlock = { cid, bytes };
|
1019
|
-
newsize = CBW2.blockLength(toCIDBlock({ cid, bytes }));
|
1020
|
-
} else {
|
1021
|
-
clonedt.putSync(cid, bytes);
|
1022
|
-
}
|
1023
|
-
}
|
1024
|
-
carFiles.push(await this.createCarFile(theKey, cidRootBlock.cid, clonedt));
|
1025
|
-
return carFiles;
|
1026
|
-
}
|
1027
|
-
async createCarFile(theKey, cid, t) {
|
1028
|
-
try {
|
1029
|
-
return theKey && this.ebOpts.crypto ? await encryptedEncodeCarFile(this.logger, this.ebOpts.crypto, theKey, cid, t) : await encodeCarFile([cid], t);
|
1030
|
-
} catch (e) {
|
1031
|
-
console.error("error creating car file", e);
|
1032
|
-
throw e;
|
1033
|
-
}
|
1034
|
-
}
|
1035
|
-
makeFileCarHeader(result) {
|
1036
|
-
const files = [];
|
1037
|
-
for (const [, meta] of Object.entries(result.files || {})) {
|
1038
|
-
if (meta && typeof meta === "object" && "cid" in meta && meta !== null) {
|
1039
|
-
files.push(meta.cid);
|
1040
|
-
}
|
1041
|
-
}
|
1042
|
-
return { ...result, files };
|
1043
|
-
}
|
1044
|
-
async updateCarLog(cids, fp, compact) {
|
1045
|
-
if (compact) {
|
1046
|
-
const previousCompactCid = fp.compact[fp.compact.length - 1];
|
1047
|
-
fp.compact.map((c) => c.toString()).forEach(this.seenCompacted.add, this.seenCompacted);
|
1048
|
-
this.carLog = [...uniqueCids([...this.carLog, ...fp.cars, cids], this.seenCompacted)];
|
1049
|
-
await this.removeCidsForCompact(previousCompactCid[0]);
|
1050
|
-
} else {
|
1051
|
-
this.carLog.unshift(cids);
|
1052
|
-
}
|
1053
|
-
}
|
1054
1009
|
async removeCidsForCompact(cid) {
|
1055
1010
|
const carHeader = await this.loadCarHeaderFromMeta({
|
1056
1011
|
cars: [cid]
|
@@ -1069,9 +1024,9 @@ var Loader = class {
|
|
1069
1024
|
// await this.remoteWAL!.enqueue(dbMeta, { public: false })
|
1070
1025
|
// }
|
1071
1026
|
// }
|
1072
|
-
async *entries(
|
1027
|
+
async *entries(cache2 = true) {
|
1073
1028
|
await this.ready();
|
1074
|
-
if (
|
1029
|
+
if (cache2) {
|
1075
1030
|
for (const [, block] of this.getBlockCache) {
|
1076
1031
|
yield block;
|
1077
1032
|
}
|
@@ -1153,10 +1108,6 @@ var Loader = class {
|
|
1153
1108
|
}
|
1154
1109
|
return got;
|
1155
1110
|
}
|
1156
|
-
makeCarHeader(meta, cars, compact = false) {
|
1157
|
-
const coreHeader = compact ? { cars: [], compact: cars } : { cars, compact: [] };
|
1158
|
-
return { ...coreHeader, meta };
|
1159
|
-
}
|
1160
1111
|
async loadCar(cid) {
|
1161
1112
|
if (!this.carStore) {
|
1162
1113
|
throw this.logger.Error().Msg("car store not initialized").AsError();
|
@@ -1164,72 +1115,52 @@ var Loader = class {
|
|
1164
1115
|
const loaded = await this.storesLoadCar(cid, await this.carStore(), this.remoteCarStore);
|
1165
1116
|
return loaded;
|
1166
1117
|
}
|
1167
|
-
|
1168
|
-
async storesLoadCar(cid, local, remote, publicFiles) {
|
1118
|
+
async makeDecoderAndCarReader(cid, local, remote) {
|
1169
1119
|
const cidsString = cid.toString();
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
|
1189
|
-
}
|
1190
|
-
}
|
1191
|
-
if (!loadedCar) {
|
1192
|
-
throw this.logger.Error().Url(local.url).Str("cid", cidsString).Msg("missing car files").AsError();
|
1193
|
-
}
|
1194
|
-
const rawReader = await CarReader.fromBytes(loadedCar.bytes);
|
1195
|
-
const readerP = publicFiles ? Promise.resolve(rawReader) : this.ensureDecryptedReader(rawReader);
|
1196
|
-
const cachedReaderP = readerP.then(async (reader) => {
|
1197
|
-
await this.cacheCarReader(cidsString, reader).catch(() => {
|
1198
|
-
return;
|
1199
|
-
});
|
1200
|
-
return reader;
|
1201
|
-
});
|
1202
|
-
this.carReaders.set(cidsString, cachedReaderP);
|
1203
|
-
return readerP;
|
1204
|
-
})().catch((e) => {
|
1205
|
-
this.carReaders.delete(cidsString);
|
1206
|
-
throw e;
|
1207
|
-
})
|
1208
|
-
);
|
1120
|
+
let loadedCar = void 0;
|
1121
|
+
let activeStore = local;
|
1122
|
+
try {
|
1123
|
+
this.logger.Debug().Str("cid", cidsString).Msg("loading car");
|
1124
|
+
loadedCar = await local.load(cid);
|
1125
|
+
this.logger.Debug().Bool("loadedCar", loadedCar).Msg("loaded");
|
1126
|
+
} catch (e) {
|
1127
|
+
if (remote) {
|
1128
|
+
const remoteCar = await remote.load(cid);
|
1129
|
+
if (remoteCar) {
|
1130
|
+
this.logger.Debug().Ref("cid", remoteCar.cid).Msg("saving remote car locally");
|
1131
|
+
await local.save(remoteCar);
|
1132
|
+
loadedCar = remoteCar;
|
1133
|
+
activeStore = remote;
|
1134
|
+
}
|
1135
|
+
} else {
|
1136
|
+
this.logger.Error().Str("cid", cidsString).Err(e).Msg("loading car");
|
1137
|
+
}
|
1209
1138
|
}
|
1210
|
-
|
1211
|
-
|
1212
|
-
async ensureDecryptedReader(reader) {
|
1213
|
-
const theKey = await this._getKey();
|
1214
|
-
if (this.ebOpts.public || !(theKey && this.ebOpts.crypto)) {
|
1215
|
-
return reader;
|
1139
|
+
if (!loadedCar) {
|
1140
|
+
throw this.logger.Error().Url(local.url()).Str("cid", cidsString).Msg("missing car files").AsError();
|
1216
1141
|
}
|
1217
|
-
const {
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1142
|
+
const bytes = await decode({ bytes: loadedCar.bytes, hasher: hasher3, codec: (await activeStore.keyedCrypto()).codec() });
|
1143
|
+
const rawReader = await CarReader.fromBytes(bytes.value);
|
1144
|
+
const readerP = Promise.resolve(rawReader);
|
1145
|
+
const cachedReaderP = readerP.then(async (reader) => {
|
1146
|
+
await this.cacheCarReader(cidsString, reader).catch((e) => {
|
1147
|
+
this.logger.Error().Err(e).Str("cid", cidsString).Msg("error caching car reader");
|
1148
|
+
return;
|
1149
|
+
});
|
1150
|
+
return reader;
|
1151
|
+
});
|
1152
|
+
this.carReaders.set(cidsString, cachedReaderP);
|
1153
|
+
return readerP;
|
1223
1154
|
}
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1155
|
+
//What if instead it returns an Array of CarHeader
|
1156
|
+
async storesLoadCar(cid, local, remote) {
|
1157
|
+
const cidsString = cid.toString();
|
1158
|
+
let dacr = this.carReaders.get(cidsString);
|
1159
|
+
if (!dacr) {
|
1160
|
+
dacr = this.makeDecoderAndCarReader(cid, local, remote);
|
1161
|
+
this.carReaders.set(cidsString, dacr);
|
1162
|
+
}
|
1163
|
+
return dacr;
|
1233
1164
|
}
|
1234
1165
|
async getMoreReaders(cids) {
|
1235
1166
|
const limit = pLimit(5);
|
@@ -1238,20 +1169,344 @@ var Loader = class {
|
|
1238
1169
|
}
|
1239
1170
|
};
|
1240
1171
|
|
1172
|
+
// src/runtime/keyed-crypto.ts
|
1173
|
+
var keyed_crypto_exports = {};
|
1174
|
+
__export(keyed_crypto_exports, {
|
1175
|
+
BlockIvKeyIdCodec: () => BlockIvKeyIdCodec,
|
1176
|
+
keyedCryptoFactory: () => keyedCryptoFactory
|
1177
|
+
});
|
1178
|
+
import { base58btc as base58btc2 } from "multiformats/bases/base58";
|
1179
|
+
import { sha256 as hasher4 } from "multiformats/hashes/sha2";
|
1180
|
+
import * as CBOR from "cborg";
|
1181
|
+
var generateIV = {
|
1182
|
+
random: {
|
1183
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1184
|
+
calc: async (ko, crypto, data) => {
|
1185
|
+
return crypto.randomBytes(ko.ivLength);
|
1186
|
+
},
|
1187
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1188
|
+
verify: async (ko, crypto, iv, data) => {
|
1189
|
+
return true;
|
1190
|
+
}
|
1191
|
+
},
|
1192
|
+
hash: {
|
1193
|
+
calc: async (ko, crypto, data) => {
|
1194
|
+
const hash = await hasher4.digest(data);
|
1195
|
+
const hashBytes = new Uint8Array(hash.bytes);
|
1196
|
+
const hashArray = new Uint8Array(ko.ivLength * 8);
|
1197
|
+
for (let i = 0; i < hashBytes.length; i++) {
|
1198
|
+
hashArray[i % ko.ivLength] ^= hashBytes[i];
|
1199
|
+
}
|
1200
|
+
return hashArray;
|
1201
|
+
},
|
1202
|
+
verify: async function(ko, crypto, iv, data) {
|
1203
|
+
return ko.url.getParam("ivverify") !== "disable" && UInt8ArrayEqual(iv, await this.calc(ko, crypto, data));
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
};
|
1207
|
+
function getGenerateIVFn(url, opts) {
|
1208
|
+
const ivhash = opts.ivCalc || url.getParam("ivhash") || "hash";
|
1209
|
+
return generateIV[ivhash] || generateIV["hash"];
|
1210
|
+
}
|
1211
|
+
var BlockIvKeyIdCodec = class {
|
1212
|
+
constructor(ko, iv, opts) {
|
1213
|
+
this.code = 3147065;
|
1214
|
+
this.name = "Fireproof@encrypted-block:aes-gcm";
|
1215
|
+
this.ko = ko;
|
1216
|
+
this.iv = iv;
|
1217
|
+
this.opts = opts || {};
|
1218
|
+
}
|
1219
|
+
async encode(data) {
|
1220
|
+
const calcIv = this.iv || await getGenerateIVFn(this.ko.url, this.opts).calc(this.ko, this.ko.crypto, data);
|
1221
|
+
const { iv } = this.ko.algo(calcIv);
|
1222
|
+
const fprt = await this.ko.fingerPrint();
|
1223
|
+
const keyId = base58btc2.decode(fprt);
|
1224
|
+
this.ko.logger.Debug().Str("fp", fprt).Msg("encode");
|
1225
|
+
return CBOR.encode({
|
1226
|
+
iv,
|
1227
|
+
keyId,
|
1228
|
+
data: await this.ko._encrypt({ iv, bytes: data })
|
1229
|
+
});
|
1230
|
+
}
|
1231
|
+
async decode(abytes) {
|
1232
|
+
let bytes;
|
1233
|
+
if (abytes instanceof Uint8Array) {
|
1234
|
+
bytes = abytes;
|
1235
|
+
} else {
|
1236
|
+
bytes = new Uint8Array(abytes);
|
1237
|
+
}
|
1238
|
+
const { iv, keyId, data } = CBOR.decode(bytes);
|
1239
|
+
const fprt = await this.ko.fingerPrint();
|
1240
|
+
this.ko.logger.Debug().Str("fp", base58btc2.encode(keyId)).Msg("decode");
|
1241
|
+
if (base58btc2.encode(keyId) !== fprt) {
|
1242
|
+
throw this.ko.logger.Error().Str("fp", fprt).Str("keyId", base58btc2.encode(keyId)).Msg("keyId mismatch").AsError();
|
1243
|
+
}
|
1244
|
+
const result = await this.ko._decrypt({ iv, bytes: data });
|
1245
|
+
if (!this.opts?.noIVVerify && !await getGenerateIVFn(this.ko.url, this.opts).verify(this.ko, this.ko.crypto, iv, result)) {
|
1246
|
+
throw this.ko.logger.Error().Msg("iv missmatch").AsError();
|
1247
|
+
}
|
1248
|
+
return result;
|
1249
|
+
}
|
1250
|
+
};
|
1251
|
+
var keyedCrypto = class {
|
1252
|
+
constructor(url, key, cyopt, sthis) {
|
1253
|
+
this.ivLength = 12;
|
1254
|
+
this.isEncrypting = true;
|
1255
|
+
this.logger = ensureLogger(sthis, "keyedCrypto");
|
1256
|
+
this.crypto = cyopt;
|
1257
|
+
this.key = key;
|
1258
|
+
this.url = url;
|
1259
|
+
}
|
1260
|
+
fingerPrint() {
|
1261
|
+
return Promise.resolve(this.key.fingerPrint);
|
1262
|
+
}
|
1263
|
+
codec(iv, opts) {
|
1264
|
+
return new BlockIvKeyIdCodec(this, iv, opts);
|
1265
|
+
}
|
1266
|
+
algo(iv) {
|
1267
|
+
return {
|
1268
|
+
name: "AES-GCM",
|
1269
|
+
iv: iv || this.crypto.randomBytes(this.ivLength),
|
1270
|
+
tagLength: 128
|
1271
|
+
};
|
1272
|
+
}
|
1273
|
+
async _decrypt(data) {
|
1274
|
+
this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("decrypting");
|
1275
|
+
return new Uint8Array(await this.crypto.decrypt(this.algo(data.iv), this.key.key, data.bytes));
|
1276
|
+
}
|
1277
|
+
async _encrypt(data) {
|
1278
|
+
this.logger.Debug().Len(data.bytes).Str("fp", this.key.fingerPrint).Msg("encrypting");
|
1279
|
+
const a = this.algo(data.iv);
|
1280
|
+
return new Uint8Array(await this.crypto.encrypt(a, this.key.key, data.bytes));
|
1281
|
+
}
|
1282
|
+
};
|
1283
|
+
var nullCodec = class {
|
1284
|
+
constructor() {
|
1285
|
+
this.code = 0;
|
1286
|
+
this.name = "Fireproof@unencrypted-block";
|
1287
|
+
}
|
1288
|
+
encode(data) {
|
1289
|
+
return data;
|
1290
|
+
}
|
1291
|
+
decode(data) {
|
1292
|
+
return data;
|
1293
|
+
}
|
1294
|
+
};
|
1295
|
+
var noCrypto = class {
|
1296
|
+
constructor(url, cyrt, sthis) {
|
1297
|
+
this.ivLength = 0;
|
1298
|
+
this.code = 0;
|
1299
|
+
this.name = "Fireproof@unencrypted-block";
|
1300
|
+
this.isEncrypting = false;
|
1301
|
+
this._fingerPrint = "noCrypto:" + Math.random();
|
1302
|
+
this.logger = ensureLogger(sthis, "noCrypto");
|
1303
|
+
this.crypto = cyrt;
|
1304
|
+
this.url = url;
|
1305
|
+
}
|
1306
|
+
fingerPrint() {
|
1307
|
+
return Promise.resolve(this._fingerPrint);
|
1308
|
+
}
|
1309
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1310
|
+
codec(iv) {
|
1311
|
+
return new nullCodec();
|
1312
|
+
}
|
1313
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1314
|
+
algo(iv) {
|
1315
|
+
return {
|
1316
|
+
name: "noCrypto",
|
1317
|
+
iv: new Uint8Array(),
|
1318
|
+
tagLength: 0
|
1319
|
+
};
|
1320
|
+
}
|
1321
|
+
_decrypt() {
|
1322
|
+
throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
|
1323
|
+
}
|
1324
|
+
_encrypt() {
|
1325
|
+
throw this.logger.Error().Msg("noCrypto.decrypt not implemented").AsError();
|
1326
|
+
}
|
1327
|
+
};
|
1328
|
+
async function keyedCryptoFactory(url, kb, sthis) {
|
1329
|
+
const storekey = url.getParam("storekey");
|
1330
|
+
if (storekey && storekey !== "insecure") {
|
1331
|
+
let rkey = await kb.getNamedKey(storekey, true);
|
1332
|
+
if (rkey.isErr()) {
|
1333
|
+
try {
|
1334
|
+
rkey = await kb.toKeyWithFingerPrint(storekey);
|
1335
|
+
} catch (e) {
|
1336
|
+
throw sthis.logger.Error().Err(e).Str("keybag", kb.rt.id()).Str("name", storekey).Msg("getNamedKey failed").AsError();
|
1337
|
+
}
|
1338
|
+
}
|
1339
|
+
return new keyedCrypto(url, rkey.Ok(), kb.rt.crypto, sthis);
|
1340
|
+
}
|
1341
|
+
return new noCrypto(url, kb.rt.crypto, sthis);
|
1342
|
+
}
|
1343
|
+
|
1344
|
+
// src/blockstore/fragment-gateway.ts
|
1345
|
+
import { base58btc as base58btc3 } from "multiformats/bases/base58";
|
1346
|
+
import { encode as encode3, decode as decode3 } from "cborg";
|
1347
|
+
function getFragSize(url) {
|
1348
|
+
const fragSize = url.getParam("fragSize");
|
1349
|
+
let ret = 0;
|
1350
|
+
if (fragSize) {
|
1351
|
+
ret = parseInt(fragSize);
|
1352
|
+
}
|
1353
|
+
if (isNaN(ret) || ret <= 0) {
|
1354
|
+
ret = 0;
|
1355
|
+
}
|
1356
|
+
return ret;
|
1357
|
+
}
|
1358
|
+
async function getFrags(url, innerGW, headerSize, logger) {
|
1359
|
+
const fragSize = getFragSize(url);
|
1360
|
+
if (!fragSize) {
|
1361
|
+
const res = await innerGW.get(url);
|
1362
|
+
if (res.isErr()) {
|
1363
|
+
return [res];
|
1364
|
+
}
|
1365
|
+
const data = res.unwrap();
|
1366
|
+
return [
|
1367
|
+
Result.Ok({
|
1368
|
+
fid: new Uint8Array(0),
|
1369
|
+
ofs: 0,
|
1370
|
+
len: data.length,
|
1371
|
+
data
|
1372
|
+
})
|
1373
|
+
];
|
1374
|
+
}
|
1375
|
+
const firstRaw = await innerGW.get(url.build().setParam("ofs", "0").URI());
|
1376
|
+
if (firstRaw.isErr()) {
|
1377
|
+
return [firstRaw];
|
1378
|
+
}
|
1379
|
+
const firstFragment = decode3(firstRaw.unwrap());
|
1380
|
+
const blockSize = firstFragment.data.length;
|
1381
|
+
const ops = [Promise.resolve(Result.Ok(firstFragment))];
|
1382
|
+
const fidStr = base58btc3.encode(firstFragment.fid);
|
1383
|
+
const fragUrl = url.build().setParam("fid", fidStr).setParam("len", firstFragment.len.toString()).setParam("headerSize", headerSize.toString());
|
1384
|
+
for (let ofs = blockSize; ofs < firstFragment.len; ofs += blockSize) {
|
1385
|
+
ops.push(
|
1386
|
+
(async (furl, ofs2) => {
|
1387
|
+
const raw2 = await innerGW.get(furl);
|
1388
|
+
if (raw2.isErr()) {
|
1389
|
+
return raw2;
|
1390
|
+
}
|
1391
|
+
const fragment = decode3(raw2.unwrap());
|
1392
|
+
if (base58btc3.encode(fragment.fid) !== fidStr) {
|
1393
|
+
return Result.Err(logger.Error().Msg("Fragment fid mismatch").AsError());
|
1394
|
+
}
|
1395
|
+
if (fragment.ofs !== ofs2) {
|
1396
|
+
return Result.Err(logger.Error().Uint64("ofs", ofs2).Msg("Fragment ofs mismatch").AsError());
|
1397
|
+
}
|
1398
|
+
return Result.Ok(fragment);
|
1399
|
+
})(fragUrl.setParam("ofs", ofs.toString()).URI(), ofs)
|
1400
|
+
);
|
1401
|
+
}
|
1402
|
+
return Promise.all(ops);
|
1403
|
+
}
|
1404
|
+
var FragmentGateway = class {
|
1405
|
+
constructor(sthis, innerGW) {
|
1406
|
+
this.fidLength = 4;
|
1407
|
+
this.headerSize = 32;
|
1408
|
+
this.sthis = ensureSuperLog(sthis, "FragmentGateway");
|
1409
|
+
this.logger = this.sthis.logger;
|
1410
|
+
this.innerGW = innerGW;
|
1411
|
+
}
|
1412
|
+
slicer(url, body) {
|
1413
|
+
const fragSize = getFragSize(url);
|
1414
|
+
if (!fragSize) {
|
1415
|
+
return [this.innerGW.put(url, body)];
|
1416
|
+
}
|
1417
|
+
const blocksize = fragSize - this.headerSize;
|
1418
|
+
if (blocksize <= 0) {
|
1419
|
+
throw this.logger.Error().Uint64("fragSize", fragSize).Uint64("headerSize", this.headerSize).Msg("Fragment size is too small").AsError();
|
1420
|
+
}
|
1421
|
+
const ops = [];
|
1422
|
+
const fid = this.sthis.nextId(this.fidLength);
|
1423
|
+
const fragUrl = url.build().setParam("fid", fid.str).setParam("len", body.length.toString()).setParam("headerSize", this.headerSize.toString());
|
1424
|
+
for (let ofs = 0; ofs < body.length; ofs += blocksize) {
|
1425
|
+
const block = encode3({
|
1426
|
+
fid: fid.bin,
|
1427
|
+
ofs,
|
1428
|
+
len: body.length,
|
1429
|
+
data: body.slice(ofs, ofs + blocksize)
|
1430
|
+
});
|
1431
|
+
if (block.length > fragSize) {
|
1432
|
+
throw this.logger.Error().Uint64("block", block.length).Uint64("fragSize", fragSize).Msg("Block size to big").AsError();
|
1433
|
+
}
|
1434
|
+
ops.push(this.innerGW.put(fragUrl.setParam("ofs", ofs.toString()).URI(), block));
|
1435
|
+
}
|
1436
|
+
return ops;
|
1437
|
+
}
|
1438
|
+
buildUrl(baseUrl, key) {
|
1439
|
+
return this.innerGW.buildUrl(baseUrl, key);
|
1440
|
+
}
|
1441
|
+
async destroy(iurl) {
|
1442
|
+
return this.innerGW.destroy(iurl);
|
1443
|
+
}
|
1444
|
+
async start(url) {
|
1445
|
+
this.headerSize = encode3({
|
1446
|
+
fid: this.sthis.nextId(this.fidLength).bin,
|
1447
|
+
ofs: 1024 * 1024,
|
1448
|
+
// 32bit
|
1449
|
+
len: 16 * 1024 * 1024,
|
1450
|
+
// 32bit
|
1451
|
+
data: new Uint8Array(1024)
|
1452
|
+
}).length - 1024;
|
1453
|
+
return this.innerGW.start(url);
|
1454
|
+
}
|
1455
|
+
async close(url) {
|
1456
|
+
return this.innerGW.close(url);
|
1457
|
+
}
|
1458
|
+
async put(url, body) {
|
1459
|
+
await Promise.all(this.slicer(url, body));
|
1460
|
+
return Result.Ok(void 0);
|
1461
|
+
}
|
1462
|
+
async get(url) {
|
1463
|
+
const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
|
1464
|
+
let buffer = void 0;
|
1465
|
+
for (const rfrag of rfrags) {
|
1466
|
+
if (rfrag.isErr()) {
|
1467
|
+
return Result.Err(rfrag.Err());
|
1468
|
+
}
|
1469
|
+
const frag = rfrag.Ok();
|
1470
|
+
buffer = buffer || new Uint8Array(frag.len);
|
1471
|
+
buffer.set(frag.data, frag.ofs);
|
1472
|
+
}
|
1473
|
+
return Result.Ok(buffer || new Uint8Array(0));
|
1474
|
+
}
|
1475
|
+
async delete(url) {
|
1476
|
+
const rfrags = await getFrags(url, this.innerGW, this.headerSize, this.logger);
|
1477
|
+
for (const rfrag of rfrags) {
|
1478
|
+
if (rfrag.isErr()) {
|
1479
|
+
return Result.Err(rfrag.Err());
|
1480
|
+
}
|
1481
|
+
const frag = rfrag.Ok();
|
1482
|
+
const fidStr = base58btc3.encode(frag.fid);
|
1483
|
+
const fragUrl = url.build().setParam("fid", fidStr).setParam("len", frag.len.toString()).setParam("headerSize", this.headerSize.toString()).URI();
|
1484
|
+
await this.innerGW.delete(fragUrl);
|
1485
|
+
}
|
1486
|
+
return Result.Ok(void 0);
|
1487
|
+
}
|
1488
|
+
};
|
1489
|
+
|
1241
1490
|
// src/blockstore/store.ts
|
1242
1491
|
function guardVersion(url) {
|
1243
|
-
if (!url.
|
1244
|
-
return
|
1492
|
+
if (!url.hasParam("version")) {
|
1493
|
+
return Result3.Err(`missing version: ${url.toString()}`);
|
1245
1494
|
}
|
1246
|
-
return
|
1495
|
+
return Result3.Ok(url);
|
1247
1496
|
}
|
1248
|
-
var
|
1249
|
-
constructor(name, url, logger) {
|
1497
|
+
var BaseStoreImpl = class {
|
1498
|
+
constructor(name, url, opts, sthis, logger) {
|
1250
1499
|
this._onStarted = [];
|
1251
1500
|
this._onClosed = [];
|
1252
1501
|
this.name = name;
|
1253
|
-
this.
|
1254
|
-
this.
|
1502
|
+
this._url = url;
|
1503
|
+
this.keybag = opts.keybag;
|
1504
|
+
this.sthis = sthis;
|
1505
|
+
this.logger = logger.With().Ref("url", () => this._url.toString()).Str("name", name).Logger();
|
1506
|
+
this.gateway = new FragmentGateway(this.sthis, opts.gateway);
|
1507
|
+
}
|
1508
|
+
url() {
|
1509
|
+
return this._url;
|
1255
1510
|
}
|
1256
1511
|
onStarted(fn) {
|
1257
1512
|
this._onStarted.push(fn);
|
@@ -1259,106 +1514,164 @@ var VersionedStore = class {
|
|
1259
1514
|
onClosed(fn) {
|
1260
1515
|
this._onClosed.push(fn);
|
1261
1516
|
}
|
1517
|
+
async keyedCrypto() {
|
1518
|
+
return keyedCryptoFactory(this._url, await this.keybag(), this.sthis);
|
1519
|
+
}
|
1520
|
+
async start() {
|
1521
|
+
this.logger.Debug().Str("storeType", this.storeType).Msg("starting-gateway-pre");
|
1522
|
+
this._url = this._url.build().setParam("store", this.storeType).URI();
|
1523
|
+
const res = await this.gateway.start(this._url);
|
1524
|
+
if (res.isErr()) {
|
1525
|
+
this.logger.Error().Result("gw-start", res).Msg("started-gateway");
|
1526
|
+
return res;
|
1527
|
+
}
|
1528
|
+
this._url = res.Ok();
|
1529
|
+
const kb = await this.keybag();
|
1530
|
+
const skRes = await kb.ensureKeyFromUrl(this._url, () => {
|
1531
|
+
const idx = this._url.getParam("index");
|
1532
|
+
const storeKeyName = [this.name];
|
1533
|
+
if (idx) {
|
1534
|
+
storeKeyName.push(idx);
|
1535
|
+
}
|
1536
|
+
storeKeyName.push(this.storeType);
|
1537
|
+
return storeKeyName.join(":");
|
1538
|
+
});
|
1539
|
+
if (skRes.isErr()) {
|
1540
|
+
return skRes;
|
1541
|
+
}
|
1542
|
+
this._url = skRes.Ok();
|
1543
|
+
const version = guardVersion(this._url);
|
1544
|
+
if (version.isErr()) {
|
1545
|
+
this.logger.Error().Result("version", version).Msg("guardVersion");
|
1546
|
+
await this.close();
|
1547
|
+
return version;
|
1548
|
+
}
|
1549
|
+
if (this.ready) {
|
1550
|
+
const fn = this.ready.bind(this);
|
1551
|
+
const ready = await exception2Result(fn);
|
1552
|
+
if (ready.isErr()) {
|
1553
|
+
await this.close();
|
1554
|
+
return ready;
|
1555
|
+
}
|
1556
|
+
}
|
1557
|
+
this._onStarted.forEach((fn) => fn());
|
1558
|
+
this.logger.Debug().Msg("started");
|
1559
|
+
return version;
|
1560
|
+
}
|
1262
1561
|
};
|
1263
|
-
var
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1562
|
+
var MetaStoreImpl = class extends BaseStoreImpl {
|
1563
|
+
constructor(sthis, name, url, opts) {
|
1564
|
+
super(
|
1565
|
+
name,
|
1566
|
+
url,
|
1567
|
+
{
|
1568
|
+
...opts
|
1569
|
+
},
|
1570
|
+
sthis,
|
1571
|
+
ensureLogger(sthis, "MetaStoreImpl")
|
1572
|
+
);
|
1573
|
+
this.storeType = "meta";
|
1574
|
+
this.subscribers = /* @__PURE__ */ new Map();
|
1575
|
+
}
|
1576
|
+
onLoad(branch, loadHandler) {
|
1577
|
+
const subscribers = this.subscribers.get(branch) || [];
|
1578
|
+
subscribers.push(loadHandler);
|
1579
|
+
this.subscribers.set(branch, subscribers);
|
1580
|
+
return () => {
|
1581
|
+
const subscribers2 = this.subscribers.get(branch) || [];
|
1582
|
+
const idx = subscribers2.indexOf(loadHandler);
|
1583
|
+
if (idx > -1) subscribers2.splice(idx, 1);
|
1584
|
+
};
|
1585
|
+
}
|
1586
|
+
makeHeader({ cars }) {
|
1272
1587
|
const toEncode = { cars };
|
1273
|
-
if (key) toEncode.key = key;
|
1274
1588
|
return format(toEncode);
|
1275
1589
|
}
|
1276
1590
|
parseHeader(headerData) {
|
1277
1591
|
const got = parse(headerData);
|
1278
1592
|
return got;
|
1279
1593
|
}
|
1280
|
-
async
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1594
|
+
async handleSubscribers(dbMetas, branch) {
|
1595
|
+
try {
|
1596
|
+
const subscribers = this.subscribers.get(branch) || [];
|
1597
|
+
await Promise.all(subscribers.map((subscriber) => subscriber(dbMetas)));
|
1598
|
+
} catch (e) {
|
1599
|
+
this.logger.Error().Err(e).Msg("handleSubscribers").AsError();
|
1285
1600
|
}
|
1286
|
-
|
1287
|
-
|
1601
|
+
}
|
1602
|
+
async handleByteHeads(byteHeads, branch = "main") {
|
1603
|
+
let dbMetas;
|
1604
|
+
try {
|
1605
|
+
dbMetas = this.dbMetasForByteHeads(byteHeads);
|
1606
|
+
} catch (e) {
|
1607
|
+
throw this.logger.Error().Err(e).Msg("parseHeader").AsError();
|
1608
|
+
}
|
1609
|
+
await this.handleSubscribers(dbMetas, branch);
|
1610
|
+
return dbMetas;
|
1611
|
+
}
|
1612
|
+
dbMetasForByteHeads(byteHeads) {
|
1613
|
+
return byteHeads.map((bytes) => {
|
1614
|
+
const txt = this.sthis.txt.decode(bytes);
|
1615
|
+
return this.parseHeader(txt);
|
1616
|
+
});
|
1288
1617
|
}
|
1289
1618
|
async load(branch) {
|
1290
|
-
|
1291
|
-
|
1619
|
+
branch = branch || "main";
|
1620
|
+
this.logger.Debug().Str("branch", branch).Msg("loading");
|
1621
|
+
const url = await this.gateway.buildUrl(this.url(), branch);
|
1292
1622
|
if (url.isErr()) {
|
1293
|
-
throw this.logger.Error().Result("buidUrl", url).Str("branch", branch
|
1623
|
+
throw this.logger.Error().Result("buidUrl", url).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
|
1294
1624
|
}
|
1295
1625
|
const bytes = await this.gateway.get(url.Ok());
|
1296
1626
|
if (bytes.isErr()) {
|
1297
1627
|
if (isNotFoundError(bytes)) {
|
1298
|
-
return void 0;
|
1299
|
-
}
|
1300
|
-
throw this.logger.Error().Url(url.Ok()).Result("bytes:", bytes).Msg("gateway get").AsError();
|
1301
|
-
}
|
1302
|
-
try {
|
1303
|
-
return [this.parseHeader(textDecoder.decode(bytes.Ok()))];
|
1304
|
-
} catch (e) {
|
1305
|
-
throw this.logger.Error().Err(e).Msg("parseHeader").AsError();
|
1628
|
+
return void 0;
|
1629
|
+
}
|
1630
|
+
throw this.logger.Error().Url(url.Ok()).Result("bytes:", bytes).Msg("gateway get").AsError();
|
1306
1631
|
}
|
1632
|
+
return this.handleByteHeads([bytes.Ok()], branch);
|
1307
1633
|
}
|
1308
|
-
async save(meta, branch
|
1634
|
+
async save(meta, branch) {
|
1635
|
+
branch = branch || "main";
|
1309
1636
|
this.logger.Debug().Str("branch", branch).Any("meta", meta).Msg("saving meta");
|
1310
1637
|
const bytes = this.makeHeader(meta);
|
1311
|
-
const url = await this.gateway.buildUrl(this.url, branch);
|
1638
|
+
const url = await this.gateway.buildUrl(this.url(), branch);
|
1312
1639
|
if (url.isErr()) {
|
1313
|
-
throw this.logger.Error().Err(url.Err()).Str("branch", branch).
|
1640
|
+
throw this.logger.Error().Err(url.Err()).Str("branch", branch).Msg("got error from gateway.buildUrl").AsError();
|
1314
1641
|
}
|
1315
|
-
const res = await this.gateway.put(url.Ok(),
|
1642
|
+
const res = await this.gateway.put(url.Ok(), this.sthis.txt.encode(bytes));
|
1316
1643
|
if (res.isErr()) {
|
1317
1644
|
throw this.logger.Error().Err(res.Err()).Msg("got error from gateway.put").AsError();
|
1318
1645
|
}
|
1319
|
-
|
1646
|
+
await this.handleSubscribers([meta], branch);
|
1647
|
+
return res;
|
1320
1648
|
}
|
1321
1649
|
async close() {
|
1322
|
-
await this.gateway.close(this.url);
|
1650
|
+
await this.gateway.close(this.url());
|
1323
1651
|
this._onClosed.forEach((fn) => fn());
|
1324
|
-
return
|
1652
|
+
return Result3.Ok(void 0);
|
1325
1653
|
}
|
1326
1654
|
async destroy() {
|
1327
|
-
return this.gateway.destroy(this.url);
|
1655
|
+
return this.gateway.destroy(this.url());
|
1328
1656
|
}
|
1329
1657
|
};
|
1330
|
-
var
|
1331
|
-
|
1658
|
+
var DataStoreImpl = class extends BaseStoreImpl {
|
1659
|
+
// readonly tag: string = "car-base";
|
1660
|
+
constructor(sthis, name, url, opts) {
|
1332
1661
|
super(
|
1333
1662
|
name,
|
1334
1663
|
url,
|
1335
|
-
|
1336
|
-
|
1337
|
-
}
|
1664
|
+
{
|
1665
|
+
...opts
|
1666
|
+
},
|
1667
|
+
sthis,
|
1668
|
+
ensureLogger(sthis, "DataStoreImpl")
|
1338
1669
|
);
|
1339
|
-
this.
|
1340
|
-
this.gateway = gateway;
|
1341
|
-
}
|
1342
|
-
async start() {
|
1343
|
-
this.logger.Debug().Msg("starting-gateway");
|
1344
|
-
const res = await this.gateway.start(this.url);
|
1345
|
-
if (res.isErr()) {
|
1346
|
-
this.logger.Error().Result("gw-start", res).Msg("started-gateway");
|
1347
|
-
return res;
|
1348
|
-
}
|
1349
|
-
this._onStarted.forEach((fn) => fn());
|
1350
|
-
const version = guardVersion(this.url);
|
1351
|
-
if (version.isErr()) {
|
1352
|
-
this.logger.Error().Result("version", version).Msg("guardVersion");
|
1353
|
-
await this.close();
|
1354
|
-
return version;
|
1355
|
-
}
|
1356
|
-
this.logger.Debug().Msg("started");
|
1357
|
-
return version;
|
1670
|
+
this.storeType = "data";
|
1358
1671
|
}
|
1359
1672
|
async load(cid) {
|
1360
1673
|
this.logger.Debug().Any("cid", cid).Msg("loading");
|
1361
|
-
const url = await this.gateway.buildUrl(this.url, cid.toString());
|
1674
|
+
const url = await this.gateway.buildUrl(this.url(), cid.toString());
|
1362
1675
|
if (url.isErr()) {
|
1363
1676
|
throw this.logger.Error().Err(url.Err()).Str("cid", cid.toString()).Msg("got error from gateway.buildUrl").AsError();
|
1364
1677
|
}
|
@@ -1371,7 +1684,7 @@ var DataStore = class extends VersionedStore {
|
|
1371
1684
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1372
1685
|
async save(car, opts) {
|
1373
1686
|
this.logger.Debug().Any("cid", car.cid.toString()).Msg("saving");
|
1374
|
-
const url = await this.gateway.buildUrl(this.url, car.cid.toString());
|
1687
|
+
const url = await this.gateway.buildUrl(this.url(), car.cid.toString());
|
1375
1688
|
if (url.isErr()) {
|
1376
1689
|
throw this.logger.Error().Err(url.Err()).Ref("cid", car.cid).Msg("got error from gateway.buildUrl").AsError();
|
1377
1690
|
}
|
@@ -1382,46 +1695,53 @@ var DataStore = class extends VersionedStore {
|
|
1382
1695
|
return res.Ok();
|
1383
1696
|
}
|
1384
1697
|
async remove(cid) {
|
1385
|
-
const url = await this.gateway.buildUrl(this.url, cid.toString());
|
1698
|
+
const url = await this.gateway.buildUrl(this.url(), cid.toString());
|
1386
1699
|
if (url.isErr()) {
|
1387
1700
|
return url;
|
1388
1701
|
}
|
1389
1702
|
return this.gateway.delete(url.Ok());
|
1390
1703
|
}
|
1391
1704
|
async close() {
|
1392
|
-
await this.gateway.close(this.url);
|
1705
|
+
await this.gateway.close(this.url());
|
1393
1706
|
this._onClosed.forEach((fn) => fn());
|
1394
|
-
return
|
1707
|
+
return Result3.Ok(void 0);
|
1395
1708
|
}
|
1396
1709
|
destroy() {
|
1397
|
-
return this.gateway.destroy(this.url);
|
1710
|
+
return this.gateway.destroy(this.url());
|
1398
1711
|
}
|
1399
1712
|
};
|
1400
|
-
var
|
1401
|
-
constructor(loader, url,
|
1402
|
-
super(
|
1403
|
-
|
1713
|
+
var WALStoreImpl = class extends BaseStoreImpl {
|
1714
|
+
constructor(loader, url, opts) {
|
1715
|
+
super(
|
1716
|
+
loader.name,
|
1717
|
+
url,
|
1718
|
+
{
|
1719
|
+
...opts
|
1720
|
+
},
|
1721
|
+
loader.sthis,
|
1722
|
+
ensureLogger(loader.sthis, "WALStoreImpl")
|
1723
|
+
);
|
1724
|
+
this.storeType = "wal";
|
1404
1725
|
this._ready = new ResolveOnce2();
|
1405
1726
|
this.walState = { operations: [], noLoaderOps: [], fileOperations: [] };
|
1406
1727
|
this.processing = void 0;
|
1407
1728
|
this.processQueue = new CommitQueue();
|
1408
|
-
this.
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1729
|
+
this.ready = async () => {
|
1730
|
+
return this._ready.once(async () => {
|
1731
|
+
const walState = await this.load().catch((e) => {
|
1732
|
+
this.logger.Error().Any("error", e).Msg("error loading wal");
|
1733
|
+
return void 0;
|
1734
|
+
});
|
1735
|
+
if (!walState) {
|
1736
|
+
this.walState.operations = [];
|
1737
|
+
this.walState.fileOperations = [];
|
1738
|
+
} else {
|
1739
|
+
this.walState.operations = walState.operations || [];
|
1740
|
+
this.walState.fileOperations = walState.fileOperations || [];
|
1741
|
+
}
|
1416
1742
|
});
|
1417
|
-
|
1418
|
-
|
1419
|
-
this.walState.fileOperations = [];
|
1420
|
-
} else {
|
1421
|
-
this.walState.operations = walState.operations || [];
|
1422
|
-
this.walState.fileOperations = walState.fileOperations || [];
|
1423
|
-
}
|
1424
|
-
});
|
1743
|
+
};
|
1744
|
+
this.loader = loader;
|
1425
1745
|
}
|
1426
1746
|
async enqueue(dbMeta, opts) {
|
1427
1747
|
await this.ready();
|
@@ -1431,19 +1751,23 @@ var RemoteWAL = class extends VersionedStore {
|
|
1431
1751
|
this.walState.operations.push(dbMeta);
|
1432
1752
|
}
|
1433
1753
|
await this.save(this.walState);
|
1434
|
-
void this.
|
1754
|
+
void this.process();
|
1435
1755
|
}
|
1436
1756
|
async enqueueFile(fileCid, publicFile = false) {
|
1437
1757
|
await this.ready();
|
1438
1758
|
this.walState.fileOperations.push({ cid: fileCid, public: publicFile });
|
1439
1759
|
}
|
1440
|
-
async
|
1760
|
+
async process() {
|
1441
1761
|
await this.ready();
|
1442
1762
|
if (!this.loader.remoteCarStore) return;
|
1443
1763
|
await this.processQueue.enqueue(async () => {
|
1444
|
-
|
1764
|
+
try {
|
1765
|
+
await this._doProcess();
|
1766
|
+
} catch (e) {
|
1767
|
+
this.logger.Error().Any("error", e).Msg("error processing wal");
|
1768
|
+
}
|
1445
1769
|
if (this.walState.operations.length || this.walState.fileOperations.length || this.walState.noLoaderOps.length) {
|
1446
|
-
setTimeout(() => void this.
|
1770
|
+
setTimeout(() => void this.process(), 0);
|
1447
1771
|
}
|
1448
1772
|
});
|
1449
1773
|
}
|
@@ -1461,7 +1785,7 @@ var RemoteWAL = class extends VersionedStore {
|
|
1461
1785
|
for (const cid of dbMeta.cars) {
|
1462
1786
|
const car = await (await this.loader.carStore()).load(cid);
|
1463
1787
|
if (!car) {
|
1464
|
-
if (
|
1788
|
+
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
|
1465
1789
|
throw this.logger.Error().Ref("cid", cid).Msg("missing local car").AsError();
|
1466
1790
|
} else {
|
1467
1791
|
await throwFalsy(this.loader.remoteCarStore).save(car);
|
@@ -1476,7 +1800,7 @@ var RemoteWAL = class extends VersionedStore {
|
|
1476
1800
|
for (const cid of dbMeta.cars) {
|
1477
1801
|
const car = await (await this.loader.carStore()).load(cid).catch(() => null);
|
1478
1802
|
if (!car) {
|
1479
|
-
if (
|
1803
|
+
if (carLogIncludesGroup(this.loader.carLog, dbMeta.cars))
|
1480
1804
|
throw this.logger.Error().Ref("cid", cid).Msg(`missing local car`).AsError();
|
1481
1805
|
} else {
|
1482
1806
|
await throwFalsy(this.loader.remoteCarStore).save(car);
|
@@ -1501,11 +1825,7 @@ var RemoteWAL = class extends VersionedStore {
|
|
1501
1825
|
const res = await Promise.allSettled(uploads);
|
1502
1826
|
const errors = res.filter((r) => r.status === "rejected");
|
1503
1827
|
if (errors.length) {
|
1504
|
-
throw this.logger.Error().Any(
|
1505
|
-
"errors",
|
1506
|
-
errors.map((e) => e.reason)
|
1507
|
-
).Msg("error uploading").AsError();
|
1508
|
-
errors[0].reason;
|
1828
|
+
throw this.logger.Error().Any("errors", errors).Msg("error uploading").AsError();
|
1509
1829
|
}
|
1510
1830
|
if (operations.length) {
|
1511
1831
|
const lastOp = operations[operations.length - 1];
|
@@ -1520,29 +1840,11 @@ var RemoteWAL = class extends VersionedStore {
|
|
1520
1840
|
})();
|
1521
1841
|
await rmlp;
|
1522
1842
|
}
|
1523
|
-
async start() {
|
1524
|
-
const res = await this.gateway.start(this.url);
|
1525
|
-
if (res.isErr()) {
|
1526
|
-
return res;
|
1527
|
-
}
|
1528
|
-
const ver = guardVersion(this.url);
|
1529
|
-
if (ver.isErr()) {
|
1530
|
-
await this.close();
|
1531
|
-
return ver;
|
1532
|
-
}
|
1533
|
-
const ready = await exception2Result(() => this.ready());
|
1534
|
-
this._onStarted.forEach((fn) => fn());
|
1535
|
-
if (ready.isErr()) {
|
1536
|
-
await this.close();
|
1537
|
-
return ready;
|
1538
|
-
}
|
1539
|
-
return ready;
|
1540
|
-
}
|
1541
1843
|
async load() {
|
1542
1844
|
this.logger.Debug().Msg("loading");
|
1543
|
-
const filepath = await this.gateway.buildUrl(this.url, "main");
|
1845
|
+
const filepath = await this.gateway.buildUrl(this.url(), "main");
|
1544
1846
|
if (filepath.isErr()) {
|
1545
|
-
throw this.logger.Error().Err(filepath.Err()).
|
1847
|
+
throw this.logger.Error().Err(filepath.Err()).Url(this.url()).Msg("error building url").AsError();
|
1546
1848
|
}
|
1547
1849
|
const bytes = await this.gateway.get(filepath.Ok());
|
1548
1850
|
if (bytes.isErr()) {
|
@@ -1552,15 +1854,15 @@ var RemoteWAL = class extends VersionedStore {
|
|
1552
1854
|
throw this.logger.Error().Err(bytes.Err()).Msg("error get").AsError();
|
1553
1855
|
}
|
1554
1856
|
try {
|
1555
|
-
return bytes && parse(
|
1857
|
+
return bytes && parse(this.sthis.txt.decode(bytes.Ok()));
|
1556
1858
|
} catch (e) {
|
1557
1859
|
throw this.logger.Error().Err(e).Msg("error parse").AsError();
|
1558
1860
|
}
|
1559
1861
|
}
|
1560
1862
|
async save(state) {
|
1561
|
-
const filepath = await this.gateway.buildUrl(this.url, "main");
|
1863
|
+
const filepath = await this.gateway.buildUrl(this.url(), "main");
|
1562
1864
|
if (filepath.isErr()) {
|
1563
|
-
throw this.logger.Error().Err(filepath.Err()).
|
1865
|
+
throw this.logger.Error().Err(filepath.Err()).Url(this.url()).Msg("error building url").AsError();
|
1564
1866
|
}
|
1565
1867
|
let encoded;
|
1566
1868
|
try {
|
@@ -1568,55 +1870,67 @@ var RemoteWAL = class extends VersionedStore {
|
|
1568
1870
|
} catch (e) {
|
1569
1871
|
throw this.logger.Error().Err(e).Any("state", state).Msg("error format").AsError();
|
1570
1872
|
}
|
1571
|
-
const res = await this.gateway.put(filepath.Ok(),
|
1873
|
+
const res = await this.gateway.put(filepath.Ok(), this.sthis.txt.encode(encoded));
|
1572
1874
|
if (res.isErr()) {
|
1573
1875
|
throw this.logger.Error().Err(res.Err()).Str("filePath", filepath.Ok().toString()).Msg("error saving").AsError();
|
1574
1876
|
}
|
1575
1877
|
}
|
1576
1878
|
async close() {
|
1577
|
-
await this.gateway.close(this.url);
|
1879
|
+
await this.gateway.close(this.url());
|
1578
1880
|
this._onClosed.forEach((fn) => fn());
|
1579
|
-
return
|
1881
|
+
return Result3.Ok(void 0);
|
1580
1882
|
}
|
1581
1883
|
destroy() {
|
1582
|
-
return this.gateway.destroy(this.url);
|
1884
|
+
return this.gateway.destroy(this.url());
|
1583
1885
|
}
|
1584
1886
|
};
|
1585
1887
|
|
1586
1888
|
// src/blockstore/store-factory.ts
|
1587
1889
|
function ensureIsIndex(url, isIndex) {
|
1588
1890
|
if (isIndex) {
|
1589
|
-
url.
|
1590
|
-
return url;
|
1591
|
-
} else {
|
1592
|
-
url.searchParams.delete("index");
|
1593
|
-
return url;
|
1594
|
-
}
|
1595
|
-
}
|
1596
|
-
function toURL(pathOrUrl, isIndex) {
|
1597
|
-
if (pathOrUrl instanceof URL) return ensureIsIndex(pathOrUrl, isIndex);
|
1598
|
-
try {
|
1599
|
-
const url = new URL(pathOrUrl);
|
1600
|
-
return ensureIsIndex(url, isIndex);
|
1601
|
-
} catch (e) {
|
1602
|
-
const url = new URL(`file://${pathOrUrl}`);
|
1603
|
-
return ensureIsIndex(url, isIndex);
|
1891
|
+
return url.build().setParam("index", isIndex).URI();
|
1604
1892
|
}
|
1893
|
+
return url.build().delParam("index").URI();
|
1605
1894
|
}
|
1606
|
-
var storeFactory = /* @__PURE__ */ new Map();
|
1607
1895
|
function ensureName(name, url) {
|
1608
|
-
if (!url.
|
1609
|
-
url.
|
1896
|
+
if (!url.hasParam("name")) {
|
1897
|
+
return url.build().setParam("name", name).URI();
|
1610
1898
|
}
|
1899
|
+
return url;
|
1611
1900
|
}
|
1901
|
+
var storeFactory = /* @__PURE__ */ new Map();
|
1612
1902
|
function buildURL(optURL, loader) {
|
1613
1903
|
const storeOpts = loader.ebOpts.store;
|
1614
1904
|
const obuItem = Array.from(storeFactory.values()).find((items) => items.overrideBaseURL);
|
1615
1905
|
let obuUrl;
|
1616
1906
|
if (obuItem && obuItem.overrideBaseURL) {
|
1617
|
-
obuUrl =
|
1907
|
+
obuUrl = URI3.from(obuItem.overrideBaseURL);
|
1618
1908
|
}
|
1619
|
-
|
1909
|
+
const ret = ensureIsIndex(
|
1910
|
+
URI3.from(optURL || obuUrl || dataDir(loader.sthis, loader.name, storeOpts.stores?.base)),
|
1911
|
+
storeOpts.isIndex
|
1912
|
+
);
|
1913
|
+
return ret;
|
1914
|
+
}
|
1915
|
+
var onceGateway = new KeyedResolvOnce2();
|
1916
|
+
async function getGatewayFromURL(url, sthis) {
|
1917
|
+
return onceGateway.get(url.toString()).once(async () => {
|
1918
|
+
const item = storeFactory.get(url.protocol);
|
1919
|
+
if (item) {
|
1920
|
+
const ret = {
|
1921
|
+
gateway: await item.gateway(sthis),
|
1922
|
+
test: await item.test(sthis)
|
1923
|
+
};
|
1924
|
+
const res = await ret.gateway.start(url);
|
1925
|
+
if (res.isErr()) {
|
1926
|
+
sthis.logger.Error().Result("start", res).Msg("start failed");
|
1927
|
+
return void 0;
|
1928
|
+
}
|
1929
|
+
return ret;
|
1930
|
+
}
|
1931
|
+
sthis.logger.Warn().Url(url).Msg("unsupported protocol");
|
1932
|
+
return void 0;
|
1933
|
+
});
|
1620
1934
|
}
|
1621
1935
|
function registerStoreProtocol(item) {
|
1622
1936
|
let protocol = item.protocol;
|
@@ -1625,8 +1939,7 @@ function registerStoreProtocol(item) {
|
|
1625
1939
|
}
|
1626
1940
|
if (storeFactory.has(protocol)) {
|
1627
1941
|
if (!item.overrideBaseURL && storeFactory.get(protocol) !== item) {
|
1628
|
-
|
1629
|
-
logger.Warn().Msg(`protocol ${protocol} already registered`);
|
1942
|
+
throw new Error(`we need a logger here`);
|
1630
1943
|
return () => {
|
1631
1944
|
};
|
1632
1945
|
}
|
@@ -1641,106 +1954,83 @@ function registerStoreProtocol(item) {
|
|
1641
1954
|
storeFactory.delete(protocol);
|
1642
1955
|
};
|
1643
1956
|
}
|
1644
|
-
function runStoreFactory(url, logger, run) {
|
1645
|
-
const item = storeFactory.get(url.protocol);
|
1646
|
-
if (!item) {
|
1647
|
-
throw logger.Error().Url(url).Str("protocol", url.protocol).Any("keys", Array(storeFactory.keys())).Msg(`unsupported protocol`).AsError();
|
1648
|
-
}
|
1649
|
-
logger.Debug().Str("protocol", url.protocol).Msg("run");
|
1650
|
-
return run(item);
|
1651
|
-
}
|
1652
|
-
var onceLoadDataGateway = new KeyedResolvOnce();
|
1653
|
-
function loadDataGateway(url, logger) {
|
1654
|
-
return onceLoadDataGateway.get(url.protocol).once(async () => {
|
1655
|
-
return runStoreFactory(url, logger, async (item) => item.data(logger));
|
1656
|
-
});
|
1657
|
-
}
|
1658
|
-
var onceDataStoreFactory = new KeyedResolvOnce();
|
1659
1957
|
async function dataStoreFactory(loader) {
|
1660
|
-
const url = buildURL(loader.ebOpts.store.stores?.data, loader);
|
1661
|
-
|
1662
|
-
const
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
}
|
1671
|
-
logger.Debug().Str("prepared", store.url.toString()).Msg("produced");
|
1672
|
-
return store;
|
1673
|
-
});
|
1674
|
-
}
|
1675
|
-
var onceLoadMetaGateway = new KeyedResolvOnce();
|
1676
|
-
function loadMetaGateway(url, logger) {
|
1677
|
-
return onceLoadMetaGateway.get(url.protocol).once(async () => {
|
1678
|
-
return runStoreFactory(url, logger, async (item) => item.meta(logger));
|
1958
|
+
const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.data, loader)).build().setParam("store", "data").URI();
|
1959
|
+
const sthis = ensureSuperLog(loader.sthis, "dataStoreFactory", { url: url.toString() });
|
1960
|
+
const gateway = await getGatewayFromURL(url, sthis);
|
1961
|
+
if (!gateway) {
|
1962
|
+
throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
|
1963
|
+
}
|
1964
|
+
const store = new DataStoreImpl(sthis, loader.name, url, {
|
1965
|
+
gateway: gateway.gateway,
|
1966
|
+
keybag: () => getKeyBag(loader.sthis, {
|
1967
|
+
...loader.ebOpts.keyBag
|
1968
|
+
})
|
1679
1969
|
});
|
1970
|
+
return store;
|
1680
1971
|
}
|
1681
|
-
var onceMetaStoreFactory = new KeyedResolvOnce();
|
1682
1972
|
async function metaStoreFactory(loader) {
|
1683
|
-
const url = buildURL(loader.ebOpts.store.stores?.meta, loader);
|
1684
|
-
|
1685
|
-
|
1686
|
-
url
|
1687
|
-
|
1688
|
-
logger.
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
}
|
1695
|
-
return store;
|
1696
|
-
});
|
1697
|
-
}
|
1698
|
-
var onceWalGateway = new KeyedResolvOnce();
|
1699
|
-
function loadWalGateway(url, logger) {
|
1700
|
-
return onceWalGateway.get(url.protocol).once(async () => {
|
1701
|
-
return runStoreFactory(url, logger, async (item) => item.wal(logger));
|
1973
|
+
const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.meta, loader)).build().setParam("store", "meta").URI();
|
1974
|
+
const sthis = ensureSuperLog(loader.sthis, "metaStoreFactory", { url: () => url.toString() });
|
1975
|
+
sthis.logger.Debug().Str("protocol", url.protocol).Msg("pre-protocol switch");
|
1976
|
+
const gateway = await getGatewayFromURL(url, sthis);
|
1977
|
+
if (!gateway) {
|
1978
|
+
throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
|
1979
|
+
}
|
1980
|
+
const store = new MetaStoreImpl(loader.sthis, loader.name, url, {
|
1981
|
+
gateway: gateway.gateway,
|
1982
|
+
keybag: () => getKeyBag(loader.sthis, {
|
1983
|
+
...loader.ebOpts.keyBag
|
1984
|
+
})
|
1702
1985
|
});
|
1986
|
+
return store;
|
1703
1987
|
}
|
1704
|
-
var onceRemoteWalFactory = new KeyedResolvOnce();
|
1705
1988
|
async function remoteWalFactory(loader) {
|
1706
|
-
const url = buildURL(loader.ebOpts.store.stores?.
|
1707
|
-
|
1708
|
-
const
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
}
|
1718
|
-
return store;
|
1989
|
+
const url = ensureName(loader.name, buildURL(loader.ebOpts.store.stores?.wal, loader)).build().setParam("store", "wal").URI();
|
1990
|
+
const sthis = ensureSuperLog(loader.sthis, "remoteWalFactory", { url: url.toString() });
|
1991
|
+
const gateway = await getGatewayFromURL(url, sthis);
|
1992
|
+
if (!gateway) {
|
1993
|
+
throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
|
1994
|
+
}
|
1995
|
+
sthis.logger.Debug().Str("prepared", url.toString()).Msg("produced");
|
1996
|
+
const store = new WALStoreImpl(loader, url, {
|
1997
|
+
gateway: gateway.gateway,
|
1998
|
+
keybag: () => getKeyBag(loader.sthis, {
|
1999
|
+
...loader.ebOpts.keyBag
|
2000
|
+
})
|
1719
2001
|
});
|
2002
|
+
return store;
|
1720
2003
|
}
|
1721
|
-
async function testStoreFactory(url,
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
return runStoreFactory(url, logger, async (item) => item.test(logger));
|
2004
|
+
async function testStoreFactory(url, sthis) {
|
2005
|
+
sthis = ensureSuperLog(sthis, "testStoreFactory");
|
2006
|
+
const gateway = await getGatewayFromURL(url, sthis);
|
2007
|
+
if (!gateway) {
|
2008
|
+
throw sthis.logger.Error().Url(url).Msg("gateway not found").AsError();
|
2009
|
+
}
|
2010
|
+
return gateway.test;
|
1729
2011
|
}
|
1730
|
-
function
|
1731
|
-
const
|
2012
|
+
async function ensureStart(store, logger) {
|
2013
|
+
const ret = await store.start();
|
2014
|
+
if (ret.isErr()) {
|
2015
|
+
throw logger.Error().Result("start", ret).Msg("start failed").AsError();
|
2016
|
+
}
|
2017
|
+
logger.Debug().Url(ret.Ok(), "prepared").Msg("produced");
|
2018
|
+
return store;
|
2019
|
+
}
|
2020
|
+
function toStoreRuntime(opts, sthis) {
|
2021
|
+
const logger = ensureLogger(sthis, "toStoreRuntime", {});
|
1732
2022
|
return {
|
1733
|
-
makeMetaStore: (loader) => {
|
2023
|
+
makeMetaStore: async (loader) => {
|
1734
2024
|
logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeMetaStore).Msg("makeMetaStore");
|
1735
|
-
return (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader);
|
2025
|
+
return ensureStart(await (loader.ebOpts.store.makeMetaStore || metaStoreFactory)(loader), logger);
|
1736
2026
|
},
|
1737
|
-
makeDataStore: (loader) => {
|
2027
|
+
makeDataStore: async (loader) => {
|
1738
2028
|
logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeDataStore).Msg("makeDataStore");
|
1739
|
-
return (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader);
|
2029
|
+
return ensureStart(await (loader.ebOpts.store.makeDataStore || dataStoreFactory)(loader), logger);
|
1740
2030
|
},
|
1741
|
-
|
1742
|
-
logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.
|
1743
|
-
return (loader.ebOpts.store.
|
2031
|
+
makeWALStore: async (loader) => {
|
2032
|
+
logger.Debug().Str("fromOpts", "" + !!loader.ebOpts.store.makeWALStore).Msg("makeRemoteWAL");
|
2033
|
+
return ensureStart(await (loader.ebOpts.store.makeWALStore || remoteWalFactory)(loader), logger);
|
1744
2034
|
},
|
1745
2035
|
encodeFile: opts.encodeFile || encodeFile,
|
1746
2036
|
decodeFile: opts.decodeFile || decodeFile
|
@@ -1748,43 +2038,200 @@ function toStoreRuntime(opts, ilogger) {
|
|
1748
2038
|
}
|
1749
2039
|
registerStoreProtocol({
|
1750
2040
|
protocol: "file:",
|
1751
|
-
|
1752
|
-
const {
|
1753
|
-
return new
|
1754
|
-
},
|
1755
|
-
meta: async (logger) => {
|
1756
|
-
const { FileMetaGateway } = await import("./store-file-VJ6BI4II.js");
|
1757
|
-
return new FileMetaGateway(logger);
|
1758
|
-
},
|
1759
|
-
wal: async (logger) => {
|
1760
|
-
const { FileWALGateway } = await import("./store-file-VJ6BI4II.js");
|
1761
|
-
return new FileWALGateway(logger);
|
2041
|
+
gateway: async (logger) => {
|
2042
|
+
const { FileGateway } = await import("./gateway-YSNUK2L3.js");
|
2043
|
+
return new FileGateway(logger);
|
1762
2044
|
},
|
1763
2045
|
test: async (logger) => {
|
1764
|
-
const { FileTestStore } = await import("./
|
2046
|
+
const { FileTestStore } = await import("./gateway-YSNUK2L3.js");
|
1765
2047
|
return new FileTestStore(logger);
|
1766
2048
|
}
|
1767
2049
|
});
|
1768
2050
|
registerStoreProtocol({
|
1769
2051
|
protocol: "indexdb:",
|
1770
|
-
|
1771
|
-
const {
|
1772
|
-
return new
|
1773
|
-
},
|
1774
|
-
meta: async (logger) => {
|
1775
|
-
const { IndexDBMetaGateway } = await import("./store-indexdb-WLRSICCB.js");
|
1776
|
-
return new IndexDBMetaGateway(logger);
|
1777
|
-
},
|
1778
|
-
wal: async (logger) => {
|
1779
|
-
const { IndexDBMetaGateway } = await import("./store-indexdb-WLRSICCB.js");
|
1780
|
-
return new IndexDBMetaGateway(logger);
|
2052
|
+
gateway: async (logger) => {
|
2053
|
+
const { IndexDBGateway } = await import("./gateway-IZRHJWPE.js");
|
2054
|
+
return new IndexDBGateway(logger);
|
1781
2055
|
},
|
1782
2056
|
test: async (logger) => {
|
1783
|
-
const { IndexDBTestStore } = await import("./
|
2057
|
+
const { IndexDBTestStore } = await import("./gateway-IZRHJWPE.js");
|
1784
2058
|
return new IndexDBTestStore(logger);
|
1785
2059
|
}
|
1786
2060
|
});
|
1787
2061
|
|
2062
|
+
// src/blockstore/connection-base.ts
|
2063
|
+
import { EventBlock, decodeEventBlock } from "@web3-storage/pail/clock";
|
2064
|
+
import { MemoryBlockstore as MemoryBlockstore2 } from "@web3-storage/pail/block";
|
2065
|
+
|
2066
|
+
// src/blockstore/task-manager.ts
|
2067
|
+
var TaskManager = class {
|
2068
|
+
constructor(loader) {
|
2069
|
+
this.eventsWeHandled = /* @__PURE__ */ new Set();
|
2070
|
+
this.queue = [];
|
2071
|
+
this.isProcessing = false;
|
2072
|
+
this.loader = loader;
|
2073
|
+
this.logger = ensureLogger(loader.sthis, "TaskManager");
|
2074
|
+
}
|
2075
|
+
async handleEvent(eventBlock) {
|
2076
|
+
const cid = eventBlock.cid.toString();
|
2077
|
+
const parents = eventBlock.value.parents.map((cid2) => cid2.toString());
|
2078
|
+
for (const parent of parents) {
|
2079
|
+
this.eventsWeHandled.add(parent);
|
2080
|
+
}
|
2081
|
+
this.queue.push({ cid, eventBlock, retries: 0 });
|
2082
|
+
this.queue = this.queue.filter(({ cid: cid2 }) => !this.eventsWeHandled.has(cid2));
|
2083
|
+
void this.processQueue();
|
2084
|
+
}
|
2085
|
+
async processQueue() {
|
2086
|
+
if (this.isProcessing) return;
|
2087
|
+
this.isProcessing = true;
|
2088
|
+
const filteredQueue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
|
2089
|
+
const first = filteredQueue[0];
|
2090
|
+
if (!first) {
|
2091
|
+
return;
|
2092
|
+
}
|
2093
|
+
try {
|
2094
|
+
this.loader?.remoteMetaStore?.handleByteHeads([first.eventBlock.value.data.dbMeta]);
|
2095
|
+
this.eventsWeHandled.add(first.cid);
|
2096
|
+
this.queue = this.queue.filter(({ cid }) => !this.eventsWeHandled.has(cid));
|
2097
|
+
} catch (err) {
|
2098
|
+
if (first.retries++ > 3) {
|
2099
|
+
this.logger.Error().Str("cid", first.cid).Msg("failed to process event block after 3 retries");
|
2100
|
+
this.queue = this.queue.filter(({ cid }) => cid !== first.cid);
|
2101
|
+
}
|
2102
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
2103
|
+
throw this.logger.Error().Err(err).Msg("failed to process event block").AsError();
|
2104
|
+
} finally {
|
2105
|
+
this.isProcessing = false;
|
2106
|
+
if (this.queue.length > 0) {
|
2107
|
+
void this.processQueue();
|
2108
|
+
}
|
2109
|
+
}
|
2110
|
+
}
|
2111
|
+
};
|
2112
|
+
|
2113
|
+
// src/blockstore/store-remote.ts
|
2114
|
+
async function RemoteDataStore(sthis, name, url, opts) {
|
2115
|
+
const ds = new DataStoreImpl(sthis, name, url, opts);
|
2116
|
+
await ds.start();
|
2117
|
+
return ds;
|
2118
|
+
}
|
2119
|
+
async function RemoteMetaStore(sthis, name, url, opts) {
|
2120
|
+
const ms = new MetaStoreImpl(sthis, name, url, opts);
|
2121
|
+
await ms.start();
|
2122
|
+
return ms;
|
2123
|
+
}
|
2124
|
+
|
2125
|
+
// src/blockstore/connection-base.ts
|
2126
|
+
var ConnectionBase = class {
|
2127
|
+
constructor(url, logger) {
|
2128
|
+
// readonly ready: Promise<unknown>;
|
2129
|
+
// todo move to LRU blockstore https://github.com/web3-storage/w3clock/blob/main/src/worker/block.js
|
2130
|
+
this.eventBlocks = new MemoryBlockstore2();
|
2131
|
+
this.parents = [];
|
2132
|
+
this.loaded = Promise.resolve();
|
2133
|
+
this.logger = logger;
|
2134
|
+
this.url = url;
|
2135
|
+
}
|
2136
|
+
async refresh() {
|
2137
|
+
await throwFalsy(throwFalsy(this.loader).remoteMetaStore).load("main");
|
2138
|
+
await (await throwFalsy(this.loader).WALStore()).process();
|
2139
|
+
}
|
2140
|
+
async connect_X({ loader }) {
|
2141
|
+
if (!loader) throw this.logger.Error().Msg("loader is required").AsError();
|
2142
|
+
await this.connectMeta_X({ loader });
|
2143
|
+
await this.connectStorage_X({ loader });
|
2144
|
+
}
|
2145
|
+
async connectMeta_X({ loader }) {
|
2146
|
+
if (!loader) throw this.logger.Error().Msg("connectMeta_X: loader is required").AsError();
|
2147
|
+
this.loader = loader;
|
2148
|
+
this.taskManager = new TaskManager(loader);
|
2149
|
+
await this.onConnect();
|
2150
|
+
const metaUrl = this.url.build().defParam("store", "meta").URI();
|
2151
|
+
const gateway = await getGatewayFromURL(metaUrl, this.loader.sthis);
|
2152
|
+
if (!gateway) throw this.logger.Error().Url(metaUrl).Msg("connectMeta_X: gateway is required").AsError();
|
2153
|
+
const name = metaUrl.toString();
|
2154
|
+
const remote = await RemoteMetaStore(loader.sthis, name, metaUrl, {
|
2155
|
+
gateway: gateway.gateway,
|
2156
|
+
keybag: () => getKeyBag(loader.sthis, loader.ebOpts.keyBag)
|
2157
|
+
});
|
2158
|
+
remote.onLoad("main", async (metas) => {
|
2159
|
+
if (metas) {
|
2160
|
+
this.logger.Debug().Any("metas", metas).Bool("loader", this.loader).Msg("connectMeta_X: handleDbMetasFromStore pre");
|
2161
|
+
await throwFalsy(this.loader).handleDbMetasFromStore(metas);
|
2162
|
+
this.logger.Debug().Any("metas", metas).Msg("connectMeta_X: handleDbMetasFromStore post");
|
2163
|
+
}
|
2164
|
+
});
|
2165
|
+
this.loader.remoteMetaStore = remote;
|
2166
|
+
this.loaded = this.loader.ready().then(async () => {
|
2167
|
+
remote.load("main").then(async () => {
|
2168
|
+
(await throwFalsy(this.loader).WALStore()).process();
|
2169
|
+
});
|
2170
|
+
});
|
2171
|
+
}
|
2172
|
+
async connectStorage_X({ loader }) {
|
2173
|
+
if (!loader) throw this.logger.Error().Msg("connectStorage_X: loader is required").AsError();
|
2174
|
+
this.loader = loader;
|
2175
|
+
const dataUrl = this.url.build().defParam("store", "data").URI();
|
2176
|
+
const gateway = await getGatewayFromURL(dataUrl, this.loader.sthis);
|
2177
|
+
if (!gateway) throw this.logger.Error().Url(dataUrl).Msg("connectStorage_X: gateway is required").AsError();
|
2178
|
+
const name = dataUrl.toString();
|
2179
|
+
loader.remoteCarStore = await RemoteDataStore(loader.sthis, name, this.url, {
|
2180
|
+
gateway: gateway.gateway,
|
2181
|
+
keybag: () => getKeyBag(loader.sthis, this.loader?.ebOpts.keyBag)
|
2182
|
+
});
|
2183
|
+
loader.remoteFileStore = loader.remoteCarStore;
|
2184
|
+
}
|
2185
|
+
async createEventBlock(bytes) {
|
2186
|
+
const data = {
|
2187
|
+
dbMeta: bytes
|
2188
|
+
};
|
2189
|
+
const event = await EventBlock.create(
|
2190
|
+
data,
|
2191
|
+
this.parents
|
2192
|
+
);
|
2193
|
+
await this.eventBlocks.put(event.cid, event.bytes);
|
2194
|
+
return event;
|
2195
|
+
}
|
2196
|
+
async decodeEventBlock(bytes) {
|
2197
|
+
const event = await decodeEventBlock(bytes);
|
2198
|
+
return event;
|
2199
|
+
}
|
2200
|
+
// move this stuff to connect
|
2201
|
+
// async getDashboardURL(compact = true) {
|
2202
|
+
// const baseUrl = 'https://dashboard.fireproof.storage/'
|
2203
|
+
// if (!this.loader?.remoteCarStore) return new URL('/howto', baseUrl)
|
2204
|
+
// // if (compact) {
|
2205
|
+
// // await this.compact()
|
2206
|
+
// // }
|
2207
|
+
// const currents = await this.loader?.metaStore?.load()
|
2208
|
+
// if (!currents) throw new Error("Can't sync empty database: save data first")
|
2209
|
+
// if (currents.length > 1)
|
2210
|
+
// throw new Error("Can't sync database with split heads: make an update first")
|
2211
|
+
// const current = currents[0]
|
2212
|
+
// const params = {
|
2213
|
+
// car: current.car.toString()
|
2214
|
+
// }
|
2215
|
+
// if (current.key) {
|
2216
|
+
// // @ts-ignore
|
2217
|
+
// params.key = current.key.toString()
|
2218
|
+
// }
|
2219
|
+
// // @ts-ignore
|
2220
|
+
// if (this.name) {
|
2221
|
+
// // @ts-ignore
|
2222
|
+
// params.name = this.name
|
2223
|
+
// }
|
2224
|
+
// const url = new URL('/import#' + new URLSearchParams(params).toString(), baseUrl)
|
2225
|
+
// console.log('Import to dashboard: ' + url.toString())
|
2226
|
+
// return url
|
2227
|
+
// }
|
2228
|
+
// openDashboard() {
|
2229
|
+
// void this.getDashboardURL().then(url => {
|
2230
|
+
// if (url) window.open(url.toString(), '_blank')
|
2231
|
+
// })
|
2232
|
+
// }
|
2233
|
+
};
|
2234
|
+
|
1788
2235
|
// src/crdt-helpers.ts
|
1789
2236
|
function time(tag) {
|
1790
2237
|
}
|
@@ -1833,7 +2280,7 @@ async function writeDocContent(store, blocks, update, logger) {
|
|
1833
2280
|
await processFiles(store, blocks, update.value, logger);
|
1834
2281
|
value = { doc: update.value };
|
1835
2282
|
}
|
1836
|
-
const block = await
|
2283
|
+
const block = await encode({ value, hasher: hasher5, codec });
|
1837
2284
|
blocks.putSync(block.cid, block.bytes);
|
1838
2285
|
return block.cid;
|
1839
2286
|
}
|
@@ -1842,10 +2289,16 @@ async function processFiles(store, blocks, doc, logger) {
|
|
1842
2289
|
await processFileset(logger, store, blocks, doc._files);
|
1843
2290
|
}
|
1844
2291
|
if (doc._publicFiles) {
|
1845
|
-
await processFileset(
|
2292
|
+
await processFileset(
|
2293
|
+
logger,
|
2294
|
+
store,
|
2295
|
+
blocks,
|
2296
|
+
doc._publicFiles
|
2297
|
+
/*, true*/
|
2298
|
+
);
|
1846
2299
|
}
|
1847
2300
|
}
|
1848
|
-
async function processFileset(logger, store, blocks, files
|
2301
|
+
async function processFileset(logger, store, blocks, files) {
|
1849
2302
|
const dbBlockstore = blocks.parent;
|
1850
2303
|
if (!dbBlockstore.loader) throw logger.Error().Msg("Missing loader, database name is required").AsError();
|
1851
2304
|
const t = new CarTransaction(dbBlockstore);
|
@@ -1867,9 +2320,10 @@ async function processFileset(logger, store, blocks, files, publicFiles = false)
|
|
1867
2320
|
}
|
1868
2321
|
}
|
1869
2322
|
if (didPut.length) {
|
1870
|
-
const car = await dbBlockstore.loader.commitFiles(
|
1871
|
-
|
1872
|
-
|
2323
|
+
const car = await dbBlockstore.loader.commitFiles(
|
2324
|
+
t,
|
2325
|
+
{ files }
|
2326
|
+
);
|
1873
2327
|
if (car) {
|
1874
2328
|
for (const name of didPut) {
|
1875
2329
|
files[name] = { car, ...files[name] };
|
@@ -1903,7 +2357,7 @@ function readFileset(blocks, files, isPublic = false) {
|
|
1903
2357
|
fileMeta.file = async () => await blocks.ebOpts.storeRuntime.decodeFile(
|
1904
2358
|
{
|
1905
2359
|
get: async (cid) => {
|
1906
|
-
return await blocks.getFile(throwFalsy(fileMeta.car), cid
|
2360
|
+
return await blocks.getFile(throwFalsy(fileMeta.car), cid);
|
1907
2361
|
}
|
1908
2362
|
},
|
1909
2363
|
fileMeta.cid,
|
@@ -1917,7 +2371,7 @@ function readFileset(blocks, files, isPublic = false) {
|
|
1917
2371
|
async function getValueFromLink(blocks, link, logger) {
|
1918
2372
|
const block = await blocks.get(link);
|
1919
2373
|
if (!block) throw logger.Error().Str("link", link.toString()).Msg(`Missing linked block`).AsError();
|
1920
|
-
const { value } = await
|
2374
|
+
const { value } = await decode({ bytes: block.bytes, hasher: hasher5, codec });
|
1921
2375
|
const cvalue = {
|
1922
2376
|
...value,
|
1923
2377
|
cid: link
|
@@ -1926,17 +2380,21 @@ async function getValueFromLink(blocks, link, logger) {
|
|
1926
2380
|
return cvalue;
|
1927
2381
|
}
|
1928
2382
|
var DirtyEventFetcher = class extends EventFetcher {
|
2383
|
+
constructor(logger, blocks) {
|
2384
|
+
super(blocks);
|
2385
|
+
this.logger = logger;
|
2386
|
+
}
|
1929
2387
|
async get(link) {
|
1930
2388
|
try {
|
1931
2389
|
return super.get(link);
|
1932
2390
|
} catch (e) {
|
1933
|
-
|
2391
|
+
this.logger.Error().Ref("link", link.toString()).Err(e).Msg("Missing event");
|
1934
2392
|
return { value: void 0 };
|
1935
2393
|
}
|
1936
2394
|
}
|
1937
2395
|
};
|
1938
2396
|
async function clockChangesSince(blocks, head, since, opts, logger) {
|
1939
|
-
const eventsFetcher = opts.dirty ? new DirtyEventFetcher(blocks) : new EventFetcher(blocks);
|
2397
|
+
const eventsFetcher = opts.dirty ? new DirtyEventFetcher(logger, blocks) : new EventFetcher(blocks);
|
1940
2398
|
const keys = /* @__PURE__ */ new Set();
|
1941
2399
|
const updates = await gatherUpdates(
|
1942
2400
|
blocks,
|
@@ -2034,18 +2492,17 @@ async function doCompact(blockLog, head, logger) {
|
|
2034
2492
|
async function getBlock(blocks, cidString) {
|
2035
2493
|
const block = await blocks.get(parse2(cidString));
|
2036
2494
|
if (!block) throw new Error(`Missing block ${cidString}`);
|
2037
|
-
const { cid, value } = await
|
2038
|
-
return new
|
2495
|
+
const { cid, value } = await decode({ bytes: block.bytes, codec, hasher: hasher5 });
|
2496
|
+
return new Block({ cid, value, bytes: block.bytes });
|
2039
2497
|
}
|
2040
2498
|
|
2041
2499
|
// src/indexer-helpers.ts
|
2042
|
-
import {
|
2043
|
-
import
|
2044
|
-
import * as codec3 from "@ipld/dag-cbor";
|
2500
|
+
import { sha256 as hasher6 } from "multiformats/hashes/sha2";
|
2501
|
+
import * as codec2 from "@ipld/dag-cbor";
|
2045
2502
|
import charwise from "charwise";
|
2046
2503
|
import * as DbIndex from "prolly-trees/db-index";
|
2047
|
-
import { bf
|
2048
|
-
import { nocache as
|
2504
|
+
import { bf, simpleCompare } from "prolly-trees/utils";
|
2505
|
+
import { nocache as cache } from "prolly-trees/cache";
|
2049
2506
|
var IndexTree = class {
|
2050
2507
|
};
|
2051
2508
|
function refCompare(aRef, bRef) {
|
@@ -2061,8 +2518,8 @@ function compare(a, b) {
|
|
2061
2518
|
if (comp !== 0) return comp;
|
2062
2519
|
return refCompare(aRef, bRef);
|
2063
2520
|
}
|
2064
|
-
var byKeyOpts = { cache
|
2065
|
-
var byIdOpts = { cache
|
2521
|
+
var byKeyOpts = { cache, chunker: bf(30), codec: codec2, hasher: hasher6, compare };
|
2522
|
+
var byIdOpts = { cache, chunker: bf(30), codec: codec2, hasher: hasher6, compare: simpleCompare };
|
2066
2523
|
function indexEntriesForChanges(changes, mapFn) {
|
2067
2524
|
const indexEntries = [];
|
2068
2525
|
changes.forEach(({ id: key, value, del }) => {
|
@@ -2090,7 +2547,7 @@ function makeProllyGetBlock(blocks) {
|
|
2090
2547
|
const block = await blocks.get(address);
|
2091
2548
|
if (!block) throw new Error(`Missing block ${address.toString()}`);
|
2092
2549
|
const { cid, bytes } = block;
|
2093
|
-
return
|
2550
|
+
return create({ cid, bytes, hasher: hasher6, codec: codec2 });
|
2094
2551
|
};
|
2095
2552
|
}
|
2096
2553
|
async function bulkIndex(tblocks, inIndex, indexEntries, opts) {
|
@@ -2161,25 +2618,25 @@ function encodeKey(key) {
|
|
2161
2618
|
}
|
2162
2619
|
|
2163
2620
|
// src/indexer.ts
|
2164
|
-
function index({ _crdt }, name, mapFn, meta) {
|
2621
|
+
function index(sthis, { _crdt }, name, mapFn, meta) {
|
2165
2622
|
if (mapFn && meta) throw _crdt.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
|
2166
2623
|
if (mapFn && mapFn.constructor.name !== "Function") throw _crdt.logger.Error().Msg("mapFn must be a function").AsError();
|
2167
2624
|
if (_crdt.indexers.has(name)) {
|
2168
2625
|
const idx = _crdt.indexers.get(name);
|
2169
2626
|
idx.applyMapFn(name, mapFn, meta);
|
2170
2627
|
} else {
|
2171
|
-
const idx = new Index(_crdt, name, mapFn, meta);
|
2628
|
+
const idx = new Index(sthis, _crdt, name, mapFn, meta);
|
2172
2629
|
_crdt.indexers.set(name, idx);
|
2173
2630
|
}
|
2174
2631
|
return _crdt.indexers.get(name);
|
2175
2632
|
}
|
2176
2633
|
var Index = class {
|
2177
|
-
constructor(crdt, name, mapFn, meta) {
|
2634
|
+
constructor(sthis, crdt, name, mapFn, meta) {
|
2178
2635
|
this.mapFnString = "";
|
2179
2636
|
this.byKey = new IndexTree();
|
2180
2637
|
this.byId = new IndexTree();
|
2181
2638
|
this.includeDocsDefault = false;
|
2182
|
-
this.logger = ensureLogger(
|
2639
|
+
this.logger = ensureLogger(sthis, "Index");
|
2183
2640
|
this.blockstore = crdt.indexBlockstore;
|
2184
2641
|
this.crdt = crdt;
|
2185
2642
|
this.applyMapFn(name, mapFn, meta);
|
@@ -2234,7 +2691,7 @@ var Index = class {
|
|
2234
2691
|
}
|
2235
2692
|
if (this.mapFnString) {
|
2236
2693
|
if (this.mapFnString !== mapFn.toString()) {
|
2237
|
-
throw this.logger.Error().Msg("cannot apply different mapFn app").AsError();
|
2694
|
+
throw this.logger.Error().Str("mapFnString", this.mapFnString).Str("mapFn", mapFn.toString()).Msg("cannot apply different mapFn app").AsError();
|
2238
2695
|
}
|
2239
2696
|
} else {
|
2240
2697
|
this.mapFnString = mapFn.toString();
|
@@ -2428,7 +2885,7 @@ var CRDTClock = class {
|
|
2428
2885
|
this.emptyWatchers = /* @__PURE__ */ new Set();
|
2429
2886
|
this._ready = new ResolveOnce3();
|
2430
2887
|
this.blockstore = blockstore;
|
2431
|
-
this.logger = ensureLogger(blockstore.
|
2888
|
+
this.logger = ensureLogger(blockstore.sthis, "CRDTClock");
|
2432
2889
|
this.applyHeadQueue = applyHeadQueue(this.int_applyHead.bind(this), this.logger);
|
2433
2890
|
}
|
2434
2891
|
async ready() {
|
@@ -2501,7 +2958,7 @@ var CRDTClock = class {
|
|
2501
2958
|
}
|
2502
2959
|
return { head: advancedHead };
|
2503
2960
|
},
|
2504
|
-
{ noLoader }
|
2961
|
+
{ noLoader, add: false }
|
2505
2962
|
);
|
2506
2963
|
this.setHead(meta.head);
|
2507
2964
|
}
|
@@ -2535,13 +2992,14 @@ async function advanceBlocks(logger, newHead, tblocks, head) {
|
|
2535
2992
|
|
2536
2993
|
// src/crdt.ts
|
2537
2994
|
var CRDT = class {
|
2538
|
-
constructor(name, opts = {}) {
|
2539
|
-
this.onceReady = new ResolveOnce4();
|
2995
|
+
constructor(sthis, name, opts = {}) {
|
2540
2996
|
this.indexers = /* @__PURE__ */ new Map();
|
2997
|
+
this.onceReady = new ResolveOnce4();
|
2998
|
+
this.sthis = sthis;
|
2541
2999
|
this.name = name;
|
2542
|
-
this.logger = ensureLogger(
|
3000
|
+
this.logger = ensureLogger(sthis, "CRDT");
|
2543
3001
|
this.opts = opts;
|
2544
|
-
this.blockstore = blockstoreFactory({
|
3002
|
+
this.blockstore = blockstoreFactory(sthis, {
|
2545
3003
|
name,
|
2546
3004
|
applyMeta: async (meta) => {
|
2547
3005
|
const crdtMeta = meta;
|
@@ -2553,22 +3011,20 @@ var CRDT = class {
|
|
2553
3011
|
return { head: this.clock.head };
|
2554
3012
|
},
|
2555
3013
|
autoCompact: this.opts.autoCompact || 100,
|
2556
|
-
crypto: this.opts.crypto,
|
2557
3014
|
store: { ...this.opts.store, isIndex: void 0 },
|
2558
3015
|
public: this.opts.public,
|
2559
3016
|
meta: this.opts.meta,
|
2560
3017
|
threshold: this.opts.threshold
|
2561
3018
|
});
|
2562
|
-
this.indexBlockstore = blockstoreFactory({
|
3019
|
+
this.indexBlockstore = blockstoreFactory(sthis, {
|
2563
3020
|
name,
|
2564
3021
|
applyMeta: async (meta) => {
|
2565
3022
|
const idxCarMeta = meta;
|
2566
3023
|
if (!idxCarMeta.indexes) throw this.logger.Error().Msg("missing indexes").AsError();
|
2567
3024
|
for (const [name2, idx] of Object.entries(idxCarMeta.indexes)) {
|
2568
|
-
index({ _crdt: this }, name2, void 0, idx);
|
3025
|
+
index(this.sthis, { _crdt: this }, name2, void 0, idx);
|
2569
3026
|
}
|
2570
3027
|
},
|
2571
|
-
crypto: this.opts.crypto,
|
2572
3028
|
store: { ...this.opts.store, isIndex: this.opts.store?.isIndex || "idx" },
|
2573
3029
|
public: this.opts.public
|
2574
3030
|
});
|
@@ -2579,17 +3035,6 @@ var CRDT = class {
|
|
2579
3035
|
}
|
2580
3036
|
});
|
2581
3037
|
}
|
2582
|
-
async ready() {
|
2583
|
-
return this.onceReady.once(async () => {
|
2584
|
-
await Promise.all([this.blockstore.ready(), this.indexBlockstore.ready(), this.clock.ready()]);
|
2585
|
-
});
|
2586
|
-
}
|
2587
|
-
async close() {
|
2588
|
-
await Promise.all([this.blockstore.close(), this.indexBlockstore.close(), this.clock.close()]);
|
2589
|
-
}
|
2590
|
-
async destroy() {
|
2591
|
-
await Promise.all([this.blockstore.destroy(), this.indexBlockstore.destroy()]);
|
2592
|
-
}
|
2593
3038
|
async bulk(updates) {
|
2594
3039
|
await this.ready();
|
2595
3040
|
const prevHead = [...this.clock.head];
|
@@ -2610,6 +3055,21 @@ var CRDT = class {
|
|
2610
3055
|
await this.clock.applyHead(done.meta.head, prevHead, updates);
|
2611
3056
|
return done.meta;
|
2612
3057
|
}
|
3058
|
+
async ready() {
|
3059
|
+
return this.onceReady.once(async () => {
|
3060
|
+
try {
|
3061
|
+
await Promise.all([this.blockstore.ready(), this.indexBlockstore.ready(), this.clock.ready()]);
|
3062
|
+
} catch (e) {
|
3063
|
+
throw this.logger.Error().Err(e).Msg("CRDT not ready").AsError();
|
3064
|
+
}
|
3065
|
+
});
|
3066
|
+
}
|
3067
|
+
async close() {
|
3068
|
+
await Promise.all([this.blockstore.close(), this.indexBlockstore.close(), this.clock.close()]);
|
3069
|
+
}
|
3070
|
+
async destroy() {
|
3071
|
+
await Promise.all([this.blockstore.destroy(), this.indexBlockstore.destroy()]);
|
3072
|
+
}
|
2613
3073
|
// if (snap) await this.clock.applyHead(crdtMeta.head, this.clock.head)
|
2614
3074
|
async allDocs() {
|
2615
3075
|
await this.ready();
|
@@ -2657,8 +3117,9 @@ var Database = class {
|
|
2657
3117
|
this._ready = new ResolveOnce5();
|
2658
3118
|
this.name = name;
|
2659
3119
|
this.opts = opts || this.opts;
|
2660
|
-
this.
|
2661
|
-
this.
|
3120
|
+
this.sthis = ensureSuperThis(this.opts);
|
3121
|
+
this.logger = ensureLogger(this.sthis, "Database");
|
3122
|
+
this._crdt = new CRDT(this.sthis, name, this.opts);
|
2662
3123
|
this.blockstore = this._crdt.blockstore;
|
2663
3124
|
this._writeQueue = writeQueue(async (updates) => {
|
2664
3125
|
return await this._crdt.bulk(updates);
|
@@ -2682,7 +3143,7 @@ var Database = class {
|
|
2682
3143
|
}
|
2683
3144
|
async ready() {
|
2684
3145
|
return this._ready.once(async () => {
|
2685
|
-
await
|
3146
|
+
await this.sthis.start();
|
2686
3147
|
await this._crdt.ready();
|
2687
3148
|
await this.blockstore.ready();
|
2688
3149
|
});
|
@@ -2702,7 +3163,7 @@ var Database = class {
|
|
2702
3163
|
await this.ready();
|
2703
3164
|
this.logger.Debug().Str("id", doc._id).Msg("put");
|
2704
3165
|
const { _id, ...value } = doc;
|
2705
|
-
const docId = _id ||
|
3166
|
+
const docId = _id || this.sthis.nextId().str;
|
2706
3167
|
const result = await this._writeQueue.push({
|
2707
3168
|
id: docId,
|
2708
3169
|
value: {
|
@@ -2767,7 +3228,7 @@ var Database = class {
|
|
2767
3228
|
await this.ready();
|
2768
3229
|
this.logger.Debug().Any("field", field).Any("opts", opts).Msg("query");
|
2769
3230
|
const _crdt = this._crdt;
|
2770
|
-
const idx = typeof field === "string" ? index({ _crdt }, field) : index({ _crdt }, makeName(field.toString()), field);
|
3231
|
+
const idx = typeof field === "string" ? index(this.sthis, { _crdt }, field) : index(this.sthis, { _crdt }, makeName(field.toString()), field);
|
2771
3232
|
return await idx.query(opts);
|
2772
3233
|
}
|
2773
3234
|
async compact() {
|
@@ -2804,12 +3265,7 @@ function fireproof(name, opts) {
|
|
2804
3265
|
const key = JSON.stringify(
|
2805
3266
|
toSortedArray({
|
2806
3267
|
name,
|
2807
|
-
stores: toSortedArray(opts?.store?.stores)
|
2808
|
-
makeMetaStore: !!opts?.store?.makeMetaStore,
|
2809
|
-
makeDataStore: !!opts?.store?.makeDataStore,
|
2810
|
-
makeRemoteWAL: !!opts?.store?.makeRemoteWAL,
|
2811
|
-
encodeFile: !!opts?.store?.encodeFile,
|
2812
|
-
decodeFile: !!opts?.store?.decodeFile
|
3268
|
+
stores: toSortedArray(opts?.store?.stores)
|
2813
3269
|
})
|
2814
3270
|
);
|
2815
3271
|
let db = Database.databases.get(key);
|
@@ -2824,7 +3280,10 @@ function makeName(fnString) {
|
|
2824
3280
|
let found = null;
|
2825
3281
|
const matches = Array.from(fnString.matchAll(regex), (match) => match[1].trim());
|
2826
3282
|
if (matches.length === 0) {
|
2827
|
-
found = /=>\s*(
|
3283
|
+
found = /=>\s*{?\s*([^{}]+)\s*}?/.exec(fnString);
|
3284
|
+
if (found && found[1].includes("return")) {
|
3285
|
+
found = null;
|
3286
|
+
}
|
2828
3287
|
}
|
2829
3288
|
if (!found) {
|
2830
3289
|
return fnString;
|
@@ -2833,19 +3292,49 @@ function makeName(fnString) {
|
|
2833
3292
|
}
|
2834
3293
|
}
|
2835
3294
|
|
3295
|
+
// src/runtime/index.ts
|
3296
|
+
var runtime_exports = {};
|
3297
|
+
__export(runtime_exports, {
|
3298
|
+
FILESTORE_VERSION: () => FILESTORE_VERSION,
|
3299
|
+
INDEXDB_VERSION: () => INDEXDB_VERSION,
|
3300
|
+
files: () => files_exports,
|
3301
|
+
getFileName: () => getFileName,
|
3302
|
+
getFileSystem: () => getFileSystem,
|
3303
|
+
getPath: () => getPath,
|
3304
|
+
kb: () => key_bag_exports,
|
3305
|
+
kc: () => keyed_crypto_exports,
|
3306
|
+
mf: () => wait_pr_multiformats_exports,
|
3307
|
+
toArrayBuffer: () => toArrayBuffer
|
3308
|
+
});
|
3309
|
+
|
3310
|
+
// src/runtime/wait-pr-multiformats/index.ts
|
3311
|
+
var wait_pr_multiformats_exports = {};
|
3312
|
+
__export(wait_pr_multiformats_exports, {
|
3313
|
+
block: () => block_exports,
|
3314
|
+
codec: () => codec_interface_exports
|
3315
|
+
});
|
3316
|
+
|
3317
|
+
// src/runtime/wait-pr-multiformats/codec-interface.ts
|
3318
|
+
var codec_interface_exports = {};
|
3319
|
+
|
2836
3320
|
// src/version.ts
|
2837
3321
|
var PACKAGE_VERSION = Object.keys({
|
2838
|
-
"0.19.
|
3322
|
+
"0.19.9-dev-frag": "xxxx"
|
2839
3323
|
})[0];
|
2840
3324
|
export {
|
2841
3325
|
CRDT,
|
2842
3326
|
Database,
|
2843
3327
|
Index,
|
3328
|
+
NotFoundError,
|
2844
3329
|
PACKAGE_VERSION,
|
2845
3330
|
Result,
|
3331
|
+
UInt8ArrayEqual,
|
2846
3332
|
blockstore_exports as blockstore,
|
2847
3333
|
blockstore_exports as bs,
|
3334
|
+
dataDir,
|
2848
3335
|
ensureLogger,
|
3336
|
+
ensureSuperLog,
|
3337
|
+
ensureSuperThis,
|
2849
3338
|
exception2Result,
|
2850
3339
|
exceptionWrapper,
|
2851
3340
|
falsyToUndef,
|
@@ -2855,6 +3344,7 @@ export {
|
|
2855
3344
|
getStore,
|
2856
3345
|
index,
|
2857
3346
|
isFalsy,
|
3347
|
+
isNotFoundError,
|
2858
3348
|
runtime_exports as rt,
|
2859
3349
|
runtime_exports as runtime,
|
2860
3350
|
throwFalsy
|