@adobe/data-persistence 0.9.90

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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +258 -0
  3. package/dist/backend/memory-backend.d.ts +6 -0
  4. package/dist/backend/memory-backend.js +92 -0
  5. package/dist/backend/memory-backend.js.map +1 -0
  6. package/dist/backend/memory-backend.test.d.ts +1 -0
  7. package/dist/backend/memory-backend.test.js +7 -0
  8. package/dist/backend/memory-backend.test.js.map +1 -0
  9. package/dist/backend/memory-file.d.ts +7 -0
  10. package/dist/backend/memory-file.js +90 -0
  11. package/dist/backend/memory-file.js.map +1 -0
  12. package/dist/backend/memory-file.test.d.ts +1 -0
  13. package/dist/backend/memory-file.test.js +5 -0
  14. package/dist/backend/memory-file.test.js.map +1 -0
  15. package/dist/backend/persistence-backend.conformance.d.ts +10 -0
  16. package/dist/backend/persistence-backend.conformance.js +104 -0
  17. package/dist/backend/persistence-backend.conformance.js.map +1 -0
  18. package/dist/backend/persistence-backend.d.ts +54 -0
  19. package/dist/backend/persistence-backend.js +3 -0
  20. package/dist/backend/persistence-backend.js.map +1 -0
  21. package/dist/backend/random-access-file.conformance.d.ts +20 -0
  22. package/dist/backend/random-access-file.conformance.js +156 -0
  23. package/dist/backend/random-access-file.conformance.js.map +1 -0
  24. package/dist/backend/random-access-file.d.ts +39 -0
  25. package/dist/backend/random-access-file.js +3 -0
  26. package/dist/backend/random-access-file.js.map +1 -0
  27. package/dist/backend/validate-rel-path.d.ts +14 -0
  28. package/dist/backend/validate-rel-path.js +44 -0
  29. package/dist/backend/validate-rel-path.js.map +1 -0
  30. package/dist/backend/validate-rel-path.test.d.ts +1 -0
  31. package/dist/backend/validate-rel-path.test.js +37 -0
  32. package/dist/backend/validate-rel-path.test.js.map +1 -0
  33. package/dist/browser/browser-worker-bootstrap.d.ts +1 -0
  34. package/dist/browser/browser-worker-bootstrap.js +97 -0
  35. package/dist/browser/browser-worker-bootstrap.js.map +1 -0
  36. package/dist/browser/browser-worker-transport.browser.test.d.ts +1 -0
  37. package/dist/browser/browser-worker-transport.browser.test.js +156 -0
  38. package/dist/browser/browser-worker-transport.browser.test.js.map +1 -0
  39. package/dist/browser/browser-worker-transport.d.ts +33 -0
  40. package/dist/browser/browser-worker-transport.js +120 -0
  41. package/dist/browser/browser-worker-transport.js.map +1 -0
  42. package/dist/browser/create-opfs-provider.d.ts +23 -0
  43. package/dist/browser/create-opfs-provider.js +49 -0
  44. package/dist/browser/create-opfs-provider.js.map +1 -0
  45. package/dist/browser/index.d.ts +6 -0
  46. package/dist/browser/index.js +12 -0
  47. package/dist/browser/index.js.map +1 -0
  48. package/dist/browser/mount-opfs.d.ts +12 -0
  49. package/dist/browser/mount-opfs.js +15 -0
  50. package/dist/browser/mount-opfs.js.map +1 -0
  51. package/dist/browser/opfs-backend-lock.browser.test.d.ts +1 -0
  52. package/dist/browser/opfs-backend-lock.browser.test.js +127 -0
  53. package/dist/browser/opfs-backend-lock.browser.test.js.map +1 -0
  54. package/dist/browser/opfs-backend.d.ts +6 -0
  55. package/dist/browser/opfs-backend.js +162 -0
  56. package/dist/browser/opfs-backend.js.map +1 -0
  57. package/dist/browser/opfs-lock-test-worker.d.ts +1 -0
  58. package/dist/browser/opfs-lock-test-worker.js +50 -0
  59. package/dist/browser/opfs-lock-test-worker.js.map +1 -0
  60. package/dist/browser/opfs-sync-file.d.ts +10 -0
  61. package/dist/browser/opfs-sync-file.js +58 -0
  62. package/dist/browser/opfs-sync-file.js.map +1 -0
  63. package/dist/encoder/create-column-encoder.d.ts +15 -0
  64. package/dist/encoder/create-column-encoder.js +110 -0
  65. package/dist/encoder/create-column-encoder.js.map +1 -0
  66. package/dist/encoder/journal-snapshot-codec.d.ts +21 -0
  67. package/dist/encoder/journal-snapshot-codec.js +103 -0
  68. package/dist/encoder/journal-snapshot-codec.js.map +1 -0
  69. package/dist/encoder/journal-snapshot-codec.test.d.ts +1 -0
  70. package/dist/encoder/journal-snapshot-codec.test.js +96 -0
  71. package/dist/encoder/journal-snapshot-codec.test.js.map +1 -0
  72. package/dist/encoder/types.d.ts +72 -0
  73. package/dist/encoder/types.js +3 -0
  74. package/dist/encoder/types.js.map +1 -0
  75. package/dist/index.d.ts +24 -0
  76. package/dist/index.js +15 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/journal/journal-codec.d.ts +28 -0
  79. package/dist/journal/journal-codec.js +82 -0
  80. package/dist/journal/journal-codec.js.map +1 -0
  81. package/dist/journal/journal-codec.test.d.ts +1 -0
  82. package/dist/journal/journal-codec.test.js +106 -0
  83. package/dist/journal/journal-codec.test.js.map +1 -0
  84. package/dist/journal/journal-entry.d.ts +63 -0
  85. package/dist/journal/journal-entry.js +28 -0
  86. package/dist/journal/journal-entry.js.map +1 -0
  87. package/dist/node/create-node-fs-provider.d.ts +34 -0
  88. package/dist/node/create-node-fs-provider.js +48 -0
  89. package/dist/node/create-node-fs-provider.js.map +1 -0
  90. package/dist/node/index.d.ts +6 -0
  91. package/dist/node/index.js +10 -0
  92. package/dist/node/index.js.map +1 -0
  93. package/dist/node/mount-node-fs.d.ts +12 -0
  94. package/dist/node/mount-node-fs.js +15 -0
  95. package/dist/node/mount-node-fs.js.map +1 -0
  96. package/dist/node/node-fs-backend-lock.node.test.d.ts +1 -0
  97. package/dist/node/node-fs-backend-lock.node.test.js +160 -0
  98. package/dist/node/node-fs-backend-lock.node.test.js.map +1 -0
  99. package/dist/node/node-fs-backend.d.ts +21 -0
  100. package/dist/node/node-fs-backend.js +186 -0
  101. package/dist/node/node-fs-backend.js.map +1 -0
  102. package/dist/node/node-fs-backend.node.test.d.ts +1 -0
  103. package/dist/node/node-fs-backend.node.test.js +17 -0
  104. package/dist/node/node-fs-backend.node.test.js.map +1 -0
  105. package/dist/node/node-fs-file.d.ts +6 -0
  106. package/dist/node/node-fs-file.js +57 -0
  107. package/dist/node/node-fs-file.js.map +1 -0
  108. package/dist/node/node-fs-file.node.test.d.ts +1 -0
  109. package/dist/node/node-fs-file.node.test.js +13 -0
  110. package/dist/node/node-fs-file.node.test.js.map +1 -0
  111. package/dist/node/node-fs-provider.node.test.d.ts +1 -0
  112. package/dist/node/node-fs-provider.node.test.js +119 -0
  113. package/dist/node/node-fs-provider.node.test.js.map +1 -0
  114. package/dist/node/node-worker-bootstrap.d.ts +1 -0
  115. package/dist/node/node-worker-bootstrap.js +104 -0
  116. package/dist/node/node-worker-bootstrap.js.map +1 -0
  117. package/dist/node/node-worker-transport.d.ts +27 -0
  118. package/dist/node/node-worker-transport.js +152 -0
  119. package/dist/node/node-worker-transport.js.map +1 -0
  120. package/dist/node/node-worker-transport.node.test.d.ts +1 -0
  121. package/dist/node/node-worker-transport.node.test.js +147 -0
  122. package/dist/node/node-worker-transport.node.test.js.map +1 -0
  123. package/dist/perftest/perf-harness.d.ts +74 -0
  124. package/dist/perftest/perf-harness.js +147 -0
  125. package/dist/perftest/perf-harness.js.map +1 -0
  126. package/dist/perftest/persistence-perf.d.ts +2 -0
  127. package/dist/perftest/persistence-perf.js +290 -0
  128. package/dist/perftest/persistence-perf.js.map +1 -0
  129. package/dist/perftest/run.d.ts +1 -0
  130. package/dist/perftest/run.js +28 -0
  131. package/dist/perftest/run.js.map +1 -0
  132. package/dist/provider/create-memory-provider.d.ts +16 -0
  133. package/dist/provider/create-memory-provider.js +44 -0
  134. package/dist/provider/create-memory-provider.js.map +1 -0
  135. package/dist/provider/mount.d.ts +20 -0
  136. package/dist/provider/mount.js +20 -0
  137. package/dist/provider/mount.js.map +1 -0
  138. package/dist/provider/persistence-provider.d.ts +63 -0
  139. package/dist/provider/persistence-provider.js +3 -0
  140. package/dist/provider/persistence-provider.js.map +1 -0
  141. package/dist/provider/persistence-provider.test.d.ts +9 -0
  142. package/dist/provider/persistence-provider.test.js +139 -0
  143. package/dist/provider/persistence-provider.test.js.map +1 -0
  144. package/dist/service/component-nonpersistent-durability.test.d.ts +1 -0
  145. package/dist/service/component-nonpersistent-durability.test.js +57 -0
  146. package/dist/service/component-nonpersistent-durability.test.js.map +1 -0
  147. package/dist/service/create-incremental-persistence-service.d.ts +7 -0
  148. package/dist/service/create-incremental-persistence-service.js +960 -0
  149. package/dist/service/create-incremental-persistence-service.js.map +1 -0
  150. package/dist/service/create-worker-persistence-service.d.ts +1 -0
  151. package/dist/service/create-worker-persistence-service.js +7 -0
  152. package/dist/service/create-worker-persistence-service.js.map +1 -0
  153. package/dist/service/create-worker-persistence-service.test.d.ts +1 -0
  154. package/dist/service/create-worker-persistence-service.test.js +291 -0
  155. package/dist/service/create-worker-persistence-service.test.js.map +1 -0
  156. package/dist/service/entity-location-cache.d.ts +15 -0
  157. package/dist/service/entity-location-cache.js +75 -0
  158. package/dist/service/entity-location-cache.js.map +1 -0
  159. package/dist/service/entity-location-density.test.d.ts +1 -0
  160. package/dist/service/entity-location-density.test.js +42 -0
  161. package/dist/service/entity-location-density.test.js.map +1 -0
  162. package/dist/service/incremental-persistence-service.d.ts +57 -0
  163. package/dist/service/incremental-persistence-service.js +3 -0
  164. package/dist/service/incremental-persistence-service.js.map +1 -0
  165. package/dist/service/intermediate-relocation-durability.test.d.ts +1 -0
  166. package/dist/service/intermediate-relocation-durability.test.js +89 -0
  167. package/dist/service/intermediate-relocation-durability.test.js.map +1 -0
  168. package/dist/service/internal-access.d.ts +34 -0
  169. package/dist/service/internal-access.js +43 -0
  170. package/dist/service/internal-access.js.map +1 -0
  171. package/dist/service/journal-replay.test.d.ts +1 -0
  172. package/dist/service/journal-replay.test.js +424 -0
  173. package/dist/service/journal-replay.test.js.map +1 -0
  174. package/dist/service/journal-storage-durability.test.d.ts +1 -0
  175. package/dist/service/journal-storage-durability.test.js +171 -0
  176. package/dist/service/journal-storage-durability.test.js.map +1 -0
  177. package/dist/service/load-roundtrip.test.d.ts +1 -0
  178. package/dist/service/load-roundtrip.test.js +224 -0
  179. package/dist/service/load-roundtrip.test.js.map +1 -0
  180. package/dist/service/persistence-complexity.test.d.ts +1 -0
  181. package/dist/service/persistence-complexity.test.js +275 -0
  182. package/dist/service/persistence-complexity.test.js.map +1 -0
  183. package/dist/service/worker-persistence-service.d.ts +24 -0
  184. package/dist/service/worker-persistence-service.js +8 -0
  185. package/dist/service/worker-persistence-service.js.map +1 -0
  186. package/dist/transport/inprocess-transport.d.ts +15 -0
  187. package/dist/transport/inprocess-transport.js +64 -0
  188. package/dist/transport/inprocess-transport.js.map +1 -0
  189. package/dist/transport/inprocess-transport.test.d.ts +1 -0
  190. package/dist/transport/inprocess-transport.test.js +100 -0
  191. package/dist/transport/inprocess-transport.test.js.map +1 -0
  192. package/dist/transport/router.d.ts +12 -0
  193. package/dist/transport/router.js +146 -0
  194. package/dist/transport/router.js.map +1 -0
  195. package/dist/transport/transport.d.ts +105 -0
  196. package/dist/transport/transport.js +3 -0
  197. package/dist/transport/transport.js.map +1 -0
  198. package/package.json +59 -0
@@ -0,0 +1,156 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ //
3
+ // Browser E2E for the worker transport. Uses a real DOM Worker
4
+ // pointing at the bootstrap script, with the OPFS-backed router on
5
+ // the worker side. Vite/Vitest's transformer compiles the .ts worker
6
+ // entry on the fly via `new URL(...)`.
7
+ import { Database } from "@adobe/data/ecs";
8
+ import { F32, Vec3 } from "@adobe/data/math";
9
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
10
+ import { createBrowserWorkerTransport } from "./browser-worker-transport.js";
11
+ import { createWorkerPersistenceService } from "../service/create-worker-persistence-service.js";
12
+ // Helper: build a transport over a freshly-spawned worker. Vite picks
13
+ // up `new Worker(new URL(...), { type: "module" })` and bundles the
14
+ // bootstrap as a separate worker chunk.
15
+ const spawnWorker = () => new Worker(new URL("./browser-worker-bootstrap.ts", import.meta.url), { type: "module" });
16
+ // Each test gets its own clean OPFS root by clearing every entry under
17
+ // the per-origin OPFS directory before the test runs. Vitest browser
18
+ // shares the origin across tests, so without this we'd leak state.
19
+ const wipeOpfs = async () => {
20
+ if (typeof navigator === "undefined" || !navigator.storage?.getDirectory)
21
+ return;
22
+ const root = await navigator.storage.getDirectory();
23
+ const keys = [];
24
+ for await (const name of root.keys()) {
25
+ keys.push(name);
26
+ }
27
+ for (const name of keys) {
28
+ await root.removeEntry(name, { recursive: true });
29
+ }
30
+ };
31
+ const particlePlugin = Database.Plugin.create({
32
+ components: {
33
+ position: Vec3.schema,
34
+ velocity: Vec3.schema,
35
+ mass: F32.schema,
36
+ },
37
+ archetypes: {
38
+ Particle: ["position", "velocity", "mass"],
39
+ },
40
+ transactions: {
41
+ spawn(t, args) {
42
+ return t.archetypes.Particle.insert({
43
+ position: [args.x, args.y, args.z],
44
+ velocity: [0, 0, 0],
45
+ mass: args.mass,
46
+ });
47
+ },
48
+ move(t, args) {
49
+ t.update(args.entity, { position: [args.x, args.y, args.z] });
50
+ },
51
+ },
52
+ });
53
+ describe("createBrowserWorkerTransport (E2E, OPFS)", () => {
54
+ beforeEach(async () => {
55
+ await wipeOpfs();
56
+ });
57
+ afterEach(async () => {
58
+ await wipeOpfs();
59
+ });
60
+ it("round-trips entities through real Worker + OPFS", async () => {
61
+ const { createMemoryBackend } = await import("../backend/memory-backend.js");
62
+ let savedEntity;
63
+ // Saving phase.
64
+ {
65
+ const db = Database.create(particlePlugin);
66
+ const worker = spawnWorker();
67
+ const transport = createBrowserWorkerTransport({ worker });
68
+ // The backend on the main thread is unused at runtime when a
69
+ // transport is supplied — the worker owns the real OPFS backend.
70
+ // A memory backend satisfies the type seam.
71
+ const service = await createWorkerPersistenceService({
72
+ database: db,
73
+ backend: createMemoryBackend(),
74
+ transport,
75
+ checkpoint: { everyNTransactions: 0, idleMs: 0 },
76
+ });
77
+ savedEntity = db.transactions.spawn({ x: 1, y: 2, z: 3, mass: 10 });
78
+ db.transactions.move({ entity: savedEntity, x: 100, y: 200, z: 300 });
79
+ await service.flush();
80
+ await service.checkpoint();
81
+ await service.dispose();
82
+ // Caller-owned transport: must close explicitly so the
83
+ // worker shuts down and releases its OPFS access handles.
84
+ await transport.close();
85
+ }
86
+ // Loading phase: brand-new worker, brand-new database.
87
+ {
88
+ const db = Database.create(particlePlugin);
89
+ const worker = spawnWorker();
90
+ const transport = createBrowserWorkerTransport({ worker });
91
+ const service = await createWorkerPersistenceService({
92
+ database: db,
93
+ backend: createMemoryBackend(),
94
+ transport,
95
+ checkpoint: { everyNTransactions: 0, idleMs: 0 },
96
+ });
97
+ await service.load();
98
+ const view = db.read(savedEntity);
99
+ expect(view).not.toBeNull();
100
+ if (view !== null) {
101
+ expect(Array.from(view.position)).toEqual([100, 200, 300]);
102
+ expect(Array.from(view.velocity)).toEqual([0, 0, 0]);
103
+ expect(view.mass).toBe(10);
104
+ }
105
+ await service.dispose();
106
+ await transport.close();
107
+ }
108
+ });
109
+ it("survives multiple inserts and recovers all of them", async () => {
110
+ const { createMemoryBackend } = await import("../backend/memory-backend.js");
111
+ const ids = [];
112
+ {
113
+ const db = Database.create(particlePlugin);
114
+ const worker = spawnWorker();
115
+ const transport = createBrowserWorkerTransport({ worker });
116
+ const service = await createWorkerPersistenceService({
117
+ database: db,
118
+ backend: createMemoryBackend(),
119
+ transport,
120
+ checkpoint: { everyNTransactions: 0, idleMs: 0 },
121
+ });
122
+ for (let i = 0; i < 10; i++) {
123
+ const id = db.transactions.spawn({ x: i, y: i * 2, z: i * 3, mass: i * 0.5 });
124
+ if (id !== undefined)
125
+ ids.push(id);
126
+ }
127
+ await service.flush();
128
+ await service.checkpoint();
129
+ await service.dispose();
130
+ await transport.close();
131
+ }
132
+ {
133
+ const db = Database.create(particlePlugin);
134
+ const worker = spawnWorker();
135
+ const transport = createBrowserWorkerTransport({ worker });
136
+ const service = await createWorkerPersistenceService({
137
+ database: db,
138
+ backend: createMemoryBackend(),
139
+ transport,
140
+ checkpoint: { everyNTransactions: 0, idleMs: 0 },
141
+ });
142
+ await service.load();
143
+ for (let i = 0; i < ids.length; i++) {
144
+ const view = db.read(ids[i]);
145
+ expect(view).not.toBeNull();
146
+ if (view !== null) {
147
+ expect(Array.from(view.position)).toEqual([i, i * 2, i * 3]);
148
+ expect(view.mass).toBe(i * 0.5);
149
+ }
150
+ }
151
+ await service.dispose();
152
+ await transport.close();
153
+ }
154
+ });
155
+ });
156
+ //# sourceMappingURL=browser-worker-transport.browser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-worker-transport.browser.test.js","sourceRoot":"","sources":["../../src/browser/browser-worker-transport.browser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { Transport } from "../transport/transport.js";
2
+ /**
3
+ * Configuration for {@link createBrowserWorkerTransport}. The worker
4
+ * is constructed by the caller — bundlers (Vite, webpack, esbuild,
5
+ * Rolldown) all support `new Worker(new URL("./entry.js", import.meta.url), ...)`
6
+ * and need that pattern present in user code to discover the worker
7
+ * entry. Passing the worker in keeps this transport bundler-agnostic.
8
+ *
9
+ * Example (Vite):
10
+ *
11
+ * ```ts
12
+ * import workerUrl from "@adobe/data-persistence/browser-worker?url";
13
+ * const worker = new Worker(workerUrl, { type: "module" });
14
+ * const transport = createBrowserWorkerTransport({ worker });
15
+ * ```
16
+ */
17
+ export interface BrowserWorkerTransportOptions {
18
+ readonly worker: Worker;
19
+ /**
20
+ * If true, calling `transport.close()` also calls `worker.terminate()`.
21
+ * Defaults to true. Set to false when the same worker is shared
22
+ * across multiple consumers.
23
+ */
24
+ readonly terminateOnClose?: boolean;
25
+ }
26
+ /**
27
+ * Transport that frames the persistence protocol over a DOM Worker.
28
+ * The worker side must run the bootstrap from this package
29
+ * (`@adobe/data-persistence/browser-worker`). Bytes-bearing ops
30
+ * transfer their ArrayBuffer payloads via the postMessage transfer
31
+ * list for zero-copy hand-off.
32
+ */
33
+ export declare const createBrowserWorkerTransport: (options: BrowserWorkerTransportOptions) => Transport;
@@ -0,0 +1,120 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ /**
3
+ * Transport that frames the persistence protocol over a DOM Worker.
4
+ * The worker side must run the bootstrap from this package
5
+ * (`@adobe/data-persistence/browser-worker`). Bytes-bearing ops
6
+ * transfer their ArrayBuffer payloads via the postMessage transfer
7
+ * list for zero-copy hand-off.
8
+ */
9
+ export const createBrowserWorkerTransport = (options) => {
10
+ const { worker, terminateOnClose = true } = options;
11
+ const handlers = new Set();
12
+ const pendingRequests = new Map();
13
+ let closed = false;
14
+ let nextSentinelId = 1;
15
+ worker.addEventListener("message", (ev) => {
16
+ const msg = ev.data;
17
+ if (msg.kind === "ack") {
18
+ const resolver = pendingRequests.get(msg.id);
19
+ if (resolver !== undefined) {
20
+ pendingRequests.delete(msg.id);
21
+ resolver(msg);
22
+ }
23
+ }
24
+ for (const h of handlers)
25
+ h(msg);
26
+ });
27
+ worker.addEventListener("error", (ev) => {
28
+ // Surface unexpected worker errors as unhandled rejections so they
29
+ // don't get silently swallowed.
30
+ queueMicrotask(() => {
31
+ throw ev.error ?? new Error(ev.message);
32
+ });
33
+ });
34
+ const transferListFor = (op) => {
35
+ if (op.kind === "writeColumnSlice" || op.kind === "appendJournal") {
36
+ return [op.bytes];
37
+ }
38
+ return [];
39
+ };
40
+ // The Transport interface accepts `readonly Transferable[]`, but
41
+ // Worker.postMessage requires a mutable `Transferable[]`. Copy
42
+ // (cheap; usually 0 or 1 element) instead of casting.
43
+ const toMutableTransfer = (list, op) => list === undefined ? transferListFor(op) : [...list];
44
+ return {
45
+ send(op, transfer) {
46
+ if (closed)
47
+ throw new Error("Transport is closed");
48
+ worker.postMessage(op, toMutableTransfer(transfer, op));
49
+ },
50
+ request(op, transfer) {
51
+ if (closed)
52
+ throw new Error("Transport is closed");
53
+ return new Promise((resolve, reject) => {
54
+ // The transport's request<T>() generic is a contract
55
+ // with the caller about the expected reply payload;
56
+ // there is no way to verify it at runtime, so the
57
+ // reply is `unknown` until the caller asserts.
58
+ pendingRequests.set(op.id, (msg) => {
59
+ if (msg.error !== undefined)
60
+ reject(new Error(msg.error));
61
+ else
62
+ resolve(msg.value);
63
+ });
64
+ worker.postMessage(op, toMutableTransfer(transfer, op));
65
+ });
66
+ },
67
+ onMessage(handler) {
68
+ handlers.add(handler);
69
+ return () => handlers.delete(handler);
70
+ },
71
+ async flush() {
72
+ // See node-worker-transport for the sentinel rationale: the
73
+ // worker processes messages in receive order, so an acked
74
+ // sentinel implies all earlier sends were also handled.
75
+ await new Promise((resolve, reject) => {
76
+ const id = -nextSentinelId;
77
+ nextSentinelId += 1;
78
+ pendingRequests.set(id, (msg) => {
79
+ if (msg.error !== undefined)
80
+ reject(new Error(msg.error));
81
+ else
82
+ resolve();
83
+ });
84
+ worker.postMessage({ id, kind: "listDir", path: "." });
85
+ });
86
+ },
87
+ async close() {
88
+ if (closed)
89
+ return;
90
+ closed = true;
91
+ // Graceful shutdown: ask the worker to close its router
92
+ // (which releases all OPFS sync access handles) and wait
93
+ // for its ack before terminating. Without this wait, OPFS
94
+ // can still report "Access Handles cannot be created" on
95
+ // the next test/run because file releases are not yet
96
+ // visible to the next worker.
97
+ const id = -nextSentinelId;
98
+ nextSentinelId += 1;
99
+ const ackPromise = new Promise((resolve) => {
100
+ pendingRequests.set(id, () => resolve());
101
+ });
102
+ try {
103
+ worker.postMessage({ kind: "shutdown", id });
104
+ // Cap the wait so a wedged worker can't hang close().
105
+ await Promise.race([
106
+ ackPromise,
107
+ new Promise((resolve) => setTimeout(resolve, 1000)),
108
+ ]);
109
+ }
110
+ catch {
111
+ // postMessage may throw if the worker is already gone.
112
+ }
113
+ handlers.clear();
114
+ pendingRequests.clear();
115
+ if (terminateOnClose)
116
+ worker.terminate();
117
+ },
118
+ };
119
+ };
120
+ //# sourceMappingURL=browser-worker-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-worker-transport.js","sourceRoot":"","sources":["../../src/browser/browser-worker-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { PersistenceProvider } from "../provider/persistence-provider.js";
2
+ /**
3
+ * Creates a browser persistence provider backed by the Origin Private
4
+ * File System (OPFS). Always uses a dedicated `Worker` because
5
+ * `FileSystemSyncAccessHandle` requires a worker context.
6
+ *
7
+ * ```ts
8
+ * import { mount } from "@adobe/data-persistence";
9
+ * import { createOpfsProvider } from "@adobe/data-persistence/browser";
10
+ *
11
+ * const m = await mount(createOpfsProvider(), database);
12
+ * await m.service.load();
13
+ * // ...run app...
14
+ * await m.dispose();
15
+ * ```
16
+ *
17
+ * Pass an explicit `FileSystemDirectoryHandle` to use a subdirectory
18
+ * instead of the per-origin OPFS root.
19
+ *
20
+ * Must be called from the main thread or a shared worker — NOT from
21
+ * inside a dedicated worker.
22
+ */
23
+ export declare const createOpfsProvider: (root?: FileSystemDirectoryHandle) => PersistenceProvider;
@@ -0,0 +1,49 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ import { createIncrementalPersistenceService } from "../service/create-incremental-persistence-service.js";
3
+ import { createBrowserWorkerTransport } from "./browser-worker-transport.js";
4
+ import { createOpfsBackend } from "./opfs-backend.js";
5
+ /**
6
+ * Creates a browser persistence provider backed by the Origin Private
7
+ * File System (OPFS). Always uses a dedicated `Worker` because
8
+ * `FileSystemSyncAccessHandle` requires a worker context.
9
+ *
10
+ * ```ts
11
+ * import { mount } from "@adobe/data-persistence";
12
+ * import { createOpfsProvider } from "@adobe/data-persistence/browser";
13
+ *
14
+ * const m = await mount(createOpfsProvider(), database);
15
+ * await m.service.load();
16
+ * // ...run app...
17
+ * await m.dispose();
18
+ * ```
19
+ *
20
+ * Pass an explicit `FileSystemDirectoryHandle` to use a subdirectory
21
+ * instead of the per-origin OPFS root.
22
+ *
23
+ * Must be called from the main thread or a shared worker — NOT from
24
+ * inside a dedicated worker.
25
+ */
26
+ export const createOpfsProvider = (root) => ({
27
+ providerName: "OpfsProvider",
28
+ async mount(database, mountOptions) {
29
+ const resolvedRoot = root ?? await navigator.storage.getDirectory();
30
+ const worker = new Worker(new URL("./browser-worker-bootstrap.js", import.meta.url), { type: "module" });
31
+ const transport = createBrowserWorkerTransport({ worker });
32
+ const backend = await createOpfsBackend(resolvedRoot);
33
+ const service = await createIncrementalPersistenceService({
34
+ database,
35
+ backend,
36
+ transport,
37
+ autoPersist: mountOptions?.autoPersist,
38
+ checkpoint: mountOptions?.checkpoint,
39
+ });
40
+ return {
41
+ service,
42
+ async dispose() {
43
+ await service.dispose();
44
+ await transport.close();
45
+ },
46
+ };
47
+ },
48
+ });
49
+ //# sourceMappingURL=create-opfs-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-opfs-provider.js","sourceRoot":"","sources":["../../src/browser/create-opfs-provider.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAGvD,OAAO,EAAE,mCAAmC,EAAE,MAAM,sDAAsD,CAAC;AAE3G,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAC9B,IAAgC,EACb,EAAE,CAAC,CAAC;IACvB,YAAY,EAAE,cAAc;IAE5B,KAAK,CAAC,KAAK,CACP,QAA0D,EAC1D,YAAmC;QAEnC,MAAM,YAAY,GAAG,IAAI,IAAI,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAEpE,MAAM,MAAM,GAAG,IAAI,MAAM,CACrB,IAAI,GAAG,CAAC,+BAA+B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,CACrB,CAAC;QAEF,MAAM,SAAS,GAAG,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,YAAY,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,MAAM,mCAAmC,CAAC;YACtD,QAAQ;YACR,OAAO;YACP,SAAS;YACT,WAAW,EAAE,YAAY,EAAE,WAAW;YACtC,UAAU,EAAE,YAAY,EAAE,UAAU;SACvC,CAAC,CAAC;QAEH,OAAO;YACH,OAAO;YACP,KAAK,CAAC,OAAO;gBACT,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;gBACxB,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;YAC5B,CAAC;SACJ,CAAC;IACN,CAAC;CACJ,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { createOpfsSyncFile } from "./opfs-sync-file.js";
2
+ export { createOpfsBackend } from "./opfs-backend.js";
3
+ export { createBrowserWorkerTransport, type BrowserWorkerTransportOptions, } from "./browser-worker-transport.js";
4
+ export { createOpfsProvider } from "./create-opfs-provider.js";
5
+ /** @deprecated Use `mount(createOpfsProvider(root?), db, opts)` instead. */
6
+ export { mountOpfs } from "./mount-opfs.js";
@@ -0,0 +1,12 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ // Browser-only entry point. Re-exports OPFS-based factories and the
3
+ // browser worker transport. Note that the OPFS factories only function
4
+ // inside a dedicated Worker — main-thread imports are allowed (the
5
+ // factories will throw at call time, not at import).
6
+ export { createOpfsSyncFile } from "./opfs-sync-file.js";
7
+ export { createOpfsBackend } from "./opfs-backend.js";
8
+ export { createBrowserWorkerTransport, } from "./browser-worker-transport.js";
9
+ export { createOpfsProvider } from "./create-opfs-provider.js";
10
+ /** @deprecated Use `mount(createOpfsProvider(root?), db, opts)` instead. */
11
+ export { mountOpfs } from "./mount-opfs.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,oEAAoE;AACpE,uEAAuE;AACvE,mEAAmE;AACnE,qDAAqD;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EACH,4BAA4B,GAE/B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,4EAA4E;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { MountOptions, PersistenceMount } from "../service/worker-persistence-service.js";
2
+ /**
3
+ * @deprecated Use `mount(createOpfsProvider(root?), database, opts)` instead.
4
+ *
5
+ * ```ts
6
+ * import { mount } from "@adobe/data-persistence";
7
+ * import { createOpfsProvider } from "@adobe/data-persistence/browser";
8
+ *
9
+ * const m = await mount(createOpfsProvider(), database);
10
+ * ```
11
+ */
12
+ export declare const mountOpfs: (options: Omit<MountOptions<FileSystemDirectoryHandle>, "root"> & Partial<Pick<MountOptions<FileSystemDirectoryHandle>, "root">>) => Promise<PersistenceMount>;
@@ -0,0 +1,15 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ import { mount } from "../provider/mount.js";
3
+ import { createOpfsProvider } from "./create-opfs-provider.js";
4
+ /**
5
+ * @deprecated Use `mount(createOpfsProvider(root?), database, opts)` instead.
6
+ *
7
+ * ```ts
8
+ * import { mount } from "@adobe/data-persistence";
9
+ * import { createOpfsProvider } from "@adobe/data-persistence/browser";
10
+ *
11
+ * const m = await mount(createOpfsProvider(), database);
12
+ * ```
13
+ */
14
+ export const mountOpfs = async (options) => mount(createOpfsProvider(options.root), options.database, { autoPersist: options.autoPersist, checkpoint: options.checkpoint });
15
+ //# sourceMappingURL=mount-opfs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-opfs.js","sourceRoot":"","sources":["../../src/browser/mount-opfs.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAGvD,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAC1B,OACkE,EACzC,EAAE,CAC3B,KAAK,CACD,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,EAChC,OAAO,CAAC,QAAQ,EAChB,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CACvE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,127 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ //
3
+ // Single-writer lock behavior for the OPFS backend. Sync access
4
+ // handles are exclusive per file by spec, so opening one on
5
+ // `lock.json` and holding it gives us mutex semantics that the
6
+ // user-agent automatically releases on worker termination.
7
+ //
8
+ // The OPFS backend can only be constructed inside a dedicated worker
9
+ // (sync access handles are worker-only by spec), so this suite drives
10
+ // a tiny test-only worker bootstrap that wraps acquire / release via
11
+ // postMessage.
12
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
13
+ const spawnLockWorker = () => new Worker(new URL("./opfs-lock-test-worker.ts", import.meta.url), { type: "module" });
14
+ const wrapWorker = (worker) => {
15
+ let nextId = 1;
16
+ const pending = new Map();
17
+ worker.addEventListener("message", (ev) => {
18
+ const data = ev.data;
19
+ const resolve = pending.get(data.id);
20
+ if (resolve !== undefined) {
21
+ pending.delete(data.id);
22
+ resolve(data);
23
+ }
24
+ });
25
+ const request = (payload) => {
26
+ const id = nextId++;
27
+ return new Promise(resolve => {
28
+ pending.set(id, resolve);
29
+ worker.postMessage({ ...payload, id });
30
+ });
31
+ };
32
+ return {
33
+ async acquire(dirName) {
34
+ const result = await request({
35
+ cmd: "acquire",
36
+ dirName,
37
+ });
38
+ return result.cmd === "acquired"
39
+ ? { ok: true }
40
+ : { ok: false, error: result.error ?? "unknown" };
41
+ },
42
+ async release() {
43
+ await request({ cmd: "release" });
44
+ },
45
+ terminate() {
46
+ worker.terminate();
47
+ },
48
+ };
49
+ };
50
+ const removeIfExists = async (parent, name) => {
51
+ try {
52
+ await parent.removeEntry(name, { recursive: true });
53
+ }
54
+ catch {
55
+ // best-effort
56
+ }
57
+ };
58
+ describe("opfs-backend single-writer lock (in-worker)", () => {
59
+ let parent;
60
+ let dirName;
61
+ const workers = [];
62
+ beforeEach(async () => {
63
+ parent = await navigator.storage.getDirectory();
64
+ dirName = `lock-test-${Date.now()}-${Math.random().toString(36).slice(2)}`;
65
+ });
66
+ afterEach(async () => {
67
+ for (const w of workers) {
68
+ w.terminate();
69
+ }
70
+ workers.length = 0;
71
+ await removeIfExists(parent, dirName);
72
+ });
73
+ it("first worker acquires successfully", async () => {
74
+ const w = spawnLockWorker();
75
+ workers.push(w);
76
+ const wrapped = wrapWorker(w);
77
+ const r = await wrapped.acquire(dirName);
78
+ expect(r.ok).toBe(true);
79
+ await wrapped.release();
80
+ });
81
+ it("second worker on the same root fails to acquire while first holds", async () => {
82
+ const wA = spawnLockWorker();
83
+ const wB = spawnLockWorker();
84
+ workers.push(wA, wB);
85
+ const a = wrapWorker(wA);
86
+ const b = wrapWorker(wB);
87
+ const ra = await a.acquire(dirName);
88
+ expect(ra.ok).toBe(true);
89
+ const rb = await b.acquire(dirName);
90
+ expect(rb.ok).toBe(false);
91
+ if (!rb.ok) {
92
+ expect(rb.error).toMatch(/lock contended/);
93
+ }
94
+ await a.release();
95
+ });
96
+ it("a second worker can acquire after the first releases", async () => {
97
+ const wA = spawnLockWorker();
98
+ workers.push(wA);
99
+ const a = wrapWorker(wA);
100
+ expect((await a.acquire(dirName)).ok).toBe(true);
101
+ await a.release();
102
+ const wB = spawnLockWorker();
103
+ workers.push(wB);
104
+ const b = wrapWorker(wB);
105
+ expect((await b.acquire(dirName)).ok).toBe(true);
106
+ await b.release();
107
+ });
108
+ it("a second worker can acquire after the first is terminated (auto-release)", async () => {
109
+ const wA = spawnLockWorker();
110
+ workers.push(wA);
111
+ const a = wrapWorker(wA);
112
+ expect((await a.acquire(dirName)).ok).toBe(true);
113
+ // No release call. Just terminate. The OS / user-agent should
114
+ // tear down the sync access handle on worker shutdown.
115
+ wA.terminate();
116
+ // Give the agent a tick to actually release. Browsers do this
117
+ // synchronously in practice but a yield costs nothing.
118
+ await new Promise(r => setTimeout(r, 50));
119
+ const wB = spawnLockWorker();
120
+ workers.push(wB);
121
+ const b = wrapWorker(wB);
122
+ const rb = await b.acquire(dirName);
123
+ expect(rb.ok).toBe(true);
124
+ await b.release();
125
+ });
126
+ });
127
+ //# sourceMappingURL=opfs-backend-lock.browser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opfs-backend-lock.browser.test.js","sourceRoot":"","sources":["../../src/browser/opfs-backend-lock.browser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { PersistenceBackend } from "../backend/persistence-backend.js";
2
+ /**
3
+ * OPFS backend. Must be constructed inside a dedicated worker because
4
+ * the underlying RandomAccessFile uses sync access handles.
5
+ */
6
+ export declare const createOpfsBackend: (root: FileSystemDirectoryHandle) => Promise<PersistenceBackend>;