@chester-hill-solutions/stow-s3 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,9 +4,22 @@ TypeScript APIs for native S3 sessions, workspaces and embedded browser storage.
4
4
 
5
5
  ## Install
6
6
 
7
- The TypeScript package is not yet published to npm. v0.3.3 ships native binaries
8
- as [GitHub downloads](https://github.com/chester-hill-solutions/stow-s3/releases/tag/v0.3.3).
9
- Build the TypeScript client from a source checkout:
7
+ Install the public npm package:
8
+
9
+ ```sh
10
+ npm install @chester-hill-solutions/stow-s3@0.3.7
11
+ ```
12
+
13
+ Node.js 20 or newer is required. Linux and macOS on x64 or ARM64 receive their native carrier automatically.
14
+ Native process APIs need no Go installation or `STOW_BIN` override.
15
+ Embedded and browser APIs use the included WASM assets.
16
+ Remove any old scope override to `npm.pkg.github.com`; this package is published on npmjs.
17
+
18
+ Standalone v0.3.7 binaries are also available as
19
+ [GitHub downloads](https://github.com/chester-hill-solutions/stow-s3/releases/tag/v0.3.7).
20
+ Use WSL on Windows.
21
+
22
+ For local development, build a source checkout:
10
23
 
11
24
  ```sh
12
25
  git clone https://github.com/chester-hill-solutions/stow-s3
@@ -17,11 +30,9 @@ npm run build --prefix packages/stow-s3
17
30
  export STOW_BIN="$PWD/bin/stow-s3"
18
31
  ```
19
32
 
20
- Use `STOW_BIN` for the native process APIs.
21
- Embedded WASM APIs use the built package assets.
22
- Registry publication is deferred. Do not rely on a registry install for v0.3.3.
33
+ Use `STOW_BIN` to select the source-built native binary during development.
23
34
  <!-- repo-only:start -->
24
- See the [release checkpoint](../../docs/release-verification-2026-10-14.md) for availability.
35
+ See the [npm publication record](../../docs/development/npm-publishing.md#published-037) for release verification.
25
36
  <!-- repo-only:end -->
26
37
 
27
38
  ## Usage
@@ -124,7 +135,7 @@ const summary = await withStow(async (session) => {
124
135
 
125
136
  - Source checkouts use `STOW_BIN`. A platform package can supply the binary in a published distribution.
126
137
  <!-- repo-only:start -->
127
- See the [release checkpoint](../../docs/release-verification-2026-10-14.md) before using registry installation.
138
+ See the [release checkpoint](../../docs/history/releases/release-verification-2026-10-14.md) before using registry installation.
128
139
  <!-- repo-only:end -->
129
140
  - `STOW_*`, `S3_*`, and `AWS_*` are stripped from the child environment, so
130
141
  ambient cloud configuration cannot turn a local session into a run-through one.
@@ -167,13 +178,13 @@ The wrapper also exports resume, same-machine handoff, diff, restore, portable
167
178
  checkpoint export, and import helpers. These calls return the CLI's JSON result
168
179
  and use the same validation and limits as the Go implementation. They require
169
180
  the package's platform binary or `STOW_BIN` when developing from a checkout.
170
- See [`docs/task-manifest.md`](../../docs/task-manifest.md) for the schema,
181
+ See [`docs/contracts/task-manifest.md`](../../docs/contracts/task-manifest.md) for the schema,
171
182
  archive rules, and the filesystem-isolation boundary. This is a persistent
172
183
  workspace API; it is separate from the disposable S3 session APIs above.
173
184
 
174
185
  ### Browser persistence profile
175
186
 
176
- The additive [`@chester-hill-solutions/stow-s3/browser`](../../docs/browser-persistence.md) entry
187
+ The additive [`@chester-hill-solutions/stow-s3/browser`](../../docs/guides/browser-persistence.md) entry
177
188
  point coordinates durable commits around the embedded memory profile. The
178
189
  `openBrowserEmbeddedStow` wrapper replays the committed generation during async
179
190
  open, serializes operations FIFO, and commits each mutation before its promise
@@ -212,7 +223,7 @@ unchanged.
212
223
  this profile. Undo/redo and pending sync receipts survive reopen; remote writes
213
224
  use an expected ETag or expected absence, and conflicts retain local edits.
214
225
  `S3ObjectSyncRemote` is available from the separate `./browser-s3` entry point.
215
- See [the API and limits](../../docs/browser-file-history.md), or run
226
+ See [the API and limits](../../docs/guides/browser-file-history.md), or run
216
227
  `make browser-editor` from the repository root for the offline editor demo.
217
228
 
218
229
  CLI equivalent:
@@ -246,7 +257,7 @@ It supports shared chunks, atomic revisions, bounded range reads and conditional
246
257
  `/worker` exports `AsyncEmbeddedStow`.
247
258
  `/browser-wasm` provides `loadBrowserPersistentWasmHost` for durable host storage.
248
259
 
249
- Use the [project guide](../../docs/browser-project-storage.md) or [worker guide](../../docs/browser-worker-runtime.md) to get started.
260
+ Use the [project guide](../../docs/guides/browser-project-storage.md) or [worker guide](../../docs/guides/browser-worker-runtime.md) to get started.
250
261
 
251
262
  <!-- repo-only:start -->
252
263
  See the [1 GiB test record](../../docs/benchmarks/browser-project-2026-10-12.json).
@@ -1 +1 @@
1
- {"version":3,"file":"async-streams.d.ts","sourceRoot":"","sources":["../src/async-streams.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0D,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACrI,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,eAAO,MAAM,2BAA2B,QAAa,CAAC;AAEtD,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAClC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnG;AAED,qBAAa,wBAAwB;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,qBAAqB;IAEpD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC;IA6B5I,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC;YA2CpG,OAAO;CAOtB"}
1
+ {"version":3,"file":"async-streams.d.ts","sourceRoot":"","sources":["../src/async-streams.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0D,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACrI,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,eAAO,MAAM,2BAA2B,QAAa,CAAC;AAEtD,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAClC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnG;AAOD,qBAAa,wBAAwB;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,qBAAqB;IAEpD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC;IA6B5I,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC;YAyCpG,OAAO;CAOtB"}
@@ -46,18 +46,13 @@ export class EmbeddedStreamOperations {
46
46
  const opened = await this.invoke({ op: "openObjectRead", bucket, key });
47
47
  const token = opened.token;
48
48
  const object = fromBridgeObject(opened.object);
49
- let closed = false;
50
- let closePromise;
49
+ let state = { kind: "open" };
51
50
  const close = () => {
52
- if (closePromise !== undefined)
53
- return closePromise;
54
- closed = true;
55
- closePromise = this.cleanup("closeObjectRead", token).catch((error) => {
56
- closed = false;
57
- closePromise = undefined;
58
- throw error;
59
- });
60
- return closePromise;
51
+ if (state.kind !== "open")
52
+ return state.completion;
53
+ const completion = this.cleanup("closeObjectRead", token).then(() => { state = { kind: "closed", completion }; }, (error) => { state = { kind: "open" }; throw error; });
54
+ state = { kind: "closing", completion };
55
+ return completion;
61
56
  };
62
57
  if (options.signal?.aborted) {
63
58
  await close();
@@ -67,7 +62,7 @@ export class EmbeddedStreamOperations {
67
62
  const chunks = (async function* () {
68
63
  let read = 0;
69
64
  try {
70
- while (!closed && read < object.size) {
65
+ while (state.kind === "open" && read < object.size) {
71
66
  options.signal?.throwIfAborted();
72
67
  const length = Math.min(EMBEDDED_STREAM_CHUNK_BYTES, object.size - read);
73
68
  const result = await invoke({ op: "readObjectChunk", token, length }, undefined, options);
@@ -1 +1 @@
1
- {"version":3,"file":"async-streams.js","sourceRoot":"","sources":["../src/async-streams.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"async-streams.js","sourceRoot":"","sources":["../src/async-streams.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb-lifecycle.d.ts","sourceRoot":"","sources":["../src/indexeddb-lifecycle.ts"],"names":[],"mappings":"AACA,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AACD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAW3G"}
1
+ {"version":3,"file":"indexeddb-lifecycle.d.ts","sourceRoot":"","sources":["../src/indexeddb-lifecycle.ts"],"names":[],"mappings":"AACA,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB;AACD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuB3G"}
@@ -1,14 +1,32 @@
1
1
  import { BrowserPersistenceError } from "./browser-types.js";
2
2
  export function openIndexedDatabase(factory, options) {
3
3
  return new Promise((resolve, reject) => {
4
+ let state = "pending";
4
5
  const request = factory.open(options.name, options.version);
5
- request.onupgradeneeded = () => options.upgrade(request.result);
6
+ request.onupgradeneeded = () => {
7
+ if (state !== "pending") {
8
+ request.transaction?.abort();
9
+ return;
10
+ }
11
+ options.upgrade(request.result);
12
+ };
6
13
  request.onsuccess = () => {
14
+ if (state !== "pending") {
15
+ request.result.close();
16
+ return;
17
+ }
18
+ state = "opened";
7
19
  request.result.onversionchange = () => request.result.close();
8
20
  resolve(request.result);
9
21
  };
10
- request.onerror = () => reject(request.error ?? new Error(options.failedMessage));
11
- request.onblocked = () => reject(new BrowserPersistenceError("persistence_denied", options.blockedMessage));
22
+ request.onerror = () => {
23
+ state = "rejected";
24
+ reject(request.error ?? new Error(options.failedMessage));
25
+ };
26
+ request.onblocked = () => {
27
+ state = "rejected";
28
+ reject(new BrowserPersistenceError("persistence_denied", options.blockedMessage));
29
+ };
12
30
  });
13
31
  }
14
32
  //# sourceMappingURL=indexeddb-lifecycle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb-lifecycle.js","sourceRoot":"","sources":["../src/indexeddb-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAQ7D,MAAM,UAAU,mBAAmB,CAAC,OAAmB,EAAE,OAA4B;IACnF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5D,OAAO,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChE,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE;YACvB,OAAO,CAAC,MAAM,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9D,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC,CAAC;QACF,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAClF,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,uBAAuB,CAAC,oBAAoB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IAC9G,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"indexeddb-lifecycle.js","sourceRoot":"","sources":["../src/indexeddb-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAQ7D,MAAM,UAAU,mBAAmB,CAAC,OAAmB,EAAE,OAA4B;IACnF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,KAAK,GAAsC,SAAS,CAAC;QACzD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5D,OAAO,CAAC,eAAe,GAAG,GAAG,EAAE;YAC7B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YAClE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC,CAAC;QACF,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE;YACvB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YAC5D,KAAK,GAAG,QAAQ,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9D,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC,CAAC;QACF,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;YACrB,KAAK,GAAG,UAAU,CAAC;YACnB,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAC5D,CAAC,CAAC;QACF,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE;YACvB,KAAK,GAAG,UAAU,CAAC;YACnB,MAAM,CAAC,IAAI,uBAAuB,CAAC,oBAAoB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;QACpF,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -7,19 +7,16 @@ export declare class IndexedDbPersistenceAdapter implements PersistenceAdapter {
7
7
  private readonly objectStoreName;
8
8
  private readonly lockManager;
9
9
  private readonly lockName;
10
- private database;
11
- private namespace;
12
- private ownership;
13
- private closePromise;
14
- private closed;
10
+ private lifecycle;
15
11
  constructor(options?: IndexedDbPersistenceAdapterOptions);
16
12
  open(namespace: string): Promise<void>;
13
+ private acquireResources;
17
14
  private get stores();
18
15
  load(namespace: string): Promise<PersistenceSnapshot | null>;
19
16
  commit(namespace: string, expectedGeneration: number, changes: PersistenceChange[]): Promise<number>;
20
17
  clear(namespace: string, expectedGeneration: number): Promise<number>;
21
18
  close(): Promise<void>;
22
19
  private closeInternal;
23
- private ensureNamespace;
20
+ private resourcesFor;
24
21
  }
25
22
  //# sourceMappingURL=indexeddb-persistence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb-persistence.d.ts","sourceRoot":"","sources":["../src/indexeddb-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kCAAkC,EAEvC,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,oBAAoB,CAAC;AAoB5B,qBAAa,2BAA4B,YAAW,kBAAkB;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IACzD,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,GAAE,kCAAuC;IAUtD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC5C,OAAO,KAAK,MAAM,GAMjB;IAEK,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAc5D,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,iBAAiB,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC;IAeZ,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAKd,aAAa;IA2B3B,OAAO,CAAC,eAAe;CAWxB"}
1
+ {"version":3,"file":"indexeddb-persistence.d.ts","sourceRoot":"","sources":["../src/indexeddb-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kCAAkC,EAEvC,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,oBAAoB,CAAC;AAoC5B,qBAAa,2BAA4B,YAAW,kBAAkB;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IACzD,OAAO,CAAC,SAAS,CAAsC;gBAE3C,OAAO,GAAE,kCAAuC;IAUtD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAqB9B,gBAAgB;IAqB9B,OAAO,KAAK,MAAM,GAMjB;IAEK,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAU5D,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,iBAAiB,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC;IAWZ,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU3E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAWR,aAAa;IAuB3B,OAAO,CAAC,YAAY;CAarB"}
@@ -14,11 +14,7 @@ export class IndexedDbPersistenceAdapter {
14
14
  objectStoreName;
15
15
  lockManager;
16
16
  lockName;
17
- database;
18
- namespace;
19
- ownership;
20
- closePromise;
21
- closed = false;
17
+ lifecycle = { kind: "idle" };
22
18
  constructor(options = {}) {
23
19
  this.factory = options.indexedDB ?? globalIndexedDb();
24
20
  this.databaseName = options.databaseName ?? DEFAULT_DATABASE_NAME;
@@ -30,28 +26,39 @@ export class IndexedDbPersistenceAdapter {
30
26
  }
31
27
  async open(namespace) {
32
28
  validatePersistenceNamespace(namespace);
33
- if (this.closed) {
29
+ if (this.lifecycle.kind !== "idle") {
30
+ if (this.lifecycle.kind === "opening" || this.lifecycle.kind === "open") {
31
+ throw new BrowserPersistenceError("already_open", "persistence namespace is already open or opening");
32
+ }
34
33
  throw new BrowserPersistenceError("closed", "persistence adapter is closed");
35
34
  }
36
- if (this.namespace !== undefined) {
37
- throw new BrowserPersistenceError("already_open", "persistence namespace is already open");
35
+ const completion = this.acquireResources(namespace);
36
+ this.lifecycle = { kind: "opening", completion };
37
+ try {
38
+ const resources = await completion;
39
+ // Close owns the pending acquisition once it transitions to closing.
40
+ if (this.lifecycle.kind !== "opening")
41
+ throw new BrowserPersistenceError("closed", "persistence adapter is closed");
42
+ this.lifecycle = { kind: "open", resources };
43
+ }
44
+ catch (error) {
45
+ if (this.lifecycle.kind === "opening")
46
+ this.lifecycle = { kind: "idle" };
47
+ throw mapAdapterError(error);
38
48
  }
39
- const ownershipKey = this.lockName(namespace);
40
- this.ownership = await acquireOwnership(ownershipKey, this.lockManager);
49
+ }
50
+ async acquireResources(namespace) {
51
+ const ownership = await acquireOwnership(this.lockName(namespace), this.lockManager);
41
52
  try {
42
- this.database = await openDatabase(this.factory, this.databaseName, this.manifestStoreName, this.bucketStoreName, this.objectStoreName);
43
- this.namespace = namespace;
53
+ const database = await openDatabase(this.factory, this.databaseName, this.manifestStoreName, this.bucketStoreName, this.objectStoreName);
54
+ return { database, namespace, ownership };
44
55
  }
45
56
  catch (error) {
46
- const ownership = this.ownership;
47
- this.ownership = undefined;
48
- if (ownership !== undefined) {
49
- try {
50
- await ownership.release();
51
- }
52
- catch {
53
- // Preserve the database-open failure.
54
- }
57
+ try {
58
+ await ownership.release();
59
+ }
60
+ catch {
61
+ // Preserve the database-open failure.
55
62
  }
56
63
  throw mapAdapterError(error);
57
64
  }
@@ -64,11 +71,7 @@ export class IndexedDbPersistenceAdapter {
64
71
  };
65
72
  }
66
73
  async load(namespace) {
67
- this.ensureNamespace(namespace);
68
- const database = this.database;
69
- if (database === undefined) {
70
- throw new BrowserPersistenceError("persistence_error", "persistence database is not open");
71
- }
74
+ const { database } = this.resourcesFor(namespace);
72
75
  try {
73
76
  const raw = await readNamespace(database, namespace, this.stores);
74
77
  return raw === null ? null : normalizeSnapshot(raw);
@@ -78,13 +81,9 @@ export class IndexedDbPersistenceAdapter {
78
81
  }
79
82
  }
80
83
  async commit(namespace, expectedGeneration, changes) {
81
- this.ensureNamespace(namespace);
84
+ const { database } = this.resourcesFor(namespace);
82
85
  validateGeneration(expectedGeneration);
83
86
  const normalizedChanges = changes.map(normalizeChange);
84
- const database = this.database;
85
- if (database === undefined) {
86
- throw new BrowserPersistenceError("persistence_error", "persistence database is not open");
87
- }
88
87
  try {
89
88
  return await commitChanges(database, namespace, expectedGeneration, normalizedChanges, this.stores);
90
89
  }
@@ -93,12 +92,8 @@ export class IndexedDbPersistenceAdapter {
93
92
  }
94
93
  }
95
94
  async clear(namespace, expectedGeneration) {
96
- this.ensureNamespace(namespace);
95
+ const { database } = this.resourcesFor(namespace);
97
96
  validateGeneration(expectedGeneration);
98
- const database = this.database;
99
- if (database === undefined) {
100
- throw new BrowserPersistenceError("persistence_error", "persistence database is not open");
101
- }
102
97
  try {
103
98
  return await clearNamespace(database, namespace, expectedGeneration, this.stores);
104
99
  }
@@ -106,48 +101,57 @@ export class IndexedDbPersistenceAdapter {
106
101
  throw mapAdapterError(error);
107
102
  }
108
103
  }
109
- async close() {
110
- this.closePromise ??= this.closeInternal();
111
- return this.closePromise;
104
+ close() {
105
+ const previous = this.lifecycle;
106
+ if (previous.kind === "closing" || previous.kind === "closed" || previous.kind === "failed")
107
+ return previous.completion;
108
+ const completion = Promise.resolve().then(() => this.closeInternal(previous)).then(() => { this.lifecycle = { kind: "closed", completion }; }, (error) => { this.lifecycle = { kind: "failed", completion }; throw mapAdapterError(error); });
109
+ this.lifecycle = { kind: "closing", completion };
110
+ return completion;
112
111
  }
113
- async closeInternal() {
114
- this.closed = true;
115
- const database = this.database;
116
- const ownership = this.ownership;
117
- this.database = undefined;
118
- this.namespace = undefined;
119
- this.ownership = undefined;
120
- let firstError;
121
- if (database !== undefined) {
112
+ async closeInternal(previous) {
113
+ if (previous.kind === "idle")
114
+ return;
115
+ let resources;
116
+ if (previous.kind === "opening") {
122
117
  try {
123
- database.close();
124
- }
125
- catch (error) {
126
- firstError = error;
118
+ resources = await previous.completion;
127
119
  }
120
+ catch {
121
+ return;
122
+ } // Failed acquisition releases its own ownership.
128
123
  }
129
- if (ownership !== undefined) {
130
- try {
131
- await ownership.release();
132
- }
133
- catch (error) {
134
- firstError ??= error;
135
- }
124
+ else
125
+ resources = previous.resources;
126
+ let firstError;
127
+ try {
128
+ resources.database.close();
129
+ }
130
+ catch (error) {
131
+ firstError = error;
132
+ }
133
+ try {
134
+ await resources.ownership.release();
135
+ }
136
+ catch (error) {
137
+ firstError ??= error;
136
138
  }
137
139
  if (firstError !== undefined) {
138
140
  throw mapAdapterError(firstError);
139
141
  }
140
142
  }
141
- ensureNamespace(namespace) {
142
- if (this.closed) {
143
+ resourcesFor(namespace) {
144
+ const state = this.lifecycle;
145
+ if (state.kind !== "open") {
146
+ if (state.kind === "idle" || state.kind === "opening") {
147
+ throw new BrowserPersistenceError("persistence_error", "persistence namespace is not open");
148
+ }
143
149
  throw new BrowserPersistenceError("closed", "persistence adapter is closed");
144
150
  }
145
- if (this.namespace === undefined) {
146
- throw new BrowserPersistenceError("persistence_error", "persistence namespace is not open");
147
- }
148
- if (this.namespace !== namespace) {
151
+ if (state.resources.namespace !== namespace) {
149
152
  throw new BrowserPersistenceError("persistence_error", "persistence namespace does not match");
150
153
  }
154
+ return state.resources;
151
155
  }
152
156
  }
153
157
  function globalIndexedDb() {
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb-persistence.js","sourceRoot":"","sources":["../src/indexeddb-persistence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"indexeddb-persistence.js","sourceRoot":"","sources":["../src/indexeddb-persistence.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chester-hill-solutions/stow-s3",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "TypeScript client for the stow local S3-compatible dev bucket service",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -71,10 +71,10 @@
71
71
  "@smithy/types": "^4.1.0"
72
72
  },
73
73
  "optionalDependencies": {
74
- "@chester-hill-solutions/stow-s3-darwin-arm64": "0.3.5",
75
- "@chester-hill-solutions/stow-s3-darwin-x64": "0.3.5",
76
- "@chester-hill-solutions/stow-s3-linux-arm64": "0.3.5",
77
- "@chester-hill-solutions/stow-s3-linux-x64": "0.3.5"
74
+ "@chester-hill-solutions/stow-s3-darwin-arm64": "0.3.7",
75
+ "@chester-hill-solutions/stow-s3-darwin-x64": "0.3.7",
76
+ "@chester-hill-solutions/stow-s3-linux-arm64": "0.3.7",
77
+ "@chester-hill-solutions/stow-s3-linux-x64": "0.3.7"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@aws-sdk/s3-request-presigner": "3.1160.0",
@@ -18,6 +18,11 @@ export interface AsyncOperationInvoker {
18
18
  <T>(request: Record<string, unknown>, data?: Uint8Array, options?: WorkerCallOptions): Promise<T>;
19
19
  }
20
20
 
21
+ // Cleanup failure returns to open so callers can retry releasing the host token.
22
+ type ReadStreamState =
23
+ | { kind: "open" }
24
+ | { kind: "closing" | "closed"; completion: Promise<void> };
25
+
21
26
  export class EmbeddedStreamOperations {
22
27
  constructor(private readonly invoke: AsyncOperationInvoker) {}
23
28
 
@@ -55,17 +60,15 @@ export class EmbeddedStreamOperations {
55
60
  const opened = await this.invoke<{ token: string; object: BridgeObject }>({ op: "openObjectRead", bucket, key });
56
61
  const token = opened.token;
57
62
  const object = fromBridgeObject(opened.object);
58
- let closed = false;
59
- let closePromise: Promise<void> | undefined;
63
+ let state: ReadStreamState = { kind: "open" };
60
64
  const close = () => {
61
- if (closePromise !== undefined) return closePromise;
62
- closed = true;
63
- closePromise = this.cleanup("closeObjectRead", token).catch((error: unknown) => {
64
- closed = false;
65
- closePromise = undefined;
66
- throw error;
67
- });
68
- return closePromise;
65
+ if (state.kind !== "open") return state.completion;
66
+ const completion: Promise<void> = this.cleanup("closeObjectRead", token).then(
67
+ () => { state = { kind: "closed", completion }; },
68
+ (error: unknown) => { state = { kind: "open" }; throw error; },
69
+ );
70
+ state = { kind: "closing", completion };
71
+ return completion;
69
72
  };
70
73
  if (options.signal?.aborted) {
71
74
  await close();
@@ -75,7 +78,7 @@ export class EmbeddedStreamOperations {
75
78
  const chunks = (async function* () {
76
79
  let read = 0;
77
80
  try {
78
- while (!closed && read < object.size) {
81
+ while (state.kind === "open" && read < object.size) {
79
82
  options.signal?.throwIfAborted();
80
83
  const length = Math.min(EMBEDDED_STREAM_CHUNK_BYTES, object.size - read);
81
84
  const result = await invoke<{ eof: boolean; data?: Uint8Array }>({ op: "readObjectChunk", token, length }, undefined, options);
@@ -8,13 +8,25 @@ interface DatabaseOpenOptions {
8
8
  }
9
9
  export function openIndexedDatabase(factory: IDBFactory, options: DatabaseOpenOptions): Promise<IDBDatabase> {
10
10
  return new Promise((resolve, reject) => {
11
+ let state: "pending" | "opened" | "rejected" = "pending";
11
12
  const request = factory.open(options.name, options.version);
12
- request.onupgradeneeded = () => options.upgrade(request.result);
13
+ request.onupgradeneeded = () => {
14
+ if (state !== "pending") { request.transaction?.abort(); return; }
15
+ options.upgrade(request.result);
16
+ };
13
17
  request.onsuccess = () => {
18
+ if (state !== "pending") { request.result.close(); return; }
19
+ state = "opened";
14
20
  request.result.onversionchange = () => request.result.close();
15
21
  resolve(request.result);
16
22
  };
17
- request.onerror = () => reject(request.error ?? new Error(options.failedMessage));
18
- request.onblocked = () => reject(new BrowserPersistenceError("persistence_denied", options.blockedMessage));
23
+ request.onerror = () => {
24
+ state = "rejected";
25
+ reject(request.error ?? new Error(options.failedMessage));
26
+ };
27
+ request.onblocked = () => {
28
+ state = "rejected";
29
+ reject(new BrowserPersistenceError("persistence_denied", options.blockedMessage));
30
+ };
19
31
  });
20
32
  }
@@ -26,6 +26,22 @@ interface Ownership {
26
26
  release(): Promise<void>;
27
27
  }
28
28
 
29
+ interface OpenPersistence {
30
+ database: IDBDatabase;
31
+ namespace: string;
32
+ ownership: Ownership;
33
+ }
34
+
35
+ type ActiveLifecycle =
36
+ | { kind: "idle" }
37
+ | { kind: "opening"; completion: Promise<OpenPersistence> }
38
+ | { kind: "open"; resources: OpenPersistence };
39
+
40
+ type AdapterLifecycle = ActiveLifecycle
41
+ | { kind: "closing"; completion: Promise<void> }
42
+ | { kind: "closed"; completion: Promise<void> }
43
+ | { kind: "failed"; completion: Promise<void> };
44
+
29
45
  export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
30
46
  private readonly factory: IDBFactory | undefined;
31
47
  private readonly databaseName: string;
@@ -34,11 +50,7 @@ export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
34
50
  private readonly objectStoreName: string;
35
51
  private readonly lockManager: LockManagerLike | undefined;
36
52
  private readonly lockName: (namespace: string) => string;
37
- private database: IDBDatabase | undefined;
38
- private namespace: string | undefined;
39
- private ownership: Ownership | undefined;
40
- private closePromise: Promise<void> | undefined;
41
- private closed = false;
53
+ private lifecycle: AdapterLifecycle = { kind: "idle" };
42
54
 
43
55
  constructor(options: IndexedDbPersistenceAdapterOptions = {}) {
44
56
  this.factory = options.indexedDB ?? globalIndexedDb();
@@ -52,32 +64,41 @@ export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
52
64
 
53
65
  async open(namespace: string): Promise<void> {
54
66
  validatePersistenceNamespace(namespace);
55
- if (this.closed) {
67
+ if (this.lifecycle.kind !== "idle") {
68
+ if (this.lifecycle.kind === "opening" || this.lifecycle.kind === "open") {
69
+ throw new BrowserPersistenceError("already_open", "persistence namespace is already open or opening");
70
+ }
56
71
  throw new BrowserPersistenceError("closed", "persistence adapter is closed");
57
72
  }
58
- if (this.namespace !== undefined) {
59
- throw new BrowserPersistenceError("already_open", "persistence namespace is already open");
73
+ const completion = this.acquireResources(namespace);
74
+ this.lifecycle = { kind: "opening", completion };
75
+ try {
76
+ const resources = await completion;
77
+ // Close owns the pending acquisition once it transitions to closing.
78
+ if (this.lifecycle.kind !== "opening") throw new BrowserPersistenceError("closed", "persistence adapter is closed");
79
+ this.lifecycle = { kind: "open", resources };
80
+ } catch (error) {
81
+ if (this.lifecycle.kind === "opening") this.lifecycle = { kind: "idle" };
82
+ throw mapAdapterError(error);
60
83
  }
61
- const ownershipKey = this.lockName(namespace);
62
- this.ownership = await acquireOwnership(ownershipKey, this.lockManager);
84
+ }
85
+
86
+ private async acquireResources(namespace: string): Promise<OpenPersistence> {
87
+ const ownership = await acquireOwnership(this.lockName(namespace), this.lockManager);
63
88
  try {
64
- this.database = await openDatabase(
89
+ const database = await openDatabase(
65
90
  this.factory,
66
91
  this.databaseName,
67
92
  this.manifestStoreName,
68
93
  this.bucketStoreName,
69
94
  this.objectStoreName,
70
95
  );
71
- this.namespace = namespace;
96
+ return { database, namespace, ownership };
72
97
  } catch (error) {
73
- const ownership = this.ownership;
74
- this.ownership = undefined;
75
- if (ownership !== undefined) {
76
- try {
77
- await ownership.release();
78
- } catch {
79
- // Preserve the database-open failure.
80
- }
98
+ try {
99
+ await ownership.release();
100
+ } catch {
101
+ // Preserve the database-open failure.
81
102
  }
82
103
  throw mapAdapterError(error);
83
104
  }
@@ -92,11 +113,7 @@ export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
92
113
  }
93
114
 
94
115
  async load(namespace: string): Promise<PersistenceSnapshot | null> {
95
- this.ensureNamespace(namespace);
96
- const database = this.database;
97
- if (database === undefined) {
98
- throw new BrowserPersistenceError("persistence_error", "persistence database is not open");
99
- }
116
+ const { database } = this.resourcesFor(namespace);
100
117
  try {
101
118
  const raw = await readNamespace(database, namespace, this.stores);
102
119
  return raw === null ? null : normalizeSnapshot(raw);
@@ -110,13 +127,9 @@ export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
110
127
  expectedGeneration: number,
111
128
  changes: PersistenceChange[],
112
129
  ): Promise<number> {
113
- this.ensureNamespace(namespace);
130
+ const { database } = this.resourcesFor(namespace);
114
131
  validateGeneration(expectedGeneration);
115
132
  const normalizedChanges = changes.map(normalizeChange);
116
- const database = this.database;
117
- if (database === undefined) {
118
- throw new BrowserPersistenceError("persistence_error", "persistence database is not open");
119
- }
120
133
  try {
121
134
  return await commitChanges(database, namespace, expectedGeneration, normalizedChanges, this.stores);
122
135
  } catch (error) {
@@ -125,12 +138,8 @@ export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
125
138
  }
126
139
 
127
140
  async clear(namespace: string, expectedGeneration: number): Promise<number> {
128
- this.ensureNamespace(namespace);
141
+ const { database } = this.resourcesFor(namespace);
129
142
  validateGeneration(expectedGeneration);
130
- const database = this.database;
131
- if (database === undefined) {
132
- throw new BrowserPersistenceError("persistence_error", "persistence database is not open");
133
- }
134
143
  try {
135
144
  return await clearNamespace(database, namespace, expectedGeneration, this.stores);
136
145
  } catch (error) {
@@ -138,48 +147,52 @@ export class IndexedDbPersistenceAdapter implements PersistenceAdapter {
138
147
  }
139
148
  }
140
149
 
141
- async close(): Promise<void> {
142
- this.closePromise ??= this.closeInternal();
143
- return this.closePromise;
150
+ close(): Promise<void> {
151
+ const previous = this.lifecycle;
152
+ if (previous.kind === "closing" || previous.kind === "closed" || previous.kind === "failed") return previous.completion;
153
+ const completion: Promise<void> = Promise.resolve().then(() => this.closeInternal(previous)).then(
154
+ () => { this.lifecycle = { kind: "closed", completion }; },
155
+ (error: unknown) => { this.lifecycle = { kind: "failed", completion }; throw mapAdapterError(error); },
156
+ );
157
+ this.lifecycle = { kind: "closing", completion };
158
+ return completion;
144
159
  }
145
160
 
146
- private async closeInternal(): Promise<void> {
147
- this.closed = true;
148
- const database = this.database;
149
- const ownership = this.ownership;
150
- this.database = undefined;
151
- this.namespace = undefined;
152
- this.ownership = undefined;
161
+ private async closeInternal(previous: ActiveLifecycle): Promise<void> {
162
+ if (previous.kind === "idle") return;
163
+ let resources: OpenPersistence;
164
+ if (previous.kind === "opening") {
165
+ try { resources = await previous.completion; }
166
+ catch { return; } // Failed acquisition releases its own ownership.
167
+ } else resources = previous.resources;
153
168
  let firstError: unknown;
154
- if (database !== undefined) {
155
- try {
156
- database.close();
157
- } catch (error) {
158
- firstError = error;
159
- }
169
+ try {
170
+ resources.database.close();
171
+ } catch (error) {
172
+ firstError = error;
160
173
  }
161
- if (ownership !== undefined) {
162
- try {
163
- await ownership.release();
164
- } catch (error) {
165
- firstError ??= error;
166
- }
174
+ try {
175
+ await resources.ownership.release();
176
+ } catch (error) {
177
+ firstError ??= error;
167
178
  }
168
179
  if (firstError !== undefined) {
169
180
  throw mapAdapterError(firstError);
170
181
  }
171
182
  }
172
183
 
173
- private ensureNamespace(namespace: string): void {
174
- if (this.closed) {
184
+ private resourcesFor(namespace: string): OpenPersistence {
185
+ const state = this.lifecycle;
186
+ if (state.kind !== "open") {
187
+ if (state.kind === "idle" || state.kind === "opening") {
188
+ throw new BrowserPersistenceError("persistence_error", "persistence namespace is not open");
189
+ }
175
190
  throw new BrowserPersistenceError("closed", "persistence adapter is closed");
176
191
  }
177
- if (this.namespace === undefined) {
178
- throw new BrowserPersistenceError("persistence_error", "persistence namespace is not open");
179
- }
180
- if (this.namespace !== namespace) {
192
+ if (state.resources.namespace !== namespace) {
181
193
  throw new BrowserPersistenceError("persistence_error", "persistence namespace does not match");
182
194
  }
195
+ return state.resources;
183
196
  }
184
197
  }
185
198