@freqhole/reliquary 0.3.12 → 0.3.13

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.
Files changed (40) hide show
  1. package/README.md +3 -4
  2. package/dist/blobs/bytes-backend.d.ts +8 -2
  3. package/dist/blobs/bytes-backend.d.ts.map +1 -1
  4. package/dist/blobs/bytes-backend.js +9 -3
  5. package/dist/blobs/db.d.ts +0 -1
  6. package/dist/blobs/db.d.ts.map +1 -1
  7. package/dist/blobs/db.js +5 -8
  8. package/dist/blobs/db.test.d.ts.map +1 -1
  9. package/dist/blobs/db.test.js +13 -32
  10. package/dist/blobs/store.d.ts +9 -3
  11. package/dist/blobs/store.d.ts.map +1 -1
  12. package/dist/blobs/store.js +16 -28
  13. package/dist/blobs/store.test.js +36 -24
  14. package/dist/blobs/types.d.ts +3 -7
  15. package/dist/blobs/types.d.ts.map +1 -1
  16. package/dist/blobs/types.js +5 -5
  17. package/dist/utils/index.d.ts +0 -1
  18. package/dist/utils/index.d.ts.map +1 -1
  19. package/dist/utils/index.js +0 -1
  20. package/dist/worker/blob-worker-client.d.ts +0 -5
  21. package/dist/worker/blob-worker-client.d.ts.map +1 -1
  22. package/dist/worker/blob-worker-client.js +1 -15
  23. package/dist/worker/blob-worker-client.test.js +2 -10
  24. package/dist/worker/blob-worker-logic.d.ts +3 -14
  25. package/dist/worker/blob-worker-logic.d.ts.map +1 -1
  26. package/dist/worker/blob-worker-logic.js +7 -24
  27. package/dist/worker/blob-worker-logic.test.js +1 -9
  28. package/dist/worker/blob-worker.d.ts +1 -2
  29. package/dist/worker/blob-worker.d.ts.map +1 -1
  30. package/dist/worker/blob-worker.js +3 -4
  31. package/dist/worker/index.d.ts +1 -1
  32. package/dist/worker/index.d.ts.map +1 -1
  33. package/dist/worker/index.js +1 -1
  34. package/package.json +1 -1
  35. package/dist/utils/hash.d.ts +0 -13
  36. package/dist/utils/hash.d.ts.map +0 -1
  37. package/dist/utils/hash.js +0 -31
  38. package/dist/utils/hash.test.d.ts +0 -2
  39. package/dist/utils/hash.test.d.ts.map +0 -1
  40. package/dist/utils/hash.test.js +0 -56
package/README.md CHANGED
@@ -8,10 +8,9 @@ utils. rust crate `reliquary` + npm package `@freqhole/reliquary`.
8
8
 
9
9
  ## architecture
10
10
 
11
- blake3 is the canonical content address everywhere (sha256 kept only as a legacy secondary
12
- index). iroh p2p is a transport, not the architecture - the store contracts and transfer
13
- flows are transport-injected. this library never owns an http server: range serving stays in
14
- the consuming app.
11
+ blake3 is the sole canonical content address everywhere. iroh p2p is a transport, not the
12
+ architecture - the store contracts and transfer flows are transport-injected. this library
13
+ never owns an http server: range serving stays in the consuming app.
15
14
 
16
15
  ```mermaid
17
16
  graph LR
@@ -16,8 +16,14 @@ export interface BytesBackend {
16
16
  export declare function isOPFSSupported(): boolean;
17
17
  export declare function createOpfsBackend(): BytesBackend;
18
18
  export declare function createCacheBackend(): BytesBackend;
19
- /** the default resolver chain: OPFS first, Cache API fallback. */
20
- export declare function defaultBytesChain(): BytesBackend[];
19
+ /** the default resolver chain: OPFS first, Cache API fallback. pass
20
+ * `skipOpfs` to drop OPFS entirely - for engines where
21
+ * `navigator.storage.getDirectory` is feature-detectable but silently
22
+ * non-functional (confirmed real 2026-10-07 on macOS Catalina's bundled
23
+ * WebKit: OPFS writes/reads never throw, but every read comes back
24
+ * empty - a blob URL registers with the right MIME type yet "has no
25
+ * content" in the inspector). */
26
+ export declare function defaultBytesChain(skipOpfs?: boolean): BytesBackend[];
21
27
  /**
22
28
  * write bytes through the chain, trying each backend in order until one
23
29
  * accepts the write. returns the name of the backend that succeeded, or
@@ -1 +1 @@
1
- {"version":3,"file":"bytes-backend.d.ts","sourceRoot":"","sources":["../../src/blobs/bytes-backend.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC;;iBAEa;IACb,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,+DAA+D;IAC/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAYD,wBAAgB,iBAAiB,IAAI,YAAY,CAmEhD;AAgBD,wBAAgB,kBAAkB,IAAI,YAAY,CA8DjD;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,IAAI,YAAY,EAAE,CAElD;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAMlC;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,EACV,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED,sEAAsE;AACtE,wBAAsB,eAAe,CACnC,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,EACV,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;kDAEkD;AAClD,wBAAsB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF"}
1
+ {"version":3,"file":"bytes-backend.d.ts","sourceRoot":"","sources":["../../src/blobs/bytes-backend.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC;;iBAEa;IACb,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,+DAA+D;IAC/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAYD,wBAAgB,iBAAiB,IAAI,YAAY,CAmEhD;AAgBD,wBAAgB,kBAAkB,IAAI,YAAY,CA8DjD;AAED;;;;;;kCAMkC;AAClC,wBAAgB,iBAAiB,CAAC,QAAQ,UAAQ,GAAG,YAAY,EAAE,CAElE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAMlC;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,EACV,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED,sEAAsE;AACtE,wBAAsB,eAAe,CACnC,KAAK,EAAE,YAAY,EAAE,EACrB,EAAE,EAAE,MAAM,EACV,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;kDAEkD;AAClD,wBAAsB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF"}
@@ -190,9 +190,15 @@ export function createCacheBackend() {
190
190
  },
191
191
  };
192
192
  }
193
- /** the default resolver chain: OPFS first, Cache API fallback. */
194
- export function defaultBytesChain() {
195
- return [createOpfsBackend(), createCacheBackend()];
193
+ /** the default resolver chain: OPFS first, Cache API fallback. pass
194
+ * `skipOpfs` to drop OPFS entirely - for engines where
195
+ * `navigator.storage.getDirectory` is feature-detectable but silently
196
+ * non-functional (confirmed real 2026-10-07 on macOS Catalina's bundled
197
+ * WebKit: OPFS writes/reads never throw, but every read comes back
198
+ * empty - a blob URL registers with the right MIME type yet "has no
199
+ * content" in the inspector). */
200
+ export function defaultBytesChain(skipOpfs = false) {
201
+ return skipOpfs ? [createCacheBackend()] : [createOpfsBackend(), createCacheBackend()];
196
202
  }
197
203
  /**
198
204
  * write bytes through the chain, trying each backend in order until one
@@ -1,7 +1,6 @@
1
1
  import type { BlobRecord } from "./types.js";
2
2
  export declare function putRecord(dbName: string, record: BlobRecord): Promise<void>;
3
3
  export declare function getRecord(dbName: string, blobId: string): Promise<BlobRecord | null>;
4
- export declare function getRecordBySha256(dbName: string, sha256: string): Promise<BlobRecord | null>;
5
4
  export declare function getRecordByBlake3(dbName: string, blake3: string): Promise<BlobRecord | null>;
6
5
  export declare function deleteRecord(dbName: string, blobId: string): Promise<void>;
7
6
  export declare function clearRecords(dbName: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/blobs/db.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA6I7C,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjF;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAS1F;AA4BD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAE5F;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAE5F;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAchF;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAchE;AAQD,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrG;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcxG;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAYrF;AAED,wBAAsB,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBrG;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcnE;AAaD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC1C,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3B;mDAC+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC,CA8EtG"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/blobs/db.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA+I7C,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjF;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAS1F;AA4BD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAE5F;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAchF;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAchE;AAQD,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAYrF;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcnE;AAaD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC1C,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC3B;mDAC+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,aAAa,CAAC,CA+ExB"}
package/dist/blobs/db.js CHANGED
@@ -1,8 +1,6 @@
1
1
  // the metadata side of the resolver chain: an IndexedDB-backed record
2
2
  // store keyed by blob_id (the blake3 hex digest), with secondary indexes
3
- // so a record can also be found by its legacy sha256, by blake3 alone
4
- // (covering a record whose primary key is a legacy sha256), by blob_type,
5
- // or by parent_blob_id.
3
+ // so a record can also be found by blob_type or parent_blob_id.
6
4
  //
7
5
  // follows a "open fresh, close when done" pattern for every operation
8
6
  // rather than holding one long-lived connection open - simple, and avoids
@@ -14,7 +12,7 @@ const DB_VERSION = 3;
14
12
  // by openDb's version-fallback path to detect an already-existing database
15
13
  // that's missing an index added by a newer db.ts than whatever build last
16
14
  // touched it.
17
- const BLOB_INDEXES = ["sha256", "blake3", "blob_type", "parent_blob_id", "size", "created_at"];
15
+ const BLOB_INDEXES = ["blake3", "blob_type", "parent_blob_id", "size", "created_at"];
18
16
  const REFS_INDEXES = ["blob_id", "canvas_doc_id"];
19
17
  function openVersioned(dbName, version) {
20
18
  return new Promise((resolve, reject) => {
@@ -51,7 +49,9 @@ function openVersioned(dbName, version) {
51
49
  // this before purging local bytes, instead of scanning every
52
50
  // canvas. composite key so re-adding an existing ref is a no-op
53
51
  // (put with the same key overwrites, add() would throw).
54
- const refs = db.createObjectStore(REFS_STORE_NAME, { keyPath: ["blob_id", "canvas_doc_id"] });
52
+ const refs = db.createObjectStore(REFS_STORE_NAME, {
53
+ keyPath: ["blob_id", "canvas_doc_id"],
54
+ });
55
55
  for (const name of REFS_INDEXES) {
56
56
  refs.createIndex(name, name, { unique: false });
57
57
  }
@@ -185,9 +185,6 @@ async function getByIndex(dbName, indexName, value) {
185
185
  tx.oncomplete = () => db.close();
186
186
  });
187
187
  }
188
- export function getRecordBySha256(dbName, sha256) {
189
- return getByIndex(dbName, "sha256", sha256);
190
- }
191
188
  export function getRecordByBlake3(dbName, blake3) {
192
189
  return getByIndex(dbName, "blake3", blake3);
193
190
  }
@@ -1 +1 @@
1
- {"version":3,"file":"db.test.d.ts","sourceRoot":"","sources":["../../src/blobs/db.test.ts"],"names":[],"mappings":"AAGA,OAAO,qBAAqB,CAAC"}
1
+ {"version":3,"file":"db.test.d.ts","sourceRoot":"","sources":["../../src/blobs/db.test.ts"],"names":[],"mappings":"AAIA,OAAO,qBAAqB,CAAC"}
@@ -1,9 +1,10 @@
1
1
  // exercises the metadata layer directly: CRUD + secondary indexes
2
- // (sha256, blake3) that make the record resolver chain possible.
2
+ // (blake3, blob_type, parent_blob_id) that make the record resolver chain
3
+ // possible.
3
4
  import "fake-indexeddb/auto";
4
5
  import { IDBFactory } from "fake-indexeddb";
5
6
  import { beforeEach, describe, expect, it } from "vitest";
6
- import { addCanvasRef, clearCanvasRefs, clearRecords, deleteRecord, getCanvasRefs, getRecord, getRecordByBlake3, getRecordBySha256, listBlobs, putRecord, removeAllCanvasRefsForCanvas, removeCanvasRef, } from "./db.js";
7
+ import { addCanvasRef, clearCanvasRefs, clearRecords, deleteRecord, getCanvasRefs, getRecord, getRecordByBlake3, listBlobs, putRecord, removeAllCanvasRefsForCanvas, removeCanvasRef, } from "./db.js";
7
8
  const DB_NAME = "blobs-db-test";
8
9
  beforeEach(() => {
9
10
  globalThis.indexedDB = new IDBFactory();
@@ -12,7 +13,6 @@ function makeRecord(overrides = {}) {
12
13
  return {
13
14
  blob_id: "blake3-aaa",
14
15
  blake3: "blake3-aaa",
15
- sha256: "sha256-aaa",
16
16
  filename: "song.mp3",
17
17
  mime: "audio/mpeg",
18
18
  size: 1234,
@@ -39,32 +39,14 @@ describe("putRecord / getRecord", () => {
39
39
  expect(record?.filename).toBe("second.mp3");
40
40
  });
41
41
  });
42
- describe("getRecordBySha256 / getRecordByBlake3", () => {
43
- it("finds a record by its sha256 index", async () => {
44
- const record = makeRecord();
45
- await putRecord(DB_NAME, record);
46
- expect(await getRecordBySha256(DB_NAME, "sha256-aaa")).toEqual(record);
47
- });
42
+ describe("getRecordByBlake3", () => {
48
43
  it("finds a record by its blake3 index", async () => {
49
44
  const record = makeRecord();
50
45
  await putRecord(DB_NAME, record);
51
46
  expect(await getRecordByBlake3(DB_NAME, "blake3-aaa")).toEqual(record);
52
47
  });
53
- it("finds a legacy record whose primary key is a sha256, not its blake3", async () => {
54
- // simulates a record created before blake3 became canonical: blob_id
55
- // is the legacy sha256, but blake3 is known and indexed separately.
56
- const legacy = makeRecord({
57
- blob_id: "sha256-legacy",
58
- blake3: "blake3-discovered-later",
59
- sha256: "sha256-legacy",
60
- });
61
- await putRecord(DB_NAME, legacy);
62
- expect(await getRecordByBlake3(DB_NAME, "blake3-discovered-later")).toEqual(legacy);
63
- expect(await getRecord(DB_NAME, "sha256-legacy")).toEqual(legacy);
64
- });
65
48
  it("returns null for an empty hash rather than matching everything", async () => {
66
49
  await putRecord(DB_NAME, makeRecord());
67
- expect(await getRecordBySha256(DB_NAME, "")).toBeNull();
68
50
  expect(await getRecordByBlake3(DB_NAME, "")).toBeNull();
69
51
  });
70
52
  });
@@ -134,7 +116,6 @@ describe("pre-existing database at a higher version", () => {
134
116
  const req = indexedDB.open(dbName, 3);
135
117
  req.onupgradeneeded = () => {
136
118
  const store = req.result.createObjectStore("blobs", { keyPath: "blob_id" });
137
- store.createIndex("sha256", "sha256", { unique: false });
138
119
  store.createIndex("blake3", "blake3", { unique: false });
139
120
  };
140
121
  req.onsuccess = () => {
@@ -151,22 +132,22 @@ describe("pre-existing database at a higher version", () => {
151
132
  it("repairs a missing index even when both stores already exist at DB_VERSION", async () => {
152
133
  // reproduces a real-world case: a database that reached DB_VERSION
153
134
  // under an earlier build of this module - one that created both
154
- // stores but not yet the "sha256" index added later. since both
155
- // stores already exist and the version already matches, naively
135
+ // stores but not yet the "parent_blob_id" index added later. since
136
+ // both stores already exist and the version already matches, naively
156
137
  // reusing that version would never fire onupgradeneeded again,
157
- // permanently leaving the missing index unrepaired - getRecordBySha256
158
- // would then always report a miss instead of finding the record
159
- // (getByIndex falls through gracefully rather than throwing, so a
160
- // silent "never repaired" regression wouldn't otherwise be caught).
138
+ // permanently leaving the missing index unrepaired - resolveBlob's
139
+ // lookups would then always report a miss instead of finding the
140
+ // record (getByIndex falls through gracefully rather than throwing,
141
+ // so a silent "never repaired" regression wouldn't otherwise be
142
+ // caught).
161
143
  const dbName = "already-at-version-missing-index-db";
162
144
  await new Promise((resolve, reject) => {
163
145
  const req = indexedDB.open(dbName, 3);
164
146
  req.onupgradeneeded = () => {
165
147
  const db = req.result;
166
148
  const store = db.createObjectStore("blobs", { keyPath: "blob_id" });
167
- // deliberately missing: "sha256" index.
168
149
  store.createIndex("blake3", "blake3", { unique: false });
169
- store.createIndex("blob_type", "blob_type", { unique: false });
150
+ // deliberately missing: "blob_type" index.
170
151
  store.createIndex("parent_blob_id", "parent_blob_id", { unique: false });
171
152
  store.createIndex("size", "size", { unique: false });
172
153
  store.createIndex("created_at", "created_at", { unique: false });
@@ -184,7 +165,7 @@ describe("pre-existing database at a higher version", () => {
184
165
  });
185
166
  const record = makeRecord();
186
167
  await putRecord(dbName, record);
187
- expect(await getRecordBySha256(dbName, record.sha256)).toEqual(record);
168
+ expect(await getRecordByBlake3(dbName, record.blake3)).toEqual(record);
188
169
  });
189
170
  });
190
171
  describe("listBlobs", () => {
@@ -1,7 +1,7 @@
1
1
  import { type ListBlobsOptions, type ListBlobsPage } from "./db.js";
2
2
  import type { BlobLocalityInfo, BlobRecord, NewBlobMeta } from "./types.js";
3
3
  export { isOPFSSupported } from "./bytes-backend.js";
4
- export type { BlobLocalityInfo, BlobLocalityMetadata, BlobRecord, BlobType, BytesBackendName, NewBlobMeta } from "./types.js";
4
+ export type { BlobLocalityInfo, BlobLocalityMetadata, BlobRecord, BlobType, BytesBackendName, NewBlobMeta, } from "./types.js";
5
5
  export type { ListBlobsOptions, ListBlobsPage } from "./db.js";
6
6
  /** default IndexedDB database name for apps that don't need to preserve an
7
7
  * existing one. */
@@ -19,6 +19,13 @@ export interface BlobStoreOptions {
19
19
  * caller didn't expect is worse than a loud failure the caller can
20
20
  * retry or surface. */
21
21
  allowCacheFallback?: boolean;
22
+ /** when true, skip OPFS entirely and always use the Cache API - for
23
+ * engines where OPFS is feature-detectable (`navigator.storage.
24
+ * getDirectory` exists) but silently non-functional: confirmed real
25
+ * 2026-10-07 on macOS Catalina's bundled WebKit, every OPFS read came
26
+ * back empty (no exception anywhere) despite writes reporting
27
+ * success. defaults to false. */
28
+ disableOpfs?: boolean;
22
29
  }
23
30
  export interface StoreBlobFromFileOptions {
24
31
  onProgress?: (fraction: number) => void;
@@ -29,7 +36,6 @@ export interface BlobStore {
29
36
  storeBlobFromFile(file: File, meta?: Partial<NewBlobMeta>, options?: StoreBlobFromFileOptions): Promise<BlobRecord>;
30
37
  getBlobRecord(blobId: string): Promise<BlobRecord | null>;
31
38
  getBlobRecordByBlake3(blake3: string): Promise<BlobRecord | null>;
32
- getBlobRecordBySha256(sha256: string): Promise<BlobRecord | null>;
33
39
  resolveBlob(blobId: string, blake3?: string): Promise<BlobRecord | null>;
34
40
  getBlobMetadata(blobId: string, blake3?: string): Promise<BlobRecord | null>;
35
41
  getBlobData(blobId: string, blake3?: string): Promise<ArrayBuffer | null>;
@@ -55,6 +61,6 @@ export interface BlobStore {
55
61
  /** create a blob store instance. each instance owns its own object-url
56
62
  * cache; construct one per app (not per component/request). */
57
63
  export declare function createBlobStore(options?: BlobStoreOptions): BlobStore;
58
- export { writeThroughChain, readThroughChain, hasBytesInChain, removeFromChain } from "./bytes-backend.js";
64
+ export { writeThroughChain, readThroughChain, hasBytesInChain, removeFromChain, } from "./bytes-backend.js";
59
65
  export type { BytesBackend } from "./bytes-backend.js";
60
66
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/blobs/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/blobs/store.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,10 @@
1
1
  // the blake3-canonical blob record store: ties the metadata side (db.ts,
2
2
  // IndexedDB) to the bytes side (bytes-backend.ts, OPFS + Cache API) behind
3
- // one API, and implements the resolver chain that lets old sha256-era
4
- // references keep working alongside new blake3-keyed records.
3
+ // one API.
5
4
  //
6
5
  // "resolver chain" here means two related lookup chains:
7
- // - record resolution (`resolveBlob`): primary key -> blake3 index ->
8
- // sha256 index -> blake3 index again with a separately-known hash.
9
- // this is what lets a caller pass either a blake3 or a legacy sha256
10
- // and get the same record back.
6
+ // - record resolution (`resolveBlob`): primary key -> blake3 index
7
+ // (separately-known hash).
11
8
  // - bytes resolution (`bytes-backend.ts`'s `readThroughChain`): a
12
9
  // record's `storage_backend` field says where its bytes were written;
13
10
  // when that's unknown (a record predating the field) every backend is
@@ -19,9 +16,9 @@
19
16
  // storage (OPFS directory, Cache API cache) is content-addressed by
20
17
  // blake3 and shared at the origin regardless of which app wrote it, so it
21
18
  // is not parameterized per store instance - see `bytes-backend.ts`.
22
- import { hashBlake3, hashSha256, streamFileToOpfs } from "../worker/index.js";
23
- import { addCanvasRef, clearCanvasRefs, clearRecords, deleteRecord, getCanvasRefs, getRecord, getRecordByBlake3, getRecordBySha256, listBlobs, putRecord, removeAllCanvasRefsForCanvas, removeCanvasRef, } from "./db.js";
24
- import { createOpfsBackend, defaultBytesChain, hasBytesInChain, readThroughChain, removeFromChain, writeThroughChain, } from "./bytes-backend.js";
19
+ import { hashBlake3, streamFileToOpfs } from "../worker/index.js";
20
+ import { addCanvasRef, clearCanvasRefs, clearRecords, deleteRecord, getCanvasRefs, getRecord, getRecordByBlake3, listBlobs, putRecord, removeAllCanvasRefsForCanvas, removeCanvasRef, } from "./db.js";
21
+ import { createCacheBackend, createOpfsBackend, defaultBytesChain, hasBytesInChain, readThroughChain, removeFromChain, writeThroughChain, } from "./bytes-backend.js";
25
22
  export { isOPFSSupported } from "./bytes-backend.js";
26
23
  /** default IndexedDB database name for apps that don't need to preserve an
27
24
  * existing one. */
@@ -34,7 +31,11 @@ const STREAM_UPLOAD_THRESHOLD = 8 * 1024 * 1024;
34
31
  * cache; construct one per app (not per component/request). */
35
32
  export function createBlobStore(options = {}) {
36
33
  const dbName = options.dbName ?? DEFAULT_DB_NAME;
37
- const chain = options.allowCacheFallback ? defaultBytesChain() : [createOpfsBackend()];
34
+ const chain = options.disableOpfs
35
+ ? [createCacheBackend()]
36
+ : options.allowCacheFallback
37
+ ? defaultBytesChain()
38
+ : [createOpfsBackend()];
38
39
  const blobUrlCache = new Map();
39
40
  let beforeUnloadRegistered = false;
40
41
  function ensureBeforeUnloadListener() {
@@ -48,9 +49,9 @@ export function createBlobStore(options = {}) {
48
49
  beforeUnloadRegistered = true;
49
50
  }
50
51
  async function storeBlob(data, meta) {
51
- // hash before writing anything - both hashers copy their input rather
52
+ // hash before writing anything - blake3 hashing copies its input rather
52
53
  // than transferring it, so `data` is still intact for the write below.
53
- const [blake3, sha256] = await Promise.all([hashBlake3(new Uint8Array(data)), hashSha256(data)]);
54
+ const blake3 = await hashBlake3(new Uint8Array(data));
54
55
  const blobId = blake3;
55
56
  // dedup - content-addressed, so a pre-existing record for this blake3
56
57
  // means the bytes are already stored under it.
@@ -68,7 +69,6 @@ export function createBlobStore(options = {}) {
68
69
  const record = {
69
70
  blob_id: blobId,
70
71
  blake3,
71
- sha256,
72
72
  filename: meta.filename,
73
73
  mime: meta.mime,
74
74
  size: data.byteLength,
@@ -90,9 +90,6 @@ export function createBlobStore(options = {}) {
90
90
  const existing = await getRecord(dbName, blake3);
91
91
  if (existing)
92
92
  return existing;
93
- // sha256 is legacy-only - it's never computed for a streamed
94
- // upload, since brand-new content has no old sha256-keyed
95
- // reference that would need it.
96
93
  const record = {
97
94
  blob_id: blake3,
98
95
  blake3,
@@ -129,15 +126,10 @@ export function createBlobStore(options = {}) {
129
126
  function getBlobRecordByBlake3(blake3) {
130
127
  return getRecordByBlake3(dbName, blake3);
131
128
  }
132
- function getBlobRecordBySha256(sha256) {
133
- return getRecordBySha256(dbName, sha256);
134
- }
135
129
  /**
136
130
  * resolve a blobId to a record using multiple lookup strategies: primary
137
- * key -> blake3 index (blobId itself) -> sha256 index -> blake3 index
138
- * (separately-known hash). handles both id generations - blake3 is
139
- * canonical now, sha256-keyed records are legacy but must keep
140
- * resolving.
131
+ * key -> blake3 index (blobId itself) -> blake3 index (separately-known
132
+ * hash).
141
133
  */
142
134
  async function resolveBlob(blobId, blake3) {
143
135
  if (!blobId)
@@ -148,9 +140,6 @@ export function createBlobStore(options = {}) {
148
140
  const byIdAsBlake3 = await getRecordByBlake3(dbName, blobId);
149
141
  if (byIdAsBlake3)
150
142
  return byIdAsBlake3;
151
- const bySha = await getRecordBySha256(dbName, blobId);
152
- if (bySha)
153
- return bySha;
154
143
  if (blake3) {
155
144
  const byBlake3 = await getRecordByBlake3(dbName, blake3);
156
145
  if (byBlake3)
@@ -245,7 +234,6 @@ export function createBlobStore(options = {}) {
245
234
  storeBlobFromFile,
246
235
  getBlobRecord,
247
236
  getBlobRecordByBlake3,
248
- getBlobRecordBySha256,
249
237
  resolveBlob,
250
238
  getBlobMetadata: resolveBlob,
251
239
  getBlobData,
@@ -266,4 +254,4 @@ export function createBlobStore(options = {}) {
266
254
  // low-level building blocks re-exported for callers that need to compose
267
255
  // their own resolver chain (e.g. a future transfer layer writing
268
256
  // already-hashed, already-verified bytes without re-hashing them here).
269
- export { writeThroughChain, readThroughChain, hasBytesInChain, removeFromChain } from "./bytes-backend.js";
257
+ export { writeThroughChain, readThroughChain, hasBytesInChain, removeFromChain, } from "./bytes-backend.js";
@@ -4,10 +4,11 @@
4
4
  // (db.ts) and the bytes layer (bytes-backend.ts) together behind
5
5
  // createBlobStore(). the worker (hashing + the OPFS write path) is mocked
6
6
  // since no environment here has a real Worker or a bundled midden module -
7
- // the mock computes a deterministic fake "blake3" from the sha256 digest
8
- // (real crypto.subtle is available in happy-dom) and writes bytes through
9
- // the exact same fake OPFS directory the direct-read path uses, so the
10
- // round trip is meaningful.
7
+ // the mock computes a deterministic fake "blake3" from a sha256 digest
8
+ // (real crypto.subtle is available in happy-dom, sha256 is just used here
9
+ // as a convenient stand-in digest, not a feature under test) and writes
10
+ // bytes through the exact same fake OPFS directory the direct-read path
11
+ // uses, so the round trip is meaningful.
11
12
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
12
13
  import { fakeIdbHarness } from "../testing/index.js";
13
14
  // ---- fake OPFS (same shape as blob-worker-logic.test.ts / bytes-backend.test.ts) ----
@@ -17,7 +18,10 @@ class FakeWritable {
17
18
  this.file = file;
18
19
  }
19
20
  async write(data) {
20
- this.file.bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer);
21
+ this.file.bytes =
22
+ data instanceof ArrayBuffer
23
+ ? new Uint8Array(data)
24
+ : new Uint8Array(data.buffer);
21
25
  }
22
26
  async close() { }
23
27
  }
@@ -61,7 +65,7 @@ function installFakeOpfs() {
61
65
  },
62
66
  });
63
67
  }
64
- async function fakeSha256Hex(data) {
68
+ async function fakeDigestHex(data) {
65
69
  const digest = await crypto.subtle.digest("SHA-256", data);
66
70
  return Array.from(new Uint8Array(digest))
67
71
  .map((b) => b.toString(16).padStart(2, "0"))
@@ -82,18 +86,17 @@ vi.mock("../worker/index.js", () => ({
82
86
  }),
83
87
  // a real blake3 digest is unavailable in this test environment (no
84
88
  // bundled midden module) - derive a distinct, deterministic stand-in
85
- // from the sha256 digest so different content still gets different
86
- // content addresses. neither hasher writes any bytes - matching the
89
+ // from a sha256 digest so different content still gets different
90
+ // content addresses. the hasher doesn't write any bytes - matching the
87
91
  // real worker client, which only hashes here.
88
92
  hashBlake3: vi.fn(async (data) => {
89
- const sha256 = await fakeSha256Hex(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
90
- return `b3-${sha256}`;
93
+ const digest = await fakeDigestHex(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
94
+ return `b3-${digest}`;
91
95
  }),
92
- hashSha256: vi.fn(async (data) => fakeSha256Hex(data)),
93
96
  streamFileToOpfs: vi.fn(async (file) => {
94
97
  const buffer = await file.arrayBuffer();
95
- const sha256 = await fakeSha256Hex(buffer);
96
- const blake3 = `b3-${sha256}`;
98
+ const digest = await fakeDigestHex(buffer);
99
+ const blake3 = `b3-${digest}`;
97
100
  await writeToFakeOpfs(blake3, buffer);
98
101
  return { blake3, size: buffer.byteLength };
99
102
  }),
@@ -228,7 +231,10 @@ describe("storeBlob / getBlob / getBlobData", () => {
228
231
  // available but must NOT be used since allowCacheFallback defaults to
229
232
  // false (Q25: loam's crash-loud semantics are the default).
230
233
  const store = createBlobStore({ dbName: "store-test-no-fallback-default" });
231
- await expect(store.storeBlob(textBuffer("opfs-less content"), { filename: "no-opfs.txt", mime: "text/plain" })).rejects.toThrow(/no bytes backend accepted/);
234
+ await expect(store.storeBlob(textBuffer("opfs-less content"), {
235
+ filename: "no-opfs.txt",
236
+ mime: "text/plain",
237
+ })).rejects.toThrow(/no bytes backend accepted/);
232
238
  });
233
239
  });
234
240
  describe("storeBlobFromFile", () => {
@@ -237,17 +243,15 @@ describe("storeBlobFromFile", () => {
237
243
  const file = new File([textBuffer("small file contents")], "small.txt", { type: "text/plain" });
238
244
  const record = await store.storeBlobFromFile(file);
239
245
  expect(record.filename).toBe("small.txt");
240
- expect(record.sha256).toBeTruthy();
241
246
  const data = await store.getBlobData(record.blob_id);
242
247
  expect(new TextDecoder().decode(data)).toBe("small file contents");
243
248
  });
244
- it("streams large files and omits sha256 (legacy-only, never computed for streamed uploads)", async () => {
249
+ it("streams large files", async () => {
245
250
  const store = createBlobStore({ dbName: "store-test-file-large" });
246
251
  const bigBytes = new Uint8Array(8 * 1024 * 1024 + 10).fill(7);
247
252
  const file = new File([bigBytes], "large.bin", { type: "application/octet-stream" });
248
253
  const record = await store.storeBlobFromFile(file);
249
254
  expect(record.size).toBe(bigBytes.byteLength);
250
- expect(record.sha256).toBeUndefined();
251
255
  const data = await store.getBlobData(record.blob_id);
252
256
  expect(data?.byteLength).toBe(bigBytes.byteLength);
253
257
  });
@@ -261,11 +265,10 @@ describe("storeBlobFromFile", () => {
261
265
  });
262
266
  });
263
267
  describe("resolveBlob", () => {
264
- it("resolves a legacy sha256-primary-keyed record by its blake3 index", async () => {
268
+ it("resolves a record whose primary key differs from its blake3", async () => {
265
269
  await putRecord("store-test-resolve", {
266
- blob_id: "legacy-sha256-key",
270
+ blob_id: "legacy-key",
267
271
  blake3: "blake3-known-later",
268
- sha256: "legacy-sha256-key",
269
272
  filename: "legacy.txt",
270
273
  mime: "text/plain",
271
274
  size: 4,
@@ -276,13 +279,16 @@ describe("resolveBlob", () => {
276
279
  });
277
280
  const store = createBlobStore({ dbName: "store-test-resolve" });
278
281
  expect(await store.resolveBlob("blake3-known-later")).not.toBeNull();
279
- expect(await store.resolveBlob("legacy-sha256-key")).not.toBeNull();
282
+ expect(await store.resolveBlob("legacy-key")).not.toBeNull();
280
283
  expect(await store.resolveBlob("anything", "blake3-known-later")).not.toBeNull();
281
284
  expect(await store.resolveBlob("nothing-matches")).toBeNull();
282
285
  });
283
286
  it("getBlobMetadata is an alias for resolveBlob", async () => {
284
287
  const store = createBlobStore({ dbName: "store-test-metadata-alias" });
285
- const record = await store.storeBlob(textBuffer("meta"), { filename: "m.txt", mime: "text/plain" });
288
+ const record = await store.storeBlob(textBuffer("meta"), {
289
+ filename: "m.txt",
290
+ mime: "text/plain",
291
+ });
286
292
  expect(await store.getBlobMetadata(record.blob_id)).toEqual(record);
287
293
  });
288
294
  });
@@ -367,8 +373,14 @@ describe("deleteBlob / clearAll", () => {
367
373
  });
368
374
  it("clearAll wipes every record and every backend's bytes", async () => {
369
375
  const store = createBlobStore({ dbName: "store-test-clear-all" });
370
- const a = await store.storeBlob(textBuffer("clear-all-a"), { filename: "a.txt", mime: "text/plain" });
371
- const b = await store.storeBlob(textBuffer("clear-all-b"), { filename: "b.txt", mime: "text/plain" });
376
+ const a = await store.storeBlob(textBuffer("clear-all-a"), {
377
+ filename: "a.txt",
378
+ mime: "text/plain",
379
+ });
380
+ const b = await store.storeBlob(textBuffer("clear-all-b"), {
381
+ filename: "b.txt",
382
+ mime: "text/plain",
383
+ });
372
384
  await store.clearAll();
373
385
  expect(await store.getBlobRecord(a.blob_id)).toBeNull();
374
386
  expect(await store.getBlobRecord(b.blob_id)).toBeNull();
@@ -8,12 +8,8 @@ export interface BlobRecord {
8
8
  /** canonical id - the blake3 hex digest. */
9
9
  blob_id: string;
10
10
  /** blake3 hex digest (same value as blob_id for every record created by
11
- * this store; kept as its own field, and its own index, so a record
12
- * legacy-keyed by sha256 can still be found by blake3 once known). */
11
+ * this store; kept as its own field, and its own index). */
13
12
  blake3: string;
14
- /** legacy sha256 hex digest, kept for records/references that predate
15
- * blake3 becoming canonical. never computed for new streamed uploads. */
16
- sha256?: string;
17
13
  filename: string;
18
14
  mime: string;
19
15
  size: number;
@@ -26,8 +22,8 @@ export interface BlobRecord {
26
22
  storage_backend?: BytesBackendName;
27
23
  }
28
24
  /** everything needed to store a new blob, other than the bytes and the
29
- * fields this store computes/fills in itself (blob_id, blake3, sha256,
30
- * size, created_at, storage_backend). */
25
+ * fields this store computes/fills in itself (blob_id, blake3, size,
26
+ * created_at, storage_backend). */
31
27
  export interface NewBlobMeta {
32
28
  filename: string;
33
29
  mime: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/blobs/types.ts"],"names":[],"mappings":"AAQA,kFAAkF;AAClF,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEzE;;2EAE2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB;;2EAEuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf;8EAC0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,QAAQ,CAAC;IACpB;qDACiD;IACjD,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,gBAAgB,CAAC;CACpC;AAED;;0CAE0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/blobs/types.ts"],"names":[],"mappings":"AAQA,kFAAkF;AAClF,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEzE;;2EAE2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB;iEAC6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,QAAQ,CAAC;IACpB;qDACiD;IACjD,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,gBAAgB,CAAC;CACpC;AAED;;oCAEoC;AACpC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC"}
@@ -1,8 +1,8 @@
1
1
  // shared shapes for the blake3-canonical blob record store.
2
2
  //
3
- // core schema: blake3 primary key, sha256 legacy index, blob_type, parent
4
- // linkage. this browser version omits native-only fields (on-disk path,
5
- // external flag, soft-delete bookkeeping) and app-specific classification
6
- // fields (e.g. domain tags) - callers that want classification can use
7
- // the `metadata` field.
3
+ // core schema: blake3 primary key, blob_type, parent linkage. this
4
+ // browser version omits native-only fields (on-disk path, external flag,
5
+ // soft-delete bookkeeping) and app-specific classification fields (e.g.
6
+ // domain tags) - callers that want classification can use the
7
+ // `metadata` field.
8
8
  export {};
@@ -1,4 +1,3 @@
1
- export * from "./hash.js";
2
1
  export * from "./image-utils.js";
3
2
  export * from "./log.js";
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC"}
@@ -1,3 +1,2 @@
1
- export * from "./hash.js";
2
1
  export * from "./image-utils.js";
3
2
  export * from "./log.js";
@@ -31,10 +31,6 @@ export declare function shutdownBlobWorker(): void;
31
31
  * underlying buffer.
32
32
  */
33
33
  export declare function hashBlake3(data: Uint8Array): Promise<string>;
34
- /**
35
- * sha256 hash of an ArrayBuffer.
36
- */
37
- export declare function hashSha256(data: ArrayBuffer): Promise<string>;
38
34
  /**
39
35
  * base64-encode an ArrayBuffer.
40
36
  *
@@ -50,7 +46,6 @@ export declare function base64Encode(buffer: ArrayBuffer): Promise<string>;
50
46
  */
51
47
  export declare function processBlobBytes(buffer: ArrayBuffer, filename: string, mime: string): Promise<{
52
48
  blob_id: string;
53
- sha256: string;
54
49
  blake3: string;
55
50
  size: number;
56
51
  mime: string;
@@ -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;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"}
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;AAqBtD;;;;;;;;;;;;;;;;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;;;;;;;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,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAcD;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"}
@@ -8,7 +8,6 @@
8
8
  // the client falls back to a synchronous in-process implementation so
9
9
  // callers don't have to branch.
10
10
  import * as Comlink from "comlink";
11
- import { sha256Hex } from "../utils/hash.js";
12
11
  import { loadMiddenBlake3 } from "./midden-blake3.js";
13
12
  import { BLOB_WORKER_READY_MESSAGE } from "./blob-worker-logic.js";
14
13
  import { log } from "../utils/log.js";
@@ -149,15 +148,6 @@ export async function hashBlake3(data) {
149
148
  return worker.hashBlake3(data);
150
149
  return fallbackHashBlake3(data);
151
150
  }
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
151
  /**
162
152
  * base64-encode an ArrayBuffer.
163
153
  *
@@ -182,13 +172,9 @@ export async function processBlobBytes(buffer, filename, mime) {
182
172
  return worker.processBlobBytes(Comlink.transfer(buffer, [buffer]), filename, mime);
183
173
  }
184
174
  // main-thread fallback path - rare, mostly for tests.
185
- const [sha256, blake3] = await Promise.all([
186
- sha256Hex(buffer),
187
- fallbackHashBlake3(new Uint8Array(buffer)),
188
- ]);
175
+ const blake3 = await fallbackHashBlake3(new Uint8Array(buffer));
189
176
  return {
190
177
  blob_id: blake3,
191
- sha256,
192
178
  blake3,
193
179
  size: buffer.byteLength,
194
180
  mime,
@@ -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, hashBlake3Streaming, hashSha256, processBlobBytes, resizeImageToWebpDataUrl, shutdownBlobWorker, streamFileToOpfs, writeBlobToOpfs, } from "./blob-worker-client.js";
3
+ import { base64Decode, base64Encode, generateThumbnailDataUrl, getBlobWorker, hashBlake3, hashBlake3Streaming, 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
@@ -84,13 +84,6 @@ describe("hashBlake3", () => {
84
84
  expect(await hashBlake3(new Uint8Array([1, 2, 3]))).toBe("");
85
85
  });
86
86
  });
87
- describe("hashSha256", () => {
88
- it("falls back to a real sha-256 digest with no worker", async () => {
89
- const bytes = new TextEncoder().encode("abc");
90
- const hash = await hashSha256(bytes.buffer);
91
- expect(hash).toBe("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
92
- });
93
- });
94
87
  describe("base64Encode / base64Decode", () => {
95
88
  it("round-trips bytes through the fallback path", async () => {
96
89
  const original = new Uint8Array([0, 1, 2, 253, 254, 255]);
@@ -100,12 +93,11 @@ describe("base64Encode / base64Decode", () => {
100
93
  });
101
94
  });
102
95
  describe("processBlobBytes", () => {
103
- it("hashes without a worker (blake3 empty, sha256 real)", async () => {
96
+ it("hashes without a worker (blake3 empty)", async () => {
104
97
  const bytes = new TextEncoder().encode("hello world");
105
98
  const result = await processBlobBytes(bytes.buffer, "hello.txt", "text/plain");
106
99
  expect(result.blake3).toBe("");
107
100
  expect(result.blob_id).toBe("");
108
- expect(result.sha256).toBe("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
109
101
  expect(result.size).toBe(bytes.byteLength);
110
102
  });
111
103
  });
@@ -12,12 +12,6 @@ export declare const OPFS_DIR = "reliquary-blobs";
12
12
  * it does not export `hash_blake3`.
13
13
  */
14
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
15
  /**
22
16
  * base64-encode an ArrayBuffer. uses chunked btoa to avoid stack overflow
23
17
  * on large buffers (`String.fromCharCode(...veryLargeArray)` blows up).
@@ -42,20 +36,15 @@ export declare function writeBlobToOpfs(blobId: string, data: ArrayBuffer): Prom
42
36
  export declare function readBlobFromOpfs(blobId: string): Promise<ArrayBuffer | null>;
43
37
  export interface ProcessedBlob {
44
38
  blob_id: string;
45
- sha256: string;
46
39
  blake3: string;
47
40
  size: number;
48
41
  mime: string;
49
42
  filename: string;
50
43
  }
51
44
  /**
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.
45
+ * one-shot: hash bytes (blake3), write to OPFS, return metadata. lets
46
+ * callers avoid round-trips across the worker boundary for an upload.
47
+ * `data` should be transferred.
59
48
  */
60
49
  export declare function processBlobBytes(data: ArrayBuffer, filename: string, mime: string): Promise<ProcessedBlob>;
61
50
  export interface ResizeImageOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"blob-worker-logic.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-logic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blob-worker-logic.d.ts","sourceRoot":"","sources":["../../src/worker/blob-worker-logic.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- // blob worker logic - the CPU-bound blob work (blake3 hashing, sha256
2
- // hashing, base64 encode/decode, OPFS writes, thumbnail generation, chunked
3
- // upload sessions) that `blob-worker.ts` exposes over comlink.
1
+ // blob worker logic - the CPU-bound blob work (blake3 hashing, base64
2
+ // encode/decode, OPFS writes, thumbnail generation, chunked upload
3
+ // sessions) that `blob-worker.ts` exposes over comlink.
4
4
  //
5
5
  // kept free of comlink/postMessage side effects on purpose: this module is
6
6
  // what the test suite imports directly, and what `blob-worker.ts` (the
@@ -12,7 +12,6 @@
12
12
  // degrades to an empty string and the streaming upload/selftest functions
13
13
  // throw a clear error, matching the graceful-degradation contract of the
14
14
  // rest of this file.
15
- import { sha256Hex } from "../utils/hash.js";
16
15
  import { loadMiddenBlake3 } from "./midden-blake3.js";
17
16
  import { log } from "../utils/log.js";
18
17
  const TAG = "blob.worker.logic";
@@ -43,14 +42,6 @@ export async function hashBlake3(data) {
43
42
  return "";
44
43
  }
45
44
  }
46
- /**
47
- * compute sha256 hash via SubtleCrypto. SubtleCrypto.digest is already
48
- * async/non-blocking on the main thread, but this is exposed here too so
49
- * callers can do sha256 + blake3 in a single round-trip.
50
- */
51
- export async function hashSha256(data) {
52
- return sha256Hex(data);
53
- }
54
45
  /**
55
46
  * base64-encode an ArrayBuffer. uses chunked btoa to avoid stack overflow
56
47
  * on large buffers (`String.fromCharCode(...veryLargeArray)` blows up).
@@ -140,23 +131,15 @@ export async function readBlobFromOpfs(blobId) {
140
131
  }
141
132
  }
142
133
  /**
143
- * one-shot: hash bytes (sha256 + blake3), write to OPFS, return metadata.
144
- * lets callers avoid three round-trips across the worker boundary for an
145
- * upload. `data` should be transferred.
146
- *
147
- * blake3 is the canonical blob id (matches iroh-blobs / a native rust
148
- * store); sha256 is still computed so legacy sha256-keyed records and old
149
- * doc references keep resolving via the sha256 index.
134
+ * one-shot: hash bytes (blake3), write to OPFS, return metadata. lets
135
+ * callers avoid round-trips across the worker boundary for an upload.
136
+ * `data` should be transferred.
150
137
  */
151
138
  export async function processBlobBytes(data, filename, mime) {
152
- // run sha256 and blake3 concurrently. SubtleCrypto.digest does its own
153
- // copy of the bytes, so we can't transfer-and-reuse - do them in parallel
154
- // and let the runtime overlap them.
155
- const [sha256, blake3] = await Promise.all([hashSha256(data), hashBlake3(new Uint8Array(data))]);
139
+ const blake3 = await hashBlake3(new Uint8Array(data));
156
140
  await writeBlobToOpfs(blake3, data);
157
141
  return {
158
142
  blob_id: blake3,
159
- sha256,
160
143
  blake3,
161
144
  size: data.byteLength,
162
145
  mime,
@@ -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, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, hashSha256, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadBegin, writeBlobToOpfs, } from "./blob-worker-logic.js";
3
+ import { base64Decode, base64Encode, generateThumbnailDataUrl, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, 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
@@ -91,13 +91,6 @@ afterEach(() => {
91
91
  vi.unstubAllGlobals();
92
92
  resetMiddenBlake3Cache();
93
93
  });
94
- describe("hashSha256", () => {
95
- it("hashes a known buffer to its well-known sha-256 digest", async () => {
96
- const bytes = new TextEncoder().encode("abc");
97
- const hash = await hashSha256(bytes.buffer);
98
- expect(hash).toBe("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
99
- });
100
- });
101
94
  describe("hashBlake3", () => {
102
95
  it("degrades to an empty string when no midden module is bundled", async () => {
103
96
  const hash = await hashBlake3(new Uint8Array([1, 2, 3]));
@@ -154,7 +147,6 @@ describe("processBlobBytes", () => {
154
147
  // to an empty string, and blob_id mirrors it (documented behavior).
155
148
  expect(result.blake3).toBe("");
156
149
  expect(result.blob_id).toBe(result.blake3);
157
- expect(result.sha256).toBe("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
158
150
  });
159
151
  });
160
152
  describe("uploadBegin", () => {
@@ -1,7 +1,6 @@
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";
1
+ import { base64Decode, base64Encode, generateThumbnailDataUrl, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, 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
- hashSha256: typeof hashSha256;
5
4
  base64Encode: typeof base64Encode;
6
5
  base64Decode: typeof base64Decode;
7
6
  writeBlobToOpfs: typeof writeBlobToOpfs;
@@ -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,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"}
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,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;;;;;;;;;;;;;;;;;;;CAmBR,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,CAAC"}
@@ -1,5 +1,5 @@
1
- // blob worker entry - moves CPU-bound blob work (blake3 hashing, sha256
2
- // hashing, base64 encode/decode, OPFS writes) off the main thread.
1
+ // blob worker entry - moves CPU-bound blob work (blake3 hashing, base64
2
+ // encode/decode, OPFS writes) off the main thread.
3
3
  //
4
4
  // architecture: comlink-exposed module. spun up lazily by
5
5
  // `blob-worker-client.ts` on first use. shares no state with the main
@@ -12,10 +12,9 @@
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, hashAbort, hashBegin, hashBlake3, hashFinish, hashPush, 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, opfsStoreSelftest, opfsStoreSelftestPersistence, processBlobBytes, readBlobFromOpfs, resizeImageToWebpDataUrl, uploadAbort, uploadBegin, uploadFinish, uploadPush, writeBlobToOpfs, } from "./blob-worker-logic.js";
16
16
  const api = {
17
17
  hashBlake3,
18
- hashSha256,
19
18
  base64Encode,
20
19
  base64Decode,
21
20
  writeBlobToOpfs,
@@ -1,7 +1,7 @@
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, hashBlake3Streaming, hashSha256, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
4
+ export { getBlobWorker, shutdownBlobWorker, hashBlake3, hashBlake3Streaming, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
5
5
  export type { MiddenWorkerApi, MiddenWorkerIdentity, MiddenWorkerInitOptions, 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";
@@ -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,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,uBAAuB,EACvB,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,EACL,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,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"}
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,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,uBAAuB,EACvB,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,EACL,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,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"}
@@ -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, hashBlake3Streaming, hashSha256, base64Encode, base64Decode, processBlobBytes, writeBlobToOpfs, streamFileToOpfs, resizeImageToWebpDataUrl, generateThumbnailDataUrl, } from "./blob-worker-client.js";
2
+ export { getBlobWorker, shutdownBlobWorker, hashBlake3, hashBlake3Streaming, 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, WorkerRadioHandle, } 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.3.12",
3
+ "version": "0.3.13",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "freqhole media blob storage domain: content-addressed blobs, transfer, worker, solid helpers",
@@ -1,13 +0,0 @@
1
- /**
2
- * hash of an ArrayBuffer (or a view over one) as a lowercase hex string.
3
- */
4
- export declare function sha256Hex(data: ArrayBuffer | ArrayBufferView): Promise<string>;
5
- /**
6
- * hash of a File/Blob's contents as a lowercase hex string.
7
- */
8
- export declare function sha256HexOfBlob(blob: Blob): Promise<string>;
9
- /**
10
- * true if `data` hashes to `expectedHex` (case-insensitive).
11
- */
12
- export declare function verifySha256Hex(data: ArrayBuffer | ArrayBufferView, expectedHex: string): Promise<boolean>;
13
- //# sourceMappingURL=hash.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAMpF;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAEjE;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,GAAG,eAAe,EACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAGlB"}
@@ -1,31 +0,0 @@
1
- // sha256 hashing helpers built on the web crypto subtle api. used wherever a
2
- // content hash is needed but the full blake3-canonical blob pipeline (./blobs,
3
- // ./worker) is overkill - legacy sha256 references, quick integrity checks, etc.
4
- /**
5
- * hash of an ArrayBuffer (or a view over one) as a lowercase hex string.
6
- */
7
- export async function sha256Hex(data) {
8
- const buffer = ArrayBuffer.isView(data)
9
- ? data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)
10
- : data;
11
- const digest = await crypto.subtle.digest("SHA-256", buffer);
12
- return bufferToHex(digest);
13
- }
14
- /**
15
- * hash of a File/Blob's contents as a lowercase hex string.
16
- */
17
- export async function sha256HexOfBlob(blob) {
18
- return sha256Hex(await blob.arrayBuffer());
19
- }
20
- /**
21
- * true if `data` hashes to `expectedHex` (case-insensitive).
22
- */
23
- export async function verifySha256Hex(data, expectedHex) {
24
- const actual = await sha256Hex(data);
25
- return actual === expectedHex.toLowerCase();
26
- }
27
- function bufferToHex(buffer) {
28
- return Array.from(new Uint8Array(buffer))
29
- .map((b) => b.toString(16).padStart(2, "0"))
30
- .join("");
31
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=hash.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hash.test.d.ts","sourceRoot":"","sources":["../../src/utils/hash.test.ts"],"names":[],"mappings":""}
@@ -1,56 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { sha256Hex, sha256HexOfBlob, verifySha256Hex } from "./hash.js";
3
- // known-answer test vectors for sha-256
4
- const EMPTY_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
5
- const ABC_HASH = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
6
- function textToBuffer(text) {
7
- return new TextEncoder().encode(text).buffer;
8
- }
9
- describe("sha256Hex", () => {
10
- it("hashes an empty buffer to the well-known sha-256 empty digest", async () => {
11
- const hash = await sha256Hex(new ArrayBuffer(0));
12
- expect(hash).toBe(EMPTY_HASH);
13
- });
14
- it("hashes 'abc' to its well-known sha-256 digest", async () => {
15
- const hash = await sha256Hex(textToBuffer("abc"));
16
- expect(hash).toBe(ABC_HASH);
17
- });
18
- it("accepts an ArrayBufferView (Uint8Array) as well as a raw ArrayBuffer", async () => {
19
- const bytes = new TextEncoder().encode("abc");
20
- const hash = await sha256Hex(bytes);
21
- expect(hash).toBe(ABC_HASH);
22
- });
23
- it("only hashes the view's byte range, not the whole underlying buffer", async () => {
24
- const backing = new Uint8Array(10);
25
- backing.set(new TextEncoder().encode("abc"), 2);
26
- const view = new Uint8Array(backing.buffer, 2, 3);
27
- const hash = await sha256Hex(view);
28
- expect(hash).toBe(ABC_HASH);
29
- });
30
- it("produces different hashes for different inputs", async () => {
31
- const a = await sha256Hex(textToBuffer("hello"));
32
- const b = await sha256Hex(textToBuffer("world"));
33
- expect(a).not.toBe(b);
34
- });
35
- });
36
- describe("sha256HexOfBlob", () => {
37
- it("hashes a Blob's contents the same as its raw bytes", async () => {
38
- const blob = new Blob(["abc"]);
39
- const hash = await sha256HexOfBlob(blob);
40
- expect(hash).toBe(ABC_HASH);
41
- });
42
- });
43
- describe("verifySha256Hex", () => {
44
- it("returns true when the expected hash matches", async () => {
45
- const ok = await verifySha256Hex(textToBuffer("abc"), ABC_HASH);
46
- expect(ok).toBe(true);
47
- });
48
- it("returns false when the expected hash does not match", async () => {
49
- const ok = await verifySha256Hex(textToBuffer("abc"), EMPTY_HASH);
50
- expect(ok).toBe(false);
51
- });
52
- it("is case-insensitive when comparing the expected hash", async () => {
53
- const ok = await verifySha256Hex(textToBuffer("abc"), ABC_HASH.toUpperCase());
54
- expect(ok).toBe(true);
55
- });
56
- });