@serfab/cadre-core 0.6.0 → 0.8.1
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 +9 -8
- package/dist/authority-key.d.ts +41 -0
- package/dist/authority-key.js +52 -0
- package/dist/authority-key.js.map +1 -0
- package/dist/cadre-node.d.ts +777 -11
- package/dist/cadre-node.js +1912 -82
- package/dist/cadre-node.js.map +1 -1
- package/dist/canonical-datetime.d.ts +33 -0
- package/dist/canonical-datetime.js +38 -0
- package/dist/canonical-datetime.js.map +1 -0
- package/dist/canonical-json.d.ts +12 -0
- package/dist/canonical-json.js +33 -0
- package/dist/canonical-json.js.map +1 -0
- package/dist/control-cohort.d.ts +63 -0
- package/dist/control-cohort.js +80 -0
- package/dist/control-cohort.js.map +1 -0
- package/dist/control-database.d.ts +259 -5
- package/dist/control-database.js +541 -128
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +89 -0
- package/dist/control-formation-recorder.js +139 -0
- package/dist/control-formation-recorder.js.map +1 -0
- package/dist/control-schema.d.ts +12 -0
- package/dist/control-schema.js +199 -0
- package/dist/control-schema.js.map +1 -0
- package/dist/control-stream.d.ts +54 -0
- package/dist/control-stream.js +104 -0
- package/dist/control-stream.js.map +1 -0
- package/dist/device-token.d.ts +50 -0
- package/dist/device-token.js +66 -0
- package/dist/device-token.js.map +1 -0
- package/dist/diagnostics/connection-path.d.ts +118 -0
- package/dist/diagnostics/connection-path.js +204 -0
- package/dist/diagnostics/connection-path.js.map +1 -0
- package/dist/diagnostics/webrtc-turn-tracker.d.ts +50 -0
- package/dist/diagnostics/webrtc-turn-tracker.js +196 -0
- package/dist/diagnostics/webrtc-turn-tracker.js.map +1 -0
- package/dist/hibernation-manager.d.ts +79 -0
- package/dist/hibernation-manager.js +173 -23
- package/dist/hibernation-manager.js.map +1 -1
- package/dist/index.d.ts +25 -4
- package/dist/index.js +59 -4
- package/dist/index.js.map +1 -1
- package/dist/key-store-file.d.ts +52 -0
- package/dist/key-store-file.js +194 -0
- package/dist/key-store-file.js.map +1 -0
- package/dist/key-store.d.ts +75 -0
- package/dist/key-store.js +66 -0
- package/dist/key-store.js.map +1 -0
- package/dist/peer-authorization.d.ts +26 -0
- package/dist/peer-authorization.js +40 -0
- package/dist/peer-authorization.js.map +1 -0
- package/dist/peer-record.d.ts +89 -0
- package/dist/peer-record.js +117 -0
- package/dist/peer-record.js.map +1 -0
- package/dist/push-credentials.d.ts +34 -0
- package/dist/push-credentials.js +81 -0
- package/dist/push-credentials.js.map +1 -0
- package/dist/push-fanout.d.ts +137 -0
- package/dist/push-fanout.js +197 -0
- package/dist/push-fanout.js.map +1 -0
- package/dist/push-notifier-apns.d.ts +53 -0
- package/dist/push-notifier-apns.js +195 -0
- package/dist/push-notifier-apns.js.map +1 -0
- package/dist/push-notifier-fcm.d.ts +38 -0
- package/dist/push-notifier-fcm.js +183 -0
- package/dist/push-notifier-fcm.js.map +1 -0
- package/dist/push-notifier-shared.d.ts +18 -0
- package/dist/push-notifier-shared.js +25 -0
- package/dist/push-notifier-shared.js.map +1 -0
- package/dist/push-notifier.d.ts +71 -0
- package/dist/push-notifier.js +50 -0
- package/dist/push-notifier.js.map +1 -0
- package/dist/schema-verification.d.ts +11 -2
- package/dist/schema-verification.js +15 -4
- package/dist/schema-verification.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +210 -7
- package/dist/seed-bootstrap.js +429 -131
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.d.ts +63 -0
- package/dist/seed-trust-policy.js +56 -0
- package/dist/seed-trust-policy.js.map +1 -0
- package/dist/strand-addr-protocol.d.ts +132 -0
- package/dist/strand-addr-protocol.js +313 -0
- package/dist/strand-addr-protocol.js.map +1 -0
- package/dist/strand-cohort.d.ts +54 -0
- package/dist/strand-cohort.js +38 -0
- package/dist/strand-cohort.js.map +1 -0
- package/dist/strand-database.d.ts +54 -6
- package/dist/strand-database.js +88 -89
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +79 -19
- package/dist/strand-formation-manager.js +196 -104
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +162 -0
- package/dist/strand-formation-protocol.js +279 -0
- package/dist/strand-formation-protocol.js.map +1 -0
- package/dist/strand-instance-manager.d.ts +73 -4
- package/dist/strand-instance-manager.js +167 -41
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-member-key.d.ts +29 -0
- package/dist/strand-member-key.js +38 -0
- package/dist/strand-member-key.js.map +1 -0
- package/dist/strand-member-registry.d.ts +98 -0
- package/dist/strand-member-registry.js +129 -0
- package/dist/strand-member-registry.js.map +1 -0
- package/dist/strand-membership-writer.d.ts +361 -0
- package/dist/strand-membership-writer.js +449 -0
- package/dist/strand-membership-writer.js.map +1 -0
- package/dist/strand-solicitation.d.ts +77 -2
- package/dist/strand-solicitation.js +25 -4
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-wake-payload.d.ts +30 -0
- package/dist/strand-wake-payload.js +20 -0
- package/dist/strand-wake-payload.js.map +1 -0
- package/dist/strand-wake-protocol.d.ts +114 -0
- package/dist/strand-wake-protocol.js +257 -0
- package/dist/strand-wake-protocol.js.map +1 -0
- package/dist/strand-watcher.d.ts +6 -2
- package/dist/strand-watcher.js +57 -17
- package/dist/strand-watcher.js.map +1 -1
- package/dist/types.d.ts +413 -23
- package/dist/types.js +22 -5
- package/dist/types.js.map +1 -1
- package/package.json +14 -8
- package/src/authority-key.ts +68 -0
- package/src/cadre-node.ts +2937 -929
- package/src/canonical-datetime.ts +39 -0
- package/src/canonical-json.ts +30 -0
- package/src/control-cohort.ts +103 -0
- package/src/control-database.ts +931 -383
- package/src/control-formation-recorder.ts +151 -0
- package/src/control-schema.ts +198 -0
- package/src/control-stream.ts +128 -0
- package/src/device-token.ts +89 -0
- package/src/diagnostics/connection-path.ts +277 -0
- package/src/diagnostics/webrtc-turn-tracker.ts +222 -0
- package/src/hibernation-manager.ts +197 -28
- package/src/index.ts +273 -79
- package/src/key-store-file.ts +203 -0
- package/src/key-store.ts +99 -0
- package/src/peer-authorization.ts +53 -0
- package/src/peer-record.ts +146 -0
- package/src/push-credentials.ts +84 -0
- package/src/push-fanout.ts +272 -0
- package/src/push-notifier-apns.ts +243 -0
- package/src/push-notifier-fcm.ts +221 -0
- package/src/push-notifier-shared.ts +28 -0
- package/src/push-notifier.ts +93 -0
- package/src/schema-verification.ts +18 -4
- package/src/seed-bootstrap.ts +504 -171
- package/src/seed-trust-policy.ts +107 -0
- package/src/strand-addr-protocol.ts +410 -0
- package/src/strand-cohort.ts +77 -0
- package/src/strand-database.ts +113 -126
- package/src/strand-formation-manager.ts +233 -142
- package/src/strand-formation-protocol.ts +391 -0
- package/src/strand-instance-manager.ts +207 -56
- package/src/strand-member-key.ts +39 -0
- package/src/strand-member-registry.ts +177 -0
- package/src/strand-membership-writer.ts +640 -0
- package/src/strand-solicitation.ts +93 -4
- package/src/strand-wake-payload.ts +32 -0
- package/src/strand-wake-protocol.ts +331 -0
- package/src/strand-watcher.ts +61 -17
- package/src/types.ts +1012 -575
package/src/strand-database.ts
CHANGED
|
@@ -1,32 +1,17 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
|
-
import { Database
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { Database } from '@quereus/quereus';
|
|
3
|
+
import { connectToStrand } from '@serfab/quereus-plugin-sereus';
|
|
4
|
+
import type { SereusPluginResult } from '@serfab/quereus-plugin-sereus';
|
|
5
5
|
import type { Libp2p } from '@libp2p/interface';
|
|
6
6
|
import type { IRepo } from '@optimystic/db-core';
|
|
7
7
|
import type { IRawStorage } from '@optimystic/db-p2p';
|
|
8
8
|
import type { SAppConfig, StrandMode } from './types.js';
|
|
9
|
+
import { bootstrapFounderMembership } from './strand-membership-writer.js';
|
|
10
|
+
import { strandMemberKeyPair } from './strand-member-key.js';
|
|
9
11
|
|
|
10
12
|
const log = debug('sereus:cadre:strand-db');
|
|
11
13
|
const timing = debug('sereus:cadre:timing');
|
|
12
14
|
|
|
13
|
-
/**
|
|
14
|
-
* Minimal interface for the CollectionFactory returned by the optimystic plugin.
|
|
15
|
-
* We only need the methods we actually use.
|
|
16
|
-
*/
|
|
17
|
-
interface CollectionFactory {
|
|
18
|
-
registerLibp2pNode(networkName: string, node: Libp2p, coordinatedRepo: IRepo): void;
|
|
19
|
-
shutdown(): Promise<void>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Result of registering the optimystic plugin */
|
|
23
|
-
interface OptimysticPluginResult {
|
|
24
|
-
collectionFactory: CollectionFactory;
|
|
25
|
-
vtables: Array<{ name: string; module: unknown; auxData: unknown }>;
|
|
26
|
-
functions: Array<{ schema: unknown }>;
|
|
27
|
-
[key: string]: unknown;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
15
|
export interface StrandDatabaseConfig {
|
|
31
16
|
/** The strand ID */
|
|
32
17
|
strandId: string;
|
|
@@ -50,15 +35,43 @@ export interface StrandDatabaseConfig {
|
|
|
50
35
|
* across the two consumers.
|
|
51
36
|
*/
|
|
52
37
|
rawStorage?: IRawStorage;
|
|
38
|
+
/**
|
|
39
|
+
* Strand type (`'o'` open / `'c'` closed) from the control-network strand row.
|
|
40
|
+
* Drives the founder bootstrap: open strands get a `Header` only; closed strands
|
|
41
|
+
* also get the founding `Member`+`Authority`.
|
|
42
|
+
*/
|
|
43
|
+
strandType: 'o' | 'c';
|
|
44
|
+
/**
|
|
45
|
+
* The closed-strand `MemberPrivateKey` (base64 protobuf) from the strand row.
|
|
46
|
+
* Required when `founder` is true and `strandType` is `'c'` — it derives the
|
|
47
|
+
* founding `Member.Key`/`Authority.MemberKey`. Absent for open strands.
|
|
48
|
+
*/
|
|
49
|
+
memberPrivateKey?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Whether this node founds the strand. When true, {@link initialize} runs the
|
|
52
|
+
* one-time founder membership bootstrap after the schema is applied. Joiners
|
|
53
|
+
* leave this false and write nothing (rows arrive via sync). Defaults to false.
|
|
54
|
+
*/
|
|
55
|
+
founder?: boolean;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
/**
|
|
56
|
-
* StrandDatabase manages the sApp schema for a strand using Quereus with
|
|
57
|
-
* Each strand instance has its own isolated database with
|
|
59
|
+
* StrandDatabase manages the sApp schema for a strand using Quereus with the
|
|
60
|
+
* Optimystic backend. Each strand instance has its own isolated database with
|
|
61
|
+
* the sApp's schema applied.
|
|
62
|
+
*
|
|
63
|
+
* This class owns the `Database` lifecycle (creation, `getDatabase()`, `close()`)
|
|
64
|
+
* but delegates the actual SQL-surface composition — plugin registration, node
|
|
65
|
+
* wiring, catalog hydration, schema apply — to `connectToStrand` from
|
|
66
|
+
* `@serfab/quereus-plugin-sereus`, the single shared composition. The libp2p
|
|
67
|
+
* node is injected here, so `connectToStrand` never *creates* the node;
|
|
68
|
+
* `StrandInstanceManager` owns the node lifecycle. (The strand connection's
|
|
69
|
+
* `shutdown` still stops the injected node via the collection factory, so the
|
|
70
|
+
* manager's own `node.stop()` is an idempotent second stop — see `close()`.)
|
|
58
71
|
*/
|
|
59
72
|
export class StrandDatabase {
|
|
60
73
|
private db: Database | null = null;
|
|
61
|
-
private
|
|
74
|
+
private shutdownStrand: SereusPluginResult['shutdown'] | null = null;
|
|
62
75
|
private readonly config: StrandDatabaseConfig;
|
|
63
76
|
private initialized = false;
|
|
64
77
|
|
|
@@ -67,7 +80,9 @@ export class StrandDatabase {
|
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
/**
|
|
70
|
-
* Initialize the database
|
|
83
|
+
* Initialize the database — create the `Database` and delegate the strand
|
|
84
|
+
* SQL-surface composition (plugins, node wiring, hydrate, schema apply) to
|
|
85
|
+
* `connectToStrand` with the injected libp2p node.
|
|
71
86
|
*/
|
|
72
87
|
async initialize(): Promise<void> {
|
|
73
88
|
if (this.initialized) {
|
|
@@ -75,113 +90,83 @@ export class StrandDatabase {
|
|
|
75
90
|
return;
|
|
76
91
|
}
|
|
77
92
|
|
|
78
|
-
log('Initializing StrandDatabase for strand: %s (sApp: %s v%s)',
|
|
79
|
-
this.config.strandId,
|
|
80
|
-
this.config.sAppConfig.id,
|
|
81
|
-
this.config.sAppConfig.version
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
// Create database instance
|
|
85
|
-
this.db = new Database();
|
|
86
93
|
const sid = this.config.strandId;
|
|
87
|
-
|
|
88
|
-
// Register crypto plugin (provides digest, sign, verify functions)
|
|
89
|
-
let t0 = performance.now();
|
|
90
|
-
await registerPlugin(this.db, cryptoPlugin);
|
|
91
|
-
timing('[strandDb:%s] cryptoPlugin: %dms', sid, Math.round(performance.now() - t0));
|
|
92
|
-
log('Registered crypto plugin');
|
|
93
|
-
|
|
94
|
-
// Register optimystic plugin. In `bootstrap` mode we route through the
|
|
95
|
-
// local transactor so a solo node can initialize (schema apply etc.)
|
|
96
|
-
// without network round trips. In `networked` mode the network transactor
|
|
97
|
-
// is used. Mode is fixed for the lifetime of this Database instance; the
|
|
98
|
-
// caller must restart the strand to transition modes.
|
|
99
|
-
t0 = performance.now();
|
|
100
|
-
const networkName = `strand-${sid}`;
|
|
101
94
|
const mode: StrandMode = this.config.mode ?? 'networked';
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// the strand's raw storage (same instance the libp2p node uses) so writes
|
|
105
|
-
// persist to the host backend instead of in-memory storage.
|
|
106
|
-
const rawStorage = this.config.rawStorage;
|
|
107
|
-
const pluginConfig: Record<string, unknown> = {
|
|
108
|
-
default_transactor: defaultTransactor,
|
|
109
|
-
default_key_network: 'libp2p',
|
|
110
|
-
default_network_name: networkName,
|
|
111
|
-
enable_cache: true,
|
|
112
|
-
};
|
|
113
|
-
if (mode === 'bootstrap' && rawStorage) {
|
|
114
|
-
pluginConfig.rawStorageFactory = () => rawStorage;
|
|
115
|
-
}
|
|
116
|
-
// The plugin's published signature is `Record<string, SqlValue>` but it
|
|
117
|
-
// also reads `rawStorageFactory` (a function reference) from the same map.
|
|
118
|
-
// Cast through unknown rather than widen the public type.
|
|
119
|
-
const pluginResult = optimysticPlugin(
|
|
120
|
-
this.db,
|
|
121
|
-
pluginConfig as unknown as Parameters<typeof optimysticPlugin>[1]
|
|
122
|
-
) as OptimysticPluginResult;
|
|
123
|
-
log('Optimystic plugin registered for strand %s (mode=%s, transactor=%s, persistentStorage=%s)',
|
|
124
|
-
sid, mode, defaultTransactor, mode === 'bootstrap' && !!rawStorage);
|
|
95
|
+
log('Initializing StrandDatabase for strand: %s (sApp: %s v%s, mode=%s)',
|
|
96
|
+
sid, this.config.sAppConfig.id, this.config.sAppConfig.version, mode);
|
|
125
97
|
|
|
126
|
-
|
|
127
|
-
for (const vtable of pluginResult.vtables as Array<{ name: string; module: unknown; auxData: unknown }>) {
|
|
128
|
-
this.db.registerModule(vtable.name, vtable.module as any, vtable.auxData);
|
|
129
|
-
}
|
|
130
|
-
for (const func of pluginResult.functions as Array<{ schema: unknown }>) {
|
|
131
|
-
this.db.registerFunction(func.schema as any);
|
|
132
|
-
}
|
|
133
|
-
timing('[strandDb:%s] optimysticPlugin: %dms', sid, Math.round(performance.now() - t0));
|
|
134
|
-
|
|
135
|
-
this.collectionFactory = pluginResult.collectionFactory;
|
|
136
|
-
|
|
137
|
-
// Inject the libp2p node into the collection factory
|
|
138
|
-
t0 = performance.now();
|
|
139
|
-
this.collectionFactory.registerLibp2pNode(
|
|
140
|
-
networkName,
|
|
141
|
-
this.config.libp2pNode,
|
|
142
|
-
this.config.coordinatedRepo
|
|
143
|
-
);
|
|
144
|
-
timing('[strandDb:%s] registerLibp2pNode: %dms', sid, Math.round(performance.now() - t0));
|
|
145
|
-
log('Registered libp2p node with collection factory');
|
|
98
|
+
this.db = new Database();
|
|
146
99
|
|
|
147
|
-
//
|
|
148
|
-
// `
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
100
|
+
// Delegate to the shared composition. The node is injected, so:
|
|
101
|
+
// - `connectToStrand` never creates a node (its `createdNode` stays null);
|
|
102
|
+
// `StrandInstanceManager` owns the node lifecycle. Its `shutdown` does
|
|
103
|
+
// still stop the injected node via the collection factory, so the
|
|
104
|
+
// manager's later `node.stop()` is an idempotent second stop;
|
|
105
|
+
// - `storage` (the strand's raw storage, same instance the node uses) is
|
|
106
|
+
// handed to the plugin's local transactor in bootstrap mode so DML lands
|
|
107
|
+
// on the host backend rather than in-memory.
|
|
108
|
+
const t0 = performance.now();
|
|
109
|
+
const result = await connectToStrand(this.db, {
|
|
110
|
+
strandId: sid,
|
|
111
|
+
schema: this.config.sAppConfig.schema,
|
|
112
|
+
mode,
|
|
113
|
+
storage: this.config.rawStorage,
|
|
114
|
+
libp2pNode: this.config.libp2pNode,
|
|
115
|
+
coordinatedRepo: this.config.coordinatedRepo,
|
|
116
|
+
enableCache: true,
|
|
156
117
|
});
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
118
|
+
this.shutdownStrand = result.shutdown;
|
|
119
|
+
timing('[strandDb:%s] connectToStrand: %dms (hydrated tables=%d, indexes=%d)',
|
|
120
|
+
sid, Math.round(performance.now() - t0),
|
|
121
|
+
result.hydrated?.tables ?? 0, result.hydrated?.indexes ?? 0);
|
|
122
|
+
|
|
123
|
+
// Founder-only: write the one-time membership bootstrap now that the schema is
|
|
124
|
+
// applied (connectToStrand has returned). A throw here propagates out of
|
|
125
|
+
// initialize() so buildStrandRuntime's rollback tears the half-built strand
|
|
126
|
+
// down rather than leaking a node. Joiners skip this — their rows arrive via sync.
|
|
127
|
+
if (this.config.founder === true) {
|
|
128
|
+
await this.bootstrapFounder();
|
|
129
|
+
}
|
|
164
130
|
|
|
165
131
|
this.initialized = true;
|
|
166
132
|
log('StrandDatabase for strand %s initialized successfully', sid);
|
|
167
133
|
}
|
|
168
134
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Run the founder membership bootstrap against the freshly-composed strand DB.
|
|
137
|
+
*
|
|
138
|
+
* Derives the founding keypair from the closed-strand `memberPrivateKey` (the
|
|
139
|
+
* `Member.Key`/`Authority.MemberKey` are its public key); a closed strand with no
|
|
140
|
+
* `memberPrivateKey` throws, because it could never seat a founding authority.
|
|
141
|
+
* Open strands derive no keypair (Header only). Idempotent — see
|
|
142
|
+
* {@link bootstrapFounderMembership}.
|
|
143
|
+
*/
|
|
144
|
+
private async bootstrapFounder(): Promise<void> {
|
|
145
|
+
const { strandId, strandType, memberPrivateKey, sAppConfig } = this.config;
|
|
146
|
+
const founderKeyPair = strandType === 'c'
|
|
147
|
+
? this.deriveFounderKeyPair(strandId, memberPrivateKey)
|
|
148
|
+
: undefined;
|
|
149
|
+
await bootstrapFounderMembership(this.db!, {
|
|
150
|
+
strandId,
|
|
151
|
+
type: strandType,
|
|
152
|
+
sApp: sAppConfig,
|
|
153
|
+
founderKeyPair,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
182
156
|
|
|
183
|
-
|
|
184
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Derive the founding keypair for a closed strand from its `memberPrivateKey`,
|
|
159
|
+
* failing loudly when the key is absent (a closed strand with no founding
|
|
160
|
+
* Authority can never admit anyone).
|
|
161
|
+
*/
|
|
162
|
+
private deriveFounderKeyPair(strandId: string, memberPrivateKey: string | undefined) {
|
|
163
|
+
if (!memberPrivateKey) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Cannot found closed strand ${strandId}: the strand row has no MemberPrivateKey. ` +
|
|
166
|
+
'A closed strand needs a founding Member/Authority derived from that key.',
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return strandMemberKeyPair(memberPrivateKey);
|
|
185
170
|
}
|
|
186
171
|
|
|
187
172
|
/**
|
|
@@ -193,15 +178,18 @@ export class StrandDatabase {
|
|
|
193
178
|
}
|
|
194
179
|
|
|
195
180
|
/**
|
|
196
|
-
* Close the database and cleanup resources
|
|
181
|
+
* Close the database and cleanup resources. Runs the strand-connection
|
|
182
|
+
* shutdown (collection-factory teardown, which also stops the injected node),
|
|
183
|
+
* then closes the `Database`. `StrandInstanceManager.releaseRuntime` issues a
|
|
184
|
+
* further idempotent `node.stop()` after this returns.
|
|
197
185
|
*/
|
|
198
186
|
async close(): Promise<void> {
|
|
199
|
-
if (this.
|
|
200
|
-
await this.
|
|
201
|
-
this.
|
|
187
|
+
if (this.shutdownStrand) {
|
|
188
|
+
await this.shutdownStrand();
|
|
189
|
+
this.shutdownStrand = null;
|
|
202
190
|
}
|
|
203
191
|
if (this.db) {
|
|
204
|
-
this.db.close();
|
|
192
|
+
void this.db.close();
|
|
205
193
|
this.db = null;
|
|
206
194
|
}
|
|
207
195
|
this.initialized = false;
|
|
@@ -214,4 +202,3 @@ export class StrandDatabase {
|
|
|
214
202
|
}
|
|
215
203
|
}
|
|
216
204
|
}
|
|
217
|
-
|