@serfab/cadre-core 0.9.0 → 0.11.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 +255 -253
- package/dist/bootstrap-peer-store-file.d.ts +13 -0
- package/dist/bootstrap-peer-store-file.js +42 -0
- package/dist/bootstrap-peer-store-file.js.map +1 -0
- package/dist/bootstrap-peer-store.d.ts +73 -0
- package/dist/bootstrap-peer-store.js +128 -0
- package/dist/bootstrap-peer-store.js.map +1 -0
- package/dist/cadre-node.d.ts +1121 -81
- package/dist/cadre-node.js +2276 -262
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-authorization.d.ts +93 -0
- package/dist/control-authorization.js +57 -0
- package/dist/control-authorization.js.map +1 -0
- package/dist/control-cohort.d.ts +26 -0
- package/dist/control-cohort.js +26 -0
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +959 -54
- package/dist/control-database.js +1421 -148
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +90 -10
- package/dist/control-formation-recorder.js +130 -14
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +651 -72
- package/dist/control-schema.js.map +1 -1
- package/dist/control-stream.d.ts +38 -4
- package/dist/control-stream.js +70 -4
- package/dist/control-stream.js.map +1 -1
- package/dist/control-write-retry.d.ts +161 -0
- package/dist/control-write-retry.js +412 -0
- package/dist/control-write-retry.js.map +1 -0
- package/dist/delegate-admission.d.ts +134 -0
- package/dist/delegate-admission.js +244 -0
- package/dist/delegate-admission.js.map +1 -0
- package/dist/device-token.d.ts +11 -11
- package/dist/device-token.js +14 -13
- package/dist/device-token.js.map +1 -1
- package/dist/ed25519-key.d.ts +26 -0
- package/dist/ed25519-key.js +56 -1
- package/dist/ed25519-key.js.map +1 -1
- package/dist/file-durable-slot.d.ts +20 -0
- package/dist/file-durable-slot.js +53 -0
- package/dist/file-durable-slot.js.map +1 -0
- package/dist/formation-approval.d.ts +157 -0
- package/dist/formation-approval.js +375 -0
- package/dist/formation-approval.js.map +1 -0
- package/dist/fs-atomic.d.ts +38 -0
- package/dist/fs-atomic.js +97 -0
- package/dist/fs-atomic.js.map +1 -0
- package/dist/identity-key.d.ts +49 -0
- package/dist/identity-key.js +81 -0
- package/dist/identity-key.js.map +1 -0
- package/dist/index.d.ts +17 -7
- package/dist/index.js +40 -6
- package/dist/index.js.map +1 -1
- package/dist/key-store-file.d.ts +2 -24
- package/dist/key-store-file.js +10 -77
- package/dist/key-store-file.js.map +1 -1
- package/dist/membership-connection-gater.d.ts +146 -0
- package/dist/membership-connection-gater.js +180 -0
- package/dist/membership-connection-gater.js.map +1 -0
- package/dist/node-local-snapshot.d.ts +109 -0
- package/dist/node-local-snapshot.js +182 -0
- package/dist/node-local-snapshot.js.map +1 -0
- package/dist/peer-addr-book.d.ts +92 -0
- package/dist/peer-addr-book.js +220 -0
- package/dist/peer-addr-book.js.map +1 -0
- package/dist/peer-authorization.d.ts +135 -18
- package/dist/peer-authorization.js +152 -21
- package/dist/peer-authorization.js.map +1 -1
- package/dist/peer-record.d.ts +21 -8
- package/dist/peer-record.js +26 -10
- package/dist/peer-record.js.map +1 -1
- package/dist/relay-addrs.d.ts +45 -0
- package/dist/relay-addrs.js +103 -0
- package/dist/relay-addrs.js.map +1 -0
- package/dist/relay-reservation.d.ts +266 -0
- package/dist/relay-reservation.js +613 -0
- package/dist/relay-reservation.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +228 -56
- package/dist/seed-bootstrap.js +340 -198
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.d.ts +47 -21
- package/dist/seed-trust-policy.js +24 -15
- package/dist/seed-trust-policy.js.map +1 -1
- package/dist/strand-addr-protocol.d.ts +42 -13
- package/dist/strand-addr-protocol.js +58 -52
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-backfill.d.ts +109 -0
- package/dist/strand-backfill.js +279 -0
- package/dist/strand-backfill.js.map +1 -0
- package/dist/strand-cohort.d.ts +4 -37
- package/dist/strand-cohort.js +4 -15
- package/dist/strand-cohort.js.map +1 -1
- package/dist/strand-database.d.ts +11 -16
- package/dist/strand-database.js +19 -7
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +36 -7
- package/dist/strand-formation-manager.js +115 -15
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +103 -4
- package/dist/strand-formation-protocol.js +232 -4
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +88 -19
- package/dist/strand-instance-manager.js +178 -34
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-member-registry.d.ts +5 -5
- package/dist/strand-member-registry.js +18 -10
- package/dist/strand-member-registry.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +484 -88
- package/dist/strand-membership-writer.js +751 -128
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +99 -33
- package/dist/strand-solicitation.js +100 -52
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-transport-key.d.ts +40 -0
- package/dist/strand-transport-key.js +56 -0
- package/dist/strand-transport-key.js.map +1 -0
- package/dist/strand-wake-protocol.d.ts +9 -7
- package/dist/strand-wake-protocol.js +22 -46
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/strand-watcher.d.ts +17 -2
- package/dist/strand-watcher.js +47 -3
- package/dist/strand-watcher.js.map +1 -1
- package/dist/trusted-owner-store-file.d.ts +12 -0
- package/dist/trusted-owner-store-file.js +39 -0
- package/dist/trusted-owner-store-file.js.map +1 -0
- package/dist/trusted-owner-store.d.ts +64 -0
- package/dist/trusted-owner-store.js +126 -0
- package/dist/trusted-owner-store.js.map +1 -0
- package/dist/types.d.ts +307 -44
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -1
- package/package.json +20 -8
- package/src/arachnode-stub.ts +159 -159
- package/src/bootstrap-peer-store-file.ts +44 -0
- package/src/bootstrap-peer-store.ts +172 -0
- package/src/cadre-node.ts +5158 -2981
- package/src/canonical-json.ts +30 -30
- package/src/control-authorization.ts +114 -0
- package/src/control-cohort.ts +130 -103
- package/src/control-database.ts +2406 -948
- package/src/control-formation-recorder.ts +305 -151
- package/src/control-schema.ts +651 -72
- package/src/control-stream.ts +205 -128
- package/src/control-write-retry.ts +483 -0
- package/src/delegate-admission.ts +302 -0
- package/src/device-token.ts +94 -89
- package/src/diagnostics/connection-path.ts +277 -277
- package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
- package/src/ed25519-key.ts +66 -1
- package/src/enrollment.ts +199 -199
- package/src/file-durable-slot.ts +61 -0
- package/src/formation-approval.ts +604 -0
- package/src/fs-atomic.ts +107 -0
- package/src/hibernation-manager.ts +437 -437
- package/src/identity-key.ts +109 -0
- package/src/index.ts +137 -5
- package/src/key-store-file.ts +132 -203
- package/src/key-store.ts +99 -99
- package/src/membership-connection-gater.ts +204 -0
- package/src/node-local-snapshot.ts +260 -0
- package/src/peer-addr-book.ts +250 -0
- package/src/peer-authorization.ts +259 -81
- package/src/peer-record.ts +164 -146
- package/src/push-credentials.ts +84 -84
- package/src/push-node.ts +64 -64
- package/src/push-notifier-apns.ts +247 -247
- package/src/push-notifier-fcm.ts +220 -220
- package/src/push-notifier-shared.ts +28 -28
- package/src/push-notifier.ts +52 -52
- package/src/relay-addrs.ts +111 -0
- package/src/relay-reservation.ts +823 -0
- package/src/seed-bootstrap.ts +409 -209
- package/src/seed-trust-policy.ts +140 -107
- package/src/strand-addr-protocol.ts +441 -410
- package/src/strand-backfill.ts +366 -0
- package/src/strand-cohort.ts +38 -77
- package/src/strand-database.ts +202 -204
- package/src/strand-formation-manager.ts +491 -368
- package/src/strand-formation-protocol.ts +692 -391
- package/src/strand-instance-manager.ts +201 -46
- package/src/strand-member-key.ts +39 -39
- package/src/strand-member-registry.ts +182 -177
- package/src/strand-membership-writer.ts +938 -146
- package/src/strand-solicitation.ts +472 -407
- package/src/strand-transport-key.ts +58 -0
- package/src/strand-wake-payload.ts +32 -32
- package/src/strand-wake-protocol.ts +314 -331
- package/src/strand-watcher.ts +314 -251
- package/src/trusted-owner-store-file.ts +41 -0
- package/src/trusted-owner-store.ts +171 -0
- package/src/types.ts +1309 -1032
package/src/strand-database.ts
CHANGED
|
@@ -1,204 +1,202 @@
|
|
|
1
|
-
import debug from 'debug';
|
|
2
|
-
import { Database } from '@quereus/quereus';
|
|
3
|
-
import { connectToStrand } from '@serfab/quereus-plugin-sereus';
|
|
4
|
-
import type { SereusPluginResult } from '@serfab/quereus-plugin-sereus';
|
|
5
|
-
import type { Libp2p } from '@libp2p/interface';
|
|
6
|
-
import type { IRepo } from '@optimystic/db-core';
|
|
7
|
-
import type {
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
sid,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
*
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
*
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
this.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
}
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import { Database } from '@quereus/quereus';
|
|
3
|
+
import { connectToStrand } from '@serfab/quereus-plugin-sereus';
|
|
4
|
+
import type { SereusPluginResult } from '@serfab/quereus-plugin-sereus';
|
|
5
|
+
import type { Libp2p } from '@libp2p/interface';
|
|
6
|
+
import type { IRepo } from '@optimystic/db-core';
|
|
7
|
+
import type { SAppConfig } from './types.js';
|
|
8
|
+
import { bootstrapFounderMembership } from './strand-membership-writer.js';
|
|
9
|
+
import { strandMemberKeyPair } from './strand-member-key.js';
|
|
10
|
+
|
|
11
|
+
const log = debug('sereus:cadre:strand-db');
|
|
12
|
+
const timing = debug('sereus:cadre:timing');
|
|
13
|
+
|
|
14
|
+
export interface StrandDatabaseConfig {
|
|
15
|
+
/** The strand ID */
|
|
16
|
+
strandId: string;
|
|
17
|
+
/** sApp configuration containing the schema */
|
|
18
|
+
sAppConfig: SAppConfig;
|
|
19
|
+
/** Libp2p node for the strand network */
|
|
20
|
+
libp2pNode: Libp2p;
|
|
21
|
+
/** Coordinated repo from the libp2p node */
|
|
22
|
+
coordinatedRepo: IRepo;
|
|
23
|
+
/**
|
|
24
|
+
* Strand type (`'o'` open / `'c'` closed) from the control-network strand row.
|
|
25
|
+
* Drives the founder bootstrap: open strands get a `Header` only; closed strands
|
|
26
|
+
* also get the founding `Member`+`Manager`.
|
|
27
|
+
*/
|
|
28
|
+
strandType: 'o' | 'c';
|
|
29
|
+
/**
|
|
30
|
+
* The closed-strand `MemberPrivateKey` (base64 protobuf) from the strand row.
|
|
31
|
+
* Required when `founder` is true and `strandType` is `'c'` — it derives the
|
|
32
|
+
* founding `Member.Key`/`Manager.MemberKey`. Absent for open strands.
|
|
33
|
+
*/
|
|
34
|
+
memberPrivateKey?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether this node founds the strand. When true, {@link initialize} runs the
|
|
37
|
+
* one-time founder membership bootstrap after the schema is applied. Joiners
|
|
38
|
+
* leave this false and write nothing (rows arrive via sync). Defaults to false.
|
|
39
|
+
*/
|
|
40
|
+
founder?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* StrandDatabase manages the sApp schema for a strand using Quereus with the
|
|
45
|
+
* Optimystic backend. Each strand instance has its own isolated database with
|
|
46
|
+
* the sApp's schema applied.
|
|
47
|
+
*
|
|
48
|
+
* This class owns the `Database` lifecycle (creation, `getDatabase()`, `close()`)
|
|
49
|
+
* but delegates the actual SQL-surface composition — plugin registration, node
|
|
50
|
+
* wiring, catalog hydration, schema apply — to `connectToStrand` from
|
|
51
|
+
* `@serfab/quereus-plugin-sereus`, the single shared composition. The libp2p
|
|
52
|
+
* node is injected here, so `connectToStrand` never *creates* the node;
|
|
53
|
+
* `StrandInstanceManager` owns the node lifecycle. (The strand connection's
|
|
54
|
+
* `shutdown` still stops the injected node via the collection factory, so the
|
|
55
|
+
* manager's own `node.stop()` is an idempotent second stop — see `close()`.)
|
|
56
|
+
*/
|
|
57
|
+
export class StrandDatabase {
|
|
58
|
+
private db: Database | null = null;
|
|
59
|
+
private shutdownStrand: SereusPluginResult['shutdown'] | null = null;
|
|
60
|
+
private resolvedTransactor: SereusPluginResult['transactor'] | null = null;
|
|
61
|
+
private readonly config: StrandDatabaseConfig;
|
|
62
|
+
private initialized = false;
|
|
63
|
+
|
|
64
|
+
constructor(config: StrandDatabaseConfig) {
|
|
65
|
+
this.config = config;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Initialize the database — create the `Database` and delegate the strand
|
|
70
|
+
* SQL-surface composition (plugins, node wiring, hydrate, schema apply) to
|
|
71
|
+
* `connectToStrand` with the injected libp2p node.
|
|
72
|
+
*/
|
|
73
|
+
async initialize(): Promise<void> {
|
|
74
|
+
if (this.initialized) {
|
|
75
|
+
log('StrandDatabase for strand %s already initialized', this.config.strandId);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const sid = this.config.strandId;
|
|
80
|
+
log('Initializing StrandDatabase for strand: %s (sApp: %s v%s)',
|
|
81
|
+
sid, this.config.sAppConfig.id, this.config.sAppConfig.version);
|
|
82
|
+
|
|
83
|
+
this.db = new Database();
|
|
84
|
+
|
|
85
|
+
// Delegate to the shared composition. The node is injected, so:
|
|
86
|
+
// - `connectToStrand` never creates a node (its `createdNode` stays null);
|
|
87
|
+
// `StrandInstanceManager` owns the node lifecycle. Its `shutdown` does
|
|
88
|
+
// still stop the injected node via the collection factory, so the
|
|
89
|
+
// manager's later `node.stop()` is an idempotent second stop;
|
|
90
|
+
// - no `storage` is passed: the plugin consumes it only to build a local
|
|
91
|
+
// transactor's raw-storage factory or to create a node it was not given,
|
|
92
|
+
// and cadre-core always injects the node and runs the network transactor.
|
|
93
|
+
// (The plugin keeps its `storage` option for the browser entry point.)
|
|
94
|
+
const t0 = performance.now();
|
|
95
|
+
const result = await connectToStrand(this.db, {
|
|
96
|
+
strandId: sid,
|
|
97
|
+
schema: this.config.sAppConfig.schema,
|
|
98
|
+
libp2pNode: this.config.libp2pNode,
|
|
99
|
+
coordinatedRepo: this.config.coordinatedRepo,
|
|
100
|
+
enableCache: true,
|
|
101
|
+
});
|
|
102
|
+
this.shutdownStrand = result.shutdown;
|
|
103
|
+
this.resolvedTransactor = result.transactor;
|
|
104
|
+
timing('[strandDb:%s] connectToStrand: %dms (hydrated tables=%d, indexes=%d)',
|
|
105
|
+
sid, Math.round(performance.now() - t0),
|
|
106
|
+
result.hydrated?.tables ?? 0, result.hydrated?.indexes ?? 0);
|
|
107
|
+
|
|
108
|
+
// Founder-only: write the one-time membership bootstrap now that the schema is
|
|
109
|
+
// applied (connectToStrand has returned). A throw here propagates out of
|
|
110
|
+
// initialize() so buildStrandRuntime's rollback tears the half-built strand
|
|
111
|
+
// down rather than leaking a node. Joiners skip this — their rows arrive via sync.
|
|
112
|
+
if (this.config.founder === true) {
|
|
113
|
+
await this.bootstrapFounder();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.initialized = true;
|
|
117
|
+
log('StrandDatabase for strand %s initialized successfully', sid);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Run the founder membership bootstrap against the freshly-composed strand DB.
|
|
122
|
+
*
|
|
123
|
+
* Derives the founding keypair from the closed-strand `memberPrivateKey` (the
|
|
124
|
+
* `Member.Key`/`Manager.MemberKey` are its public key); a closed strand with no
|
|
125
|
+
* `memberPrivateKey` throws, because it could never seat a founding manager.
|
|
126
|
+
* Open strands derive no keypair (Header only). Idempotent — see
|
|
127
|
+
* {@link bootstrapFounderMembership}.
|
|
128
|
+
*/
|
|
129
|
+
private async bootstrapFounder(): Promise<void> {
|
|
130
|
+
const { strandId, strandType, memberPrivateKey, sAppConfig } = this.config;
|
|
131
|
+
const founderKeyPair = strandType === 'c'
|
|
132
|
+
? this.deriveFounderKeyPair(strandId, memberPrivateKey)
|
|
133
|
+
: undefined;
|
|
134
|
+
await bootstrapFounderMembership(this.db!, {
|
|
135
|
+
strandId,
|
|
136
|
+
type: strandType,
|
|
137
|
+
sApp: sAppConfig,
|
|
138
|
+
founderKeyPair,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Derive the founding keypair for a closed strand from its `memberPrivateKey`,
|
|
144
|
+
* failing loudly when the key is absent (a closed strand with no founding
|
|
145
|
+
* Manager can never admit anyone).
|
|
146
|
+
*/
|
|
147
|
+
private deriveFounderKeyPair(strandId: string, memberPrivateKey: string | undefined) {
|
|
148
|
+
if (!memberPrivateKey) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Cannot found closed strand ${strandId}: the strand row has no MemberPrivateKey. ` +
|
|
151
|
+
'A closed strand needs a founding Member/Manager derived from that key.',
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return strandMemberKeyPair(memberPrivateKey);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get the underlying database for queries
|
|
159
|
+
*/
|
|
160
|
+
getDatabase(): Database {
|
|
161
|
+
this.ensureInitialized();
|
|
162
|
+
return this.db!;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The Optimystic transactor this strand's connection resolved to — always
|
|
167
|
+
* `'network'` here, since cadre-core passes no `transactor` option and takes
|
|
168
|
+
* the plugin's default. Exposed so a spec measuring or asserting the network
|
|
169
|
+
* path (`strand-solo-write-budget.spec.ts`) can pin the engine it ran on
|
|
170
|
+
* rather than assume it.
|
|
171
|
+
*/
|
|
172
|
+
getTransactor(): SereusPluginResult['transactor'] {
|
|
173
|
+
this.ensureInitialized();
|
|
174
|
+
return this.resolvedTransactor!;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Close the database and cleanup resources. Runs the strand-connection
|
|
179
|
+
* shutdown (collection-factory teardown, which also stops the injected node),
|
|
180
|
+
* then closes the `Database`. `StrandInstanceManager.releaseRuntime` issues a
|
|
181
|
+
* further idempotent `node.stop()` after this returns.
|
|
182
|
+
*/
|
|
183
|
+
async close(): Promise<void> {
|
|
184
|
+
if (this.shutdownStrand) {
|
|
185
|
+
await this.shutdownStrand();
|
|
186
|
+
this.shutdownStrand = null;
|
|
187
|
+
}
|
|
188
|
+
if (this.db) {
|
|
189
|
+
void this.db.close();
|
|
190
|
+
this.db = null;
|
|
191
|
+
}
|
|
192
|
+
this.resolvedTransactor = null;
|
|
193
|
+
this.initialized = false;
|
|
194
|
+
log('StrandDatabase for strand %s closed', this.config.strandId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private ensureInitialized(): void {
|
|
198
|
+
if (!this.initialized || !this.db) {
|
|
199
|
+
throw new Error(`StrandDatabase for strand ${this.config.strandId} not initialized. Call initialize() first.`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|