@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +120 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.421",
3
+ "version": "0.2.422",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
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
- logWarn(
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?.message || String(error || '')
6515
+ refreshError: failure.error
6400
6516
  };
6401
6517
  }
6402
6518
  }