@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.
- package/README.md +252 -0
- package/dist/arachnode-stub.d.ts +60 -0
- package/dist/arachnode-stub.js +120 -0
- package/dist/arachnode-stub.js.map +1 -0
- package/dist/cadre-node.d.ts +252 -0
- package/dist/cadre-node.js +753 -0
- package/dist/cadre-node.js.map +1 -0
- package/dist/control-database.d.ts +62 -0
- package/dist/control-database.js +295 -0
- package/dist/control-database.js.map +1 -0
- package/dist/enrollment.d.ts +76 -0
- package/dist/enrollment.js +126 -0
- package/dist/enrollment.js.map +1 -0
- package/dist/hibernation-manager.d.ts +68 -0
- package/dist/hibernation-manager.js +212 -0
- package/dist/hibernation-manager.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +164 -0
- package/dist/seed-bootstrap.js +554 -0
- package/dist/seed-bootstrap.js.map +1 -0
- package/dist/strand-database.d.ts +39 -0
- package/dist/strand-database.js +108 -0
- package/dist/strand-database.js.map +1 -0
- package/dist/strand-formation-manager.d.ts +87 -0
- package/dist/strand-formation-manager.js +168 -0
- package/dist/strand-formation-manager.js.map +1 -0
- package/dist/strand-instance-manager.d.ts +60 -0
- package/dist/strand-instance-manager.js +209 -0
- package/dist/strand-instance-manager.js.map +1 -0
- package/dist/strand-solicitation.d.ts +145 -0
- package/dist/strand-solicitation.js +180 -0
- package/dist/strand-solicitation.js.map +1 -0
- package/dist/strand-watcher.d.ts +70 -0
- package/dist/strand-watcher.js +136 -0
- package/dist/strand-watcher.js.map +1 -0
- package/dist/types.d.ts +484 -0
- package/dist/types.js +26 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
- package/src/arachnode-stub.ts +160 -0
- package/src/cadre-node.ts +923 -0
- package/src/control-database.ts +376 -0
- package/src/enrollment.ts +199 -0
- package/src/hibernation-manager.ts +268 -0
- package/src/index.ts +71 -0
- package/src/seed-bootstrap.ts +753 -0
- package/src/strand-database.ts +168 -0
- package/src/strand-formation-manager.ts +277 -0
- package/src/strand-instance-manager.ts +281 -0
- package/src/strand-solicitation.ts +318 -0
- package/src/strand-watcher.ts +197 -0
- package/src/types.ts +553 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { StrandInstance, HibernationConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Callbacks for hibernation state changes
|
|
4
|
+
*/
|
|
5
|
+
export interface HibernationCallbacks {
|
|
6
|
+
onIdle: (strandId: string) => Promise<void>;
|
|
7
|
+
onHibernate: (strandId: string) => Promise<void>;
|
|
8
|
+
onWake: (strandId: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Manages strand hibernation state transitions based on activity.
|
|
12
|
+
*
|
|
13
|
+
* State machine:
|
|
14
|
+
* active → idle (after idleTimeout with no activity)
|
|
15
|
+
* idle → hibernating (after hibernateTimeout with no activity)
|
|
16
|
+
* idle → active (on activity)
|
|
17
|
+
* hibernating → active (on wake signal or check-in with pending activity)
|
|
18
|
+
*/
|
|
19
|
+
export declare class HibernationManager {
|
|
20
|
+
private readonly config;
|
|
21
|
+
private readonly callbacks;
|
|
22
|
+
private readonly timers;
|
|
23
|
+
private readonly checkInTimers;
|
|
24
|
+
private running;
|
|
25
|
+
constructor(config: HibernationConfig, callbacks: HibernationCallbacks);
|
|
26
|
+
/**
|
|
27
|
+
* Get effective timeouts for a latency hint
|
|
28
|
+
*/
|
|
29
|
+
private getTimeouts;
|
|
30
|
+
/**
|
|
31
|
+
* Start managing hibernation for all strands
|
|
32
|
+
*/
|
|
33
|
+
start(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Stop managing hibernation
|
|
36
|
+
*/
|
|
37
|
+
stop(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Register a strand for hibernation management
|
|
40
|
+
*/
|
|
41
|
+
trackStrand(instance: StrandInstance): void;
|
|
42
|
+
/**
|
|
43
|
+
* Untrack a strand from hibernation management
|
|
44
|
+
*/
|
|
45
|
+
untrackStrand(strandId: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Record activity on a strand - resets idle timer
|
|
48
|
+
*/
|
|
49
|
+
recordActivity(instance: StrandInstance): void;
|
|
50
|
+
/**
|
|
51
|
+
* Force wake a hibernating strand
|
|
52
|
+
*/
|
|
53
|
+
wakeStrand(strandId: string): Promise<void>;
|
|
54
|
+
private scheduleIdleTransition;
|
|
55
|
+
private handleIdleTimeout;
|
|
56
|
+
private scheduleHibernateTransition;
|
|
57
|
+
private handleHibernateTimeout;
|
|
58
|
+
private scheduleCheckIn;
|
|
59
|
+
private clearTimer;
|
|
60
|
+
private clearTimers;
|
|
61
|
+
/**
|
|
62
|
+
* Get the current status of hibernation tracking
|
|
63
|
+
*/
|
|
64
|
+
getStatus(): {
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
trackedStrands: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import { HIBERNATION_TIMEOUTS } from './types.js';
|
|
3
|
+
const log = debug('sereus:cadre:hibernation');
|
|
4
|
+
/**
|
|
5
|
+
* Manages strand hibernation state transitions based on activity.
|
|
6
|
+
*
|
|
7
|
+
* State machine:
|
|
8
|
+
* active → idle (after idleTimeout with no activity)
|
|
9
|
+
* idle → hibernating (after hibernateTimeout with no activity)
|
|
10
|
+
* idle → active (on activity)
|
|
11
|
+
* hibernating → active (on wake signal or check-in with pending activity)
|
|
12
|
+
*/
|
|
13
|
+
export class HibernationManager {
|
|
14
|
+
constructor(config, callbacks) {
|
|
15
|
+
this.timers = new Map();
|
|
16
|
+
this.checkInTimers = new Map();
|
|
17
|
+
this.running = false;
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.callbacks = callbacks;
|
|
20
|
+
log('HibernationManager created, enabled=%s', config.enabled);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get effective timeouts for a latency hint
|
|
24
|
+
*/
|
|
25
|
+
getTimeouts(hint) {
|
|
26
|
+
const defaults = HIBERNATION_TIMEOUTS[hint];
|
|
27
|
+
const custom = this.config.customTimeouts?.[hint];
|
|
28
|
+
if (!custom)
|
|
29
|
+
return defaults;
|
|
30
|
+
return {
|
|
31
|
+
idleTimeout: custom.idleTimeout ?? defaults.idleTimeout,
|
|
32
|
+
hibernateTimeout: custom.hibernateTimeout ?? defaults.hibernateTimeout,
|
|
33
|
+
checkInInterval: custom.checkInInterval ?? defaults.checkInInterval
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Start managing hibernation for all strands
|
|
38
|
+
*/
|
|
39
|
+
start() {
|
|
40
|
+
if (this.running)
|
|
41
|
+
return;
|
|
42
|
+
this.running = true;
|
|
43
|
+
log('HibernationManager started');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Stop managing hibernation
|
|
47
|
+
*/
|
|
48
|
+
stop() {
|
|
49
|
+
if (!this.running)
|
|
50
|
+
return;
|
|
51
|
+
this.running = false;
|
|
52
|
+
// Clear all timers
|
|
53
|
+
for (const timer of this.timers.values()) {
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
}
|
|
56
|
+
this.timers.clear();
|
|
57
|
+
for (const timer of this.checkInTimers.values()) {
|
|
58
|
+
clearInterval(timer);
|
|
59
|
+
}
|
|
60
|
+
this.checkInTimers.clear();
|
|
61
|
+
log('HibernationManager stopped');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Register a strand for hibernation management
|
|
65
|
+
*/
|
|
66
|
+
trackStrand(instance) {
|
|
67
|
+
if (!this.config.enabled || !this.running)
|
|
68
|
+
return;
|
|
69
|
+
const { strandId, latencyHint } = instance;
|
|
70
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
71
|
+
// Don't track strands that never hibernate
|
|
72
|
+
if (timeouts.idleTimeout === Infinity) {
|
|
73
|
+
log('Strand %s has realtime latency hint - no hibernation', strandId);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
log('Tracking strand %s for hibernation (hint=%s)', strandId, latencyHint);
|
|
77
|
+
this.scheduleIdleTransition(instance);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Untrack a strand from hibernation management
|
|
81
|
+
*/
|
|
82
|
+
untrackStrand(strandId) {
|
|
83
|
+
this.clearTimers(strandId);
|
|
84
|
+
log('Untracked strand %s from hibernation', strandId);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Record activity on a strand - resets idle timer
|
|
88
|
+
*/
|
|
89
|
+
recordActivity(instance) {
|
|
90
|
+
if (!this.config.enabled || !this.running)
|
|
91
|
+
return;
|
|
92
|
+
const { strandId, status, latencyHint } = instance;
|
|
93
|
+
instance.lastActivity = new Date();
|
|
94
|
+
// If idle or hibernating, wake up
|
|
95
|
+
if (status === 'idle' || status === 'hibernating') {
|
|
96
|
+
log('Activity on %s strand %s - waking', status, strandId);
|
|
97
|
+
this.clearTimers(strandId);
|
|
98
|
+
void this.callbacks.onWake(strandId);
|
|
99
|
+
}
|
|
100
|
+
// Reschedule idle transition if active
|
|
101
|
+
if (status === 'active') {
|
|
102
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
103
|
+
if (timeouts.idleTimeout !== Infinity) {
|
|
104
|
+
this.scheduleIdleTransition(instance);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Force wake a hibernating strand
|
|
110
|
+
*/
|
|
111
|
+
async wakeStrand(strandId) {
|
|
112
|
+
this.clearTimers(strandId);
|
|
113
|
+
await this.callbacks.onWake(strandId);
|
|
114
|
+
}
|
|
115
|
+
scheduleIdleTransition(instance) {
|
|
116
|
+
const { strandId, latencyHint } = instance;
|
|
117
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
118
|
+
// Clear existing timer
|
|
119
|
+
this.clearTimer(strandId);
|
|
120
|
+
// Schedule idle transition
|
|
121
|
+
const timer = setTimeout(() => {
|
|
122
|
+
this.handleIdleTimeout(instance);
|
|
123
|
+
}, timeouts.idleTimeout);
|
|
124
|
+
this.timers.set(strandId, timer);
|
|
125
|
+
}
|
|
126
|
+
handleIdleTimeout(instance) {
|
|
127
|
+
const { strandId, latencyHint } = instance;
|
|
128
|
+
if (!this.running)
|
|
129
|
+
return;
|
|
130
|
+
log('Idle timeout for strand %s', strandId);
|
|
131
|
+
// Transition to idle
|
|
132
|
+
void this.callbacks.onIdle(strandId).then(() => {
|
|
133
|
+
// Schedule hibernate transition
|
|
134
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
135
|
+
if (timeouts.hibernateTimeout !== Infinity) {
|
|
136
|
+
this.scheduleHibernateTransition(instance);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
scheduleHibernateTransition(instance) {
|
|
141
|
+
const { strandId, latencyHint } = instance;
|
|
142
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
143
|
+
// Clear existing timer
|
|
144
|
+
this.clearTimer(strandId);
|
|
145
|
+
// Schedule hibernate transition
|
|
146
|
+
const timer = setTimeout(() => {
|
|
147
|
+
this.handleHibernateTimeout(instance);
|
|
148
|
+
}, timeouts.hibernateTimeout);
|
|
149
|
+
this.timers.set(strandId, timer);
|
|
150
|
+
}
|
|
151
|
+
handleHibernateTimeout(instance) {
|
|
152
|
+
const { strandId, latencyHint } = instance;
|
|
153
|
+
if (!this.running)
|
|
154
|
+
return;
|
|
155
|
+
log('Hibernate timeout for strand %s', strandId);
|
|
156
|
+
// Transition to hibernating
|
|
157
|
+
void this.callbacks.onHibernate(strandId).then(() => {
|
|
158
|
+
// Schedule periodic check-ins
|
|
159
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
160
|
+
if (timeouts.checkInInterval !== Infinity) {
|
|
161
|
+
this.scheduleCheckIn(instance);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
scheduleCheckIn(instance) {
|
|
166
|
+
const { strandId, latencyHint } = instance;
|
|
167
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
168
|
+
// Clear existing check-in timer
|
|
169
|
+
const existing = this.checkInTimers.get(strandId);
|
|
170
|
+
if (existing) {
|
|
171
|
+
clearInterval(existing);
|
|
172
|
+
}
|
|
173
|
+
// Schedule periodic check-ins
|
|
174
|
+
const timer = setInterval(() => {
|
|
175
|
+
if (!this.running) {
|
|
176
|
+
clearInterval(timer);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
log('Check-in for hibernating strand %s', strandId);
|
|
180
|
+
instance.nextCheckIn = new Date(Date.now() + timeouts.checkInInterval);
|
|
181
|
+
// In a real implementation, this would query the cohort for pending activity
|
|
182
|
+
// For now, we just update the nextCheckIn timestamp
|
|
183
|
+
}, timeouts.checkInInterval);
|
|
184
|
+
this.checkInTimers.set(strandId, timer);
|
|
185
|
+
instance.nextCheckIn = new Date(Date.now() + timeouts.checkInInterval);
|
|
186
|
+
}
|
|
187
|
+
clearTimer(strandId) {
|
|
188
|
+
const timer = this.timers.get(strandId);
|
|
189
|
+
if (timer) {
|
|
190
|
+
clearTimeout(timer);
|
|
191
|
+
this.timers.delete(strandId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
clearTimers(strandId) {
|
|
195
|
+
this.clearTimer(strandId);
|
|
196
|
+
const checkInTimer = this.checkInTimers.get(strandId);
|
|
197
|
+
if (checkInTimer) {
|
|
198
|
+
clearInterval(checkInTimer);
|
|
199
|
+
this.checkInTimers.delete(strandId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get the current status of hibernation tracking
|
|
204
|
+
*/
|
|
205
|
+
getStatus() {
|
|
206
|
+
return {
|
|
207
|
+
enabled: this.config.enabled && this.running,
|
|
208
|
+
trackedStrands: this.timers.size + this.checkInTimers.size
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=hibernation-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hibernation-manager.js","sourceRoot":"","sources":["../src/hibernation-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { CadreNode } from './cadre-node.js';
|
|
3
|
+
export { ControlDatabase, type ControlDatabaseConfig } from './control-database.js';
|
|
4
|
+
export { StrandDatabase, type StrandDatabaseConfig } from './strand-database.js';
|
|
5
|
+
export { StrandWatcher, type StrandWatcherCallbacks, type StrandQueryable, type SAppIdLookup, type StrandRowWithApp } from './strand-watcher.js';
|
|
6
|
+
export { StrandInstanceManager, type StartStrandConfig, getStrandStoragePath } from './strand-instance-manager.js';
|
|
7
|
+
export { HibernationManager, type HibernationCallbacks } from './hibernation-manager.js';
|
|
8
|
+
export { ArachnodeStub, createArachnodeStub, type RingConfig } from './arachnode-stub.js';
|
|
9
|
+
export { EnrollmentService, type MemberVerifier, type MemberRegistry } from './enrollment.js';
|
|
10
|
+
export { StrandSolicitationService, type DisclosureValidator, type FormationUsageRecorder, type StrandProvisioner, type FormationSigner, type StrandSolicitationServiceOptions } from './strand-solicitation.js';
|
|
11
|
+
export { SeedBootstrapService, SEED_PROTOCOL, type SeedBootstrapConfig, type SeedEventCallbacks } from './seed-bootstrap.js';
|
|
12
|
+
export { StrandFormationManager, createStrandFormationManager, type StrandFormationManagerConfig, type StrandFormationManagerOptions } from './strand-formation-manager.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Core types
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
// Main CadreNode class
|
|
4
|
+
export { CadreNode } from './cadre-node.js';
|
|
5
|
+
// Control database
|
|
6
|
+
export { ControlDatabase } from './control-database.js';
|
|
7
|
+
// Strand database
|
|
8
|
+
export { StrandDatabase } from './strand-database.js';
|
|
9
|
+
// Strand management
|
|
10
|
+
export { StrandWatcher } from './strand-watcher.js';
|
|
11
|
+
export { StrandInstanceManager, getStrandStoragePath } from './strand-instance-manager.js';
|
|
12
|
+
// Hibernation
|
|
13
|
+
export { HibernationManager } from './hibernation-manager.js';
|
|
14
|
+
// Arachnode (stub)
|
|
15
|
+
export { ArachnodeStub, createArachnodeStub } from './arachnode-stub.js';
|
|
16
|
+
// Enrollment
|
|
17
|
+
export { EnrollmentService } from './enrollment.js';
|
|
18
|
+
// Strand Solicitation
|
|
19
|
+
export { StrandSolicitationService } from './strand-solicitation.js';
|
|
20
|
+
// Seed Bootstrap
|
|
21
|
+
export { SeedBootstrapService, SEED_PROTOCOL } from './seed-bootstrap.js';
|
|
22
|
+
// Strand Formation (strand-proto integration)
|
|
23
|
+
export { StrandFormationManager, createStrandFormationManager } from './strand-formation-manager.js';
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAE3B,uBAAuB;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAA8B,MAAM,uBAAuB,CAAC;AAEpF,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAA6B,MAAM,sBAAsB,CAAC;AAEjF,oBAAoB;AACpB,OAAO,EACL,aAAa,EAKd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,qBAAqB,EAErB,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAEtC,cAAc;AACd,OAAO,EACL,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;AAElC,mBAAmB;AACnB,OAAO,EACL,aAAa,EACb,mBAAmB,EAEpB,MAAM,qBAAqB,CAAC;AAE7B,aAAa;AACb,OAAO,EACL,iBAAiB,EAGlB,MAAM,iBAAiB,CAAC;AAEzB,sBAAsB;AACtB,OAAO,EACL,yBAAyB,EAM1B,MAAM,0BAA0B,CAAC;AAElC,iBAAiB;AACjB,OAAO,EACL,oBAAoB,EACpB,aAAa,EAGd,MAAM,qBAAqB,CAAC;AAE7B,8CAA8C;AAC9C,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAG7B,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { Libp2p } from '@libp2p/interface';
|
|
2
|
+
import type { ControlNetworkSeed, SeedAckMessage, AuthorizePeerOptions, ApplySeedResult, AddDroneOptions, AddPhoneOptions, DroneInitResult, InviteResult, CadreInvite } from './types.js';
|
|
3
|
+
import type { ControlDatabase } from './control-database.js';
|
|
4
|
+
/** Protocol ID for seed delivery */
|
|
5
|
+
export declare const SEED_PROTOCOL = "/sereus/seed/1.0.0";
|
|
6
|
+
/**
|
|
7
|
+
* Configuration for the SeedBootstrapService
|
|
8
|
+
*/
|
|
9
|
+
export interface SeedBootstrapConfig {
|
|
10
|
+
/** Party ID for this cadre */
|
|
11
|
+
partyId: string;
|
|
12
|
+
/** Authority private key for signing seeds and peer authorizations (base64url) */
|
|
13
|
+
authorityPrivateKey?: string;
|
|
14
|
+
/** Authority public key (base64url) - derived from private key if not provided */
|
|
15
|
+
authorityPublicKey?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Event callbacks for seed-related events
|
|
19
|
+
*/
|
|
20
|
+
export interface SeedEventCallbacks {
|
|
21
|
+
/** Called when a seed is received via the protocol */
|
|
22
|
+
onSeedReceived?: (partyId: string, peerId: string) => void;
|
|
23
|
+
/** Called when a seed is successfully applied */
|
|
24
|
+
onSeedApplied?: (partyId: string, peersAdded: number) => void;
|
|
25
|
+
/** Called when seed application fails */
|
|
26
|
+
onSeedError?: (partyId: string, error: string) => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* SeedBootstrapService handles control network seed generation and delivery.
|
|
30
|
+
*
|
|
31
|
+
* Seeds solve the cold-start problem: new nodes need control data to validate
|
|
32
|
+
* connections, but can't get data without connecting first. Seeds pre-populate
|
|
33
|
+
* the new node's cache with peer information and optionally transactions.
|
|
34
|
+
*/
|
|
35
|
+
export declare class SeedBootstrapService {
|
|
36
|
+
private readonly config;
|
|
37
|
+
private libp2pNode;
|
|
38
|
+
private controlDatabase;
|
|
39
|
+
private readonly authorityPublicKey;
|
|
40
|
+
private eventCallbacks;
|
|
41
|
+
constructor(config: SeedBootstrapConfig);
|
|
42
|
+
/**
|
|
43
|
+
* Set event callbacks for seed-related events.
|
|
44
|
+
* Used by CadreNode to emit events.
|
|
45
|
+
*/
|
|
46
|
+
setEventCallbacks(callbacks: SeedEventCallbacks): void;
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the service with libp2p node and control database
|
|
49
|
+
*/
|
|
50
|
+
initialize(libp2pNode: Libp2p, controlDatabase: ControlDatabase): void;
|
|
51
|
+
/**
|
|
52
|
+
* Authorize a new peer to join the cadre.
|
|
53
|
+
* Signs the peer ID with the authority key and inserts into CadrePeer table.
|
|
54
|
+
*/
|
|
55
|
+
authorizePeer(options: AuthorizePeerOptions): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Create a seed from the current control network state.
|
|
58
|
+
* The seed contains peer information and is signed by an authority.
|
|
59
|
+
*/
|
|
60
|
+
createSeed(): Promise<ControlNetworkSeed>;
|
|
61
|
+
/**
|
|
62
|
+
* Apply a seed to populate the peer cache and enable connections.
|
|
63
|
+
* Validates the seed signature before applying.
|
|
64
|
+
*/
|
|
65
|
+
applySeed(seed: ControlNetworkSeed): Promise<ApplySeedResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Encode a seed for out-of-band delivery (e.g., QR code, copy/paste).
|
|
68
|
+
*/
|
|
69
|
+
encodeSeed(seed: ControlNetworkSeed): string;
|
|
70
|
+
/**
|
|
71
|
+
* Decode a seed from base64url encoding.
|
|
72
|
+
*/
|
|
73
|
+
decodeSeed(encoded: string): ControlNetworkSeed;
|
|
74
|
+
/**
|
|
75
|
+
* Deliver a seed directly to a peer via the /sereus/seed/1.0.0 protocol.
|
|
76
|
+
*/
|
|
77
|
+
deliverSeed(targetMultiaddr: string, seed: ControlNetworkSeed): Promise<SeedAckMessage>;
|
|
78
|
+
/**
|
|
79
|
+
* Get this node's circuit relay address for inclusion in seeds.
|
|
80
|
+
* Returns null if no relay address is available.
|
|
81
|
+
*/
|
|
82
|
+
getRelayAddress(): Promise<string | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Validate a seed's signature.
|
|
85
|
+
*/
|
|
86
|
+
validateSeedSignature(seed: ControlNetworkSeed): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Query peers from the control database.
|
|
89
|
+
*/
|
|
90
|
+
private queryPeers;
|
|
91
|
+
/**
|
|
92
|
+
* Register the seed protocol handler.
|
|
93
|
+
*/
|
|
94
|
+
private registerProtocolHandler;
|
|
95
|
+
/**
|
|
96
|
+
* Shutdown the service.
|
|
97
|
+
*/
|
|
98
|
+
shutdown(): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Add a drone to the cadre (phone/server adds provider-hosted node).
|
|
101
|
+
*
|
|
102
|
+
* Use this when you've spawned a drone via provider API and received its
|
|
103
|
+
* peer ID and multiaddrs. This method:
|
|
104
|
+
* 1. Authorizes the drone peer
|
|
105
|
+
* 2. Creates a seed including all current peers
|
|
106
|
+
* 3. Returns the seed for sending to provider API
|
|
107
|
+
*
|
|
108
|
+
* @param options - Drone peer info from provider API
|
|
109
|
+
* @returns Seed and encoded seed for drone initialization
|
|
110
|
+
*/
|
|
111
|
+
addDrone(options: AddDroneOptions): Promise<DroneInitResult>;
|
|
112
|
+
/**
|
|
113
|
+
* Create an invite for a phone to join the cadre.
|
|
114
|
+
*
|
|
115
|
+
* Use this when a server (public IP) wants to invite a phone (NAT'd).
|
|
116
|
+
* The invite is shared out-of-band (QR code, link, etc.) and contains
|
|
117
|
+
* the server's address so the phone can dial in.
|
|
118
|
+
*
|
|
119
|
+
* @param token - Optional invite token for validation
|
|
120
|
+
* @param expiresIn - Optional expiration time in milliseconds
|
|
121
|
+
* @returns Invite and encoded invite for sharing
|
|
122
|
+
*/
|
|
123
|
+
createInvite(token?: string, expiresIn?: number): Promise<InviteResult>;
|
|
124
|
+
/**
|
|
125
|
+
* Accept a phone connection using an invite.
|
|
126
|
+
*
|
|
127
|
+
* Use this when a phone dials in with an invite token. This method:
|
|
128
|
+
* 1. Validates the token if provided
|
|
129
|
+
* 2. Authorizes the phone peer
|
|
130
|
+
*
|
|
131
|
+
* After this, the phone can sync the control database normally.
|
|
132
|
+
*
|
|
133
|
+
* @param options - Phone peer info and invite token
|
|
134
|
+
* @param issuedInvite - The original invite for validation
|
|
135
|
+
*/
|
|
136
|
+
acceptPhone(options: AddPhoneOptions, issuedInvite?: CadreInvite): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Add a phone to the cadre with relay support.
|
|
139
|
+
*
|
|
140
|
+
* Use this when both nodes are NAT'd (phone-to-phone). This method:
|
|
141
|
+
* 1. Authorizes the new phone peer
|
|
142
|
+
* 2. Creates a seed with relay addresses for dialing
|
|
143
|
+
*
|
|
144
|
+
* @param phonePeerId - Peer ID of the new phone
|
|
145
|
+
* @returns Seed with relay addresses for out-of-band delivery
|
|
146
|
+
*/
|
|
147
|
+
addPhoneWithRelay(phonePeerId: string): Promise<DroneInitResult>;
|
|
148
|
+
/**
|
|
149
|
+
* Encode an invite for out-of-band delivery.
|
|
150
|
+
*/
|
|
151
|
+
encodeInvite(invite: CadreInvite): string;
|
|
152
|
+
/**
|
|
153
|
+
* Decode an invite from base64url encoding.
|
|
154
|
+
*/
|
|
155
|
+
decodeInvite(encoded: string): CadreInvite;
|
|
156
|
+
/**
|
|
157
|
+
* Dial an authority from an invite.
|
|
158
|
+
* Use this on a phone after receiving an invite to connect to the authority.
|
|
159
|
+
*
|
|
160
|
+
* @param invite - The invite received out-of-band
|
|
161
|
+
* @returns Connection to the authority
|
|
162
|
+
*/
|
|
163
|
+
dialInvite(invite: CadreInvite): Promise<void>;
|
|
164
|
+
}
|