@serfab/quereus-plugin-sereus 0.10.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.
- package/README.md +367 -361
- package/dist/cached-storage.d.ts +95 -0
- package/dist/cached-storage.js +156 -0
- package/dist/cached-storage.js.map +1 -0
- package/dist/compose-strand.d.ts +16 -3
- package/dist/compose-strand.js +96 -50
- package/dist/compose-strand.js.map +1 -1
- package/dist/connect-browser.js +2 -1
- package/dist/connect-browser.js.map +1 -1
- package/dist/connect.js +2 -1
- package/dist/connect.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/parse-config.js +23 -11
- package/dist/parse-config.js.map +1 -1
- package/dist/plugin-browser.js +77326 -74471
- package/dist/plugin-browser.js.map +4 -4
- package/dist/strand-schema.d.ts +1 -1
- package/dist/strand-schema.js +544 -503
- package/dist/strand-schema.js.map +1 -1
- package/dist/types.d.ts +37 -10
- package/package.json +8 -8
- package/src/cached-storage.ts +178 -0
- package/src/cluster-size.ts +248 -248
- package/src/compose-strand.ts +396 -325
- package/src/connect-browser.ts +2 -1
- package/src/connect.ts +2 -1
- package/src/index.ts +2 -1
- package/src/parse-config.ts +70 -55
- package/src/plugin-browser.ts +29 -29
- package/src/plugin.ts +39 -39
- package/src/strand-schema.ts +574 -533
- package/src/types.ts +106 -78
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrap an embedder-supplied `IRawStorage` in `@optimystic/db-p2p`'s write-through
|
|
3
|
+
* raw-storage cache (`CachedRawStorage`) before handing it to a node or transactor.
|
|
4
|
+
*
|
|
5
|
+
* Why: bringing a control database or strand up is raw-storage-operation bound —
|
|
6
|
+
* uncached, a cold start re-reads the same handful of blocks ~2000 times (see the
|
|
7
|
+
* budget history in cadre-core's `test/control-start-storage-op-budget.spec.ts` and
|
|
8
|
+
* the sereus tickets `complete/optimystic-block-read-amplification-on-control-start`
|
|
9
|
+
* + `complete/optimystic-schema-catalog-reread-per-write-blows-storage-budgets`).
|
|
10
|
+
* Upstream ships the remedy as an opt-in wrapper — adoption is deliberately the
|
|
11
|
+
* consumer's choice — and this module is where Sereus opts in. It lives in this
|
|
12
|
+
* package (not cadre-core) for the same reason `cluster-size.ts` does: both the SQL
|
|
13
|
+
* plugin's own connectors (`composeStrand`, including the browser/IndexedDB path,
|
|
14
|
+
* where per-operation latency is highest) and cadre-core's control/strand seams
|
|
15
|
+
* need the identical wrap, and two copies could disagree.
|
|
16
|
+
*
|
|
17
|
+
* Soundness rests on the cache's single-process-owner invariant (upstream
|
|
18
|
+
* docs/storage.md §6): every write to the backend must funnel through the wrapped
|
|
19
|
+
* instance. Two rules uphold that:
|
|
20
|
+
*
|
|
21
|
+
* - **One wrap per inner instance** (WeakMap memo): the same `IRawStorage` reaches
|
|
22
|
+
* this function from several seams at once — cadre-core's node wiring and the
|
|
23
|
+
* strand backfill share the instance the node was built with, and the SQL
|
|
24
|
+
* plugin's `composeStrand` re-wraps whatever it is handed. Two live caches over
|
|
25
|
+
* one backend would each miss the other's writes; the memo makes the wrap
|
|
26
|
+
* idempotent instead — a caller wrapping an already-wrapped or already-seen
|
|
27
|
+
* instance gets the same object back.
|
|
28
|
+
* - **A Sereus process owns its data stores** — no second process writes the same
|
|
29
|
+
* backend, which is the invariant's other half.
|
|
30
|
+
*
|
|
31
|
+
* `MemoryRawStorage` is returned unwrapped on upstream's own guidance: the backend
|
|
32
|
+
* is already in-memory, so the cache adds bookkeeping with nothing to save.
|
|
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
|
+
*
|
|
47
|
+
* The memo dedupes *concurrent* seams; it is not what keeps a cache alive across a
|
|
48
|
+
* runtime rebuild. That is cadre-core's job, and it does it by OWNERSHIP: one
|
|
49
|
+
* resolved store per scope per runtime lifetime — a strand's store for the life of
|
|
50
|
+
* its instance (a hibernation quiesce → resume reuses the store already resolved,
|
|
51
|
+
* so the wake lands on a warm cache), the control store for the life of one
|
|
52
|
+
* `CadreNode.start()`. Because the store outlives the rebuild, so does its wrap,
|
|
53
|
+
* whether or not the embedder's provider returns a stable instance.
|
|
54
|
+
*
|
|
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.
|
|
70
|
+
*/
|
|
71
|
+
import { type IRawStorage } from '@optimystic/db-p2p/rn';
|
|
72
|
+
/**
|
|
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.
|
|
78
|
+
*/
|
|
79
|
+
export declare function wrapStorageWithCache(storage: IRawStorage, label: string): IRawStorage;
|
|
80
|
+
/**
|
|
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.
|
|
90
|
+
*
|
|
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.
|
|
94
|
+
*/
|
|
95
|
+
export declare function disposeStorageCache(storage: IRawStorage): Promise<void>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrap an embedder-supplied `IRawStorage` in `@optimystic/db-p2p`'s write-through
|
|
3
|
+
* raw-storage cache (`CachedRawStorage`) before handing it to a node or transactor.
|
|
4
|
+
*
|
|
5
|
+
* Why: bringing a control database or strand up is raw-storage-operation bound —
|
|
6
|
+
* uncached, a cold start re-reads the same handful of blocks ~2000 times (see the
|
|
7
|
+
* budget history in cadre-core's `test/control-start-storage-op-budget.spec.ts` and
|
|
8
|
+
* the sereus tickets `complete/optimystic-block-read-amplification-on-control-start`
|
|
9
|
+
* + `complete/optimystic-schema-catalog-reread-per-write-blows-storage-budgets`).
|
|
10
|
+
* Upstream ships the remedy as an opt-in wrapper — adoption is deliberately the
|
|
11
|
+
* consumer's choice — and this module is where Sereus opts in. It lives in this
|
|
12
|
+
* package (not cadre-core) for the same reason `cluster-size.ts` does: both the SQL
|
|
13
|
+
* plugin's own connectors (`composeStrand`, including the browser/IndexedDB path,
|
|
14
|
+
* where per-operation latency is highest) and cadre-core's control/strand seams
|
|
15
|
+
* need the identical wrap, and two copies could disagree.
|
|
16
|
+
*
|
|
17
|
+
* Soundness rests on the cache's single-process-owner invariant (upstream
|
|
18
|
+
* docs/storage.md §6): every write to the backend must funnel through the wrapped
|
|
19
|
+
* instance. Two rules uphold that:
|
|
20
|
+
*
|
|
21
|
+
* - **One wrap per inner instance** (WeakMap memo): the same `IRawStorage` reaches
|
|
22
|
+
* this function from several seams at once — cadre-core's node wiring and the
|
|
23
|
+
* strand backfill share the instance the node was built with, and the SQL
|
|
24
|
+
* plugin's `composeStrand` re-wraps whatever it is handed. Two live caches over
|
|
25
|
+
* one backend would each miss the other's writes; the memo makes the wrap
|
|
26
|
+
* idempotent instead — a caller wrapping an already-wrapped or already-seen
|
|
27
|
+
* instance gets the same object back.
|
|
28
|
+
* - **A Sereus process owns its data stores** — no second process writes the same
|
|
29
|
+
* backend, which is the invariant's other half.
|
|
30
|
+
*
|
|
31
|
+
* `MemoryRawStorage` is returned unwrapped on upstream's own guidance: the backend
|
|
32
|
+
* is already in-memory, so the cache adds bookkeeping with nothing to save.
|
|
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
|
+
*
|
|
47
|
+
* The memo dedupes *concurrent* seams; it is not what keeps a cache alive across a
|
|
48
|
+
* runtime rebuild. That is cadre-core's job, and it does it by OWNERSHIP: one
|
|
49
|
+
* resolved store per scope per runtime lifetime — a strand's store for the life of
|
|
50
|
+
* its instance (a hibernation quiesce → resume reuses the store already resolved,
|
|
51
|
+
* so the wake lands on a warm cache), the control store for the life of one
|
|
52
|
+
* `CadreNode.start()`. Because the store outlives the rebuild, so does its wrap,
|
|
53
|
+
* whether or not the embedder's provider returns a stable instance.
|
|
54
|
+
*
|
|
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.
|
|
70
|
+
*/
|
|
71
|
+
// Imported from the `/rn` entry — the platform-neutral surface (no Node-only
|
|
72
|
+
// transports) — because `composeStrand` reaches this module on the browser path
|
|
73
|
+
// too. Both db-p2p entrypoints re-export the same storage modules, so class
|
|
74
|
+
// identity (the `instanceof` checks below) is unaffected on Node.
|
|
75
|
+
import { CachedRawStorage, MemoryRawStorage } from '@optimystic/db-p2p/rn';
|
|
76
|
+
const wraps = new WeakMap();
|
|
77
|
+
const claims = new WeakMap();
|
|
78
|
+
/**
|
|
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.
|
|
82
|
+
*/
|
|
83
|
+
function addHolder(wrapped) {
|
|
84
|
+
const claim = claims.get(wrapped);
|
|
85
|
+
if (claim) {
|
|
86
|
+
claim.holders += 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
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.
|
|
95
|
+
*/
|
|
96
|
+
export function wrapStorageWithCache(storage, label) {
|
|
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);
|
|
110
|
+
return storage;
|
|
111
|
+
}
|
|
112
|
+
const memoized = wraps.get(storage);
|
|
113
|
+
if (memoized) {
|
|
114
|
+
addHolder(memoized);
|
|
115
|
+
return memoized;
|
|
116
|
+
}
|
|
117
|
+
const wrapped = new CachedRawStorage(storage, undefined, label);
|
|
118
|
+
wraps.set(storage, wrapped);
|
|
119
|
+
claims.set(wrapped, { inner: storage, holders: 1 });
|
|
120
|
+
return wrapped;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
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.
|
|
132
|
+
*
|
|
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.
|
|
136
|
+
*/
|
|
137
|
+
export async function disposeStorageCache(storage) {
|
|
138
|
+
if (!(storage instanceof CachedRawStorage)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
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;
|
|
151
|
+
}
|
|
152
|
+
claims.delete(storage);
|
|
153
|
+
wraps.delete(claim.inner);
|
|
154
|
+
await storage.dispose();
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=cached-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/dist/compose-strand.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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';
|
|
4
|
-
import type { StrandConnectionOptions, SereusPluginResult } from './types.js';
|
|
3
|
+
import type { IRawStorage, NodeOptions } from '@optimystic/db-p2p';
|
|
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 {
|
|
7
7
|
vtables?: VTablePluginInfo[];
|
|
@@ -29,13 +29,26 @@ 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
|
}
|
|
35
48
|
/** Context passed to the platform's storage-resolution strategy. */
|
|
36
49
|
export interface ResolveStorageContext {
|
|
37
50
|
strandId: string;
|
|
38
|
-
resolvedTransactor:
|
|
51
|
+
resolvedTransactor: StrandTransactor;
|
|
39
52
|
/** The storage the caller passed in `options.storage`, if any. */
|
|
40
53
|
requestedStorage?: IRawStorage;
|
|
41
54
|
}
|
package/dist/compose-strand.js
CHANGED
|
@@ -1,7 +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';
|
|
4
|
+
import { resolveStrandClusterSize, STRAND_CLUSTER_POLICY } from './cluster-size.js';
|
|
5
|
+
import { wrapStorageWithCache, disposeStorageCache } from './cached-storage.js';
|
|
5
6
|
const log = debug('sereus:plugin:strand');
|
|
6
7
|
const timing = debug('sereus:plugin:strand:timing');
|
|
7
8
|
/**
|
|
@@ -33,53 +34,67 @@ export function applyRegistrations(db, result) {
|
|
|
33
34
|
* vtab, hydrate the catalog, then apply the sApp schema.
|
|
34
35
|
*/
|
|
35
36
|
export async function composeStrand(db, options, platform) {
|
|
36
|
-
const { strandId, bootstrapNodes = [], schema, port = 0, enableCache = true, fretProfile = 'edge',
|
|
37
|
+
const { strandId, bootstrapNodes = [], schema, port = 0, enableCache = true, fretProfile = 'edge', transactor = 'network', } = options;
|
|
37
38
|
// Resolve (and validate) up front so a nonsense value fails before any plugin
|
|
38
39
|
// registration or node creation has happened.
|
|
39
40
|
const clusterSize = resolveStrandClusterSize(options.clusterSize);
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
if (mode !== undefined) {
|
|
45
|
-
resolvedTransactor = mode === 'bootstrap' ? 'local' : 'network';
|
|
46
|
-
}
|
|
47
|
-
else if (options.transactor !== undefined) {
|
|
48
|
-
resolvedTransactor = options.transactor;
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
resolvedTransactor = 'network';
|
|
52
|
-
}
|
|
41
|
+
// The storage engine every write and read below goes through — see
|
|
42
|
+
// `StrandConnectionOptions.transactor`. Named separately from the option so
|
|
43
|
+
// the default is applied exactly once and reported on the result.
|
|
44
|
+
const resolvedTransactor = transactor;
|
|
53
45
|
const networkName = `strand-${strandId}`;
|
|
54
|
-
log('Connecting to strand %s (network: %s,
|
|
46
|
+
log('Connecting to strand %s (network: %s, transactor=%s)', strandId, networkName, resolvedTransactor);
|
|
55
47
|
// Resolve storage. Node passes `options.storage` through; the browser
|
|
56
|
-
// defaults to IndexedDB. The resolved instance feeds BOTH the
|
|
57
|
-
//
|
|
58
|
-
// front (before pluginConfig is built).
|
|
59
|
-
|
|
48
|
+
// defaults to IndexedDB. The resolved instance feeds BOTH the local
|
|
49
|
+
// transactor's `rawStorageFactory` and node creation, so it must be decided
|
|
50
|
+
// up front (before pluginConfig is built). Wrapped in the write-through
|
|
51
|
+
// raw-storage cache (cached-storage.ts) — idempotent, so a caller that
|
|
52
|
+
// already wrapped (cadre-core's seams) passes through unchanged, with this
|
|
53
|
+
// composition counted as one more holder of that same cache.
|
|
54
|
+
const resolvedStorage = platform.resolveStorage
|
|
60
55
|
? await platform.resolveStorage({ strandId, resolvedTransactor, requestedStorage: options.storage })
|
|
61
56
|
: options.storage;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
57
|
+
const storage = resolvedStorage ? wrapStorageWithCache(resolvedStorage, strandId) : resolvedStorage;
|
|
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);
|
|
73
78
|
};
|
|
74
|
-
|
|
75
|
-
|
|
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;
|
|
76
97
|
}
|
|
77
|
-
// The plugin's published signature is `Record<string, SqlValue>` but it
|
|
78
|
-
// also reads `rawStorageFactory` (a function reference) from the same map.
|
|
79
|
-
// Cast through unknown rather than widen the public type.
|
|
80
|
-
const pluginResult = optimysticPlugin(db, pluginConfig);
|
|
81
|
-
applyRegistrations(db, pluginResult);
|
|
82
|
-
log('Registered optimystic vtables and functions');
|
|
83
98
|
const { collectionFactory } = pluginResult;
|
|
84
99
|
let createdNode = null;
|
|
85
100
|
let hydrated;
|
|
@@ -98,7 +113,7 @@ export async function composeStrand(db, options, platform) {
|
|
|
98
113
|
log('Using injected libp2p node');
|
|
99
114
|
}
|
|
100
115
|
else {
|
|
101
|
-
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 });
|
|
102
117
|
createdNode = created;
|
|
103
118
|
node = created;
|
|
104
119
|
const repo = created.coordinatedRepo;
|
|
@@ -141,11 +156,11 @@ export async function composeStrand(db, options, platform) {
|
|
|
141
156
|
// Manager/Member, invite/peer flows) is owned by the lifecycle ticket
|
|
142
157
|
// `strand-membership-lifecycle-population`.
|
|
143
158
|
log('Applying Strand membership schema for strand %s', strandId);
|
|
144
|
-
await db.exec(`
|
|
145
|
-
declare schema Strand {
|
|
146
|
-
${STRAND_SCHEMA}
|
|
147
|
-
}
|
|
148
|
-
apply schema Strand;
|
|
159
|
+
await db.exec(`
|
|
160
|
+
declare schema Strand {
|
|
161
|
+
${STRAND_SCHEMA}
|
|
162
|
+
}
|
|
163
|
+
apply schema Strand;
|
|
149
164
|
`);
|
|
150
165
|
log('Strand membership schema applied');
|
|
151
166
|
// 7. Apply the sApp schema, if provided.
|
|
@@ -155,11 +170,11 @@ export async function composeStrand(db, options, platform) {
|
|
|
155
170
|
// here so it stays a one-location edit across Node, browser, and cadre-core.
|
|
156
171
|
if (schema) {
|
|
157
172
|
log('Applying sApp schema for strand %s', strandId);
|
|
158
|
-
await db.exec(`
|
|
159
|
-
declare schema App {
|
|
160
|
-
${schema}
|
|
161
|
-
}
|
|
162
|
-
apply schema App;
|
|
173
|
+
await db.exec(`
|
|
174
|
+
declare schema App {
|
|
175
|
+
${schema}
|
|
176
|
+
}
|
|
177
|
+
apply schema App;
|
|
163
178
|
`);
|
|
164
179
|
log('sApp schema applied');
|
|
165
180
|
}
|
|
@@ -170,6 +185,7 @@ export async function composeStrand(db, options, platform) {
|
|
|
170
185
|
if (createdNode) {
|
|
171
186
|
await createdNode.stop();
|
|
172
187
|
}
|
|
188
|
+
await releaseStorageCache();
|
|
173
189
|
throw err;
|
|
174
190
|
}
|
|
175
191
|
// 8. Return result with hydrate counts + shutdown handler. `shutdown` tears
|
|
@@ -185,14 +201,44 @@ export async function composeStrand(db, options, platform) {
|
|
|
185
201
|
functions: [],
|
|
186
202
|
collations: [],
|
|
187
203
|
hydrated,
|
|
204
|
+
transactor: resolvedTransactor,
|
|
188
205
|
async shutdown() {
|
|
189
206
|
log('Shutting down strand connection %s', strandId);
|
|
190
207
|
await collectionFactory.shutdown();
|
|
191
208
|
if (createdNode) {
|
|
192
209
|
await createdNode.stop();
|
|
193
210
|
}
|
|
211
|
+
await releaseStorageCache();
|
|
194
212
|
log('Strand connection %s shut down', strandId);
|
|
195
213
|
},
|
|
196
214
|
};
|
|
197
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
|
+
}
|
|
198
244
|
//# sourceMappingURL=compose-strand.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,gBAAgB,MAAM,8CAA8C,CAAC;AAK5E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"compose-strand.js","sourceRoot":"","sources":["../src/compose-strand.ts"],"names":[],"mappings":"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"}
|
package/dist/connect-browser.js
CHANGED
|
@@ -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;
|
|
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
|
},
|
package/dist/connect.js.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { connectToStrand } from './connect.js';
|
|
2
2
|
export { MIN_CLUSTER_SIZE, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize } from './cluster-size.js';
|
|
3
|
-
export
|
|
3
|
+
export { wrapStorageWithCache, disposeStorageCache } from './cached-storage.js';
|
|
4
|
+
export type { StrandConnectionOptions, SereusPluginResult, StrandTransactor } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { connectToStrand } from './connect.js';
|
|
2
2
|
export { MIN_CLUSTER_SIZE, CONTROL_REPLICATION_BREADTH, CONTROL_CLUSTER_POLICY, DEFAULT_STRAND_CLUSTER_SIZE, STRAND_CLUSTER_POLICY, resolveStrandClusterSize } from './cluster-size.js';
|
|
3
|
+
export { wrapStorageWithCache, disposeStorageCache } from './cached-storage.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACN,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACN,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|