@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,268 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import type {
|
|
3
|
+
StrandInstance,
|
|
4
|
+
LatencyHint,
|
|
5
|
+
HibernationTimeouts,
|
|
6
|
+
HibernationConfig
|
|
7
|
+
} from './types.js';
|
|
8
|
+
import { HIBERNATION_TIMEOUTS } from './types.js';
|
|
9
|
+
|
|
10
|
+
const log = debug('sereus:cadre:hibernation');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Callbacks for hibernation state changes
|
|
14
|
+
*/
|
|
15
|
+
export interface HibernationCallbacks {
|
|
16
|
+
onIdle: (strandId: string) => Promise<void>;
|
|
17
|
+
onHibernate: (strandId: string) => Promise<void>;
|
|
18
|
+
onWake: (strandId: string) => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Manages strand hibernation state transitions based on activity.
|
|
23
|
+
*
|
|
24
|
+
* State machine:
|
|
25
|
+
* active → idle (after idleTimeout with no activity)
|
|
26
|
+
* idle → hibernating (after hibernateTimeout with no activity)
|
|
27
|
+
* idle → active (on activity)
|
|
28
|
+
* hibernating → active (on wake signal or check-in with pending activity)
|
|
29
|
+
*/
|
|
30
|
+
export class HibernationManager {
|
|
31
|
+
private readonly config: HibernationConfig;
|
|
32
|
+
private readonly callbacks: HibernationCallbacks;
|
|
33
|
+
private readonly timers: Map<string, ReturnType<typeof setTimeout>> = new Map();
|
|
34
|
+
private readonly checkInTimers: Map<string, ReturnType<typeof setInterval>> = new Map();
|
|
35
|
+
private running = false;
|
|
36
|
+
|
|
37
|
+
constructor(config: HibernationConfig, callbacks: HibernationCallbacks) {
|
|
38
|
+
this.config = config;
|
|
39
|
+
this.callbacks = callbacks;
|
|
40
|
+
log('HibernationManager created, enabled=%s', config.enabled);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get effective timeouts for a latency hint
|
|
45
|
+
*/
|
|
46
|
+
private getTimeouts(hint: LatencyHint): HibernationTimeouts {
|
|
47
|
+
const defaults = HIBERNATION_TIMEOUTS[hint];
|
|
48
|
+
const custom = this.config.customTimeouts?.[hint];
|
|
49
|
+
|
|
50
|
+
if (!custom) return defaults;
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
idleTimeout: custom.idleTimeout ?? defaults.idleTimeout,
|
|
54
|
+
hibernateTimeout: custom.hibernateTimeout ?? defaults.hibernateTimeout,
|
|
55
|
+
checkInInterval: custom.checkInInterval ?? defaults.checkInInterval
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Start managing hibernation for all strands
|
|
61
|
+
*/
|
|
62
|
+
start(): void {
|
|
63
|
+
if (this.running) return;
|
|
64
|
+
this.running = true;
|
|
65
|
+
log('HibernationManager started');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Stop managing hibernation
|
|
70
|
+
*/
|
|
71
|
+
stop(): void {
|
|
72
|
+
if (!this.running) return;
|
|
73
|
+
this.running = false;
|
|
74
|
+
|
|
75
|
+
// Clear all timers
|
|
76
|
+
for (const timer of this.timers.values()) {
|
|
77
|
+
clearTimeout(timer);
|
|
78
|
+
}
|
|
79
|
+
this.timers.clear();
|
|
80
|
+
|
|
81
|
+
for (const timer of this.checkInTimers.values()) {
|
|
82
|
+
clearInterval(timer);
|
|
83
|
+
}
|
|
84
|
+
this.checkInTimers.clear();
|
|
85
|
+
|
|
86
|
+
log('HibernationManager stopped');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Register a strand for hibernation management
|
|
91
|
+
*/
|
|
92
|
+
trackStrand(instance: StrandInstance): void {
|
|
93
|
+
if (!this.config.enabled || !this.running) return;
|
|
94
|
+
|
|
95
|
+
const { strandId, latencyHint } = instance;
|
|
96
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
97
|
+
|
|
98
|
+
// Don't track strands that never hibernate
|
|
99
|
+
if (timeouts.idleTimeout === Infinity) {
|
|
100
|
+
log('Strand %s has realtime latency hint - no hibernation', strandId);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
log('Tracking strand %s for hibernation (hint=%s)', strandId, latencyHint);
|
|
105
|
+
this.scheduleIdleTransition(instance);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Untrack a strand from hibernation management
|
|
110
|
+
*/
|
|
111
|
+
untrackStrand(strandId: string): void {
|
|
112
|
+
this.clearTimers(strandId);
|
|
113
|
+
log('Untracked strand %s from hibernation', strandId);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Record activity on a strand - resets idle timer
|
|
118
|
+
*/
|
|
119
|
+
recordActivity(instance: StrandInstance): void {
|
|
120
|
+
if (!this.config.enabled || !this.running) return;
|
|
121
|
+
|
|
122
|
+
const { strandId, status, latencyHint } = instance;
|
|
123
|
+
instance.lastActivity = new Date();
|
|
124
|
+
|
|
125
|
+
// If idle or hibernating, wake up
|
|
126
|
+
if (status === 'idle' || status === 'hibernating') {
|
|
127
|
+
log('Activity on %s strand %s - waking', status, strandId);
|
|
128
|
+
this.clearTimers(strandId);
|
|
129
|
+
void this.callbacks.onWake(strandId);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Reschedule idle transition if active
|
|
133
|
+
if (status === 'active') {
|
|
134
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
135
|
+
if (timeouts.idleTimeout !== Infinity) {
|
|
136
|
+
this.scheduleIdleTransition(instance);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Force wake a hibernating strand
|
|
143
|
+
*/
|
|
144
|
+
async wakeStrand(strandId: string): Promise<void> {
|
|
145
|
+
this.clearTimers(strandId);
|
|
146
|
+
await this.callbacks.onWake(strandId);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private scheduleIdleTransition(instance: StrandInstance): void {
|
|
150
|
+
const { strandId, latencyHint } = instance;
|
|
151
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
152
|
+
|
|
153
|
+
// Clear existing timer
|
|
154
|
+
this.clearTimer(strandId);
|
|
155
|
+
|
|
156
|
+
// Schedule idle transition
|
|
157
|
+
const timer = setTimeout(() => {
|
|
158
|
+
this.handleIdleTimeout(instance);
|
|
159
|
+
}, timeouts.idleTimeout);
|
|
160
|
+
|
|
161
|
+
this.timers.set(strandId, timer);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private handleIdleTimeout(instance: StrandInstance): void {
|
|
165
|
+
const { strandId, latencyHint } = instance;
|
|
166
|
+
|
|
167
|
+
if (!this.running) return;
|
|
168
|
+
|
|
169
|
+
log('Idle timeout for strand %s', strandId);
|
|
170
|
+
|
|
171
|
+
// Transition to idle
|
|
172
|
+
void this.callbacks.onIdle(strandId).then(() => {
|
|
173
|
+
// Schedule hibernate transition
|
|
174
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
175
|
+
if (timeouts.hibernateTimeout !== Infinity) {
|
|
176
|
+
this.scheduleHibernateTransition(instance);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private scheduleHibernateTransition(instance: StrandInstance): void {
|
|
182
|
+
const { strandId, latencyHint } = instance;
|
|
183
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
184
|
+
|
|
185
|
+
// Clear existing timer
|
|
186
|
+
this.clearTimer(strandId);
|
|
187
|
+
|
|
188
|
+
// Schedule hibernate transition
|
|
189
|
+
const timer = setTimeout(() => {
|
|
190
|
+
this.handleHibernateTimeout(instance);
|
|
191
|
+
}, timeouts.hibernateTimeout);
|
|
192
|
+
|
|
193
|
+
this.timers.set(strandId, timer);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private handleHibernateTimeout(instance: StrandInstance): void {
|
|
197
|
+
const { strandId, latencyHint } = instance;
|
|
198
|
+
|
|
199
|
+
if (!this.running) return;
|
|
200
|
+
|
|
201
|
+
log('Hibernate timeout for strand %s', strandId);
|
|
202
|
+
|
|
203
|
+
// Transition to hibernating
|
|
204
|
+
void this.callbacks.onHibernate(strandId).then(() => {
|
|
205
|
+
// Schedule periodic check-ins
|
|
206
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
207
|
+
if (timeouts.checkInInterval !== Infinity) {
|
|
208
|
+
this.scheduleCheckIn(instance);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private scheduleCheckIn(instance: StrandInstance): void {
|
|
214
|
+
const { strandId, latencyHint } = instance;
|
|
215
|
+
const timeouts = this.getTimeouts(latencyHint);
|
|
216
|
+
|
|
217
|
+
// Clear existing check-in timer
|
|
218
|
+
const existing = this.checkInTimers.get(strandId);
|
|
219
|
+
if (existing) {
|
|
220
|
+
clearInterval(existing);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Schedule periodic check-ins
|
|
224
|
+
const timer = setInterval(() => {
|
|
225
|
+
if (!this.running) {
|
|
226
|
+
clearInterval(timer);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
log('Check-in for hibernating strand %s', strandId);
|
|
231
|
+
instance.nextCheckIn = new Date(Date.now() + timeouts.checkInInterval);
|
|
232
|
+
|
|
233
|
+
// In a real implementation, this would query the cohort for pending activity
|
|
234
|
+
// For now, we just update the nextCheckIn timestamp
|
|
235
|
+
}, timeouts.checkInInterval);
|
|
236
|
+
|
|
237
|
+
this.checkInTimers.set(strandId, timer);
|
|
238
|
+
instance.nextCheckIn = new Date(Date.now() + timeouts.checkInInterval);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private clearTimer(strandId: string): void {
|
|
242
|
+
const timer = this.timers.get(strandId);
|
|
243
|
+
if (timer) {
|
|
244
|
+
clearTimeout(timer);
|
|
245
|
+
this.timers.delete(strandId);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private clearTimers(strandId: string): void {
|
|
250
|
+
this.clearTimer(strandId);
|
|
251
|
+
|
|
252
|
+
const checkInTimer = this.checkInTimers.get(strandId);
|
|
253
|
+
if (checkInTimer) {
|
|
254
|
+
clearInterval(checkInTimer);
|
|
255
|
+
this.checkInTimers.delete(strandId);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get the current status of hibernation tracking
|
|
261
|
+
*/
|
|
262
|
+
getStatus(): { enabled: boolean; trackedStrands: number } {
|
|
263
|
+
return {
|
|
264
|
+
enabled: this.config.enabled && this.running,
|
|
265
|
+
trackedStrands: this.timers.size + this.checkInTimers.size
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Core types
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
|
|
4
|
+
// Main CadreNode class
|
|
5
|
+
export { CadreNode } from './cadre-node.js';
|
|
6
|
+
|
|
7
|
+
// Control database
|
|
8
|
+
export { ControlDatabase, type ControlDatabaseConfig } from './control-database.js';
|
|
9
|
+
|
|
10
|
+
// Strand database
|
|
11
|
+
export { StrandDatabase, type StrandDatabaseConfig } from './strand-database.js';
|
|
12
|
+
|
|
13
|
+
// Strand management
|
|
14
|
+
export {
|
|
15
|
+
StrandWatcher,
|
|
16
|
+
type StrandWatcherCallbacks,
|
|
17
|
+
type StrandQueryable,
|
|
18
|
+
type SAppIdLookup,
|
|
19
|
+
type StrandRowWithApp
|
|
20
|
+
} from './strand-watcher.js';
|
|
21
|
+
export {
|
|
22
|
+
StrandInstanceManager,
|
|
23
|
+
type StartStrandConfig,
|
|
24
|
+
getStrandStoragePath
|
|
25
|
+
} from './strand-instance-manager.js';
|
|
26
|
+
|
|
27
|
+
// Hibernation
|
|
28
|
+
export {
|
|
29
|
+
HibernationManager,
|
|
30
|
+
type HibernationCallbacks
|
|
31
|
+
} from './hibernation-manager.js';
|
|
32
|
+
|
|
33
|
+
// Arachnode (stub)
|
|
34
|
+
export {
|
|
35
|
+
ArachnodeStub,
|
|
36
|
+
createArachnodeStub,
|
|
37
|
+
type RingConfig
|
|
38
|
+
} from './arachnode-stub.js';
|
|
39
|
+
|
|
40
|
+
// Enrollment
|
|
41
|
+
export {
|
|
42
|
+
EnrollmentService,
|
|
43
|
+
type MemberVerifier,
|
|
44
|
+
type MemberRegistry
|
|
45
|
+
} from './enrollment.js';
|
|
46
|
+
|
|
47
|
+
// Strand Solicitation
|
|
48
|
+
export {
|
|
49
|
+
StrandSolicitationService,
|
|
50
|
+
type DisclosureValidator,
|
|
51
|
+
type FormationUsageRecorder,
|
|
52
|
+
type StrandProvisioner,
|
|
53
|
+
type FormationSigner,
|
|
54
|
+
type StrandSolicitationServiceOptions
|
|
55
|
+
} from './strand-solicitation.js';
|
|
56
|
+
|
|
57
|
+
// Seed Bootstrap
|
|
58
|
+
export {
|
|
59
|
+
SeedBootstrapService,
|
|
60
|
+
SEED_PROTOCOL,
|
|
61
|
+
type SeedBootstrapConfig,
|
|
62
|
+
type SeedEventCallbacks
|
|
63
|
+
} from './seed-bootstrap.js';
|
|
64
|
+
|
|
65
|
+
// Strand Formation (strand-proto integration)
|
|
66
|
+
export {
|
|
67
|
+
StrandFormationManager,
|
|
68
|
+
createStrandFormationManager,
|
|
69
|
+
type StrandFormationManagerConfig,
|
|
70
|
+
type StrandFormationManagerOptions
|
|
71
|
+
} from './strand-formation-manager.js';
|