@freqhole/reliquary 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automerge/acl-filtering.d.ts +87 -0
- package/dist/automerge/acl-filtering.d.ts.map +1 -0
- package/dist/automerge/acl-filtering.js +138 -0
- package/dist/automerge/acl-filtering.test.d.ts +2 -0
- package/dist/automerge/acl-filtering.test.d.ts.map +1 -0
- package/dist/automerge/acl-filtering.test.js +302 -0
- package/dist/automerge/index.d.ts +5 -0
- package/dist/automerge/index.d.ts.map +1 -0
- package/dist/automerge/index.js +7 -0
- package/dist/automerge/iroh-network-adapter.d.ts +178 -0
- package/dist/automerge/iroh-network-adapter.d.ts.map +1 -0
- package/dist/automerge/iroh-network-adapter.js +691 -0
- package/dist/automerge/iroh-network-adapter.test.d.ts +2 -0
- package/dist/automerge/iroh-network-adapter.test.d.ts.map +1 -0
- package/dist/automerge/iroh-network-adapter.test.js +818 -0
- package/dist/automerge/types.d.ts +66 -0
- package/dist/automerge/types.d.ts.map +1 -0
- package/dist/automerge/types.js +10 -0
- package/dist/blobs/bytes-backend.d.ts +41 -0
- package/dist/blobs/bytes-backend.d.ts.map +1 -0
- package/dist/blobs/bytes-backend.js +252 -0
- package/dist/blobs/bytes-backend.test.d.ts +2 -0
- package/dist/blobs/bytes-backend.test.d.ts.map +1 -0
- package/dist/blobs/bytes-backend.test.js +241 -0
- package/dist/blobs/db.d.ts +8 -0
- package/dist/blobs/db.d.ts.map +1 -0
- package/dist/blobs/db.js +141 -0
- package/dist/blobs/db.test.d.ts +2 -0
- package/dist/blobs/db.test.d.ts.map +1 -0
- package/dist/blobs/db.test.js +120 -0
- package/dist/blobs/index.d.ts +5 -0
- package/dist/blobs/index.d.ts.map +1 -0
- package/dist/blobs/index.js +2 -0
- package/dist/blobs/store.d.ts +47 -0
- package/dist/blobs/store.d.ts.map +1 -0
- package/dist/blobs/store.js +263 -0
- package/dist/blobs/store.test.d.ts +2 -0
- package/dist/blobs/store.test.d.ts.map +1 -0
- package/dist/blobs/store.test.js +377 -0
- package/dist/blobs/types.d.ts +55 -0
- package/dist/blobs/types.d.ts.map +1 -0
- package/dist/blobs/types.js +8 -0
- package/dist/ensure/client.d.ts +19 -0
- package/dist/ensure/client.d.ts.map +1 -0
- package/dist/ensure/client.js +74 -0
- package/dist/ensure/client.test.d.ts +2 -0
- package/dist/ensure/client.test.d.ts.map +1 -0
- package/dist/ensure/client.test.js +133 -0
- package/dist/ensure/index.d.ts +4 -0
- package/dist/ensure/index.d.ts.map +1 -0
- package/dist/ensure/index.js +4 -0
- package/dist/ensure/responder.d.ts +20 -0
- package/dist/ensure/responder.d.ts.map +1 -0
- package/dist/ensure/responder.js +100 -0
- package/dist/ensure/responder.test.d.ts +2 -0
- package/dist/ensure/responder.test.d.ts.map +1 -0
- package/dist/ensure/responder.test.js +191 -0
- package/dist/ensure/types.d.ts +19 -0
- package/dist/ensure/types.d.ts.map +1 -0
- package/dist/ensure/types.js +4 -0
- package/dist/ensure/types.test.d.ts +2 -0
- package/dist/ensure/types.test.d.ts.map +1 -0
- package/dist/ensure/types.test.js +81 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +7 -0
- package/dist/solid/blob-url.d.ts +10 -0
- package/dist/solid/blob-url.d.ts.map +1 -0
- package/dist/solid/blob-url.js +34 -0
- package/dist/solid/blob-url.test.d.ts +2 -0
- package/dist/solid/blob-url.test.d.ts.map +1 -0
- package/dist/solid/blob-url.test.js +62 -0
- package/dist/solid/connection-summary.d.ts +25 -0
- package/dist/solid/connection-summary.d.ts.map +1 -0
- package/dist/solid/connection-summary.js +29 -0
- package/dist/solid/connection-summary.test.d.ts +2 -0
- package/dist/solid/connection-summary.test.d.ts.map +1 -0
- package/dist/solid/connection-summary.test.js +57 -0
- package/dist/solid/doc-store.d.ts +29 -0
- package/dist/solid/doc-store.d.ts.map +1 -0
- package/dist/solid/doc-store.js +79 -0
- package/dist/solid/doc-store.test.d.ts +2 -0
- package/dist/solid/doc-store.test.d.ts.map +1 -0
- package/dist/solid/doc-store.test.js +234 -0
- package/dist/solid/index.d.ts +4 -0
- package/dist/solid/index.d.ts.map +1 -0
- package/dist/solid/index.js +9 -0
- package/dist/solid/transfer-progress.d.ts +21 -0
- package/dist/solid/transfer-progress.d.ts.map +1 -0
- package/dist/solid/transfer-progress.js +32 -0
- package/dist/solid/transfer-progress.test.d.ts +2 -0
- package/dist/solid/transfer-progress.test.d.ts.map +1 -0
- package/dist/solid/transfer-progress.test.js +76 -0
- package/dist/testing/blob-fixtures.d.ts +19 -0
- package/dist/testing/blob-fixtures.d.ts.map +1 -0
- package/dist/testing/blob-fixtures.js +46 -0
- package/dist/testing/blob-fixtures.test.d.ts +2 -0
- package/dist/testing/blob-fixtures.test.d.ts.map +1 -0
- package/dist/testing/blob-fixtures.test.js +46 -0
- package/dist/testing/idb-harness.d.ts +10 -0
- package/dist/testing/idb-harness.d.ts.map +1 -0
- package/dist/testing/idb-harness.js +17 -0
- package/dist/testing/idb-harness.test.d.ts +2 -0
- package/dist/testing/idb-harness.test.d.ts.map +1 -0
- package/dist/testing/idb-harness.test.js +48 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +11 -0
- package/dist/testing/media.d.ts +15 -0
- package/dist/testing/media.d.ts.map +1 -0
- package/dist/testing/media.js +37 -0
- package/dist/testing/media.test.d.ts +2 -0
- package/dist/testing/media.test.d.ts.map +1 -0
- package/dist/testing/media.test.js +47 -0
- package/dist/testing/mock-blob-fetch.d.ts +33 -0
- package/dist/testing/mock-blob-fetch.d.ts.map +1 -0
- package/dist/testing/mock-blob-fetch.js +39 -0
- package/dist/testing/mock-blob-fetch.test.d.ts +2 -0
- package/dist/testing/mock-blob-fetch.test.d.ts.map +1 -0
- package/dist/testing/mock-blob-fetch.test.js +65 -0
- package/dist/testing/mock-node.d.ts +36 -0
- package/dist/testing/mock-node.d.ts.map +1 -0
- package/dist/testing/mock-node.js +97 -0
- package/dist/testing/mock-node.test.d.ts +2 -0
- package/dist/testing/mock-node.test.d.ts.map +1 -0
- package/dist/testing/mock-node.test.js +66 -0
- package/dist/testing/streams.d.ts +68 -0
- package/dist/testing/streams.d.ts.map +1 -0
- package/dist/testing/streams.js +99 -0
- package/dist/testing/streams.test.d.ts +2 -0
- package/dist/testing/streams.test.d.ts.map +1 -0
- package/dist/testing/streams.test.js +82 -0
- package/dist/transfer/cancellation.d.ts +8 -0
- package/dist/transfer/cancellation.d.ts.map +1 -0
- package/dist/transfer/cancellation.js +19 -0
- package/dist/transfer/index.d.ts +8 -0
- package/dist/transfer/index.d.ts.map +1 -0
- package/dist/transfer/index.js +4 -0
- package/dist/transfer/prefetch.d.ts +38 -0
- package/dist/transfer/prefetch.d.ts.map +1 -0
- package/dist/transfer/prefetch.js +61 -0
- package/dist/transfer/prefetch.test.d.ts +2 -0
- package/dist/transfer/prefetch.test.d.ts.map +1 -0
- package/dist/transfer/prefetch.test.js +136 -0
- package/dist/transfer/serve.d.ts +66 -0
- package/dist/transfer/serve.d.ts.map +1 -0
- package/dist/transfer/serve.js +126 -0
- package/dist/transfer/serve.test.d.ts +2 -0
- package/dist/transfer/serve.test.d.ts.map +1 -0
- package/dist/transfer/serve.test.js +101 -0
- package/dist/transfer/snatch.d.ts +39 -0
- package/dist/transfer/snatch.d.ts.map +1 -0
- package/dist/transfer/snatch.js +289 -0
- package/dist/transfer/snatch.test.d.ts +2 -0
- package/dist/transfer/snatch.test.d.ts.map +1 -0
- package/dist/transfer/snatch.test.js +337 -0
- package/dist/transfer/types.d.ts +85 -0
- package/dist/transfer/types.d.ts.map +1 -0
- package/dist/transfer/types.js +15 -0
- package/dist/utils/hash.d.ts +13 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +31 -0
- package/dist/utils/hash.test.d.ts +2 -0
- package/dist/utils/hash.test.d.ts.map +1 -0
- package/dist/utils/hash.test.js +56 -0
- package/dist/utils/image-utils.d.ts +28 -0
- package/dist/utils/image-utils.d.ts.map +1 -0
- package/dist/utils/image-utils.js +113 -0
- package/dist/utils/image-utils.test.d.ts +2 -0
- package/dist/utils/image-utils.test.d.ts.map +1 -0
- package/dist/utils/image-utils.test.js +181 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/log.d.ts +22 -0
- package/dist/utils/log.d.ts.map +1 -0
- package/dist/utils/log.js +100 -0
- package/dist/utils/log.test.d.ts +2 -0
- package/dist/utils/log.test.d.ts.map +1 -0
- package/dist/utils/log.test.js +113 -0
- package/dist/worker/blob-worker-client.d.ts +118 -0
- package/dist/worker/blob-worker-client.d.ts.map +1 -0
- package/dist/worker/blob-worker-client.js +361 -0
- package/dist/worker/blob-worker-client.test.d.ts +2 -0
- package/dist/worker/blob-worker-client.test.d.ts.map +1 -0
- package/dist/worker/blob-worker-client.test.js +137 -0
- package/dist/worker/blob-worker-logic.d.ts +120 -0
- package/dist/worker/blob-worker-logic.d.ts.map +1 -0
- package/dist/worker/blob-worker-logic.js +368 -0
- package/dist/worker/blob-worker-logic.test.d.ts +2 -0
- package/dist/worker/blob-worker-logic.test.d.ts.map +1 -0
- package/dist/worker/blob-worker-logic.test.js +191 -0
- package/dist/worker/blob-worker.d.ts +21 -0
- package/dist/worker/blob-worker.d.ts.map +1 -0
- package/dist/worker/blob-worker.js +44 -0
- package/dist/worker/index.d.ts +12 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +6 -0
- package/dist/worker/midden-blake3.d.ts +23 -0
- package/dist/worker/midden-blake3.d.ts.map +1 -0
- package/dist/worker/midden-blake3.js +47 -0
- package/dist/worker/midden-blake3.test.d.ts +2 -0
- package/dist/worker/midden-blake3.test.d.ts.map +1 -0
- package/dist/worker/midden-blake3.test.js +25 -0
- package/dist/worker/midden-not-bundled.stub.d.ts +1 -0
- package/dist/worker/midden-not-bundled.stub.d.ts.map +1 -0
- package/dist/worker/midden-not-bundled.stub.js +10 -0
- package/dist/worker/midden-stub.d.ts +10 -0
- package/dist/worker/midden-stub.d.ts.map +1 -0
- package/dist/worker/midden-stub.js +31 -0
- package/dist/worker/midden-stub.test.d.ts +2 -0
- package/dist/worker/midden-stub.test.d.ts.map +1 -0
- package/dist/worker/midden-stub.test.js +25 -0
- package/dist/worker/midden-worker-client.d.ts +103 -0
- package/dist/worker/midden-worker-client.d.ts.map +1 -0
- package/dist/worker/midden-worker-client.js +246 -0
- package/dist/worker/midden-worker-client.test.d.ts +2 -0
- package/dist/worker/midden-worker-client.test.d.ts.map +1 -0
- package/dist/worker/midden-worker-client.test.js +151 -0
- package/dist/worker/midden-worker-contract.d.ts +87 -0
- package/dist/worker/midden-worker-contract.d.ts.map +1 -0
- package/dist/worker/midden-worker-contract.js +30 -0
- package/package.json +90 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
// blob-worker-client - lazy comlink wrapper around the blob worker.
|
|
2
|
+
//
|
|
3
|
+
// the worker is spun up on first call to `getBlobWorker()` and reused for
|
|
4
|
+
// the lifetime of the page. importing this module costs nothing - the
|
|
5
|
+
// worker bundle is only fetched/instantiated on first use.
|
|
6
|
+
//
|
|
7
|
+
// in environments without Worker support (e.g. SSR / certain test runners)
|
|
8
|
+
// the client falls back to a synchronous in-process implementation so
|
|
9
|
+
// callers don't have to branch.
|
|
10
|
+
import * as Comlink from "comlink";
|
|
11
|
+
import { sha256Hex } from "../utils/hash.js";
|
|
12
|
+
import { loadMiddenBlake3 } from "./midden-blake3.js";
|
|
13
|
+
import { BLOB_WORKER_READY_MESSAGE } from "./blob-worker-logic.js";
|
|
14
|
+
import { log } from "../utils/log.js";
|
|
15
|
+
const TAG = "blob.worker";
|
|
16
|
+
let workerProxy = null;
|
|
17
|
+
let workerInstance = null;
|
|
18
|
+
let workerReadyPromise = null;
|
|
19
|
+
// generous - the worker's top-level module may load a wasm-backed midden
|
|
20
|
+
// module (when the embedding app bundles one) before it can register its
|
|
21
|
+
// Comlink message listener. slow CI runners / cold caches can take a few
|
|
22
|
+
// seconds for this.
|
|
23
|
+
const WORKER_READY_TIMEOUT_MS = 20_000;
|
|
24
|
+
function canSpawnWorker() {
|
|
25
|
+
return typeof Worker !== "undefined";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* get (and lazily spawn) the comlink-wrapped blob worker proxy.
|
|
29
|
+
*
|
|
30
|
+
* returns null if Worker isn't available, or if the worker doesn't signal
|
|
31
|
+
* readiness within `WORKER_READY_TIMEOUT_MS` - callers should branch and use
|
|
32
|
+
* a main-thread fallback (every exported helper below already does this).
|
|
33
|
+
*
|
|
34
|
+
* waits for an explicit "ready" postMessage from the worker before handing
|
|
35
|
+
* out the Comlink proxy. this avoids a real race: the worker's module top
|
|
36
|
+
* level may await a wasm module's instantiation before calling
|
|
37
|
+
* `Comlink.expose()` (which registers the "message" listener). an RPC call
|
|
38
|
+
* sent before that listener exists fires with no listener attached and is
|
|
39
|
+
* silently dropped forever - the caller's promise then never resolves.
|
|
40
|
+
* waiting for the ready signal (sent immediately after `Comlink.expose()`
|
|
41
|
+
* in blob-worker.ts) guarantees the listener is registered before any real
|
|
42
|
+
* RPC call goes out.
|
|
43
|
+
*/
|
|
44
|
+
export async function getBlobWorker() {
|
|
45
|
+
if (workerProxy)
|
|
46
|
+
return workerProxy;
|
|
47
|
+
if (!canSpawnWorker())
|
|
48
|
+
return null;
|
|
49
|
+
if (workerReadyPromise)
|
|
50
|
+
return workerReadyPromise;
|
|
51
|
+
workerReadyPromise = (async () => {
|
|
52
|
+
// standard web-platform worker construction: resolves relative to this
|
|
53
|
+
// module's own compiled location, so it works under vite, webpack 5,
|
|
54
|
+
// and plain browsers without a bundler-specific import suffix.
|
|
55
|
+
const worker = new Worker(new URL("./blob-worker.js", import.meta.url), { type: "module" });
|
|
56
|
+
const ready = await new Promise((resolve) => {
|
|
57
|
+
const timeout = setTimeout(() => {
|
|
58
|
+
worker.removeEventListener("message", onMessage);
|
|
59
|
+
worker.removeEventListener("error", onError);
|
|
60
|
+
log.warn(TAG, `worker did not signal ready within ${WORKER_READY_TIMEOUT_MS}ms`);
|
|
61
|
+
resolve(false);
|
|
62
|
+
}, WORKER_READY_TIMEOUT_MS);
|
|
63
|
+
const onMessage = (e) => {
|
|
64
|
+
if (e.data !== BLOB_WORKER_READY_MESSAGE)
|
|
65
|
+
return;
|
|
66
|
+
clearTimeout(timeout);
|
|
67
|
+
worker.removeEventListener("error", onError);
|
|
68
|
+
worker.removeEventListener("message", onMessage);
|
|
69
|
+
resolve(true);
|
|
70
|
+
};
|
|
71
|
+
// a worker script that fails to load (network error, blocked by a dev
|
|
72
|
+
// server's file-serving restrictions, syntax error, etc.) fires an
|
|
73
|
+
// `error` event, never a `message` - without this listener the promise
|
|
74
|
+
// above would otherwise sit unresolved for the full ready-timeout with
|
|
75
|
+
// no indication anything went wrong.
|
|
76
|
+
const onError = (e) => {
|
|
77
|
+
clearTimeout(timeout);
|
|
78
|
+
worker.removeEventListener("message", onMessage);
|
|
79
|
+
worker.removeEventListener("error", onError);
|
|
80
|
+
log.warn(TAG, "worker failed to load:", e.message || e);
|
|
81
|
+
resolve(false);
|
|
82
|
+
};
|
|
83
|
+
worker.addEventListener("message", onMessage);
|
|
84
|
+
worker.addEventListener("error", onError);
|
|
85
|
+
});
|
|
86
|
+
if (!ready) {
|
|
87
|
+
worker.terminate();
|
|
88
|
+
// allow a future call to retry (e.g. a one-off slow load) instead of
|
|
89
|
+
// permanently caching this failure.
|
|
90
|
+
workerReadyPromise = null;
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
workerInstance = worker;
|
|
94
|
+
workerProxy = Comlink.wrap(worker);
|
|
95
|
+
return workerProxy;
|
|
96
|
+
})();
|
|
97
|
+
return workerReadyPromise;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* tear down the worker. mainly useful for tests; production code can leave
|
|
101
|
+
* the worker alive for the page lifetime.
|
|
102
|
+
*/
|
|
103
|
+
export function shutdownBlobWorker() {
|
|
104
|
+
if (workerInstance) {
|
|
105
|
+
workerInstance.terminate();
|
|
106
|
+
workerInstance = null;
|
|
107
|
+
workerProxy = null;
|
|
108
|
+
}
|
|
109
|
+
workerReadyPromise = null;
|
|
110
|
+
}
|
|
111
|
+
// ---- main-thread fallbacks -----------------------------------------------
|
|
112
|
+
// used when Worker isn't available. these mirror the worker's API exactly
|
|
113
|
+
// so consumers can share a single code path.
|
|
114
|
+
async function fallbackHashBlake3(data) {
|
|
115
|
+
try {
|
|
116
|
+
const midden = await loadMiddenBlake3();
|
|
117
|
+
if (!midden || typeof midden.hash_blake3 !== "function") {
|
|
118
|
+
log.warn(TAG, "no midden module with hash_blake3 available, blake3 hashing degraded to empty string");
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
return midden.hash_blake3(data);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
log.warn(TAG, "blake3 hashing threw, degrading to empty string:", err);
|
|
125
|
+
return "";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function fallbackBase64Encode(buffer) {
|
|
129
|
+
const bytes = new Uint8Array(buffer);
|
|
130
|
+
const chunkSize = 0x8000;
|
|
131
|
+
let binary = "";
|
|
132
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
133
|
+
const chunk = bytes.subarray(i, i + chunkSize);
|
|
134
|
+
binary += String.fromCharCode.apply(null, chunk);
|
|
135
|
+
}
|
|
136
|
+
return btoa(binary);
|
|
137
|
+
}
|
|
138
|
+
// ---- convenience helpers --------------------------------------------------
|
|
139
|
+
/**
|
|
140
|
+
* hash bytes with blake3, preferring the worker. accepts a Uint8Array.
|
|
141
|
+
* note: this DOES copy across the worker boundary (Uint8Array isn't
|
|
142
|
+
* transferable directly without giving up the underlying ArrayBuffer);
|
|
143
|
+
* for upload pipelines, prefer `processBlobBytes` which transfers the
|
|
144
|
+
* underlying buffer.
|
|
145
|
+
*/
|
|
146
|
+
export async function hashBlake3(data) {
|
|
147
|
+
const worker = await getBlobWorker();
|
|
148
|
+
if (worker)
|
|
149
|
+
return worker.hashBlake3(data);
|
|
150
|
+
return fallbackHashBlake3(data);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* sha256 hash of an ArrayBuffer.
|
|
154
|
+
*/
|
|
155
|
+
export async function hashSha256(data) {
|
|
156
|
+
const worker = await getBlobWorker();
|
|
157
|
+
if (worker)
|
|
158
|
+
return worker.hashSha256(data);
|
|
159
|
+
return sha256Hex(data);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* base64-encode an ArrayBuffer.
|
|
163
|
+
*
|
|
164
|
+
* NOTE: the buffer is structured-cloned (copied) across the worker
|
|
165
|
+
* boundary so callers can safely reuse it afterwards. if you have a
|
|
166
|
+
* dedicated buffer that won't be touched again, you can transfer
|
|
167
|
+
* ownership manually for a small perf win.
|
|
168
|
+
*/
|
|
169
|
+
export async function base64Encode(buffer) {
|
|
170
|
+
const worker = await getBlobWorker();
|
|
171
|
+
if (worker)
|
|
172
|
+
return worker.base64Encode(buffer);
|
|
173
|
+
return fallbackBase64Encode(buffer);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* one-shot upload pipeline: hash + write to OPFS in the worker, return
|
|
177
|
+
* metadata. transfers the buffer.
|
|
178
|
+
*/
|
|
179
|
+
export async function processBlobBytes(buffer, filename, mime) {
|
|
180
|
+
const worker = await getBlobWorker();
|
|
181
|
+
if (worker) {
|
|
182
|
+
return worker.processBlobBytes(Comlink.transfer(buffer, [buffer]), filename, mime);
|
|
183
|
+
}
|
|
184
|
+
// main-thread fallback path - rare, mostly for tests.
|
|
185
|
+
const [sha256, blake3] = await Promise.all([sha256Hex(buffer), fallbackHashBlake3(new Uint8Array(buffer))]);
|
|
186
|
+
return {
|
|
187
|
+
blob_id: blake3,
|
|
188
|
+
sha256,
|
|
189
|
+
blake3,
|
|
190
|
+
size: buffer.byteLength,
|
|
191
|
+
mime,
|
|
192
|
+
filename,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* write a blob to OPFS via the worker (uses `FileSystemSyncAccessHandle`
|
|
197
|
+
* for max throughput).
|
|
198
|
+
*
|
|
199
|
+
* NOTE: the buffer is structured-cloned (copied) across the worker
|
|
200
|
+
* boundary so callers can safely reuse it afterwards - important for
|
|
201
|
+
* code paths that read or return the buffer after kicking off an OPFS
|
|
202
|
+
* write (e.g. a snatch/download cache-back-fill). for the upload pipeline
|
|
203
|
+
* use `processBlobBytes` instead, which transfers.
|
|
204
|
+
*/
|
|
205
|
+
export async function writeBlobToOpfs(blobId, buffer) {
|
|
206
|
+
const worker = await getBlobWorker();
|
|
207
|
+
if (worker) {
|
|
208
|
+
await worker.writeBlobToOpfs(blobId, buffer);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
// no main-thread fallback - opfs writes from main thread don't have a
|
|
212
|
+
// sync access handle path anyway. silently no-op.
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* stream a File into OPFS via the worker's chunked upload session:
|
|
216
|
+
* incremental blake3 + incremental sync-access-handle writes, so neither
|
|
217
|
+
* thread ever holds the whole payload. each chunk buffer is transferred
|
|
218
|
+
* (zero-copy) across the worker boundary.
|
|
219
|
+
*
|
|
220
|
+
* `onProgress` reports bytes pushed / file size (0..1) per chunk.
|
|
221
|
+
* `signal` cancels between chunks: the worker session is aborted (temp
|
|
222
|
+
* file cleaned up) and a DOMException AbortError is thrown.
|
|
223
|
+
*
|
|
224
|
+
* returns { blake3, size } - the file lands in OPFS under its blake3
|
|
225
|
+
* content address. throws when streaming isn't available (no worker, no
|
|
226
|
+
* OPFS sync handles, no midden module bundled); callers should fall back
|
|
227
|
+
* to the one-shot processBlobBytes path.
|
|
228
|
+
*/
|
|
229
|
+
export async function streamFileToOpfs(file, options) {
|
|
230
|
+
const worker = await getBlobWorker();
|
|
231
|
+
if (!worker)
|
|
232
|
+
throw new Error("streaming upload unavailable: no blob worker");
|
|
233
|
+
const sessionId = await worker.uploadBegin();
|
|
234
|
+
const reader = file.stream().getReader();
|
|
235
|
+
let bytesPushed = 0;
|
|
236
|
+
try {
|
|
237
|
+
for (;;) {
|
|
238
|
+
if (options?.signal?.aborted) {
|
|
239
|
+
throw new DOMException("upload cancelled", "AbortError");
|
|
240
|
+
}
|
|
241
|
+
const { done, value } = await reader.read();
|
|
242
|
+
if (done)
|
|
243
|
+
break;
|
|
244
|
+
// chunks are usually freshly-allocated exact buffers, but a view into
|
|
245
|
+
// a larger buffer is legal - slice to exact bytes before transferring
|
|
246
|
+
const exact = value.byteOffset === 0 && value.byteLength === value.buffer.byteLength
|
|
247
|
+
? value.buffer
|
|
248
|
+
: value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
|
|
249
|
+
const chunkLen = value.byteLength;
|
|
250
|
+
await worker.uploadPush(sessionId, Comlink.transfer(exact, [exact]));
|
|
251
|
+
bytesPushed += chunkLen;
|
|
252
|
+
if (options?.onProgress && file.size > 0) {
|
|
253
|
+
options.onProgress(Math.min(1, bytesPushed / file.size));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return await worker.uploadFinish(sessionId);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
await worker.uploadAbort(sessionId).catch(() => { });
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
reader.releaseLock();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* resize an image Blob to a (default WebP) data URL.
|
|
268
|
+
* prefers the blob worker (keeps the decode/encode work off the main
|
|
269
|
+
* thread); falls back to a main-thread `OffscreenCanvas` path if the
|
|
270
|
+
* worker isn't available. returns null on failure (non-image input,
|
|
271
|
+
* decode failure, etc.).
|
|
272
|
+
*/
|
|
273
|
+
export async function resizeImageToWebpDataUrl(blob, options) {
|
|
274
|
+
const worker = await getBlobWorker();
|
|
275
|
+
if (worker)
|
|
276
|
+
return worker.resizeImageToWebpDataUrl(blob, options);
|
|
277
|
+
return mainThreadResizeImage(blob, options);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* generate a thumbnail data URL (default 200x200 WebP @ q=0.75) for an
|
|
281
|
+
* image Blob. delegates to the worker.
|
|
282
|
+
*/
|
|
283
|
+
export async function generateThumbnailDataUrl(blob, maxSize = 200) {
|
|
284
|
+
if (!blob.type.startsWith("image/"))
|
|
285
|
+
return null;
|
|
286
|
+
return resizeImageToWebpDataUrl(blob, {
|
|
287
|
+
maxWidth: maxSize,
|
|
288
|
+
maxHeight: maxSize,
|
|
289
|
+
quality: 0.75,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* decode a base64 string into a Uint8Array via the worker. for large
|
|
294
|
+
* payloads (megabyte-scale snatch responses) this avoids blocking the
|
|
295
|
+
* main thread on a tight `String.charCodeAt` loop.
|
|
296
|
+
*/
|
|
297
|
+
export async function base64Decode(b64) {
|
|
298
|
+
const worker = await getBlobWorker();
|
|
299
|
+
if (worker)
|
|
300
|
+
return worker.base64Decode(b64);
|
|
301
|
+
// main-thread fallback
|
|
302
|
+
const binary = atob(b64);
|
|
303
|
+
const out = new Uint8Array(binary.length);
|
|
304
|
+
for (let i = 0; i < binary.length; i++)
|
|
305
|
+
out[i] = binary.charCodeAt(i);
|
|
306
|
+
return out;
|
|
307
|
+
}
|
|
308
|
+
// ---- main-thread fallbacks -----------------------------------------------
|
|
309
|
+
async function mainThreadResizeImage(blob, options) {
|
|
310
|
+
if (typeof OffscreenCanvas === "undefined" || typeof createImageBitmap !== "function") {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
const maxWidth = options?.maxWidth ?? 200;
|
|
314
|
+
const maxHeight = options?.maxHeight ?? 200;
|
|
315
|
+
const quality = options?.quality ?? 0.8;
|
|
316
|
+
const cropSquare = options?.cropSquare ?? false;
|
|
317
|
+
const mime = options?.mime ?? "image/webp";
|
|
318
|
+
let bitmap = null;
|
|
319
|
+
try {
|
|
320
|
+
bitmap = await createImageBitmap(blob);
|
|
321
|
+
let sx = 0;
|
|
322
|
+
let sy = 0;
|
|
323
|
+
let sw = bitmap.width;
|
|
324
|
+
let sh = bitmap.height;
|
|
325
|
+
if (cropSquare) {
|
|
326
|
+
const minDim = Math.min(bitmap.width, bitmap.height);
|
|
327
|
+
sx = (bitmap.width - minDim) / 2;
|
|
328
|
+
sy = (bitmap.height - minDim) / 2;
|
|
329
|
+
sw = minDim;
|
|
330
|
+
sh = minDim;
|
|
331
|
+
}
|
|
332
|
+
const aspect = sw / sh;
|
|
333
|
+
let outW = sw;
|
|
334
|
+
let outH = sh;
|
|
335
|
+
if (outW > maxWidth) {
|
|
336
|
+
outW = maxWidth;
|
|
337
|
+
outH = Math.round(outW / aspect);
|
|
338
|
+
}
|
|
339
|
+
if (outH > maxHeight) {
|
|
340
|
+
outH = maxHeight;
|
|
341
|
+
outW = Math.round(outH * aspect);
|
|
342
|
+
}
|
|
343
|
+
outW = Math.max(1, outW);
|
|
344
|
+
outH = Math.max(1, outH);
|
|
345
|
+
const canvas = new OffscreenCanvas(outW, outH);
|
|
346
|
+
const ctx = canvas.getContext("2d");
|
|
347
|
+
if (!ctx)
|
|
348
|
+
return null;
|
|
349
|
+
ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, outW, outH);
|
|
350
|
+
const out = await canvas.convertToBlob({ type: mime, quality });
|
|
351
|
+
const buf = await out.arrayBuffer();
|
|
352
|
+
const b64 = await fallbackBase64Encode(buf);
|
|
353
|
+
return `data:${mime};base64,${b64}`;
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
finally {
|
|
359
|
+
bitmap?.close();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-worker-client.test.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
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";
|
|
4
|
+
import { resetMiddenBlake3Cache } from "./midden-blake3.js";
|
|
5
|
+
import { log } from "../utils/log.js";
|
|
6
|
+
// this test environment has no `Worker` global, so every helper below
|
|
7
|
+
// exercises its main-thread fallback path - the same path used in
|
|
8
|
+
// environments without Worker support (SSR, certain test runners) -
|
|
9
|
+
// except the `getBlobWorker` tests below that explicitly stub in a fake
|
|
10
|
+
// `Worker` to exercise the real ready-handshake logic instead.
|
|
11
|
+
/** minimal fake `Worker`: enough of the `EventTarget`-based message/error
|
|
12
|
+
* surface for the ready-handshake tests below, without a real thread. */
|
|
13
|
+
class FakeWorker extends EventTarget {
|
|
14
|
+
postMessage = vi.fn();
|
|
15
|
+
terminate = vi.fn();
|
|
16
|
+
}
|
|
17
|
+
class FakeImageBitmap {
|
|
18
|
+
width;
|
|
19
|
+
height;
|
|
20
|
+
constructor(width, height) {
|
|
21
|
+
this.width = width;
|
|
22
|
+
this.height = height;
|
|
23
|
+
}
|
|
24
|
+
close = vi.fn();
|
|
25
|
+
}
|
|
26
|
+
class FakeOffscreenCanvasContext {
|
|
27
|
+
drawImage = vi.fn();
|
|
28
|
+
}
|
|
29
|
+
class FakeOffscreenCanvas {
|
|
30
|
+
width;
|
|
31
|
+
height;
|
|
32
|
+
context = new FakeOffscreenCanvasContext();
|
|
33
|
+
constructor(width, height) {
|
|
34
|
+
this.width = width;
|
|
35
|
+
this.height = height;
|
|
36
|
+
}
|
|
37
|
+
getContext() {
|
|
38
|
+
return this.context;
|
|
39
|
+
}
|
|
40
|
+
async convertToBlob(options) {
|
|
41
|
+
return new Blob(["fake-encoded-bytes"], { type: options?.type ?? "image/webp" });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function installCanvasFakes(size = { width: 100, height: 100 }) {
|
|
45
|
+
vi.stubGlobal("createImageBitmap", vi.fn(async () => new FakeImageBitmap(size.width, size.height)));
|
|
46
|
+
vi.stubGlobal("OffscreenCanvas", FakeOffscreenCanvas);
|
|
47
|
+
}
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
vi.unstubAllGlobals();
|
|
50
|
+
resetMiddenBlake3Cache();
|
|
51
|
+
shutdownBlobWorker();
|
|
52
|
+
});
|
|
53
|
+
describe("getBlobWorker", () => {
|
|
54
|
+
it("returns null when Worker isn't available in this environment", async () => {
|
|
55
|
+
expect(await getBlobWorker()).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
it("resolves once the worker signals ready via a message, without waiting out the timeout", async () => {
|
|
58
|
+
const worker = new FakeWorker();
|
|
59
|
+
vi.stubGlobal("Worker", vi.fn(() => worker));
|
|
60
|
+
const proxyPromise = getBlobWorker();
|
|
61
|
+
worker.dispatchEvent(new MessageEvent("message", { data: "blob-worker-ready" }));
|
|
62
|
+
expect(await proxyPromise).not.toBeNull();
|
|
63
|
+
});
|
|
64
|
+
it("resolves null quickly (not after the full ready-timeout) when the worker script fails to load, and logs a warning", async () => {
|
|
65
|
+
vi.useFakeTimers();
|
|
66
|
+
const warnSpy = vi.spyOn(log, "warn");
|
|
67
|
+
const worker = new FakeWorker();
|
|
68
|
+
vi.stubGlobal("Worker", vi.fn(() => worker));
|
|
69
|
+
const proxyPromise = getBlobWorker();
|
|
70
|
+
// a worker script that fails to load fires an `error` event, never a
|
|
71
|
+
// `message` - this must resolve right away, not after the 20s
|
|
72
|
+
// ready-timeout (proven by asserting the result WITHOUT advancing
|
|
73
|
+
// fake timers at all).
|
|
74
|
+
worker.dispatchEvent(new Event("error"));
|
|
75
|
+
expect(await proxyPromise).toBeNull();
|
|
76
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
77
|
+
vi.useRealTimers();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("hashBlake3", () => {
|
|
81
|
+
it("falls back to an empty string with no worker and no midden module", async () => {
|
|
82
|
+
expect(await hashBlake3(new Uint8Array([1, 2, 3]))).toBe("");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe("hashSha256", () => {
|
|
86
|
+
it("falls back to a real sha-256 digest with no worker", async () => {
|
|
87
|
+
const bytes = new TextEncoder().encode("abc");
|
|
88
|
+
const hash = await hashSha256(bytes.buffer);
|
|
89
|
+
expect(hash).toBe("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe("base64Encode / base64Decode", () => {
|
|
93
|
+
it("round-trips bytes through the fallback path", async () => {
|
|
94
|
+
const original = new Uint8Array([0, 1, 2, 253, 254, 255]);
|
|
95
|
+
const encoded = await base64Encode(original.buffer);
|
|
96
|
+
const decoded = await base64Decode(encoded);
|
|
97
|
+
expect(Array.from(decoded)).toEqual(Array.from(original));
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe("processBlobBytes", () => {
|
|
101
|
+
it("hashes without a worker (blake3 empty, sha256 real)", async () => {
|
|
102
|
+
const bytes = new TextEncoder().encode("hello world");
|
|
103
|
+
const result = await processBlobBytes(bytes.buffer, "hello.txt", "text/plain");
|
|
104
|
+
expect(result.blake3).toBe("");
|
|
105
|
+
expect(result.blob_id).toBe("");
|
|
106
|
+
expect(result.sha256).toBe("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
|
|
107
|
+
expect(result.size).toBe(bytes.byteLength);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("writeBlobToOpfs", () => {
|
|
111
|
+
it("silently no-ops when there's no worker to delegate to", async () => {
|
|
112
|
+
await expect(writeBlobToOpfs("some-hash", new ArrayBuffer(4))).resolves.toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe("streamFileToOpfs", () => {
|
|
116
|
+
it("throws when no worker is available", async () => {
|
|
117
|
+
const file = new File(["hello"], "hello.txt", { type: "text/plain" });
|
|
118
|
+
await expect(streamFileToOpfs(file)).rejects.toThrow(/no blob worker/);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe("resizeImageToWebpDataUrl", () => {
|
|
122
|
+
it("uses the main-thread fallback and returns a data url", async () => {
|
|
123
|
+
installCanvasFakes();
|
|
124
|
+
const result = await resizeImageToWebpDataUrl(new Blob(["x"], { type: "image/png" }));
|
|
125
|
+
expect(result).toMatch(/^data:image\/webp;base64,/);
|
|
126
|
+
});
|
|
127
|
+
it("returns null when OffscreenCanvas/createImageBitmap are unavailable", async () => {
|
|
128
|
+
const result = await resizeImageToWebpDataUrl(new Blob(["x"], { type: "image/png" }));
|
|
129
|
+
expect(result).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe("generateThumbnailDataUrl", () => {
|
|
133
|
+
it("skips non-image blobs", async () => {
|
|
134
|
+
const result = await generateThumbnailDataUrl(new Blob(["x"], { type: "text/plain" }));
|
|
135
|
+
expect(result).toBeNull();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** message the worker entry posts once comlink has registered its message
|
|
2
|
+
* listener - see `blob-worker.ts` for why the ordering matters. */
|
|
3
|
+
export declare const BLOB_WORKER_READY_MESSAGE = "blob-worker-ready";
|
|
4
|
+
/** directory name for the on-disk (OPFS) blob store. exported so callers
|
|
5
|
+
* reading bytes back directly (bypassing the worker's write path, e.g.
|
|
6
|
+
* `./blobs`'s main-thread OPFS reads) always agree with the worker on
|
|
7
|
+
* where the bytes actually live. */
|
|
8
|
+
export declare const OPFS_DIR = "reliquary-blobs";
|
|
9
|
+
/**
|
|
10
|
+
* compute blake3 hash of a Uint8Array via the embedding app's midden
|
|
11
|
+
* module. returns an empty string when no such module is bundled, or when
|
|
12
|
+
* it does not export `hash_blake3`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function hashBlake3(data: Uint8Array): Promise<string>;
|
|
15
|
+
/**
|
|
16
|
+
* compute sha256 hash via SubtleCrypto. SubtleCrypto.digest is already
|
|
17
|
+
* async/non-blocking on the main thread, but this is exposed here too so
|
|
18
|
+
* callers can do sha256 + blake3 in a single round-trip.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hashSha256(data: ArrayBuffer): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* base64-encode an ArrayBuffer. uses chunked btoa to avoid stack overflow
|
|
23
|
+
* on large buffers (`String.fromCharCode(...veryLargeArray)` blows up).
|
|
24
|
+
*/
|
|
25
|
+
export declare function base64Encode(buffer: ArrayBuffer): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* decode a base64 string into a Uint8Array.
|
|
28
|
+
*/
|
|
29
|
+
export declare function base64Decode(b64: string): Promise<Uint8Array>;
|
|
30
|
+
/**
|
|
31
|
+
* write blob bytes to OPFS. prefers `FileSystemSyncAccessHandle` (worker-only,
|
|
32
|
+
* fastest path on chromium/safari/firefox) and falls back to the async
|
|
33
|
+
* writable-stream API. silently no-ops if OPFS is unavailable.
|
|
34
|
+
*
|
|
35
|
+
* `data` should be transferred across postMessage to avoid a copy.
|
|
36
|
+
*/
|
|
37
|
+
export declare function writeBlobToOpfs(blobId: string, data: ArrayBuffer): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* read blob bytes from OPFS into a transferable ArrayBuffer. returns null
|
|
40
|
+
* if the file doesn't exist or OPFS is unavailable.
|
|
41
|
+
*/
|
|
42
|
+
export declare function readBlobFromOpfs(blobId: string): Promise<ArrayBuffer | null>;
|
|
43
|
+
export interface ProcessedBlob {
|
|
44
|
+
blob_id: string;
|
|
45
|
+
sha256: string;
|
|
46
|
+
blake3: string;
|
|
47
|
+
size: number;
|
|
48
|
+
mime: string;
|
|
49
|
+
filename: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* one-shot: hash bytes (sha256 + blake3), write to OPFS, return metadata.
|
|
53
|
+
* lets callers avoid three round-trips across the worker boundary for an
|
|
54
|
+
* upload. `data` should be transferred.
|
|
55
|
+
*
|
|
56
|
+
* blake3 is the canonical blob id (matches iroh-blobs / a native rust
|
|
57
|
+
* store); sha256 is still computed so legacy sha256-keyed records and old
|
|
58
|
+
* doc references keep resolving via the sha256 index.
|
|
59
|
+
*/
|
|
60
|
+
export declare function processBlobBytes(data: ArrayBuffer, filename: string, mime: string): Promise<ProcessedBlob>;
|
|
61
|
+
export interface ResizeImageOptions {
|
|
62
|
+
/** maximum output width in pixels (default: 200) */
|
|
63
|
+
maxWidth?: number;
|
|
64
|
+
/** maximum output height in pixels (default: 200) */
|
|
65
|
+
maxHeight?: number;
|
|
66
|
+
/** WebP quality 0..1 (default: 0.8) */
|
|
67
|
+
quality?: number;
|
|
68
|
+
/** if true, center-crop to a square before resizing */
|
|
69
|
+
cropSquare?: boolean;
|
|
70
|
+
/** output mime type (default: "image/webp") */
|
|
71
|
+
mime?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* resize an image Blob to a WebP data URL via OffscreenCanvas. all heavy
|
|
75
|
+
* work (image decode, resize, WebP encode, base64 encode) happens here.
|
|
76
|
+
* returns null on any failure.
|
|
77
|
+
*
|
|
78
|
+
* the input Blob is structured-cloned across postMessage by reference
|
|
79
|
+
* (the underlying bytes aren't copied), so this is cheap to call.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resizeImageToWebpDataUrl(blob: Blob, options?: ResizeImageOptions): Promise<string | null>;
|
|
82
|
+
/**
|
|
83
|
+
* convenience wrapper that fits an image inside `maxSize` x `maxSize`,
|
|
84
|
+
* encoding WebP at 0.75 quality. skips non-image blobs.
|
|
85
|
+
*/
|
|
86
|
+
export declare function generateThumbnailDataUrl(blob: Blob, maxSize?: number): Promise<string | null>;
|
|
87
|
+
/**
|
|
88
|
+
* begin a streaming upload session. throws when the environment can't
|
|
89
|
+
* support it (no OPFS sync access handles, or no midden module with a
|
|
90
|
+
* Blake3Hasher bundled) - callers fall back to the one-shot
|
|
91
|
+
* processBlobBytes path.
|
|
92
|
+
*/
|
|
93
|
+
export declare function uploadBegin(): Promise<number>;
|
|
94
|
+
/** append the next chunk (transferred buffer) to a session. */
|
|
95
|
+
export declare function uploadPush(id: number, buffer: ArrayBuffer): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* finish a session: flush + close the temp file, then rename it to the
|
|
98
|
+
* final blake3 content address. returns { blake3, size }.
|
|
99
|
+
*/
|
|
100
|
+
export declare function uploadFinish(id: number): Promise<{
|
|
101
|
+
blake3: string;
|
|
102
|
+
size: number;
|
|
103
|
+
}>;
|
|
104
|
+
/** abort a session: close and delete the temp file. */
|
|
105
|
+
export declare function uploadAbort(id: number): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* opfs-store selftest - runs the embedding app's midden module's
|
|
108
|
+
* out-of-crate iroh-blobs store round trip against real OPFS. must run in
|
|
109
|
+
* a dedicated worker: sync access handles don't exist on the main thread.
|
|
110
|
+
* throws when no midden module (or no `opfs_store_selftest` export) is
|
|
111
|
+
* bundled.
|
|
112
|
+
*/
|
|
113
|
+
export declare function opfsStoreSelftest(): Promise<string>;
|
|
114
|
+
/**
|
|
115
|
+
* persistence selftest - blobs + tags must survive a store shutdown and
|
|
116
|
+
* reopen over the same OPFS directory (the whole point of the store:
|
|
117
|
+
* cross-reload resume without re-import). worker context required.
|
|
118
|
+
*/
|
|
119
|
+
export declare function opfsStoreSelftestPersistence(): Promise<string>;
|
|
120
|
+
//# sourceMappingURL=blob-worker-logic.d.ts.map
|
|
@@ -0,0 +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,CAYlE;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnE;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CASvE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAOnE;AAuBD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCtF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAUlF;AAID,MAAM,WAAW,aAAa;IAC5B,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;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CAcxB;AAID,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuDxB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,SAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOhG;AAoBD;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAwBnD;AAED,+DAA+D;AAC/D,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0CxF;AAED,uDAAuD;AACvD,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3D;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAOzD;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,CAAC,CAOpE"}
|