@freqhole/reliquary 0.2.15 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/worker/blob-worker-client.d.ts +19 -0
- package/dist/worker/blob-worker-client.d.ts.map +1 -1
- package/dist/worker/blob-worker-client.js +54 -1
- package/dist/worker/blob-worker-client.test.js +9 -1
- package/dist/worker/blob-worker-logic.d.ts +12 -0
- package/dist/worker/blob-worker-logic.d.ts.map +1 -1
- package/dist/worker/blob-worker-logic.js +52 -0
- package/dist/worker/blob-worker-logic.test.js +19 -2
- package/dist/worker/blob-worker.d.ts +5 -1
- package/dist/worker/blob-worker.d.ts.map +1 -1
- package/dist/worker/blob-worker.js +5 -1
- package/dist/worker/index.d.ts +2 -2
- package/dist/worker/index.d.ts.map +1 -1
- package/dist/worker/index.js +1 -1
- package/package.json +4 -4
|
@@ -89,6 +89,25 @@ export declare function streamFileToOpfs(file: File, options?: {
|
|
|
89
89
|
blake3: string;
|
|
90
90
|
size: number;
|
|
91
91
|
}>;
|
|
92
|
+
/**
|
|
93
|
+
* hash a File with blake3, streaming it in chunks so the whole payload is
|
|
94
|
+
* never materialized in memory at once - unlike `hashBlake3`, which needs
|
|
95
|
+
* a full `Uint8Array` up front (typically built via `file.arrayBuffer()`,
|
|
96
|
+
* a real crash risk for multi-gigabyte files). unlike `streamFileToOpfs`,
|
|
97
|
+
* this has no OPFS write side at all: use it when the caller already has
|
|
98
|
+
* its own on-disk storage path and just needs the hash.
|
|
99
|
+
*
|
|
100
|
+
* `onProgress` reports bytes hashed / file size (0..1) per chunk.
|
|
101
|
+
* `signal` cancels between chunks: the worker session is freed and a
|
|
102
|
+
* DOMException AbortError is thrown.
|
|
103
|
+
*
|
|
104
|
+
* falls back to the one-shot `hashBlake3` (whole-file read) when no
|
|
105
|
+
* worker is available (e.g. SSR / certain test runners).
|
|
106
|
+
*/
|
|
107
|
+
export declare function hashBlake3Streaming(file: File, options?: {
|
|
108
|
+
onProgress?: (fraction: number) => void;
|
|
109
|
+
signal?: AbortSignal;
|
|
110
|
+
}): Promise<string>;
|
|
92
111
|
export interface ResizeImageOptions {
|
|
93
112
|
maxWidth?: number;
|
|
94
113
|
maxHeight?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob-worker-client.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-client.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAsBtD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,CAuDnF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;
|
|
1
|
+
{"version":3,"file":"blob-worker-client.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-client.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAsBtD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,CAuDnF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAoCD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIlE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAInE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAIvE;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAkBD;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC1E,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkC3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC1E,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;iFAG6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,SAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOhG;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAQnE"}
|
|
@@ -182,7 +182,10 @@ export async function processBlobBytes(buffer, filename, mime) {
|
|
|
182
182
|
return worker.processBlobBytes(Comlink.transfer(buffer, [buffer]), filename, mime);
|
|
183
183
|
}
|
|
184
184
|
// main-thread fallback path - rare, mostly for tests.
|
|
185
|
-
const [sha256, blake3] = await Promise.all([
|
|
185
|
+
const [sha256, blake3] = await Promise.all([
|
|
186
|
+
sha256Hex(buffer),
|
|
187
|
+
fallbackHashBlake3(new Uint8Array(buffer)),
|
|
188
|
+
]);
|
|
186
189
|
return {
|
|
187
190
|
blob_id: blake3,
|
|
188
191
|
sha256,
|
|
@@ -263,6 +266,56 @@ export async function streamFileToOpfs(file, options) {
|
|
|
263
266
|
reader.releaseLock();
|
|
264
267
|
}
|
|
265
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* hash a File with blake3, streaming it in chunks so the whole payload is
|
|
271
|
+
* never materialized in memory at once - unlike `hashBlake3`, which needs
|
|
272
|
+
* a full `Uint8Array` up front (typically built via `file.arrayBuffer()`,
|
|
273
|
+
* a real crash risk for multi-gigabyte files). unlike `streamFileToOpfs`,
|
|
274
|
+
* this has no OPFS write side at all: use it when the caller already has
|
|
275
|
+
* its own on-disk storage path and just needs the hash.
|
|
276
|
+
*
|
|
277
|
+
* `onProgress` reports bytes hashed / file size (0..1) per chunk.
|
|
278
|
+
* `signal` cancels between chunks: the worker session is freed and a
|
|
279
|
+
* DOMException AbortError is thrown.
|
|
280
|
+
*
|
|
281
|
+
* falls back to the one-shot `hashBlake3` (whole-file read) when no
|
|
282
|
+
* worker is available (e.g. SSR / certain test runners).
|
|
283
|
+
*/
|
|
284
|
+
export async function hashBlake3Streaming(file, options) {
|
|
285
|
+
const worker = await getBlobWorker();
|
|
286
|
+
if (!worker)
|
|
287
|
+
return fallbackHashBlake3(new Uint8Array(await file.arrayBuffer()));
|
|
288
|
+
const sessionId = await worker.hashBegin();
|
|
289
|
+
const reader = file.stream().getReader();
|
|
290
|
+
let bytesHashed = 0;
|
|
291
|
+
try {
|
|
292
|
+
for (;;) {
|
|
293
|
+
if (options?.signal?.aborted) {
|
|
294
|
+
throw new DOMException("hash cancelled", "AbortError");
|
|
295
|
+
}
|
|
296
|
+
const { done, value } = await reader.read();
|
|
297
|
+
if (done)
|
|
298
|
+
break;
|
|
299
|
+
const exact = value.byteOffset === 0 && value.byteLength === value.buffer.byteLength
|
|
300
|
+
? value.buffer
|
|
301
|
+
: value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
|
|
302
|
+
const chunkLen = value.byteLength;
|
|
303
|
+
await worker.hashPush(sessionId, Comlink.transfer(exact, [exact]));
|
|
304
|
+
bytesHashed += chunkLen;
|
|
305
|
+
if (options?.onProgress && file.size > 0) {
|
|
306
|
+
options.onProgress(Math.min(1, bytesHashed / file.size));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return await worker.hashFinish(sessionId);
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
await worker.hashAbort(sessionId).catch(() => { });
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
reader.releaseLock();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
266
319
|
/**
|
|
267
320
|
* resize an image Blob to a (default WebP) data URL.
|
|
268
321
|
* prefers the blob worker (keeps the decode/encode work off the main
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import { base64Decode, base64Encode, generateThumbnailDataUrl, getBlobWorker, hashBlake3, hashSha256, processBlobBytes, resizeImageToWebpDataUrl, shutdownBlobWorker, streamFileToOpfs, writeBlobToOpfs, } from "./blob-worker-client.js";
|
|
3
|
+
import { base64Decode, base64Encode, generateThumbnailDataUrl, getBlobWorker, hashBlake3, hashBlake3Streaming, hashSha256, processBlobBytes, resizeImageToWebpDataUrl, shutdownBlobWorker, streamFileToOpfs, writeBlobToOpfs, } from "./blob-worker-client.js";
|
|
4
4
|
import { resetMiddenBlake3Cache } from "./midden-blake3.js";
|
|
5
5
|
import { log } from "../utils/log.js";
|
|
6
6
|
// this test environment has no `Worker` global, so every helper below
|
|
@@ -120,6 +120,14 @@ describe("streamFileToOpfs", () => {
|
|
|
120
120
|
await expect(streamFileToOpfs(file)).rejects.toThrow(/no blob worker/);
|
|
121
121
|
});
|
|
122
122
|
});
|
|
123
|
+
describe("hashBlake3Streaming", () => {
|
|
124
|
+
it("falls back to the one-shot hashBlake3 path when no worker is available", async () => {
|
|
125
|
+
const file = new File(["hello"], "hello.txt", { type: "text/plain" });
|
|
126
|
+
// no worker, no midden module in this test env - degrades to "",
|
|
127
|
+
// same as the one-shot hashBlake3 fallback.
|
|
128
|
+
expect(await hashBlake3Streaming(file)).toBe("");
|
|
129
|
+
});
|
|
130
|
+
});
|
|
123
131
|
describe("resizeImageToWebpDataUrl", () => {
|
|
124
132
|
it("uses the main-thread fallback and returns a data url", async () => {
|
|
125
133
|
installCanvasFakes();
|
|
@@ -108,6 +108,18 @@ export declare function uploadFinish(id: number): Promise<{
|
|
|
108
108
|
}>;
|
|
109
109
|
/** abort a session: close and delete the temp file. */
|
|
110
110
|
export declare function uploadAbort(id: number): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* begin a streaming hash-only session. throws when the environment can't
|
|
113
|
+
* support it (no midden module with a Blake3Hasher bundled) - callers
|
|
114
|
+
* fall back to the one-shot `hashBlake3`.
|
|
115
|
+
*/
|
|
116
|
+
export declare function hashBegin(): Promise<number>;
|
|
117
|
+
/** feed the next chunk (transferred buffer) into a hash session. */
|
|
118
|
+
export declare function hashPush(id: number, buffer: ArrayBuffer): Promise<void>;
|
|
119
|
+
/** finish a session, returning the final blake3 hash. */
|
|
120
|
+
export declare function hashFinish(id: number): Promise<string>;
|
|
121
|
+
/** abort a session, freeing the hasher without finalizing. */
|
|
122
|
+
export declare function hashAbort(id: number): Promise<void>;
|
|
111
123
|
/**
|
|
112
124
|
* opfs-store selftest - runs the embedding app's midden module's
|
|
113
125
|
* out-of-crate iroh-blobs store round trip against real OPFS. must run in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob-worker-logic.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-logic.ts"],"names":[],"mappings":"AAqBA;oEACoE;AACpE,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D;;;qCAGqC;AACrC,eAAO,MAAM,QAAQ,oBAAoB,CAAC;AAE1C;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"blob-worker-logic.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -358,6 +358,58 @@ export async function uploadAbort(id) {
|
|
|
358
358
|
const dir = await getOpfsDir(false);
|
|
359
359
|
await dir?.removeEntry(session.tmpName).catch(() => { });
|
|
360
360
|
}
|
|
361
|
+
// ---- streaming hash-only sessions -----------------------------------------
|
|
362
|
+
// same incremental Blake3Hasher as the upload sessions above, but with no
|
|
363
|
+
// OPFS write side at all - for callers that already have their own on-disk
|
|
364
|
+
// storage path (e.g. spume's video import, which writes to its own OPFS
|
|
365
|
+
// directory) and just need a blake3 without materializing the whole file
|
|
366
|
+
// in memory, and without a second on-disk copy under this package's own
|
|
367
|
+
// content-addressed OPFS_DIR.
|
|
368
|
+
const hashSessions = new Map();
|
|
369
|
+
let nextHashSessionId = 1;
|
|
370
|
+
/**
|
|
371
|
+
* begin a streaming hash-only session. throws when the environment can't
|
|
372
|
+
* support it (no midden module with a Blake3Hasher bundled) - callers
|
|
373
|
+
* fall back to the one-shot `hashBlake3`.
|
|
374
|
+
*/
|
|
375
|
+
export async function hashBegin() {
|
|
376
|
+
const midden = await loadMiddenBlake3();
|
|
377
|
+
const Blake3HasherCtor = midden?.Blake3Hasher;
|
|
378
|
+
if (typeof Blake3HasherCtor !== "function") {
|
|
379
|
+
throw new Error("streaming hash unavailable: midden Blake3Hasher missing");
|
|
380
|
+
}
|
|
381
|
+
const id = nextHashSessionId++;
|
|
382
|
+
hashSessions.set(id, new Blake3HasherCtor());
|
|
383
|
+
return id;
|
|
384
|
+
}
|
|
385
|
+
/** feed the next chunk (transferred buffer) into a hash session. */
|
|
386
|
+
export async function hashPush(id, buffer) {
|
|
387
|
+
const hasher = hashSessions.get(id);
|
|
388
|
+
if (!hasher)
|
|
389
|
+
throw new Error(`unknown hash session ${id}`);
|
|
390
|
+
hasher.update(new Uint8Array(buffer));
|
|
391
|
+
}
|
|
392
|
+
/** finish a session, returning the final blake3 hash. */
|
|
393
|
+
export async function hashFinish(id) {
|
|
394
|
+
const hasher = hashSessions.get(id);
|
|
395
|
+
if (!hasher)
|
|
396
|
+
throw new Error(`unknown hash session ${id}`);
|
|
397
|
+
hashSessions.delete(id);
|
|
398
|
+
try {
|
|
399
|
+
return hasher.finalize();
|
|
400
|
+
}
|
|
401
|
+
finally {
|
|
402
|
+
hasher.free();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
/** abort a session, freeing the hasher without finalizing. */
|
|
406
|
+
export async function hashAbort(id) {
|
|
407
|
+
const hasher = hashSessions.get(id);
|
|
408
|
+
if (!hasher)
|
|
409
|
+
return;
|
|
410
|
+
hashSessions.delete(id);
|
|
411
|
+
hasher.free();
|
|
412
|
+
}
|
|
361
413
|
/**
|
|
362
414
|
* opfs-store selftest - runs the embedding app's midden module's
|
|
363
415
|
* out-of-crate iroh-blobs store round trip against real OPFS. must run in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
-
import { base64Decode, base64Encode, generateThumbnailDataUrl, hashBlake3, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadBegin, writeBlobToOpfs, } from "./blob-worker-logic.js";
|
|
3
|
+
import { base64Decode, base64Encode, generateThumbnailDataUrl, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadBegin, writeBlobToOpfs, } from "./blob-worker-logic.js";
|
|
4
4
|
import { resetMiddenBlake3Cache } from "./midden-blake3.js";
|
|
5
5
|
// ---- fake OPFS (async writable-stream fallback path only - sync access
|
|
6
6
|
// handles are worker/chromium-specific and not worth faking here; the
|
|
@@ -11,7 +11,10 @@ class FakeWritable {
|
|
|
11
11
|
this.file = file;
|
|
12
12
|
}
|
|
13
13
|
async write(data) {
|
|
14
|
-
this.file.bytes =
|
|
14
|
+
this.file.bytes =
|
|
15
|
+
data instanceof ArrayBuffer
|
|
16
|
+
? new Uint8Array(data)
|
|
17
|
+
: new Uint8Array(data.buffer);
|
|
15
18
|
}
|
|
16
19
|
async close() { }
|
|
17
20
|
}
|
|
@@ -160,6 +163,20 @@ describe("uploadBegin", () => {
|
|
|
160
163
|
await expect(uploadBegin()).rejects.toThrow(/Blake3Hasher/);
|
|
161
164
|
});
|
|
162
165
|
});
|
|
166
|
+
describe("hashBegin / hashPush / hashFinish / hashAbort", () => {
|
|
167
|
+
it("hashBegin throws a clear error when no midden Blake3Hasher is bundled", async () => {
|
|
168
|
+
await expect(hashBegin()).rejects.toThrow(/Blake3Hasher/);
|
|
169
|
+
});
|
|
170
|
+
it("hashPush throws for an unknown session id", async () => {
|
|
171
|
+
await expect(hashPush(999, new ArrayBuffer(4))).rejects.toThrow(/unknown hash session/);
|
|
172
|
+
});
|
|
173
|
+
it("hashFinish throws for an unknown session id", async () => {
|
|
174
|
+
await expect(hashFinish(999)).rejects.toThrow(/unknown hash session/);
|
|
175
|
+
});
|
|
176
|
+
it("hashAbort is a no-op for an unknown session id", async () => {
|
|
177
|
+
await expect(hashAbort(999)).resolves.toBeUndefined();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
163
180
|
describe("opfsStoreSelftest / opfsStoreSelftestPersistence", () => {
|
|
164
181
|
it("opfsStoreSelftest throws when no midden module is bundled", async () => {
|
|
165
182
|
await expect(opfsStoreSelftest()).rejects.toThrow(/opfs_store_selftest/);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { base64Decode, base64Encode, generateThumbnailDataUrl, hashBlake3, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadAbort, uploadBegin, uploadFinish, uploadPush, writeBlobToOpfs } from "./blob-worker-logic.js";
|
|
1
|
+
import { base64Decode, base64Encode, generateThumbnailDataUrl, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadAbort, uploadBegin, uploadFinish, uploadPush, writeBlobToOpfs } from "./blob-worker-logic.js";
|
|
2
2
|
declare const api: {
|
|
3
3
|
hashBlake3: typeof hashBlake3;
|
|
4
4
|
hashSha256: typeof hashSha256;
|
|
@@ -13,6 +13,10 @@ declare const api: {
|
|
|
13
13
|
uploadPush: typeof uploadPush;
|
|
14
14
|
uploadFinish: typeof uploadFinish;
|
|
15
15
|
uploadAbort: typeof uploadAbort;
|
|
16
|
+
hashBegin: typeof hashBegin;
|
|
17
|
+
hashPush: typeof hashPush;
|
|
18
|
+
hashFinish: typeof hashFinish;
|
|
19
|
+
hashAbort: typeof hashAbort;
|
|
16
20
|
opfsStoreSelftest: typeof opfsStoreSelftest;
|
|
17
21
|
opfsStoreSelftestPersistence: typeof opfsStoreSelftestPersistence;
|
|
18
22
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob-worker.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,YAAY,EACZ,YAAY,EACZ,wBAAwB,EACxB,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EAChB,MAAM,wBAAwB,CAAC;AAEhC,QAAA,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"blob-worker.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,YAAY,EACZ,YAAY,EACZ,wBAAwB,EACxB,SAAS,EACT,SAAS,EACT,UAAU,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EAChB,MAAM,wBAAwB,CAAC;AAEhC,QAAA,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;CAoBR,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,CAAC"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// worker-only glue - importing it anywhere other than as a worker script
|
|
13
13
|
// runs `Comlink.expose()` and posts a ready message for no reason.
|
|
14
14
|
import * as Comlink from "comlink";
|
|
15
|
-
import { BLOB_WORKER_READY_MESSAGE, base64Decode, base64Encode, generateThumbnailDataUrl, hashBlake3, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadAbort, uploadBegin, uploadFinish, uploadPush, writeBlobToOpfs, } from "./blob-worker-logic.js";
|
|
15
|
+
import { BLOB_WORKER_READY_MESSAGE, base64Decode, base64Encode, generateThumbnailDataUrl, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadAbort, uploadBegin, uploadFinish, uploadPush, writeBlobToOpfs, } from "./blob-worker-logic.js";
|
|
16
16
|
const api = {
|
|
17
17
|
hashBlake3,
|
|
18
18
|
hashSha256,
|
|
@@ -27,6 +27,10 @@ const api = {
|
|
|
27
27
|
uploadPush,
|
|
28
28
|
uploadFinish,
|
|
29
29
|
uploadAbort,
|
|
30
|
+
hashBegin,
|
|
31
|
+
hashPush,
|
|
32
|
+
hashFinish,
|
|
33
|
+
hashAbort,
|
|
30
34
|
opfsStoreSelftest,
|
|
31
35
|
opfsStoreSelftestPersistence,
|
|
32
36
|
};
|
package/dist/worker/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export type { ProcessedBlob, ResizeImageOptions } from "./blob-worker-logic.js";
|
|
2
2
|
export { BLOB_WORKER_READY_MESSAGE, OPFS_DIR as BLOB_OPFS_DIR } from "./blob-worker-logic.js";
|
|
3
3
|
export type { BlobWorkerApi } from "./blob-worker.js";
|
|
4
|
-
export { getBlobWorker, shutdownBlobWorker, hashBlake3, hashSha256, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
|
|
5
|
-
export type { MiddenWorkerApi, MiddenWorkerIdentity, StreamInfo } from "./midden-worker-contract.js";
|
|
4
|
+
export { getBlobWorker, shutdownBlobWorker, hashBlake3, hashBlake3Streaming, hashSha256, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
|
|
5
|
+
export type { MiddenWorkerApi, MiddenWorkerIdentity, StreamInfo, } from "./midden-worker-contract.js";
|
|
6
6
|
export { MIDDEN_WORKER_READY_MESSAGE, MIDDEN_WORKER_READY_TIMEOUT_MS, } from "./midden-worker-contract.js";
|
|
7
7
|
export type { CreateMiddenWorker } from "./midden-worker-client.js";
|
|
8
8
|
export { WorkerBiStream, WorkerImportSession, WorkerMiddenNode } from "./midden-worker-client.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE9F,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/worker/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE9F,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,mBAAmB,EACnB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,UAAU,GACX,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,GAC/B,MAAM,6BAA6B,CAAC;AAErC,YAAY,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElG,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/worker/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { BLOB_WORKER_READY_MESSAGE, OPFS_DIR as BLOB_OPFS_DIR } from "./blob-worker-logic.js";
|
|
2
|
-
export { getBlobWorker, shutdownBlobWorker, hashBlake3, hashSha256, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
|
|
2
|
+
export { getBlobWorker, shutdownBlobWorker, hashBlake3, hashBlake3Streaming, hashSha256, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
|
|
3
3
|
export { MIDDEN_WORKER_READY_MESSAGE, MIDDEN_WORKER_READY_TIMEOUT_MS, } from "./midden-worker-contract.js";
|
|
4
4
|
export { WorkerBiStream, WorkerImportSession, WorkerMiddenNode } from "./midden-worker-client.js";
|
|
5
5
|
export { MiddenNode } from "./midden-stub.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freqhole/reliquary",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "freqhole media blob storage domain: content-addressed blobs, transfer, worker, solid helpers",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
|
-
"build": "
|
|
54
|
+
"build": "node -e \"require('fs').copyFileSync('../README.md','README.md')\" && tsc -p tsconfig.json",
|
|
55
55
|
"typecheck": "tsc --noEmit",
|
|
56
56
|
"test": "vitest run"
|
|
57
57
|
},
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@automerge/automerge-repo": "^2.5.6",
|
|
63
63
|
"fake-indexeddb": "^6.0.0",
|
|
64
64
|
"solid-js": "^1.9.0",
|
|
65
|
-
"vitest": "^2.
|
|
65
|
+
"vitest": "^3.2.7"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|
|
68
68
|
"@automerge/automerge-repo": {
|
|
@@ -85,6 +85,6 @@
|
|
|
85
85
|
"happy-dom": "^20.10.6",
|
|
86
86
|
"solid-js": "^1.9.0",
|
|
87
87
|
"typescript": "^5.6.0",
|
|
88
|
-
"vitest": "^2.
|
|
88
|
+
"vitest": "^3.2.7"
|
|
89
89
|
}
|
|
90
90
|
}
|