@serfab/cadre-core 0.0.2

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.
Files changed (54) hide show
  1. package/README.md +252 -0
  2. package/dist/arachnode-stub.d.ts +60 -0
  3. package/dist/arachnode-stub.js +120 -0
  4. package/dist/arachnode-stub.js.map +1 -0
  5. package/dist/cadre-node.d.ts +252 -0
  6. package/dist/cadre-node.js +753 -0
  7. package/dist/cadre-node.js.map +1 -0
  8. package/dist/control-database.d.ts +62 -0
  9. package/dist/control-database.js +295 -0
  10. package/dist/control-database.js.map +1 -0
  11. package/dist/enrollment.d.ts +76 -0
  12. package/dist/enrollment.js +126 -0
  13. package/dist/enrollment.js.map +1 -0
  14. package/dist/hibernation-manager.d.ts +68 -0
  15. package/dist/hibernation-manager.js +212 -0
  16. package/dist/hibernation-manager.js.map +1 -0
  17. package/dist/index.d.ts +12 -0
  18. package/dist/index.js +24 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/seed-bootstrap.d.ts +164 -0
  21. package/dist/seed-bootstrap.js +554 -0
  22. package/dist/seed-bootstrap.js.map +1 -0
  23. package/dist/strand-database.d.ts +39 -0
  24. package/dist/strand-database.js +108 -0
  25. package/dist/strand-database.js.map +1 -0
  26. package/dist/strand-formation-manager.d.ts +87 -0
  27. package/dist/strand-formation-manager.js +168 -0
  28. package/dist/strand-formation-manager.js.map +1 -0
  29. package/dist/strand-instance-manager.d.ts +60 -0
  30. package/dist/strand-instance-manager.js +209 -0
  31. package/dist/strand-instance-manager.js.map +1 -0
  32. package/dist/strand-solicitation.d.ts +145 -0
  33. package/dist/strand-solicitation.js +180 -0
  34. package/dist/strand-solicitation.js.map +1 -0
  35. package/dist/strand-watcher.d.ts +70 -0
  36. package/dist/strand-watcher.js +136 -0
  37. package/dist/strand-watcher.js.map +1 -0
  38. package/dist/types.d.ts +484 -0
  39. package/dist/types.js +26 -0
  40. package/dist/types.js.map +1 -0
  41. package/package.json +67 -0
  42. package/src/arachnode-stub.ts +160 -0
  43. package/src/cadre-node.ts +923 -0
  44. package/src/control-database.ts +376 -0
  45. package/src/enrollment.ts +199 -0
  46. package/src/hibernation-manager.ts +268 -0
  47. package/src/index.ts +71 -0
  48. package/src/seed-bootstrap.ts +753 -0
  49. package/src/strand-database.ts +168 -0
  50. package/src/strand-formation-manager.ts +277 -0
  51. package/src/strand-instance-manager.ts +281 -0
  52. package/src/strand-solicitation.ts +318 -0
  53. package/src/strand-watcher.ts +197 -0
  54. package/src/types.ts +553 -0
@@ -0,0 +1,108 @@
1
+ import debug from 'debug';
2
+ import { Database, registerPlugin } from '@quereus/quereus';
3
+ import cryptoPlugin from '@optimystic/quereus-plugin-crypto/plugin';
4
+ import optimysticPlugin from '@optimystic/quereus-plugin-optimystic/plugin';
5
+ const log = debug('sereus:cadre:strand-db');
6
+ /**
7
+ * StrandDatabase manages the sApp schema for a strand using Quereus with Optimystic backend.
8
+ * Each strand instance has its own isolated database with the sApp's schema applied.
9
+ */
10
+ export class StrandDatabase {
11
+ constructor(config) {
12
+ this.db = null;
13
+ this.collectionFactory = null;
14
+ this.initialized = false;
15
+ this.config = config;
16
+ }
17
+ /**
18
+ * Initialize the database - register plugins and execute sApp schema
19
+ */
20
+ async initialize() {
21
+ if (this.initialized) {
22
+ log('StrandDatabase for strand %s already initialized', this.config.strandId);
23
+ return;
24
+ }
25
+ log('Initializing StrandDatabase for strand: %s (sApp: %s v%s)', this.config.strandId, this.config.sAppConfig.id, this.config.sAppConfig.version);
26
+ // Create database instance
27
+ this.db = new Database();
28
+ // Register crypto plugin (provides digest, sign, verify functions)
29
+ await registerPlugin(this.db, cryptoPlugin);
30
+ log('Registered crypto plugin');
31
+ // Register optimystic plugin with network transactor as default
32
+ const networkName = `strand-${this.config.strandId}`;
33
+ const pluginResult = optimysticPlugin(this.db, {
34
+ default_transactor: 'network',
35
+ default_key_network: 'libp2p',
36
+ default_network_name: networkName,
37
+ enable_cache: true,
38
+ });
39
+ // Register vtables and functions manually since we need access to collectionFactory
40
+ for (const vtable of pluginResult.vtables) {
41
+ this.db.registerModule(vtable.name, vtable.module, vtable.auxData);
42
+ }
43
+ for (const func of pluginResult.functions) {
44
+ this.db.registerFunction(func.schema);
45
+ }
46
+ this.collectionFactory = pluginResult.collectionFactory;
47
+ // Inject the libp2p node into the collection factory
48
+ this.collectionFactory.registerLibp2pNode(networkName, this.config.libp2pNode, this.config.coordinatedRepo);
49
+ log('Registered libp2p node with collection factory');
50
+ // Set optimystic as the default virtual table module so that
51
+ // `declare schema` tables (which omit USING) are backed by optimystic
52
+ // instead of the built-in memory module.
53
+ this.db.setDefaultVtabName('optimystic');
54
+ this.db.setDefaultVtabArgs({
55
+ networkName,
56
+ transactor: 'network',
57
+ keyNetwork: 'libp2p',
58
+ });
59
+ log('Set default vtab to optimystic (networkName=%s)', networkName);
60
+ // Execute the sApp schema DDL
61
+ await this.executeSchema();
62
+ this.initialized = true;
63
+ log('StrandDatabase for strand %s initialized successfully', this.config.strandId);
64
+ }
65
+ async executeSchema() {
66
+ const rawSchema = this.config.sAppConfig.schema;
67
+ log('Applying sApp schema for strand %s', this.config.strandId);
68
+ // Wrap the raw schema DDL in a declarative schema block and apply it.
69
+ // This ensures proper schema management with diff/apply semantics.
70
+ // The schema is applied to a named schema 'App' to keep it isolated.
71
+ const wrappedSchema = `
72
+ declare schema App {
73
+ ${rawSchema}
74
+ }
75
+ apply schema App;
76
+ `;
77
+ await this.db.exec(wrappedSchema);
78
+ log('sApp schema applied to strand %s', this.config.strandId);
79
+ }
80
+ /**
81
+ * Get the underlying database for queries
82
+ */
83
+ getDatabase() {
84
+ this.ensureInitialized();
85
+ return this.db;
86
+ }
87
+ /**
88
+ * Close the database and cleanup resources
89
+ */
90
+ async close() {
91
+ if (this.collectionFactory) {
92
+ await this.collectionFactory.shutdown();
93
+ this.collectionFactory = null;
94
+ }
95
+ if (this.db) {
96
+ this.db.close();
97
+ this.db = null;
98
+ }
99
+ this.initialized = false;
100
+ log('StrandDatabase for strand %s closed', this.config.strandId);
101
+ }
102
+ ensureInitialized() {
103
+ if (!this.initialized || !this.db) {
104
+ throw new Error(`StrandDatabase for strand ${this.config.strandId} not initialized. Call initialize() first.`);
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=strand-database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strand-database.js","sourceRoot":"","sources":["../src/strand-database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import type { Libp2p } from '@libp2p/interface';
2
+ import type { OpenInvitation, FormStrandResult, StrandFormationDisclosure } from './types.js';
3
+ import type { DisclosureValidator, FormationUsageRecorder, StrandProvisioner } from './strand-solicitation.js';
4
+ /**
5
+ * Configuration for StrandFormationManager
6
+ */
7
+ export interface StrandFormationManagerConfig {
8
+ /** Session timeout in milliseconds */
9
+ sessionTimeoutMs?: number;
10
+ /** Step timeout in milliseconds */
11
+ stepTimeoutMs?: number;
12
+ /** Maximum concurrent sessions */
13
+ maxConcurrentSessions?: number;
14
+ /** Enable debug logging */
15
+ enableDebugLogging?: boolean;
16
+ /** Protocol ID override */
17
+ protocolId?: string;
18
+ }
19
+ /**
20
+ * Options for creating a StrandFormationManager
21
+ */
22
+ export interface StrandFormationManagerOptions {
23
+ /** Validates disclosures from initiators */
24
+ disclosureValidator?: DisclosureValidator;
25
+ /** Records and validates token usage */
26
+ formationUsageRecorder?: FormationUsageRecorder;
27
+ /** Provisions strands after validation */
28
+ strandProvisioner?: StrandProvisioner;
29
+ /** This party's ID for identification */
30
+ partyId: string;
31
+ /** This party's cadre peer addresses */
32
+ cadrePeerAddrs?: string[];
33
+ /** Configuration options */
34
+ config?: StrandFormationManagerConfig;
35
+ }
36
+ /**
37
+ * StrandFormationManager bridges cadre-core's strand solicitation interfaces
38
+ * with strand-proto's SessionManager for actual protocol handling over libp2p.
39
+ *
40
+ * It implements SessionHooks by delegating to the existing interfaces:
41
+ * - DisclosureValidator -> validateIdentity
42
+ * - FormationUsageRecorder -> validateToken
43
+ * - StrandProvisioner -> provisionStrand
44
+ */
45
+ export declare class StrandFormationManager {
46
+ private readonly sessionManager;
47
+ private readonly disclosureValidator?;
48
+ private readonly formationUsageRecorder?;
49
+ private readonly strandProvisioner?;
50
+ private readonly partyId;
51
+ private readonly cadrePeerAddrs;
52
+ private registeredNodes;
53
+ constructor(options: StrandFormationManagerOptions);
54
+ /**
55
+ * Register this manager as a protocol handler on a libp2p node.
56
+ * Call this on the control network node to handle incoming formation requests.
57
+ */
58
+ registerResponder(node: Libp2p, protocolId?: string): void;
59
+ /**
60
+ * Unregister the protocol handler from a libp2p node.
61
+ */
62
+ unregisterResponder(node: Libp2p, protocolId?: string): void;
63
+ /**
64
+ * Form a strand with a responder via an open invitation.
65
+ *
66
+ * This is the initiator-side operation. It:
67
+ * 1. Converts the OpenInvitation to a BootstrapLink
68
+ * 2. Calls SessionManager.initiateBootstrap()
69
+ * 3. Returns the result as a FormStrandResult
70
+ */
71
+ formStrand(invitation: OpenInvitation, disclosure: StrandFormationDisclosure, node: Libp2p): Promise<FormStrandResult>;
72
+ /**
73
+ * Get the number of active sessions
74
+ */
75
+ getActiveSessionCounts(): {
76
+ listeners: number;
77
+ dialers: number;
78
+ };
79
+ /**
80
+ * Create SessionHooks that delegate to our interfaces
81
+ */
82
+ private createSessionHooks;
83
+ }
84
+ /**
85
+ * Create a StrandFormationManager with the given options
86
+ */
87
+ export declare function createStrandFormationManager(options: StrandFormationManagerOptions): StrandFormationManager;
@@ -0,0 +1,168 @@
1
+ import debug from 'debug';
2
+ import { createBootstrapManager, DEFAULT_PROTOCOL_ID } from '@serfab/strand-proto';
3
+ const log = debug('sereus:cadre:formation-manager');
4
+ /**
5
+ * StrandFormationManager bridges cadre-core's strand solicitation interfaces
6
+ * with strand-proto's SessionManager for actual protocol handling over libp2p.
7
+ *
8
+ * It implements SessionHooks by delegating to the existing interfaces:
9
+ * - DisclosureValidator -> validateIdentity
10
+ * - FormationUsageRecorder -> validateToken
11
+ * - StrandProvisioner -> provisionStrand
12
+ */
13
+ export class StrandFormationManager {
14
+ constructor(options) {
15
+ this.registeredNodes = new Set();
16
+ this.disclosureValidator = options.disclosureValidator;
17
+ this.formationUsageRecorder = options.formationUsageRecorder;
18
+ this.strandProvisioner = options.strandProvisioner;
19
+ this.partyId = options.partyId;
20
+ this.cadrePeerAddrs = options.cadrePeerAddrs ?? [];
21
+ // Create SessionHooks that delegate to our interfaces
22
+ const hooks = this.createSessionHooks();
23
+ // Create the underlying SessionManager
24
+ const config = {
25
+ sessionTimeoutMs: options.config?.sessionTimeoutMs ?? 30000,
26
+ stepTimeoutMs: options.config?.stepTimeoutMs ?? 5000,
27
+ maxConcurrentSessions: options.config?.maxConcurrentSessions ?? 100,
28
+ enableDebugLogging: options.config?.enableDebugLogging ?? false,
29
+ protocolId: options.config?.protocolId ?? DEFAULT_PROTOCOL_ID
30
+ };
31
+ this.sessionManager = createBootstrapManager(hooks, config);
32
+ log('StrandFormationManager created for party: %s', this.partyId);
33
+ }
34
+ /**
35
+ * Register this manager as a protocol handler on a libp2p node.
36
+ * Call this on the control network node to handle incoming formation requests.
37
+ */
38
+ registerResponder(node, protocolId) {
39
+ if (this.registeredNodes.has(node)) {
40
+ log('Node already registered');
41
+ return;
42
+ }
43
+ this.sessionManager.register(node, protocolId);
44
+ this.registeredNodes.add(node);
45
+ log('Registered as responder on node');
46
+ }
47
+ /**
48
+ * Unregister the protocol handler from a libp2p node.
49
+ */
50
+ unregisterResponder(node, protocolId) {
51
+ if (!this.registeredNodes.has(node)) {
52
+ return;
53
+ }
54
+ this.sessionManager.unregister(node, protocolId);
55
+ this.registeredNodes.delete(node);
56
+ log('Unregistered from node');
57
+ }
58
+ /**
59
+ * Form a strand with a responder via an open invitation.
60
+ *
61
+ * This is the initiator-side operation. It:
62
+ * 1. Converts the OpenInvitation to a BootstrapLink
63
+ * 2. Calls SessionManager.initiateBootstrap()
64
+ * 3. Returns the result as a FormStrandResult
65
+ */
66
+ async formStrand(invitation, disclosure, node) {
67
+ log('Forming strand with invitation token: %s', invitation.token);
68
+ // Convert OpenInvitation to BootstrapLink
69
+ const link = {
70
+ responderPeerAddrs: invitation.bootstrap,
71
+ token: invitation.token,
72
+ tokenExpiryUtc: invitation.expiration.toISOString(),
73
+ mode: 'responderCreates' // Responder provisions the strand
74
+ };
75
+ // The disclosure is passed via the identityBundle in the contact message
76
+ // We store it temporarily so the hooks can access it
77
+ // Note: strand-proto's DialerSession constructs the contact message internally
78
+ // We need to extend this to pass the disclosure - for now we use partyId
79
+ const result = await this.sessionManager.initiateBootstrap(link, node);
80
+ log('Strand formed: %s', result.strand.strandId);
81
+ return {
82
+ memberKey: this.partyId, // The initiator's member key
83
+ invitePrivateKey: '', // Would come from key generation
84
+ strandId: result.strand.strandId
85
+ };
86
+ }
87
+ /**
88
+ * Get the number of active sessions
89
+ */
90
+ getActiveSessionCounts() {
91
+ return this.sessionManager.getActiveSessionCounts();
92
+ }
93
+ /**
94
+ * Create SessionHooks that delegate to our interfaces
95
+ */
96
+ createSessionHooks() {
97
+ return {
98
+ validateToken: async (token, sessionId) => {
99
+ log('validateToken: %s (session: %s)', token, sessionId);
100
+ if (!this.formationUsageRecorder) {
101
+ // No recorder configured - accept all tokens
102
+ return { mode: 'responderCreates', valid: true };
103
+ }
104
+ const tokenCheck = await this.formationUsageRecorder.isTokenValid(token);
105
+ if (!tokenCheck.valid) {
106
+ log('Token invalid: %s', token);
107
+ return { mode: 'responderCreates', valid: false };
108
+ }
109
+ const isUsed = await this.formationUsageRecorder.isTokenUsed(token);
110
+ if (isUsed) {
111
+ log('Token already used: %s', token);
112
+ return { mode: 'responderCreates', valid: false };
113
+ }
114
+ return { mode: 'responderCreates', valid: true };
115
+ },
116
+ validateIdentity: async (identity, sessionId) => {
117
+ log('validateIdentity (session: %s)', sessionId);
118
+ if (!this.disclosureValidator) {
119
+ // No validator configured - accept all identities
120
+ return true;
121
+ }
122
+ // Extract disclosure from identity bundle
123
+ const disclosure = identity;
124
+ // We need the token here - it's passed via the contact message
125
+ // For now, use a placeholder - this will be refined
126
+ const token = identity?.token ?? '';
127
+ return this.disclosureValidator.validateDisclosure(token, disclosure);
128
+ },
129
+ provisionStrand: async (creator, creatorPartyId, otherPartyId, sessionId) => {
130
+ log('provisionStrand: creator=%s, other=%s (session: %s)', creatorPartyId, otherPartyId, sessionId);
131
+ if (!this.strandProvisioner) {
132
+ // No provisioner - return a placeholder
133
+ const strandId = `strand-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
134
+ return {
135
+ strand: { strandId, createdBy: creator },
136
+ dbConnectionInfo: { endpoint: 'local', credentialsRef: '' }
137
+ };
138
+ }
139
+ // Determine initiator/responder keys based on creator
140
+ const initiatorKey = creator === 'initiator' ? creatorPartyId : otherPartyId;
141
+ const responderKey = creator === 'responder' ? creatorPartyId : otherPartyId;
142
+ const result = await this.strandProvisioner.provisionStrand('', // sAppId - would come from invitation
143
+ initiatorKey, responderKey);
144
+ return {
145
+ strand: { strandId: result.strandId, createdBy: creator },
146
+ dbConnectionInfo: { endpoint: 'local', credentialsRef: '' }
147
+ };
148
+ },
149
+ validateResponse: async (response, sessionId) => {
150
+ log('validateResponse (session: %s)', sessionId);
151
+ // Accept all responses for now
152
+ return true;
153
+ },
154
+ validateDatabaseResult: async (result, sessionId) => {
155
+ log('validateDatabaseResult (session: %s)', sessionId);
156
+ // Accept all database results for now
157
+ return true;
158
+ }
159
+ };
160
+ }
161
+ }
162
+ /**
163
+ * Create a StrandFormationManager with the given options
164
+ */
165
+ export function createStrandFormationManager(options) {
166
+ return new StrandFormationManager(options);
167
+ }
168
+ //# sourceMappingURL=strand-formation-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strand-formation-manager.js","sourceRoot":"","sources":["../src/strand-formation-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { StrandInstance, StrandRow, StorageConfig, NetworkConfig, LatencyHint, NodeProfile, SAppConfig } from './types.js';
2
+ /**
3
+ * Configuration for starting a strand instance
4
+ */
5
+ export interface StartStrandConfig {
6
+ strandRow: StrandRow;
7
+ /** sApp configuration provided by the hosting application */
8
+ sAppConfig: SAppConfig;
9
+ storage?: StorageConfig;
10
+ network?: NetworkConfig;
11
+ profile: NodeProfile;
12
+ defaultLatencyHint: LatencyHint;
13
+ }
14
+ /**
15
+ * Get the isolated storage path for a specific strand.
16
+ *
17
+ * @deprecated This function uses Node.js path module which is not available in React Native.
18
+ * Use a storage provider factory function instead, which receives the strandId and can
19
+ * create strand-specific storage paths using platform-appropriate methods.
20
+ *
21
+ * @example
22
+ * // Instead of using getStrandStoragePath, use a storage provider factory:
23
+ * const storage = {
24
+ * provider: (strandId: string) => new FileRawStorage(`./data/strands/${strandId}`)
25
+ * };
26
+ */
27
+ export declare function getStrandStoragePath(basePath: string, strandId: string): string;
28
+ /**
29
+ * Manages individual strand instances - creates and destroys isolated libp2p nodes
30
+ * for each strand the cadre participates in.
31
+ */
32
+ export declare class StrandInstanceManager {
33
+ private instances;
34
+ private stopping;
35
+ constructor();
36
+ /**
37
+ * Get all current strand instances
38
+ */
39
+ getInstances(): Map<string, StrandInstance>;
40
+ /**
41
+ * Get a specific strand instance
42
+ */
43
+ getInstance(strandId: string): StrandInstance | undefined;
44
+ /**
45
+ * Check if a strand is currently running
46
+ */
47
+ hasStrand(strandId: string): boolean;
48
+ /**
49
+ * Start a new strand instance
50
+ */
51
+ startStrand(config: StartStrandConfig): Promise<StrandInstance>;
52
+ /**
53
+ * Stop a strand instance
54
+ */
55
+ stopStrand(strandId: string): Promise<void>;
56
+ /**
57
+ * Stop all strand instances
58
+ */
59
+ stopAll(): Promise<void>;
60
+ }
@@ -0,0 +1,209 @@
1
+ import debug from 'debug';
2
+ import { createLibp2pNode } from '@optimystic/db-p2p';
3
+ import { StrandDatabase } from './strand-database.js';
4
+ const log = debug('sereus:cadre:strand-manager');
5
+ /**
6
+ * Get the isolated storage path for a specific strand.
7
+ *
8
+ * @deprecated This function uses Node.js path module which is not available in React Native.
9
+ * Use a storage provider factory function instead, which receives the strandId and can
10
+ * create strand-specific storage paths using platform-appropriate methods.
11
+ *
12
+ * @example
13
+ * // Instead of using getStrandStoragePath, use a storage provider factory:
14
+ * const storage = {
15
+ * provider: (strandId: string) => new FileRawStorage(`./data/strands/${strandId}`)
16
+ * };
17
+ */
18
+ export function getStrandStoragePath(basePath, strandId) {
19
+ // Check if we're in a Node.js environment
20
+ if (typeof process === 'undefined' || !process.versions?.node) {
21
+ throw new Error('getStrandStoragePath is not available in React Native. ' +
22
+ 'Use a storage provider factory function instead.');
23
+ }
24
+ // Dynamically require path only in Node.js
25
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
26
+ const path = require('path');
27
+ // Sanitize strandId for filesystem safety (UUIDs should be safe, but just in case)
28
+ const safeId = strandId.replace(/[^a-zA-Z0-9-]/g, '_');
29
+ return path.join(basePath, 'strands', safeId);
30
+ }
31
+ /**
32
+ * Resolve a storage provider for a specific strand.
33
+ * If the provider is a factory function, call it with the strandId.
34
+ *
35
+ * @param provider - Storage provider (instance or factory)
36
+ * @param strandId - The strand ID to create storage for
37
+ * @returns The resolved IRawStorage instance, or undefined if no provider
38
+ */
39
+ function resolveStrandStorage(provider, strandId) {
40
+ if (!provider) {
41
+ return undefined;
42
+ }
43
+ return typeof provider === 'function' ? provider(strandId) : provider;
44
+ }
45
+ /**
46
+ * Manages individual strand instances - creates and destroys isolated libp2p nodes
47
+ * for each strand the cadre participates in.
48
+ */
49
+ export class StrandInstanceManager {
50
+ constructor() {
51
+ this.instances = new Map();
52
+ this.stopping = false;
53
+ log('StrandInstanceManager created');
54
+ }
55
+ /**
56
+ * Get all current strand instances
57
+ */
58
+ getInstances() {
59
+ return new Map(this.instances);
60
+ }
61
+ /**
62
+ * Get a specific strand instance
63
+ */
64
+ getInstance(strandId) {
65
+ return this.instances.get(strandId);
66
+ }
67
+ /**
68
+ * Check if a strand is currently running
69
+ */
70
+ hasStrand(strandId) {
71
+ return this.instances.has(strandId);
72
+ }
73
+ /**
74
+ * Start a new strand instance
75
+ */
76
+ async startStrand(config) {
77
+ const { strandRow, sAppConfig } = config;
78
+ const strandId = strandRow.Id;
79
+ if (this.stopping) {
80
+ throw new Error('StrandInstanceManager is stopping');
81
+ }
82
+ if (this.instances.has(strandId)) {
83
+ log('Strand %s already running', strandId);
84
+ return this.instances.get(strandId);
85
+ }
86
+ log('Starting strand instance: %s (sApp: %s v%s)', strandId, sAppConfig.id, sAppConfig.version);
87
+ // Convert SAppConfig to SAppInfo for the instance
88
+ const sAppInfo = {
89
+ id: sAppConfig.id,
90
+ version: sAppConfig.version,
91
+ schema: sAppConfig.schema,
92
+ signature: sAppConfig.signature
93
+ };
94
+ // Determine latency hint: sApp config > default
95
+ const latencyHint = sAppConfig.latencyHint ?? config.defaultLatencyHint;
96
+ const instance = {
97
+ strandId,
98
+ status: 'starting',
99
+ sAppInfo,
100
+ memberPrivateKey: strandRow.MemberPrivateKey ?? undefined,
101
+ connectedPeers: 0,
102
+ lastActivity: new Date(),
103
+ latencyHint
104
+ };
105
+ this.instances.set(strandId, instance);
106
+ try {
107
+ // Resolve storage for this strand
108
+ // If a factory function is provided, it will be called with the strandId
109
+ // to create strand-specific storage (e.g., strand-isolated directories)
110
+ const strandStorage = resolveStrandStorage(config.storage?.provider, strandId);
111
+ if (strandStorage) {
112
+ log('Strand %s using provided storage provider', strandId);
113
+ }
114
+ // Create isolated libp2p node for this strand
115
+ // Note: protocolPrefix would be used by libp2p services, but createLibp2pNode
116
+ // may not support it yet - tracked for future implementation
117
+ const _protocolPrefix = `/sereus/strand/${strandId}`;
118
+ // Determine relay mode: if explicitly set in config, use that;
119
+ // otherwise default to true for storage profile nodes
120
+ const enableRelay = config.network?.enableRelay ?? (config.profile === 'storage');
121
+ const node = await createLibp2pNode({
122
+ port: 0, // Random port
123
+ bootstrapNodes: [], // Will be populated from strand cohort
124
+ networkName: `strand-${strandId}`,
125
+ storage: strandStorage,
126
+ fretProfile: config.profile === 'storage' ? 'core' : 'edge',
127
+ relay: enableRelay,
128
+ clusterSize: 3,
129
+ clusterPolicy: {
130
+ allowDownsize: true,
131
+ sizeTolerance: 0.5
132
+ },
133
+ arachnode: {
134
+ enableRingZulu: true
135
+ // Storage ring participation stub - will be added when arachnode is built
136
+ // storageRing: config.profile === 'storage' ? { ring: 0 } : undefined
137
+ },
138
+ ...(config.network?.transports && { transports: config.network.transports }),
139
+ ...(config.network?.listenAddrs && { listenAddrs: config.network.listenAddrs })
140
+ });
141
+ instance.libp2pNode = node;
142
+ // Create and initialize the StrandDatabase
143
+ const strandDb = new StrandDatabase({
144
+ strandId,
145
+ sAppConfig,
146
+ libp2pNode: node,
147
+ coordinatedRepo: node.coordinatedRepo
148
+ });
149
+ await strandDb.initialize();
150
+ instance.database = strandDb;
151
+ instance.status = 'active';
152
+ instance.lastActivity = new Date();
153
+ log('Strand %s started successfully with sApp %s', strandId, sAppConfig.id);
154
+ return instance;
155
+ }
156
+ catch (error) {
157
+ instance.status = 'error';
158
+ instance.error = error instanceof Error ? error.message : String(error);
159
+ log('Failed to start strand %s: %s', strandId, instance.error);
160
+ throw error;
161
+ }
162
+ }
163
+ /**
164
+ * Stop a strand instance
165
+ */
166
+ async stopStrand(strandId) {
167
+ const instance = this.instances.get(strandId);
168
+ if (!instance) {
169
+ log('Strand %s not found', strandId);
170
+ return;
171
+ }
172
+ log('Stopping strand instance: %s', strandId);
173
+ instance.status = 'stopping';
174
+ try {
175
+ // Close the database before stopping libp2p
176
+ if (instance.database) {
177
+ await instance.database.close();
178
+ instance.database = undefined;
179
+ }
180
+ if (instance.libp2pNode) {
181
+ await instance.libp2pNode.stop();
182
+ instance.libp2pNode = undefined;
183
+ }
184
+ instance.status = 'stopped';
185
+ this.instances.delete(strandId);
186
+ log('Strand %s stopped successfully', strandId);
187
+ }
188
+ catch (error) {
189
+ instance.status = 'error';
190
+ instance.error = error instanceof Error ? error.message : String(error);
191
+ log('Error stopping strand %s: %s', strandId, instance.error);
192
+ throw error;
193
+ }
194
+ }
195
+ /**
196
+ * Stop all strand instances
197
+ */
198
+ async stopAll() {
199
+ this.stopping = true;
200
+ log('Stopping all strand instances (%d)', this.instances.size);
201
+ const stopPromises = Array.from(this.instances.keys()).map(id => this.stopStrand(id).catch(err => {
202
+ log('Error stopping strand %s during shutdown: %s', id, err);
203
+ }));
204
+ await Promise.all(stopPromises);
205
+ this.stopping = false;
206
+ log('All strand instances stopped');
207
+ }
208
+ }
209
+ //# sourceMappingURL=strand-instance-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strand-instance-manager.js","sourceRoot":"","sources":["../src/strand-instance-manager.ts"],"names":[],"mappings":"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"}