@naylence/runtime 0.3.14 → 0.3.16
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/dist/browser/index.cjs +1160 -977
- package/dist/browser/index.mjs +1157 -979
- package/dist/cjs/browser.js +15 -0
- package/dist/cjs/naylence/fame/factory-manifest.js +2 -0
- package/dist/cjs/naylence/fame/node/connection-retry-policy-factory.js +22 -0
- package/dist/cjs/naylence/fame/node/connection-retry-policy.js +2 -0
- package/dist/cjs/naylence/fame/node/default-connection-retry-policy-factory.js +36 -0
- package/dist/cjs/naylence/fame/node/default-connection-retry-policy.js +51 -0
- package/dist/cjs/naylence/fame/node/factory-commons.js +15 -0
- package/dist/cjs/naylence/fame/node/index.js +6 -1
- package/dist/cjs/naylence/fame/node/node-config.js +4 -0
- package/dist/cjs/naylence/fame/node/node-factory.js +1 -0
- package/dist/cjs/naylence/fame/node/node.js +3 -0
- package/dist/cjs/naylence/fame/node/upstream-session-manager.js +63 -23
- package/dist/cjs/naylence/fame/sentinel/sentinel.js +2 -0
- package/dist/cjs/node.js +12 -1
- package/dist/cjs/version.js +2 -2
- package/dist/esm/browser.js +15 -0
- package/dist/esm/naylence/fame/factory-manifest.js +2 -0
- package/dist/esm/naylence/fame/node/connection-retry-policy-factory.js +18 -0
- package/dist/esm/naylence/fame/node/connection-retry-policy.js +1 -0
- package/dist/esm/naylence/fame/node/default-connection-retry-policy-factory.js +32 -0
- package/dist/esm/naylence/fame/node/default-connection-retry-policy.js +47 -0
- package/dist/esm/naylence/fame/node/factory-commons.js +15 -0
- package/dist/esm/naylence/fame/node/index.js +4 -0
- package/dist/esm/naylence/fame/node/node-config.js +4 -0
- package/dist/esm/naylence/fame/node/node-factory.js +1 -0
- package/dist/esm/naylence/fame/node/node.js +3 -0
- package/dist/esm/naylence/fame/node/upstream-session-manager.js +63 -23
- package/dist/esm/naylence/fame/sentinel/sentinel.js +2 -0
- package/dist/esm/node.js +12 -1
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +615 -442
- package/dist/node/index.mjs +611 -443
- package/dist/node/node.cjs +1191 -1008
- package/dist/node/node.mjs +1188 -1010
- package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
- package/dist/types/naylence/fame/node/connection-retry-policy-factory.d.ts +20 -0
- package/dist/types/naylence/fame/node/connection-retry-policy.d.ts +44 -0
- package/dist/types/naylence/fame/node/default-connection-retry-policy-factory.d.ts +15 -0
- package/dist/types/naylence/fame/node/default-connection-retry-policy.d.ts +36 -0
- package/dist/types/naylence/fame/node/factory-commons.d.ts +2 -0
- package/dist/types/naylence/fame/node/index.d.ts +4 -0
- package/dist/types/naylence/fame/node/node-config.d.ts +2 -0
- package/dist/types/naylence/fame/node/node.d.ts +3 -0
- package/dist/types/naylence/fame/node/upstream-session-manager.d.ts +13 -0
- package/dist/types/naylence/fame/sentinel/sentinel.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable for overriding max initial attempts.
|
|
3
|
+
*/
|
|
4
|
+
export const ENV_VAR_SESSION_MAX_INITIAL_ATTEMPTS = 'FAME_SESSION_MAX_INITIAL_ATTEMPTS';
|
|
5
|
+
/**
|
|
6
|
+
* Default implementation of connection retry policy.
|
|
7
|
+
*
|
|
8
|
+
* Before first successful attach:
|
|
9
|
+
* - Respects maxInitialAttempts configuration
|
|
10
|
+
* - Uses exponential backoff with jitter
|
|
11
|
+
*
|
|
12
|
+
* After first successful attach:
|
|
13
|
+
* - Always retries (unlimited) to maintain connection
|
|
14
|
+
* - Resets backoff if connection was stable for >10 seconds
|
|
15
|
+
*/
|
|
16
|
+
export class DefaultConnectionRetryPolicy {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
// Check for environment variable override
|
|
19
|
+
const envValue = typeof process !== 'undefined'
|
|
20
|
+
? process.env?.[ENV_VAR_SESSION_MAX_INITIAL_ATTEMPTS]
|
|
21
|
+
: undefined;
|
|
22
|
+
if (envValue !== undefined && envValue !== '') {
|
|
23
|
+
const parsed = parseInt(envValue, 10);
|
|
24
|
+
this.maxInitialAttempts = isNaN(parsed) ? (options.maxInitialAttempts ?? 1) : parsed;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this.maxInitialAttempts = options.maxInitialAttempts ?? 1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
shouldRetry(context) {
|
|
31
|
+
// After first successful attach, always retry to maintain connection
|
|
32
|
+
if (context.hadSuccessfulAttach) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
// maxInitialAttempts = 0 means unlimited retries
|
|
36
|
+
if (this.maxInitialAttempts === 0) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Fail if we've exceeded the configured max attempts
|
|
40
|
+
return context.attemptNumber < this.maxInitialAttempts;
|
|
41
|
+
}
|
|
42
|
+
calculateRetryDelay(_context, baseDelay) {
|
|
43
|
+
// Add jitter to prevent thundering herd
|
|
44
|
+
const jitter = Math.random() * baseDelay;
|
|
45
|
+
return baseDelay + jitter;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createResource } from '@naylence/factory';
|
|
2
2
|
import { AdmissionClientFactory } from './admission/admission-client-factory.js';
|
|
3
|
+
import { ConnectionRetryPolicyFactory, } from './connection-retry-policy-factory.js';
|
|
3
4
|
import { DefaultNodeIdentityPolicy } from './default-node-identity-policy.js';
|
|
4
5
|
import { NodeIdentityPolicyFactory, } from './node-identity-policy-factory.js';
|
|
5
6
|
import { DefaultNodeAttachClient } from './admission/default-node-attach-client.js';
|
|
@@ -124,6 +125,7 @@ export async function makeCommonOptions(config, rawConfig) {
|
|
|
124
125
|
const telemetryConfig = pickOption(config.telemetry ?? null, aliasRecord, 'trace_emitter', 'telemetry_config');
|
|
125
126
|
const securityConfig = pickOption(config.security ?? null, aliasRecord, 'security_manager', 'security_profile');
|
|
126
127
|
const identityPolicyConfig = pickOption(config.identityPolicy ?? null, aliasRecord, 'identity_policy', 'node_identity_policy');
|
|
128
|
+
const connectionRetryPolicyConfig = pickOption(config.connectionRetryPolicy ?? null, aliasRecord, 'connection_retry_policy', 'retry_policy');
|
|
127
129
|
const publicUrl = pickString(config.publicUrl ?? null, aliasRecord, 'public_url') ?? null;
|
|
128
130
|
const directParentUrl = pickString(config.directParentUrl ?? null, aliasRecord, 'direct_parent_url') ?? null;
|
|
129
131
|
const hasParentFlag = config.hasParent || Boolean(aliasRecord.has_parent ?? false);
|
|
@@ -133,6 +135,7 @@ export async function makeCommonOptions(config, rawConfig) {
|
|
|
133
135
|
const nodeMetaStore = await storageProvider.getKeyValueStore(NodeMetaRecord, NODE_META_NAMESPACE);
|
|
134
136
|
const nodeMeta = await nodeMetaStore.get('self');
|
|
135
137
|
const identityPolicy = await resolveNodeIdentityPolicy(identityPolicyConfig ?? null, expressionOptions);
|
|
138
|
+
const connectionRetryPolicy = await resolveConnectionRetryPolicy(connectionRetryPolicyConfig ?? null, expressionOptions);
|
|
136
139
|
const admissionClient = await resolveAdmissionClient(admissionConfig ?? null, expressionOptions, identityPolicy ?? undefined);
|
|
137
140
|
const hasParent = determineHasParent(hasParentFlag, directParentUrl, admissionClient);
|
|
138
141
|
const replicaStickinessManager = await resolveReplicaStickinessManager(hasParent, requestedLogicals, expressionOptions);
|
|
@@ -201,6 +204,7 @@ export async function makeCommonOptions(config, rawConfig) {
|
|
|
201
204
|
transportListeners,
|
|
202
205
|
traceEmitter,
|
|
203
206
|
identityPolicy: identityPolicy ?? undefined,
|
|
207
|
+
connectionRetryPolicy: connectionRetryPolicy ?? undefined,
|
|
204
208
|
};
|
|
205
209
|
}
|
|
206
210
|
async function resolveNodeIdentityPolicy(config, options) {
|
|
@@ -214,6 +218,17 @@ async function resolveNodeIdentityPolicy(config, options) {
|
|
|
214
218
|
return null;
|
|
215
219
|
}
|
|
216
220
|
}
|
|
221
|
+
async function resolveConnectionRetryPolicy(config, options) {
|
|
222
|
+
try {
|
|
223
|
+
return await ConnectionRetryPolicyFactory.createConnectionRetryPolicy(config ?? undefined, cloneCreateOptions(options));
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
logger.warning('connection_retry_policy_creation_failed', {
|
|
227
|
+
error: error instanceof Error ? error.message : String(error),
|
|
228
|
+
});
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
217
232
|
async function resolveStorageProvider(config, options) {
|
|
218
233
|
if (config) {
|
|
219
234
|
try {
|
|
@@ -25,3 +25,7 @@ export { DefaultNodeIdentityPolicyFactory, } from './default-node-identity-polic
|
|
|
25
25
|
export * from './token-subject-node-identity-policy.js';
|
|
26
26
|
export { TokenSubjectNodeIdentityPolicyFactory, } from './token-subject-node-identity-policy-factory.js';
|
|
27
27
|
export { NodeIdentityPolicyProfileFactory, } from './node-identity-policy-profile-factory.js';
|
|
28
|
+
export * from './connection-retry-policy.js';
|
|
29
|
+
export * from './connection-retry-policy-factory.js';
|
|
30
|
+
export * from './default-connection-retry-policy.js';
|
|
31
|
+
export { DefaultConnectionRetryPolicyFactory, } from './default-connection-retry-policy-factory.js';
|
|
@@ -23,6 +23,7 @@ const FameNodeConfigSchemaInternal = z
|
|
|
23
23
|
telemetry: z.unknown().optional().nullable(),
|
|
24
24
|
requestedCapabilities: z.array(z.string()).optional(),
|
|
25
25
|
identityPolicy: z.unknown().optional().nullable(),
|
|
26
|
+
connectionRetryPolicy: z.unknown().optional().nullable(),
|
|
26
27
|
})
|
|
27
28
|
.passthrough();
|
|
28
29
|
export function normalizeFameNodeConfig(input) {
|
|
@@ -64,6 +65,9 @@ export function normalizeFameNodeConfig(input) {
|
|
|
64
65
|
identityPolicy: parsed.identityPolicy === undefined
|
|
65
66
|
? null
|
|
66
67
|
: parsed.identityPolicy,
|
|
68
|
+
connectionRetryPolicy: parsed.connectionRetryPolicy === undefined
|
|
69
|
+
? null
|
|
70
|
+
: parsed.connectionRetryPolicy,
|
|
67
71
|
};
|
|
68
72
|
if (parsed.requestedCapabilities) {
|
|
69
73
|
normalized.requestedCapabilities = coerceStringArray(parsed.requestedCapabilities);
|
|
@@ -38,6 +38,7 @@ export class NodeFactory extends NodeLikeFactory {
|
|
|
38
38
|
nodeMetaStore: components.nodeMetaStore,
|
|
39
39
|
transportListeners: components.transportListeners,
|
|
40
40
|
defaultServiceConfigs: serviceConfigs,
|
|
41
|
+
connectionRetryPolicy: components.connectionRetryPolicy,
|
|
41
42
|
});
|
|
42
43
|
return node;
|
|
43
44
|
}
|
|
@@ -141,6 +141,8 @@ export class FameNode extends TaskSpawner {
|
|
|
141
141
|
this._acceptedLogicals = new Set(acceptedLogicalsOption);
|
|
142
142
|
const deliveryPolicyOption = resolveOption(options, 'deliveryPolicy', 'delivery_policy');
|
|
143
143
|
this._deliveryPolicy = deliveryPolicyOption ?? null;
|
|
144
|
+
const connectionRetryPolicyOption = resolveOption(options, 'connectionRetryPolicy', 'connection_retry_policy');
|
|
145
|
+
this._connectionRetryPolicy = connectionRetryPolicyOption ?? null;
|
|
144
146
|
const admissionClientOption = resolveOption(options, 'admissionClient', 'admission_client');
|
|
145
147
|
this._admissionClient = admissionClientOption ?? null;
|
|
146
148
|
const attachClientOption = resolveOption(options, 'attachClient', 'attach_client');
|
|
@@ -270,6 +272,7 @@ export class FameNode extends TaskSpawner {
|
|
|
270
272
|
onAttach: (info, connector) => this.handleAttach(info, connector),
|
|
271
273
|
onEpochChange: (epoch) => this.handleEpochChange(epoch),
|
|
272
274
|
admissionClient: this._admissionClient,
|
|
275
|
+
retryPolicy: this._connectionRetryPolicy,
|
|
273
276
|
});
|
|
274
277
|
this._sessionManager = manager;
|
|
275
278
|
await manager.start();
|
|
@@ -82,6 +82,7 @@ function normalizeOptions(options) {
|
|
|
82
82
|
const onEpochChangeValue = pickOption(record, 'onEpochChange', 'on_epoch_change');
|
|
83
83
|
const onEpochChange = typeof onEpochChangeValue === 'function' ? onEpochChangeValue : undefined;
|
|
84
84
|
const admissionClient = pickOption(record, 'admissionClient', 'admission_client');
|
|
85
|
+
const retryPolicy = pickOption(record, 'retryPolicy', 'retry_policy');
|
|
85
86
|
return {
|
|
86
87
|
node,
|
|
87
88
|
attachClient,
|
|
@@ -93,6 +94,7 @@ function normalizeOptions(options) {
|
|
|
93
94
|
onAttach: validatedOnAttach,
|
|
94
95
|
onEpochChange,
|
|
95
96
|
admissionClient: admissionClient ?? undefined,
|
|
97
|
+
retryPolicy: retryPolicy ?? undefined,
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
100
|
export class UpstreamSessionManager extends TaskSpawner {
|
|
@@ -112,6 +114,7 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
112
114
|
this.hadSuccessfulAttach = false;
|
|
113
115
|
this.lastConnectorState = null;
|
|
114
116
|
this.connectEpoch = 0;
|
|
117
|
+
this.initialAttempts = 0;
|
|
115
118
|
this._visibilityHandler = null;
|
|
116
119
|
const options = normalizeOptions(optionsInput);
|
|
117
120
|
this.node = options.node;
|
|
@@ -125,8 +128,11 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
125
128
|
this.admissionClient =
|
|
126
129
|
options.admissionClient ?? options.node.admissionClient;
|
|
127
130
|
this.wrappedHandler = this.makeHeartbeatEnabledHandler(options.inboundHandler);
|
|
131
|
+
// Store the connection retry policy (can be null, in which case default behavior applies)
|
|
132
|
+
this.connectionRetryPolicy = options.retryPolicy ?? null;
|
|
128
133
|
logger.debug('created_upstream_session_manager', {
|
|
129
134
|
target_system_id: this.targetSystemId,
|
|
135
|
+
has_retry_policy: this.connectionRetryPolicy !== null,
|
|
130
136
|
});
|
|
131
137
|
}
|
|
132
138
|
get systemId() {
|
|
@@ -242,11 +248,14 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
242
248
|
}
|
|
243
249
|
async fsmLoop() {
|
|
244
250
|
let delay = UpstreamSessionManager.BACKOFF_INITIAL;
|
|
251
|
+
this.initialAttempts = 0;
|
|
245
252
|
while (!this.stopEvent.isSet()) {
|
|
246
253
|
const startTime = Date.now();
|
|
254
|
+
this.initialAttempts += 1;
|
|
247
255
|
try {
|
|
248
256
|
await this.connectCycle();
|
|
249
257
|
delay = UpstreamSessionManager.BACKOFF_INITIAL;
|
|
258
|
+
this.initialAttempts = 0; // Reset on success
|
|
250
259
|
}
|
|
251
260
|
catch (error) {
|
|
252
261
|
// Reset backoff if the connection was alive for more than 10 seconds
|
|
@@ -256,13 +265,17 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
256
265
|
if (error instanceof TaskCancelledError) {
|
|
257
266
|
throw error;
|
|
258
267
|
}
|
|
268
|
+
// Determine if we should fail-fast or retry
|
|
269
|
+
const shouldFailFast = this.shouldFailFastOnError(error);
|
|
259
270
|
if (error instanceof FameTransportClose ||
|
|
260
271
|
error instanceof FameConnectError) {
|
|
261
272
|
logger.warning('upstream_link_closed', {
|
|
262
273
|
error: error.message,
|
|
263
|
-
will_retry:
|
|
274
|
+
will_retry: !shouldFailFast,
|
|
275
|
+
attempt: this.initialAttempts,
|
|
276
|
+
has_retry_policy: this.connectionRetryPolicy !== null,
|
|
264
277
|
});
|
|
265
|
-
if (
|
|
278
|
+
if (shouldFailFast && error instanceof FameConnectError) {
|
|
266
279
|
throw error;
|
|
267
280
|
}
|
|
268
281
|
}
|
|
@@ -277,11 +290,13 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
277
290
|
else {
|
|
278
291
|
logger.warning('upstream_link_closed', {
|
|
279
292
|
error: err.message,
|
|
280
|
-
will_retry:
|
|
293
|
+
will_retry: !shouldFailFast,
|
|
294
|
+
attempt: this.initialAttempts,
|
|
295
|
+
has_retry_policy: this.connectionRetryPolicy !== null,
|
|
281
296
|
exc_info: true,
|
|
282
297
|
});
|
|
283
298
|
}
|
|
284
|
-
if (
|
|
299
|
+
if (shouldFailFast) {
|
|
285
300
|
throw error;
|
|
286
301
|
}
|
|
287
302
|
}
|
|
@@ -289,52 +304,77 @@ export class UpstreamSessionManager extends TaskSpawner {
|
|
|
289
304
|
}
|
|
290
305
|
}
|
|
291
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Determine whether to fail immediately or continue retrying.
|
|
309
|
+
* Returns true if we should throw the error instead of retrying.
|
|
310
|
+
*/
|
|
311
|
+
shouldFailFastOnError(error) {
|
|
312
|
+
// If no policy is configured, use legacy behavior (fail-fast after first attempt)
|
|
313
|
+
if (!this.connectionRetryPolicy) {
|
|
314
|
+
// After first successful attach, always retry (existing behavior)
|
|
315
|
+
if (this.hadSuccessfulAttach) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
// Without a policy, fail on first error
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
// Delegate decision to the policy
|
|
322
|
+
const shouldRetry = this.connectionRetryPolicy.shouldRetry({
|
|
323
|
+
hadSuccessfulAttach: this.hadSuccessfulAttach,
|
|
324
|
+
attemptNumber: this.initialAttempts,
|
|
325
|
+
error,
|
|
326
|
+
});
|
|
327
|
+
return !shouldRetry;
|
|
328
|
+
}
|
|
292
329
|
async applyBackoff(delay) {
|
|
293
330
|
const jitter = Math.random() * delay;
|
|
294
|
-
await this.sleepWithStop(delay + jitter);
|
|
331
|
+
const wasWoken = await this.sleepWithStop(delay + jitter);
|
|
332
|
+
// If sleep was interrupted by visibility change (user returned to tab),
|
|
333
|
+
// reset backoff to initial delay for immediate retry with fresh backoff
|
|
334
|
+
if (wasWoken) {
|
|
335
|
+
logger.debug('backoff_reset_on_visibility_change', {
|
|
336
|
+
previous_delay: delay,
|
|
337
|
+
new_delay: UpstreamSessionManager.BACKOFF_INITIAL,
|
|
338
|
+
});
|
|
339
|
+
return UpstreamSessionManager.BACKOFF_INITIAL;
|
|
340
|
+
}
|
|
295
341
|
return Math.min(delay * 2, UpstreamSessionManager.BACKOFF_CAP);
|
|
296
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Sleep for the specified duration, but can be interrupted by stop or wake events.
|
|
345
|
+
* @returns true if interrupted by wake event (e.g., visibility change), false otherwise
|
|
346
|
+
*/
|
|
297
347
|
async sleepWithStop(delaySeconds) {
|
|
298
348
|
if (delaySeconds <= 0) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
// If the document is visible, cap the backoff delay to improve UX
|
|
302
|
-
// This ensures that if the user is watching, we retry quickly (e.g. 1s)
|
|
303
|
-
// instead of waiting for the full exponential backoff (up to 30s).
|
|
304
|
-
let effectiveDelay = delaySeconds;
|
|
305
|
-
if (typeof document !== 'undefined' &&
|
|
306
|
-
document.visibilityState === 'visible') {
|
|
307
|
-
effectiveDelay = Math.min(delaySeconds, 1.0);
|
|
308
|
-
if (effectiveDelay < delaySeconds) {
|
|
309
|
-
logger.debug('sleep_reduced_document_visible', {
|
|
310
|
-
original: delaySeconds,
|
|
311
|
-
new: effectiveDelay,
|
|
312
|
-
});
|
|
313
|
-
}
|
|
349
|
+
return false;
|
|
314
350
|
}
|
|
351
|
+
// Check if wake event is already set (e.g., visibility just changed)
|
|
315
352
|
if (this.wakeEvent.isSet()) {
|
|
316
353
|
this.wakeEvent.clear();
|
|
317
|
-
|
|
354
|
+
logger.debug('sleep_skipped_wake_event_pending');
|
|
355
|
+
return true;
|
|
318
356
|
}
|
|
319
357
|
let timeout;
|
|
320
358
|
const sleepPromise = new Promise((resolve) => {
|
|
321
359
|
timeout = setTimeout(() => {
|
|
322
360
|
timeout = undefined;
|
|
323
361
|
resolve();
|
|
324
|
-
},
|
|
362
|
+
}, delaySeconds * 1000);
|
|
325
363
|
});
|
|
326
364
|
await Promise.race([
|
|
327
365
|
sleepPromise,
|
|
328
366
|
this.stopEvent.wait(),
|
|
329
367
|
this.wakeEvent.wait(),
|
|
330
368
|
]);
|
|
331
|
-
|
|
369
|
+
const wasWoken = this.wakeEvent.isSet();
|
|
370
|
+
if (wasWoken) {
|
|
332
371
|
logger.debug('sleep_interrupted_by_wake_event');
|
|
333
372
|
this.wakeEvent.clear();
|
|
334
373
|
}
|
|
335
374
|
if (timeout !== undefined) {
|
|
336
375
|
clearTimeout(timeout);
|
|
337
376
|
}
|
|
377
|
+
return wasWoken;
|
|
338
378
|
}
|
|
339
379
|
getNodeAttachGrant(connectionGrants) {
|
|
340
380
|
if (!connectionGrants) {
|
|
@@ -154,6 +154,7 @@ export class Sentinel extends FameNode {
|
|
|
154
154
|
this.maxAttachTtlSec = opts.maxAttachTtlSec ?? null;
|
|
155
155
|
this.requestedLogicals = opts.requestedLogicals ?? [];
|
|
156
156
|
this.attachClient = opts.attachClient ?? null;
|
|
157
|
+
this.connectionRetryPolicy = opts.connectionRetryPolicy ?? null;
|
|
157
158
|
this.nodeAttachFrameHandler = new NodeAttachFrameHandler({
|
|
158
159
|
routingNode: this,
|
|
159
160
|
routeManager: this.routeManager,
|
|
@@ -703,6 +704,7 @@ export class Sentinel extends FameNode {
|
|
|
703
704
|
onAttach: (info, connector) => this.onNodeAttachToPeer(info, connector),
|
|
704
705
|
onEpochChange: (epoch) => this.onEpochChange(epoch),
|
|
705
706
|
onWelcome: async () => undefined,
|
|
707
|
+
retryPolicy: this.connectionRetryPolicy,
|
|
706
708
|
});
|
|
707
709
|
await sessionManager.start();
|
|
708
710
|
const systemId = sessionManager.systemId;
|
package/dist/esm/node.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import './naylence/fame/connector/websocket-connector-node-ssl.js';
|
|
2
|
+
import plugin from './plugin.js';
|
|
2
3
|
// Ensure Node-specific registrations (storage, sqlite, etc.) happen before
|
|
3
4
|
// the isomorphic exports are evaluated. Some factories (SQLite) must be
|
|
4
5
|
// registered early so configuration parsing that happens during runtime
|
|
5
6
|
// initialization can resolve the requested storage profiles.
|
|
6
7
|
import './naylence/fame/storage/node-index.js'; // Side-effect: registers SQLite profiles
|
|
7
|
-
//
|
|
8
|
+
// Always register the plugin directly. This ensures it is initialized even if
|
|
9
|
+
// the dynamic import mechanism (used by FAME_PLUGINS) fails or is not used.
|
|
10
|
+
(async () => {
|
|
11
|
+
try {
|
|
12
|
+
await plugin.register();
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
console.error('[naylence-runtime] Failed to auto-register plugin:', err);
|
|
16
|
+
}
|
|
17
|
+
})();
|
|
18
|
+
// Auto-register the runtime plugin in FAME_PLUGINS for child processes
|
|
8
19
|
if (typeof process !== 'undefined' && process.env) {
|
|
9
20
|
const pluginName = '@naylence/runtime';
|
|
10
21
|
const current = process.env.FAME_PLUGINS || '';
|
package/dist/esm/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This file is auto-generated during build - do not edit manually
|
|
2
|
-
// Generated from package.json version: 0.3.
|
|
2
|
+
// Generated from package.json version: 0.3.16
|
|
3
3
|
/**
|
|
4
4
|
* The package version, injected at build time.
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
|
-
export const VERSION = '0.3.
|
|
7
|
+
export const VERSION = '0.3.16';
|