@mindexec/cli 0.2.421 → 0.2.422
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/package.json +1 -1
- package/server.js +120 -4
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -699,6 +699,7 @@ async function writeStableAuthSessionPayload(content) {
|
|
|
699
699
|
}
|
|
700
700
|
|
|
701
701
|
await writePrivateTextFile(stablePath, payload);
|
|
702
|
+
clearRemoteRegistryAuthRefreshBackoff('auth-session-write');
|
|
702
703
|
return stablePath;
|
|
703
704
|
}
|
|
704
705
|
|
|
@@ -3677,6 +3678,15 @@ const REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS = Math.max(500, Number(process.env.
|
|
|
3677
3678
|
const REMOTE_REGISTRY_FOLLOWER_MISSING_SESSION_FAST_RETRY_COUNT = Math.max(
|
|
3678
3679
|
1,
|
|
3679
3680
|
Number(process.env.MINDEXEC_REMOTE_REGISTRY_MISSING_SESSION_FAST_RETRY_COUNT || 5) || 5);
|
|
3681
|
+
const REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_BASE_MS = Math.max(
|
|
3682
|
+
5000,
|
|
3683
|
+
Number(process.env.MINDEXEC_REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_BASE_MS || 30000) || 30000);
|
|
3684
|
+
const REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_MAX_MS = Math.max(
|
|
3685
|
+
REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_BASE_MS,
|
|
3686
|
+
Number(process.env.MINDEXEC_REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_MAX_MS || 300000) || 300000);
|
|
3687
|
+
const REMOTE_REGISTRY_AUTH_REFRESH_LOG_REPEAT_MS = Math.max(
|
|
3688
|
+
10000,
|
|
3689
|
+
Number(process.env.MINDEXEC_REMOTE_REGISTRY_AUTH_REFRESH_LOG_REPEAT_MS || 60000) || 60000);
|
|
3680
3690
|
const REMOTE_REGISTRY_FOLLOWER_INACTIVE_STOP_COUNT = Math.max(2, Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_STOP_COUNT || 8) || 8);
|
|
3681
3691
|
const REMOTE_REGISTRY_FOLLOWER_INACTIVE_GRACE_MS = Math.max(500, Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_GRACE_MS || 60000) || 60000);
|
|
3682
3692
|
const REMOTE_REGISTRY_INACTIVE_TARGET_RECOVERY_MS = Math.max(
|
|
@@ -3724,6 +3734,13 @@ let remoteRegistryFollowerConsecutiveMissingSession = 0;
|
|
|
3724
3734
|
let remoteRegistryFollowerConsecutiveInactiveTarget = 0;
|
|
3725
3735
|
let remoteRegistryFollowerInactiveTargetFirstAt = 0;
|
|
3726
3736
|
let remoteRegistrySessionRefreshPromise = null;
|
|
3737
|
+
let remoteRegistryAuthRefreshBackoff = {
|
|
3738
|
+
key: '',
|
|
3739
|
+
until: 0,
|
|
3740
|
+
failureCount: 0,
|
|
3741
|
+
lastError: '',
|
|
3742
|
+
lastLogAt: 0
|
|
3743
|
+
};
|
|
3727
3744
|
let remoteRegistryRealtimeSocket = null;
|
|
3728
3745
|
let remoteRegistryRealtimeSessionKey = '';
|
|
3729
3746
|
let remoteRegistryRealtimeTopic = '';
|
|
@@ -6270,6 +6287,98 @@ function parseSupabaseSessionForRegistry(content) {
|
|
|
6270
6287
|
};
|
|
6271
6288
|
}
|
|
6272
6289
|
|
|
6290
|
+
function getRemoteRegistryAuthRefreshKey(session) {
|
|
6291
|
+
const refreshToken = String(session?.refreshToken || '').trim();
|
|
6292
|
+
if (!refreshToken) {
|
|
6293
|
+
return '';
|
|
6294
|
+
}
|
|
6295
|
+
|
|
6296
|
+
const digest = crypto.createHash('sha256').update(refreshToken).digest('hex').slice(0, 24);
|
|
6297
|
+
return `${safeRemoteAgentField(session?.userId || '', 80)}|${digest}|${Number(session?.expiresAtMs || 0)}`;
|
|
6298
|
+
}
|
|
6299
|
+
|
|
6300
|
+
function clearRemoteRegistryAuthRefreshBackoff(reason = 'cleared') {
|
|
6301
|
+
if (!remoteRegistryAuthRefreshBackoff?.key) {
|
|
6302
|
+
return false;
|
|
6303
|
+
}
|
|
6304
|
+
|
|
6305
|
+
remoteRegistryAuthRefreshBackoff = {
|
|
6306
|
+
key: '',
|
|
6307
|
+
until: 0,
|
|
6308
|
+
failureCount: 0,
|
|
6309
|
+
lastError: '',
|
|
6310
|
+
lastLogAt: 0
|
|
6311
|
+
};
|
|
6312
|
+
if (VERBOSE_REMOTE_AGENT_LOGS) {
|
|
6313
|
+
logEvent('remote', `registry auth refresh backoff cleared ${formatKeyValue('reason', reason)}`, 'remote');
|
|
6314
|
+
}
|
|
6315
|
+
return true;
|
|
6316
|
+
}
|
|
6317
|
+
|
|
6318
|
+
function getRemoteRegistryAuthRefreshBackoff(session) {
|
|
6319
|
+
const key = getRemoteRegistryAuthRefreshKey(session);
|
|
6320
|
+
if (!key) {
|
|
6321
|
+
return { blocked: false, key: '' };
|
|
6322
|
+
}
|
|
6323
|
+
|
|
6324
|
+
if (remoteRegistryAuthRefreshBackoff.key !== key) {
|
|
6325
|
+
return { blocked: false, key };
|
|
6326
|
+
}
|
|
6327
|
+
|
|
6328
|
+
const now = Date.now();
|
|
6329
|
+
const until = Number(remoteRegistryAuthRefreshBackoff.until || 0);
|
|
6330
|
+
if (until > now) {
|
|
6331
|
+
return {
|
|
6332
|
+
blocked: true,
|
|
6333
|
+
key,
|
|
6334
|
+
retryInMs: Math.max(0, until - now),
|
|
6335
|
+
error: remoteRegistryAuthRefreshBackoff.lastError || 'auth-refresh-backoff',
|
|
6336
|
+
failureCount: Number(remoteRegistryAuthRefreshBackoff.failureCount || 0)
|
|
6337
|
+
};
|
|
6338
|
+
}
|
|
6339
|
+
|
|
6340
|
+
return { blocked: false, key };
|
|
6341
|
+
}
|
|
6342
|
+
|
|
6343
|
+
function recordRemoteRegistryAuthRefreshFailure(session, error, reason = 'registry') {
|
|
6344
|
+
const key = getRemoteRegistryAuthRefreshKey(session);
|
|
6345
|
+
const now = Date.now();
|
|
6346
|
+
const previousCount = remoteRegistryAuthRefreshBackoff.key === key
|
|
6347
|
+
? Number(remoteRegistryAuthRefreshBackoff.failureCount || 0)
|
|
6348
|
+
: 0;
|
|
6349
|
+
const failureCount = previousCount + 1;
|
|
6350
|
+
const backoffMs = Math.min(
|
|
6351
|
+
REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_MAX_MS,
|
|
6352
|
+
REMOTE_REGISTRY_AUTH_REFRESH_BACKOFF_BASE_MS * Math.max(1, Math.pow(2, Math.min(4, failureCount - 1))));
|
|
6353
|
+
const message = error?.message || String(error || 'auth-refresh-failed');
|
|
6354
|
+
const lastLogAt = remoteRegistryAuthRefreshBackoff.key === key
|
|
6355
|
+
? Number(remoteRegistryAuthRefreshBackoff.lastLogAt || 0)
|
|
6356
|
+
: 0;
|
|
6357
|
+
const shouldLog = lastLogAt <= 0 ||
|
|
6358
|
+
now - lastLogAt >= REMOTE_REGISTRY_AUTH_REFRESH_LOG_REPEAT_MS ||
|
|
6359
|
+
remoteRegistryAuthRefreshBackoff.lastError !== message;
|
|
6360
|
+
|
|
6361
|
+
remoteRegistryAuthRefreshBackoff = {
|
|
6362
|
+
key,
|
|
6363
|
+
until: now + backoffMs,
|
|
6364
|
+
failureCount,
|
|
6365
|
+
lastError: message,
|
|
6366
|
+
lastLogAt: shouldLog ? now : lastLogAt
|
|
6367
|
+
};
|
|
6368
|
+
|
|
6369
|
+
if (shouldLog) {
|
|
6370
|
+
logWarn(
|
|
6371
|
+
'remote',
|
|
6372
|
+
`registry auth refresh failed ${formatKeyValue('reason', reason || 'registry')} ${formatKeyValue('error', message)} ${formatKeyValue('retryInMs', backoffMs)}`);
|
|
6373
|
+
}
|
|
6374
|
+
|
|
6375
|
+
return {
|
|
6376
|
+
retryInMs: backoffMs,
|
|
6377
|
+
failureCount,
|
|
6378
|
+
error: message
|
|
6379
|
+
};
|
|
6380
|
+
}
|
|
6381
|
+
|
|
6273
6382
|
async function refreshSupabaseSessionForRegistry(config, sessionPayload, reason = 'registry') {
|
|
6274
6383
|
const currentSession = parseSupabaseSessionForRegistry(sessionPayload?.content);
|
|
6275
6384
|
if (!currentSession?.refreshToken) {
|
|
@@ -6283,6 +6392,14 @@ async function refreshSupabaseSessionForRegistry(config, sessionPayload, reason
|
|
|
6283
6392
|
return await remoteRegistrySessionRefreshPromise;
|
|
6284
6393
|
}
|
|
6285
6394
|
|
|
6395
|
+
const backoff = getRemoteRegistryAuthRefreshBackoff(currentSession);
|
|
6396
|
+
if (backoff.blocked === true) {
|
|
6397
|
+
return {
|
|
6398
|
+
ok: false,
|
|
6399
|
+
reason: `auth-refresh-backoff:${Math.ceil(Number(backoff.retryInMs || 0) / 1000)}s`
|
|
6400
|
+
};
|
|
6401
|
+
}
|
|
6402
|
+
|
|
6286
6403
|
remoteRegistrySessionRefreshPromise = (async () => {
|
|
6287
6404
|
const url = new URL('/auth/v1/token', config.url);
|
|
6288
6405
|
url.searchParams.set('grant_type', 'refresh_token');
|
|
@@ -6321,6 +6438,7 @@ async function refreshSupabaseSessionForRegistry(config, sessionPayload, reason
|
|
|
6321
6438
|
`registry auth refreshed ${formatKeyValue('reason', reason || 'registry')} ${formatKeyValue('expiresInMs', Math.max(0, session.expiresAtMs - Date.now()))}`,
|
|
6322
6439
|
'remote');
|
|
6323
6440
|
|
|
6441
|
+
clearRemoteRegistryAuthRefreshBackoff('auth-refresh-success');
|
|
6324
6442
|
return {
|
|
6325
6443
|
ok: true,
|
|
6326
6444
|
reason: 'refreshed',
|
|
@@ -6387,16 +6505,14 @@ async function readFreshSupabaseSessionForRegistry(config, reason = 'registry')
|
|
|
6387
6505
|
refreshError: refreshed.reason || 'auth-refresh-skipped'
|
|
6388
6506
|
};
|
|
6389
6507
|
} catch (error) {
|
|
6390
|
-
|
|
6391
|
-
'remote',
|
|
6392
|
-
`registry auth refresh failed ${formatKeyValue('reason', reason || 'registry')} ${formatKeyValue('error', error?.message || String(error || ''))}`);
|
|
6508
|
+
const failure = recordRemoteRegistryAuthRefreshFailure(session, error, reason);
|
|
6393
6509
|
return {
|
|
6394
6510
|
found: true,
|
|
6395
6511
|
payload: sessionPayload,
|
|
6396
6512
|
session,
|
|
6397
6513
|
refreshed: false,
|
|
6398
6514
|
expired: session.expiresAtMs > 0 && session.expiresAtMs <= Date.now(),
|
|
6399
|
-
refreshError: error
|
|
6515
|
+
refreshError: failure.error
|
|
6400
6516
|
};
|
|
6401
6517
|
}
|
|
6402
6518
|
}
|