@serfab/quereus-plugin-sereus 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,6 +31,19 @@
31
31
  * `MemoryRawStorage` is returned unwrapped on upstream's own guidance: the backend
32
32
  * is already in-memory, so the cache adds bookkeeping with nothing to save.
33
33
  *
34
+ * **{@link wrapStorageWithCache} and {@link disposeStorageCache} are a matched pair
35
+ * with a holder count between them.** Every wrap that hands back a cache this module
36
+ * created takes one claim on it; every dispose of that cache releases one. The cache
37
+ * is emptied, unregistered from the shared pool, and forgotten only when the LAST
38
+ * claim goes. That is what makes overlapping scopes safe: `CadreNodeConfig.storage.provider`
39
+ * may be a single `IRawStorage` shared by the control database and every workspace,
40
+ * and without a count the first scope to stop would retire the cache the others are
41
+ * still reading through — then the next scope to start, finding the memo empty, would
42
+ * build a SECOND cache over the same backend, and each would serve its own stale view
43
+ * (including remembered "this block does not exist" answers). It is also what lets
44
+ * `composeStrand` release its own claim unconditionally on `shutdown()` without having
45
+ * to guess whether it or cadre-core created the wrapper.
46
+ *
34
47
  * The memo dedupes *concurrent* seams; it is not what keeps a cache alive across a
35
48
  * runtime rebuild. That is cadre-core's job, and it does it by OWNERSHIP: one
36
49
  * resolved store per scope per runtime lifetime — a strand's store for the life of
@@ -39,28 +52,44 @@
39
52
  * `CadreNode.start()`. Because the store outlives the rebuild, so does its wrap,
40
53
  * whether or not the embedder's provider returns a stable instance.
41
54
  *
42
- * When a scope's runtime stops for good, cadre-core calls {@link disposeStorageCache}
43
- * — the release half of that ownership. Without it the retired wrapper's
44
- * `CacheStoreHandle` would stay in the shared pool's registry for the process
45
- * lifetime (`unregisterStore` is the only removal), one orphan per stop.
55
+ * When a scope's runtime stops for good, it calls {@link disposeStorageCache} — the
56
+ * release half of that ownership. Without it the retired wrapper's `CacheStoreHandle`
57
+ * would stay in the shared pool's registry for the process lifetime (`unregisterStore`
58
+ * is the only removal), one orphan per stop.
59
+ *
60
+ * NOTE: upstream ships an equivalent counted wrap of its own — `withReadCache`, which
61
+ * hands back a `ReadCacheLease` per caller and additionally dedupes by
62
+ * `getStoreIdentity()`, so two DISTINCT instances over one directory share one cache.
63
+ * This module keeps its own count instead, because its public surface releases by
64
+ * WRAPPER (`disposeStorageCache(storage)`) rather than by lease, and `withReadCache`
65
+ * returns no lease on its already-cached pass-through — which would leave
66
+ * `composeStrand`'s unconditional release unable to tell its own claim from cadre-core's.
67
+ * Adopting the lease API would mean changing that surface at all three call sites; worth
68
+ * doing if Sereus ever needs the identity-keyed dedupe (two `FileRawStorage` over one
69
+ * path), and not before.
46
70
  */
47
71
  import { type IRawStorage } from '@optimystic/db-p2p/rn';
48
72
  /**
49
- * The cached view of `storage`, memoized per instance. `label` names the store in
50
- * the shared pool's `stats()` (e.g. `control`, or the strand id).
73
+ * The cached view of `storage`, memoized per instance, with one holder claim taken for
74
+ * this caller — release it with {@link disposeStorageCache} when this caller's scope
75
+ * ends. `label` names the store in the shared pool's `stats()` (e.g. `control`, or the
76
+ * strand id); on a memo hit the first caller's label sticks, since a second cache over
77
+ * one backend is the failure that matters and a stale pool label is not.
51
78
  */
52
79
  export declare function wrapStorageWithCache(storage: IRawStorage, label: string): IRawStorage;
53
80
  /**
54
- * Release the cache wrapper {@link wrapStorageWithCache} returned: unregister it from
55
- * the shared pool and forget the memo, so a later re-wrap of the same inner instance
56
- * gets a live cache rather than this retired one. A disposed wrapper must never be
57
- * handed out again — its pool store id is retired and never reused — and providers
58
- * that return a stable instance per scope (the web reference app's `strand-storage.ts`,
59
- * the integration harness's `captureRawStorage`) would get exactly that back on a
60
- * relaunch if the memo were left in place.
81
+ * Release this caller's claim on the cache wrapper {@link wrapStorageWithCache} returned.
82
+ * The wrapper is emptied, unregistered from the shared pool, and dropped from the memo
83
+ * only when the LAST holder releases — so a scope stopping never retires a cache another
84
+ * live scope is still reading through, and a still-held wrapper is never replaced by a
85
+ * competing second cache over the same backend.
86
+ *
87
+ * A wrapper with no live claim is left alone: that covers both a cache the embedder built
88
+ * itself (theirs to dispose) and a late second dispose of an already-retired wrapper,
89
+ * whose successor in the memo must not be dropped.
61
90
  *
62
- * No-op for anything this module returned unwrapped (e.g. `MemoryRawStorage`), so
63
- * callers need no `instanceof` test. Only the wrapper is released: the inner store the
64
- * embedder returned is never closed — that handle stays the embedder's to manage.
91
+ * No-op for anything this module returned unwrapped (e.g. `MemoryRawStorage`), so callers
92
+ * need no `instanceof` test. Only the wrapper is released: the inner store the embedder
93
+ * returned is never closed — that handle stays the embedder's to manage.
65
94
  */
66
95
  export declare function disposeStorageCache(storage: IRawStorage): Promise<void>;
@@ -31,6 +31,19 @@
31
31
  * `MemoryRawStorage` is returned unwrapped on upstream's own guidance: the backend
32
32
  * is already in-memory, so the cache adds bookkeeping with nothing to save.
33
33
  *
34
+ * **{@link wrapStorageWithCache} and {@link disposeStorageCache} are a matched pair
35
+ * with a holder count between them.** Every wrap that hands back a cache this module
36
+ * created takes one claim on it; every dispose of that cache releases one. The cache
37
+ * is emptied, unregistered from the shared pool, and forgotten only when the LAST
38
+ * claim goes. That is what makes overlapping scopes safe: `CadreNodeConfig.storage.provider`
39
+ * may be a single `IRawStorage` shared by the control database and every workspace,
40
+ * and without a count the first scope to stop would retire the cache the others are
41
+ * still reading through — then the next scope to start, finding the memo empty, would
42
+ * build a SECOND cache over the same backend, and each would serve its own stale view
43
+ * (including remembered "this block does not exist" answers). It is also what lets
44
+ * `composeStrand` release its own claim unconditionally on `shutdown()` without having
45
+ * to guess whether it or cadre-core created the wrapper.
46
+ *
34
47
  * The memo dedupes *concurrent* seams; it is not what keeps a cache alive across a
35
48
  * runtime rebuild. That is cadre-core's job, and it does it by OWNERSHIP: one
36
49
  * resolved store per scope per runtime lifetime — a strand's store for the life of
@@ -39,10 +52,21 @@
39
52
  * `CadreNode.start()`. Because the store outlives the rebuild, so does its wrap,
40
53
  * whether or not the embedder's provider returns a stable instance.
41
54
  *
42
- * When a scope's runtime stops for good, cadre-core calls {@link disposeStorageCache}
43
- * — the release half of that ownership. Without it the retired wrapper's
44
- * `CacheStoreHandle` would stay in the shared pool's registry for the process
45
- * lifetime (`unregisterStore` is the only removal), one orphan per stop.
55
+ * When a scope's runtime stops for good, it calls {@link disposeStorageCache} — the
56
+ * release half of that ownership. Without it the retired wrapper's `CacheStoreHandle`
57
+ * would stay in the shared pool's registry for the process lifetime (`unregisterStore`
58
+ * is the only removal), one orphan per stop.
59
+ *
60
+ * NOTE: upstream ships an equivalent counted wrap of its own — `withReadCache`, which
61
+ * hands back a `ReadCacheLease` per caller and additionally dedupes by
62
+ * `getStoreIdentity()`, so two DISTINCT instances over one directory share one cache.
63
+ * This module keeps its own count instead, because its public surface releases by
64
+ * WRAPPER (`disposeStorageCache(storage)`) rather than by lease, and `withReadCache`
65
+ * returns no lease on its already-cached pass-through — which would leave
66
+ * `composeStrand`'s unconditional release unable to tell its own claim from cadre-core's.
67
+ * Adopting the lease API would mean changing that surface at all three call sites; worth
68
+ * doing if Sereus ever needs the identity-keyed dedupe (two `FileRawStorage` over one
69
+ * path), and not before.
46
70
  */
47
71
  // Imported from the `/rn` entry — the platform-neutral surface (no Node-only
48
72
  // transports) — because `composeStrand` reaches this module on the browser path
@@ -50,54 +74,83 @@
50
74
  // identity (the `instanceof` checks below) is unaffected on Node.
51
75
  import { CachedRawStorage, MemoryRawStorage } from '@optimystic/db-p2p/rn';
52
76
  const wraps = new WeakMap();
77
+ const claims = new WeakMap();
53
78
  /**
54
- * Reverse of `wraps`, so {@link disposeStorageCache} can evict the memo entry it
55
- * cannot otherwise find — `wraps` is keyed by the inner instance, and dispose is
56
- * handed the wrapper.
79
+ * Count one more holder of `wrapped`, if this module created it. A cache built outside
80
+ * this module stays its creator's to release, so it is left uncounted and
81
+ * {@link disposeStorageCache} no-ops on it.
57
82
  */
58
- const inners = new WeakMap();
83
+ function addHolder(wrapped) {
84
+ const claim = claims.get(wrapped);
85
+ if (claim) {
86
+ claim.holders += 1;
87
+ }
88
+ }
59
89
  /**
60
- * The cached view of `storage`, memoized per instance. `label` names the store in
61
- * the shared pool's `stats()` (e.g. `control`, or the strand id).
90
+ * The cached view of `storage`, memoized per instance, with one holder claim taken for
91
+ * this caller — release it with {@link disposeStorageCache} when this caller's scope
92
+ * ends. `label` names the store in the shared pool's `stats()` (e.g. `control`, or the
93
+ * strand id); on a memo hit the first caller's label sticks, since a second cache over
94
+ * one backend is the failure that matters and a stale pool label is not.
62
95
  */
63
96
  export function wrapStorageWithCache(storage, label) {
64
- if (storage instanceof MemoryRawStorage || storage instanceof CachedRawStorage) {
97
+ if (storage instanceof MemoryRawStorage) {
98
+ return storage;
99
+ }
100
+ if (storage instanceof CachedRawStorage) {
101
+ // Already the wrapper this module handed out: cadre-core wraps at its own seams
102
+ // and passes the wrapper down to `composeStrand`, which wraps again. Count the
103
+ // new holder rather than stacking a second cache over one backend.
104
+ // NOTE: a RETIRED wrapper (last holder already released) is also returned as-is,
105
+ // uncounted — the caller gets a dead cache with no error. No call site can reach
106
+ // that today: both retire sites drop their reference in the same block that
107
+ // releases. If a caller ever holds a wrapper across its own release, make this
108
+ // branch throw on an absent claim rather than hand back the corpse.
109
+ addHolder(storage);
65
110
  return storage;
66
111
  }
67
- let wrapped = wraps.get(storage);
68
- if (!wrapped) {
69
- wrapped = new CachedRawStorage(storage, undefined, label);
70
- wraps.set(storage, wrapped);
71
- inners.set(wrapped, storage);
112
+ const memoized = wraps.get(storage);
113
+ if (memoized) {
114
+ addHolder(memoized);
115
+ return memoized;
72
116
  }
117
+ const wrapped = new CachedRawStorage(storage, undefined, label);
118
+ wraps.set(storage, wrapped);
119
+ claims.set(wrapped, { inner: storage, holders: 1 });
73
120
  return wrapped;
74
121
  }
75
122
  /**
76
- * Release the cache wrapper {@link wrapStorageWithCache} returned: unregister it from
77
- * the shared pool and forget the memo, so a later re-wrap of the same inner instance
78
- * gets a live cache rather than this retired one. A disposed wrapper must never be
79
- * handed out again — its pool store id is retired and never reused — and providers
80
- * that return a stable instance per scope (the web reference app's `strand-storage.ts`,
81
- * the integration harness's `captureRawStorage`) would get exactly that back on a
82
- * relaunch if the memo were left in place.
123
+ * Release this caller's claim on the cache wrapper {@link wrapStorageWithCache} returned.
124
+ * The wrapper is emptied, unregistered from the shared pool, and dropped from the memo
125
+ * only when the LAST holder releases — so a scope stopping never retires a cache another
126
+ * live scope is still reading through, and a still-held wrapper is never replaced by a
127
+ * competing second cache over the same backend.
128
+ *
129
+ * A wrapper with no live claim is left alone: that covers both a cache the embedder built
130
+ * itself (theirs to dispose) and a late second dispose of an already-retired wrapper,
131
+ * whose successor in the memo must not be dropped.
83
132
  *
84
- * No-op for anything this module returned unwrapped (e.g. `MemoryRawStorage`), so
85
- * callers need no `instanceof` test. Only the wrapper is released: the inner store the
86
- * embedder returned is never closed — that handle stays the embedder's to manage.
133
+ * No-op for anything this module returned unwrapped (e.g. `MemoryRawStorage`), so callers
134
+ * need no `instanceof` test. Only the wrapper is released: the inner store the embedder
135
+ * returned is never closed — that handle stays the embedder's to manage.
87
136
  */
88
137
  export async function disposeStorageCache(storage) {
89
138
  if (!(storage instanceof CachedRawStorage)) {
90
139
  return;
91
140
  }
92
- const inner = inners.get(storage);
93
- if (inner) {
94
- inners.delete(storage);
95
- // Only evict the memo if it still points at THIS wrapper: a re-wrap after an
96
- // earlier dispose has already installed a live successor we must not drop.
97
- if (wraps.get(inner) === storage) {
98
- wraps.delete(inner);
99
- }
141
+ const claim = claims.get(storage);
142
+ if (!claim) {
143
+ return;
144
+ }
145
+ // Decrement, and on zero retire the bookkeeping, all in this SYNCHRONOUS prefix —
146
+ // before the await below. A wrap of the same inner instance interleaved between the
147
+ // two would otherwise find a memo entry pointing at a dying cache.
148
+ claim.holders -= 1;
149
+ if (claim.holders > 0) {
150
+ return;
100
151
  }
152
+ claims.delete(storage);
153
+ wraps.delete(claim.inner);
101
154
  await storage.dispose();
102
155
  }
103
156
  //# sourceMappingURL=cached-storage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cached-storage.js","sourceRoot":"","sources":["../src/cached-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,6EAA6E;AAC7E,gFAAgF;AAChF,4EAA4E;AAC5E,kEAAkE;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE7F,MAAM,KAAK,GAAG,IAAI,OAAO,EAAiC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,GAAG,IAAI,OAAO,EAAiC,CAAC;AAE5D;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAoB,EAAE,KAAa;IACvE,IAAI,OAAO,YAAY,gBAAgB,IAAI,OAAO,YAAY,gBAAgB,EAAE,CAAC;QAChF,OAAO,OAAO,CAAC;IAChB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC1D,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAoB;IAC7D,IAAI,CAAC,CAAC,OAAO,YAAY,gBAAgB,CAAC,EAAE,CAAC;QAC5C,OAAO;IACR,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvB,6EAA6E;QAC7E,2EAA2E;QAC3E,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC;YAClC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACF,CAAC;IACD,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"cached-storage.js","sourceRoot":"","sources":["../src/cached-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAEH,6EAA6E;AAC7E,gFAAgF;AAChF,4EAA4E;AAC5E,kEAAkE;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE7F,MAAM,KAAK,GAAG,IAAI,OAAO,EAAiC,CAAC;AAmB3D,MAAM,MAAM,GAAG,IAAI,OAAO,EAAgC,CAAC;AAE3D;;;;GAIG;AACH,SAAS,SAAS,CAAC,OAAyB;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,KAAK,EAAE,CAAC;QACX,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IACpB,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAoB,EAAE,KAAa;IACvE,IAAI,OAAO,YAAY,gBAAgB,EAAE,CAAC;QACzC,OAAO,OAAO,CAAC;IAChB,CAAC;IACD,IAAI,OAAO,YAAY,gBAAgB,EAAE,CAAC;QACzC,gFAAgF;QAChF,+EAA+E;QAC/E,mEAAmE;QACnE,iFAAiF;QACjF,iFAAiF;QACjF,4EAA4E;QAC5E,+EAA+E;QAC/E,oEAAoE;QACpE,SAAS,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,OAAO,CAAC;IAChB,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,QAAQ,EAAE,CAAC;QACd,SAAS,CAAC,QAAQ,CAAC,CAAC;QACpB,OAAO,QAAQ,CAAC;IACjB,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAChE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACpD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAoB;IAC7D,IAAI,CAAC,CAAC,OAAO,YAAY,gBAAgB,CAAC,EAAE,CAAC;QAC5C,OAAO;IACR,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO;IACR,CAAC;IACD,kFAAkF;IAClF,oFAAoF;IACpF,mEAAmE;IACnE,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IACnB,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;IACR,CAAC;IACD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACvB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;AACzB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { Database, VTablePluginInfo, FunctionPluginInfo, CollationPluginInfo } from '@quereus/quereus';
2
2
  import type { Libp2p } from '@libp2p/interface';
3
- import type { IRawStorage } from '@optimystic/db-p2p';
3
+ import type { IRawStorage, NodeOptions } from '@optimystic/db-p2p';
4
4
  import type { StrandConnectionOptions, SereusPluginResult, StrandTransactor } from './types.js';
5
5
  /** Registration shape shared by the crypto and optimystic plugin results. */
6
6
  interface PluginRegistrations {
@@ -29,6 +29,19 @@ export interface CreateNodeContext {
29
29
  * default of 10, which gates writes on any smaller party.
30
30
  */
31
31
  clusterSize: number;
32
+ /**
33
+ * The strand cluster policy, resolved here so no platform has to remember it.
34
+ * Pass it to `createLibp2pNode` verbatim.
35
+ *
36
+ * Omitting it does NOT fall back to something equivalent: Optimystic then computes
37
+ * its read-repair corroboration floor against `clusterSize` instead of against
38
+ * {@link STRAND_CLUSTER_POLICY}'s `assumedClusterSize`, which is a stricter demand
39
+ * than a two-machine strand can meet — so repair of a damaged block gives up where
40
+ * it would otherwise succeed. That is the same defect class that took the *control*
41
+ * network's e2e suite down before `42cd12c`; see `cluster-size.ts` for the reasoning
42
+ * written out in full.
43
+ */
44
+ clusterPolicy: NonNullable<NodeOptions['clusterPolicy']>;
32
45
  /** Resolved persistent storage to back the node, if any. */
33
46
  storage?: IRawStorage;
34
47
  }
@@ -1,8 +1,8 @@
1
1
  import debug from 'debug';
2
2
  import optimysticPlugin from '@optimystic/quereus-plugin-optimystic/plugin';
3
3
  import { STRAND_SCHEMA } from './strand-schema.js';
4
- import { resolveStrandClusterSize } from './cluster-size.js';
5
- import { wrapStorageWithCache } from './cached-storage.js';
4
+ import { resolveStrandClusterSize, STRAND_CLUSTER_POLICY } from './cluster-size.js';
5
+ import { wrapStorageWithCache, disposeStorageCache } from './cached-storage.js';
6
6
  const log = debug('sereus:plugin:strand');
7
7
  const timing = debug('sereus:plugin:strand:timing');
8
8
  /**
@@ -49,32 +49,52 @@ export async function composeStrand(db, options, platform) {
49
49
  // transactor's `rawStorageFactory` and node creation, so it must be decided
50
50
  // up front (before pluginConfig is built). Wrapped in the write-through
51
51
  // raw-storage cache (cached-storage.ts) — idempotent, so a caller that
52
- // already wrapped (cadre-core's seams) passes through unchanged.
52
+ // already wrapped (cadre-core's seams) passes through unchanged, with this
53
+ // composition counted as one more holder of that same cache.
53
54
  const resolvedStorage = platform.resolveStorage
54
55
  ? await platform.resolveStorage({ strandId, resolvedTransactor, requestedStorage: options.storage })
55
56
  : options.storage;
56
57
  const storage = resolvedStorage ? wrapStorageWithCache(resolvedStorage, strandId) : resolvedStorage;
57
- // 1. Register crypto plugin (digest, sign, verify, etc.)
58
- await platform.registerCrypto(db);
59
- log('Registered crypto plugin');
60
- // 2. Register optimystic plugin with transactor defaults. On the local
61
- // transactor with persistent storage, hand the same instance to the plugin so
62
- // DML persists on the host backend (not in-memory).
63
- const pluginConfig = {
64
- default_transactor: resolvedTransactor,
65
- default_key_network: 'libp2p',
66
- default_network_name: networkName,
67
- enable_cache: enableCache,
58
+ /**
59
+ * Release THIS composition's claim on the storage cache — the matching half of the
60
+ * wrap above, which took one. `wrapStorageWithCache` counts holders, so this is
61
+ * unconditionally correct whoever created the wrapper: the cache stays live while
62
+ * cadre-core (or any other seam over the same store) still holds a claim, and is
63
+ * emptied and unregistered from the shared cache pool when the last one goes. Holding
64
+ * a claim past the strand's life is not free — the registration claims the backing
65
+ * store in the pool, and a claim outliving its strand makes the next connect over that
66
+ * same directory throw.
67
+ *
68
+ * Latched, so a caller that calls `shutdown()` twice releases one claim, not two — a
69
+ * second release would consume another scope's claim.
70
+ */
71
+ let storageCacheReleased = false;
72
+ const releaseStorageCache = async () => {
73
+ if (storageCacheReleased || !storage) {
74
+ return;
75
+ }
76
+ storageCacheReleased = true;
77
+ await disposeStorageCache(storage);
68
78
  };
69
- if (resolvedTransactor === 'local' && storage) {
70
- pluginConfig.rawStorageFactory = () => storage;
79
+ // 1-2. Register the crypto and optimystic plugins. Guarded on its own, because the
80
+ // wrap above has ALREADY taken a holder claim: a registration that throws must release
81
+ // it, or the claim — and the backing store's registration in the shared cache pool —
82
+ // outlives the failed connect for the process lifetime, and no other scope can retire
83
+ // the cache. Separate from the larger try below, which has a collection factory and
84
+ // possibly a node to tear down as well; neither exists yet here.
85
+ let pluginResult;
86
+ try {
87
+ pluginResult = await registerStrandPlugins(db, platform, {
88
+ resolvedTransactor,
89
+ networkName,
90
+ enableCache,
91
+ storage,
92
+ });
93
+ }
94
+ catch (err) {
95
+ await releaseStorageCache();
96
+ throw err;
71
97
  }
72
- // The plugin's published signature is `Record<string, SqlValue>` but it
73
- // also reads `rawStorageFactory` (a function reference) from the same map.
74
- // Cast through unknown rather than widen the public type.
75
- const pluginResult = optimysticPlugin(db, pluginConfig);
76
- applyRegistrations(db, pluginResult);
77
- log('Registered optimystic vtables and functions');
78
98
  const { collectionFactory } = pluginResult;
79
99
  let createdNode = null;
80
100
  let hydrated;
@@ -93,7 +113,7 @@ export async function composeStrand(db, options, platform) {
93
113
  log('Using injected libp2p node');
94
114
  }
95
115
  else {
96
- const created = await platform.createNode({ networkName, bootstrapNodes, fretProfile, port, clusterSize, storage });
116
+ const created = await platform.createNode({ networkName, bootstrapNodes, fretProfile, port, clusterSize, clusterPolicy: STRAND_CLUSTER_POLICY, storage });
97
117
  createdNode = created;
98
118
  node = created;
99
119
  const repo = created.coordinatedRepo;
@@ -136,11 +156,11 @@ export async function composeStrand(db, options, platform) {
136
156
  // Manager/Member, invite/peer flows) is owned by the lifecycle ticket
137
157
  // `strand-membership-lifecycle-population`.
138
158
  log('Applying Strand membership schema for strand %s', strandId);
139
- await db.exec(`
140
- declare schema Strand {
141
- ${STRAND_SCHEMA}
142
- }
143
- apply schema Strand;
159
+ await db.exec(`
160
+ declare schema Strand {
161
+ ${STRAND_SCHEMA}
162
+ }
163
+ apply schema Strand;
144
164
  `);
145
165
  log('Strand membership schema applied');
146
166
  // 7. Apply the sApp schema, if provided.
@@ -150,11 +170,11 @@ export async function composeStrand(db, options, platform) {
150
170
  // here so it stays a one-location edit across Node, browser, and cadre-core.
151
171
  if (schema) {
152
172
  log('Applying sApp schema for strand %s', strandId);
153
- await db.exec(`
154
- declare schema App {
155
- ${schema}
156
- }
157
- apply schema App;
173
+ await db.exec(`
174
+ declare schema App {
175
+ ${schema}
176
+ }
177
+ apply schema App;
158
178
  `);
159
179
  log('sApp schema applied');
160
180
  }
@@ -165,6 +185,7 @@ export async function composeStrand(db, options, platform) {
165
185
  if (createdNode) {
166
186
  await createdNode.stop();
167
187
  }
188
+ await releaseStorageCache();
168
189
  throw err;
169
190
  }
170
191
  // 8. Return result with hydrate counts + shutdown handler. `shutdown` tears
@@ -187,8 +208,37 @@ export async function composeStrand(db, options, platform) {
187
208
  if (createdNode) {
188
209
  await createdNode.stop();
189
210
  }
211
+ await releaseStorageCache();
190
212
  log('Strand connection %s shut down', strandId);
191
213
  },
192
214
  };
193
215
  }
216
+ /**
217
+ * Steps 1-2 of {@link composeStrand}: register the crypto plugin, then the optimystic
218
+ * plugin carrying this strand's transactor defaults. Split out so the composition can
219
+ * guard the pair against the storage-cache claim it has already taken.
220
+ */
221
+ async function registerStrandPlugins(db, platform, strand) {
222
+ await platform.registerCrypto(db);
223
+ log('Registered crypto plugin');
224
+ // On the local transactor with persistent storage, hand the same instance to the
225
+ // plugin so DML persists on the host backend (not in-memory).
226
+ const pluginConfig = {
227
+ default_transactor: strand.resolvedTransactor,
228
+ default_key_network: 'libp2p',
229
+ default_network_name: strand.networkName,
230
+ enable_cache: strand.enableCache,
231
+ };
232
+ if (strand.resolvedTransactor === 'local' && strand.storage) {
233
+ const storage = strand.storage;
234
+ pluginConfig.rawStorageFactory = () => storage;
235
+ }
236
+ // The plugin's published signature is `Record<string, SqlValue>` but it also reads
237
+ // `rawStorageFactory` (a function reference) from the same map. Cast through unknown
238
+ // rather than widen the public type.
239
+ const pluginResult = optimysticPlugin(db, pluginConfig);
240
+ applyRegistrations(db, pluginResult);
241
+ log('Registered optimystic vtables and functions');
242
+ return pluginResult;
243
+ }
194
244
  //# sourceMappingURL=compose-strand.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"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"}
@@ -30,7 +30,7 @@ export async function connectToStrandBrowser(db, options) {
30
30
  const dbHandle = await openOptimysticWebDb(`sereus-strand-${strandId}`);
31
31
  return new IndexedDBRawStorage(dbHandle);
32
32
  },
33
- async createNode({ networkName, bootstrapNodes, fretProfile, clusterSize, storage }) {
33
+ async createNode({ networkName, bootstrapNodes, fretProfile, clusterSize, clusterPolicy, storage }) {
34
34
  return createLibp2pNode({
35
35
  transports: [webSockets(), circuitRelayTransport()],
36
36
  listenAddrs: [],
@@ -38,6 +38,7 @@ export async function connectToStrandBrowser(db, options) {
38
38
  networkName,
39
39
  fretProfile,
40
40
  clusterSize,
41
+ clusterPolicy,
41
42
  ...(storage && { storage }),
42
43
  });
43
44
  },
@@ -1 +1 @@
1
- {"version":3,"file":"connect-browser.js","sourceRoot":"","sources":["../src/connect-browser.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,0CAA0C,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAG1F,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AASxE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,EAAY,EACZ,OAAgC;IAEhC,OAAO,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE;QACjC,cAAc,CAAC,QAAQ;YACtB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAkC,CAAC,CAAC;QAC3F,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,kBAAkB,EAAE,gBAAgB,EAAE;YACtE,IAAI,gBAAgB;gBAAE,OAAO,gBAAgB,CAAC;YAC9C,iEAAiE;YACjE,8CAA8C;YAC9C,IAAI,kBAAkB,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACpD,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;YACxE,OAAO,IAAI,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE;YAClF,OAAO,gBAAgB,CAAC;gBACvB,UAAU,EAAE,CAAC,UAAU,EAAE,EAAE,qBAAqB,EAAE,CAAC;gBACnD,WAAW,EAAE,EAAE;gBACf,cAAc;gBACd,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;aAC3B,CAAoB,CAAC;QACvB,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"connect-browser.js","sourceRoot":"","sources":["../src/connect-browser.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,0CAA0C,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAG1F,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AASxE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,EAAY,EACZ,OAAgC;IAEhC,OAAO,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE;QACjC,cAAc,CAAC,QAAQ;YACtB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAkC,CAAC,CAAC;QAC3F,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,kBAAkB,EAAE,gBAAgB,EAAE;YACtE,IAAI,gBAAgB;gBAAE,OAAO,gBAAgB,CAAC;YAC9C,iEAAiE;YACjE,8CAA8C;YAC9C,IAAI,kBAAkB,KAAK,MAAM;gBAAE,OAAO,SAAS,CAAC;YACpD,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;YACxE,OAAO,IAAI,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE;YACjG,OAAO,gBAAgB,CAAC;gBACvB,UAAU,EAAE,CAAC,UAAU,EAAE,EAAE,qBAAqB,EAAE,CAAC;gBACnD,WAAW,EAAE,EAAE;gBACf,cAAc;gBACd,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,aAAa;gBACb,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;aAC3B,CAAoB,CAAC;QACvB,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
package/dist/connect.js CHANGED
@@ -13,7 +13,7 @@ export async function connectToStrand(db, options) {
13
13
  async registerCrypto(database) {
14
14
  await registerPlugin(database, cryptoPlugin);
15
15
  },
16
- async createNode({ networkName, bootstrapNodes, fretProfile, port, clusterSize, storage }) {
16
+ async createNode({ networkName, bootstrapNodes, fretProfile, port, clusterSize, clusterPolicy, storage }) {
17
17
  // Dynamically import to keep the module cross-platform friendly: this
18
18
  // pulls the Node-only `@optimystic/db-p2p` (TCP) entry, and is only
19
19
  // reached when actually creating a node (never for injected nodes).
@@ -24,6 +24,7 @@ export async function connectToStrand(db, options) {
24
24
  networkName,
25
25
  fretProfile,
26
26
  clusterSize,
27
+ clusterPolicy,
27
28
  ...(storage && { storage }),
28
29
  });
29
30
  },
@@ -1 +1 @@
1
- {"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,YAAY,MAAM,0CAA0C,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,EAAY,EACZ,OAAgC;IAEhC,OAAO,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE;QACjC,KAAK,CAAC,cAAc,CAAC,QAAQ;YAC5B,MAAM,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE;YACxF,sEAAsE;YACtE,oEAAoE;YACpE,oEAAoE;YACpE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YAChE,OAAO,gBAAgB,CAAC;gBACvB,IAAI;gBACJ,cAAc;gBACd,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;aAC3B,CAAoB,CAAC;QACvB,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,YAAY,MAAM,0CAA0C,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,EAAY,EACZ,OAAgC;IAEhC,OAAO,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE;QACjC,KAAK,CAAC,cAAc,CAAC,QAAQ;YAC5B,MAAM,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC9C,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE;YACvG,sEAAsE;YACtE,oEAAoE;YACpE,oEAAoE;YACpE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YAChE,OAAO,gBAAgB,CAAC;gBACvB,IAAI;gBACJ,cAAc;gBACd,WAAW;gBACX,WAAW;gBACX,WAAW;gBACX,aAAa;gBACb,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;aAC3B,CAAoB,CAAC;QACvB,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}