@topolo/sdk 0.8.3 → 0.8.4

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.
@@ -31,6 +31,7 @@ __export(credential_store_exports, {
31
31
  normalizeEnvironment: () => normalizeEnvironment,
32
32
  profileForEnvironment: () => profileForEnvironment,
33
33
  readConfig: () => readConfig,
34
+ refreshContextCredentialIfNeeded: () => refreshContextCredentialIfNeeded,
34
35
  refreshCredentialIfNeeded: () => refreshCredentialIfNeeded,
35
36
  resolveAgentName: () => resolveAgentName,
36
37
  resolveCredential: () => resolveCredential,
@@ -428,6 +429,46 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
428
429
  return cred;
429
430
  }
430
431
  }
432
+ async function refreshContextCredentialIfNeeded(environment, key, options = {}) {
433
+ const config = await readConfig();
434
+ const profile = profileForEnvironment(config, environment);
435
+ const context = profile.contexts?.[key];
436
+ const credential = context?.credential;
437
+ if (!credential || credential.kind !== "access_token") return credential ?? null;
438
+ const oauthClientId = context.oauthClientId ?? profile.oauthClientId;
439
+ if (!credential.refreshToken || !credential.expiresAt || !oauthClientId) return credential;
440
+ const now = Math.floor(Date.now() / 1e3);
441
+ if (!options.force && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
442
+ try {
443
+ const oauth = new TopoloOAuth({
444
+ serviceUrls: resolveServiceUrls(profile.serviceUrls, environment)
445
+ });
446
+ const tokens = await oauth.refreshToken({
447
+ clientId: oauthClientId,
448
+ refreshToken: credential.refreshToken
449
+ });
450
+ const refreshed = {
451
+ kind: "access_token",
452
+ accessToken: tokens.access_token,
453
+ ...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : { refreshToken: credential.refreshToken },
454
+ expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
455
+ };
456
+ await writeConfig(writeProfileConfig(config, environment, {
457
+ ...profile.activeContext === key ? { credential: refreshed } : {},
458
+ contexts: {
459
+ ...profile.contexts ?? {},
460
+ [key]: {
461
+ ...context,
462
+ credential: refreshed,
463
+ oauthClientId
464
+ }
465
+ }
466
+ }));
467
+ return refreshed;
468
+ } catch {
469
+ return credential;
470
+ }
471
+ }
431
472
  function resolveAgentName(configAgentName) {
432
473
  return process.env.TOPOLO_AGENT_NAME ?? configAgentName;
433
474
  }
@@ -471,6 +512,7 @@ function resolvedProfileConfig(config, environment = selectedEnvironment()) {
471
512
  normalizeEnvironment,
472
513
  profileForEnvironment,
473
514
  readConfig,
515
+ refreshContextCredentialIfNeeded,
474
516
  refreshCredentialIfNeeded,
475
517
  resolveAgentName,
476
518
  resolveCredential,
@@ -103,8 +103,12 @@ declare function resolveCredential(environment?: TopoloEnvironment): Promise<Top
103
103
  declare function refreshCredentialIfNeeded(environment?: TopoloEnvironment, options?: {
104
104
  force?: boolean;
105
105
  }): Promise<TopoloCredential | null>;
106
+ /** Refresh one stored context without changing which context is active. */
107
+ declare function refreshContextCredentialIfNeeded(environment: TopoloEnvironment, key: string, options?: {
108
+ force?: boolean;
109
+ }): Promise<TopoloCredential | null>;
106
110
  declare function resolveAgentName(configAgentName?: string): string | undefined;
107
111
  declare function resolveServiceUrls(configUrls?: Record<string, string>, environment?: TopoloEnvironment): Record<string, string> | undefined;
108
112
  declare function resolvedProfileConfig(config: TopoloConfig, environment?: TopoloEnvironment): TopoloEnvironmentProfile;
109
113
 
110
- export { ENVIRONMENT_DEFAULT_SERVICE_URLS, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, clearProfileCredential, configPath, contextKey, credentialSourceFromConfig, envVarPrefix, normalizeEnvironment, profileForEnvironment, readConfig, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, writeConfig, writeContextCredential, writeProfileConfig };
114
+ export { ENVIRONMENT_DEFAULT_SERVICE_URLS, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, clearProfileCredential, configPath, contextKey, credentialSourceFromConfig, envVarPrefix, normalizeEnvironment, profileForEnvironment, readConfig, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, writeConfig, writeContextCredential, writeProfileConfig };
@@ -103,8 +103,12 @@ declare function resolveCredential(environment?: TopoloEnvironment): Promise<Top
103
103
  declare function refreshCredentialIfNeeded(environment?: TopoloEnvironment, options?: {
104
104
  force?: boolean;
105
105
  }): Promise<TopoloCredential | null>;
106
+ /** Refresh one stored context without changing which context is active. */
107
+ declare function refreshContextCredentialIfNeeded(environment: TopoloEnvironment, key: string, options?: {
108
+ force?: boolean;
109
+ }): Promise<TopoloCredential | null>;
106
110
  declare function resolveAgentName(configAgentName?: string): string | undefined;
107
111
  declare function resolveServiceUrls(configUrls?: Record<string, string>, environment?: TopoloEnvironment): Record<string, string> | undefined;
108
112
  declare function resolvedProfileConfig(config: TopoloConfig, environment?: TopoloEnvironment): TopoloEnvironmentProfile;
109
113
 
110
- export { ENVIRONMENT_DEFAULT_SERVICE_URLS, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, clearProfileCredential, configPath, contextKey, credentialSourceFromConfig, envVarPrefix, normalizeEnvironment, profileForEnvironment, readConfig, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, writeConfig, writeContextCredential, writeProfileConfig };
114
+ export { ENVIRONMENT_DEFAULT_SERVICE_URLS, TOPOLO_ENVIRONMENTS, type TopoloConfig, type TopoloContextCredential, type TopoloEnvironment, type TopoloEnvironmentProfile, activateContext, clearProfileCredential, configPath, contextKey, credentialSourceFromConfig, envVarPrefix, normalizeEnvironment, profileForEnvironment, readConfig, refreshContextCredentialIfNeeded, refreshCredentialIfNeeded, resolveAgentName, resolveCredential, resolveServiceUrls, resolvedProfileConfig, selectedEnvironment, writeConfig, writeContextCredential, writeProfileConfig };
@@ -385,6 +385,46 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
385
385
  return cred;
386
386
  }
387
387
  }
388
+ async function refreshContextCredentialIfNeeded(environment, key, options = {}) {
389
+ const config = await readConfig();
390
+ const profile = profileForEnvironment(config, environment);
391
+ const context = profile.contexts?.[key];
392
+ const credential = context?.credential;
393
+ if (!credential || credential.kind !== "access_token") return credential ?? null;
394
+ const oauthClientId = context.oauthClientId ?? profile.oauthClientId;
395
+ if (!credential.refreshToken || !credential.expiresAt || !oauthClientId) return credential;
396
+ const now = Math.floor(Date.now() / 1e3);
397
+ if (!options.force && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
398
+ try {
399
+ const oauth = new TopoloOAuth({
400
+ serviceUrls: resolveServiceUrls(profile.serviceUrls, environment)
401
+ });
402
+ const tokens = await oauth.refreshToken({
403
+ clientId: oauthClientId,
404
+ refreshToken: credential.refreshToken
405
+ });
406
+ const refreshed = {
407
+ kind: "access_token",
408
+ accessToken: tokens.access_token,
409
+ ...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : { refreshToken: credential.refreshToken },
410
+ expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
411
+ };
412
+ await writeConfig(writeProfileConfig(config, environment, {
413
+ ...profile.activeContext === key ? { credential: refreshed } : {},
414
+ contexts: {
415
+ ...profile.contexts ?? {},
416
+ [key]: {
417
+ ...context,
418
+ credential: refreshed,
419
+ oauthClientId
420
+ }
421
+ }
422
+ }));
423
+ return refreshed;
424
+ } catch {
425
+ return credential;
426
+ }
427
+ }
388
428
  function resolveAgentName(configAgentName) {
389
429
  return process.env.TOPOLO_AGENT_NAME ?? configAgentName;
390
430
  }
@@ -427,6 +467,7 @@ export {
427
467
  normalizeEnvironment,
428
468
  profileForEnvironment,
429
469
  readConfig,
470
+ refreshContextCredentialIfNeeded,
430
471
  refreshCredentialIfNeeded,
431
472
  resolveAgentName,
432
473
  resolveCredential,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.8.3",
4
- "topoloPublishedVersion": "0.8.3",
3
+ "version": "0.8.4",
4
+ "topoloPublishedVersion": "0.8.4",
5
5
  "description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",