@topolo/sdk 0.9.0 → 0.9.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/dist/index.cjs CHANGED
@@ -127,6 +127,7 @@ var APP_API_URLS = {
127
127
  auth: "https://auth.topolo.app",
128
128
  backup: "https://backup.topolo.app",
129
129
  books: "https://books.topolo.app",
130
+ brand: "https://brand.topolo.app",
130
131
  bugfix: "https://bugfix.topolo.app",
131
132
  bytes: "https://bytes.topolo.app",
132
133
  calendar: "https://calendar.topolo.app",
@@ -309,6 +310,38 @@ var APPLICATIONS = {
309
310
  }
310
311
  ]
311
312
  },
313
+ "brand": {
314
+ "id": "brand",
315
+ "appDir": "TopoloBrand",
316
+ "name": "topolo-brand",
317
+ "packageName": "@topolo/topolo-brand",
318
+ "productionUrl": "https://brand.topolo.app",
319
+ "services": [
320
+ "brand"
321
+ ],
322
+ "deployTargets": [
323
+ {
324
+ "name": "topolo-brand",
325
+ "kind": "worker",
326
+ "apiUrl": "https://brand.topolo.app",
327
+ "domains": [
328
+ "brand.topolo.app"
329
+ ],
330
+ "routes": [
331
+ "brand.topolo.app"
332
+ ],
333
+ "appId": "brand"
334
+ },
335
+ {
336
+ "name": "topolo-brand-api",
337
+ "kind": "worker",
338
+ "apiUrl": null,
339
+ "domains": [],
340
+ "routes": [],
341
+ "appId": null
342
+ }
343
+ ]
344
+ },
312
345
  "bugfix": {
313
346
  "id": "bugfix",
314
347
  "appDir": "TopoloBugFix",
@@ -2431,6 +2464,8 @@ var TopoloClient = class _TopoloClient {
2431
2464
  requireConfirmForWrites;
2432
2465
  timeoutMs;
2433
2466
  fetchImpl;
2467
+ credentialProvider;
2468
+ credentialLoadInFlight = null;
2434
2469
  refreshCredential;
2435
2470
  refreshInFlight = null;
2436
2471
  debug;
@@ -2458,6 +2493,7 @@ var TopoloClient = class _TopoloClient {
2458
2493
  this.requireConfirmForWrites = options.requireConfirmForWrites !== false;
2459
2494
  this.timeoutMs = options.timeoutMs ?? 3e4;
2460
2495
  this.fetchImpl = options.fetch ?? fetch;
2496
+ this.credentialProvider = options.credentialProvider;
2461
2497
  this.refreshCredential = options.refreshCredential;
2462
2498
  this.debug = options.debug;
2463
2499
  }
@@ -2480,6 +2516,7 @@ var TopoloClient = class _TopoloClient {
2480
2516
  `Mutating ${method} requests require { confirm: true }. This guardrail prevents agents from issuing writes without an explicit human-in-the-loop acknowledgement.`
2481
2517
  );
2482
2518
  }
2519
+ await this.loadCurrentCredential();
2483
2520
  const resolvedService = opts.baseUrl ? { serviceKey: normalizeLookupKey(opts.service), baseUrl: requireHttpOrigin(opts.baseUrl) } : await this.resolveRequestService(opts.service);
2484
2521
  const baseUrl = resolvedService.baseUrl;
2485
2522
  const url = new URL(opts.path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
@@ -2591,6 +2628,19 @@ var TopoloClient = class _TopoloClient {
2591
2628
  });
2592
2629
  return parsed;
2593
2630
  }
2631
+ async loadCurrentCredential() {
2632
+ if (!this.credentialProvider) return;
2633
+ this.credentialLoadInFlight ??= this.credentialProvider().then((credential) => {
2634
+ if (!credential) {
2635
+ throw new TopoloAuthError("The configured Topolo credential is no longer available.");
2636
+ }
2637
+ this.credential = credential;
2638
+ return credential;
2639
+ }).finally(() => {
2640
+ this.credentialLoadInFlight = null;
2641
+ });
2642
+ await this.credentialLoadInFlight;
2643
+ }
2594
2644
  async refreshRejectedAccessToken(attemptedAccessToken) {
2595
2645
  if (this.credential.kind === "access_token" && this.credential.accessToken !== attemptedAccessToken) {
2596
2646
  return this.credential;
package/dist/index.d.cts CHANGED
@@ -58,6 +58,12 @@ interface TopoloClientOptions {
58
58
  timeoutMs?: number;
59
59
  /** Injected fetch, for testing. Defaults to global fetch. */
60
60
  fetch?: typeof fetch;
61
+ /**
62
+ * Load the credential currently stored for this client before each request.
63
+ * Long-lived hosts use this to adopt context reauthentication and claim
64
+ * changes without waiting for the previous token to fail with a 401.
65
+ */
66
+ credentialProvider?: () => Promise<TopoloCredential | null>;
61
67
  /**
62
68
  * Refresh a rejected access-token credential. When supplied, the client
63
69
  * retries one 401 response with the returned credential. Concurrent 401s
@@ -270,6 +276,8 @@ declare class TopoloClient {
270
276
  private readonly requireConfirmForWrites;
271
277
  private readonly timeoutMs;
272
278
  private readonly fetchImpl;
279
+ private readonly credentialProvider?;
280
+ private credentialLoadInFlight;
273
281
  private readonly refreshCredential?;
274
282
  private refreshInFlight;
275
283
  private readonly debug?;
@@ -293,6 +301,7 @@ declare class TopoloClient {
293
301
  * use and for the generic `topolo api` / MCP passthrough tool.
294
302
  */
295
303
  request<T = unknown>(opts: RequestOptions): Promise<T>;
304
+ private loadCurrentCredential;
296
305
  private refreshRejectedAccessToken;
297
306
  private resolveRequestService;
298
307
  private resolveLiveCallableService;
@@ -430,6 +439,7 @@ declare const APP_API_URLS: {
430
439
  readonly auth: "https://auth.topolo.app";
431
440
  readonly backup: "https://backup.topolo.app";
432
441
  readonly books: "https://books.topolo.app";
442
+ readonly brand: "https://brand.topolo.app";
433
443
  readonly bugfix: "https://bugfix.topolo.app";
434
444
  readonly bytes: "https://bytes.topolo.app";
435
445
  readonly calendar: "https://calendar.topolo.app";
@@ -579,6 +589,29 @@ declare const APPLICATIONS: {
579
589
  readonly appId: null;
580
590
  }];
581
591
  };
592
+ readonly brand: {
593
+ readonly id: "brand";
594
+ readonly appDir: "TopoloBrand";
595
+ readonly name: "topolo-brand";
596
+ readonly packageName: "@topolo/topolo-brand";
597
+ readonly productionUrl: "https://brand.topolo.app";
598
+ readonly services: readonly ["brand"];
599
+ readonly deployTargets: readonly [{
600
+ readonly name: "topolo-brand";
601
+ readonly kind: "worker";
602
+ readonly apiUrl: "https://brand.topolo.app";
603
+ readonly domains: readonly ["brand.topolo.app"];
604
+ readonly routes: readonly ["brand.topolo.app"];
605
+ readonly appId: "brand";
606
+ }, {
607
+ readonly name: "topolo-brand-api";
608
+ readonly kind: "worker";
609
+ readonly apiUrl: null;
610
+ readonly domains: readonly [];
611
+ readonly routes: readonly [];
612
+ readonly appId: null;
613
+ }];
614
+ };
582
615
  readonly bugfix: {
583
616
  readonly id: "bugfix";
584
617
  readonly appDir: "TopoloBugFix";
package/dist/index.d.ts CHANGED
@@ -58,6 +58,12 @@ interface TopoloClientOptions {
58
58
  timeoutMs?: number;
59
59
  /** Injected fetch, for testing. Defaults to global fetch. */
60
60
  fetch?: typeof fetch;
61
+ /**
62
+ * Load the credential currently stored for this client before each request.
63
+ * Long-lived hosts use this to adopt context reauthentication and claim
64
+ * changes without waiting for the previous token to fail with a 401.
65
+ */
66
+ credentialProvider?: () => Promise<TopoloCredential | null>;
61
67
  /**
62
68
  * Refresh a rejected access-token credential. When supplied, the client
63
69
  * retries one 401 response with the returned credential. Concurrent 401s
@@ -270,6 +276,8 @@ declare class TopoloClient {
270
276
  private readonly requireConfirmForWrites;
271
277
  private readonly timeoutMs;
272
278
  private readonly fetchImpl;
279
+ private readonly credentialProvider?;
280
+ private credentialLoadInFlight;
273
281
  private readonly refreshCredential?;
274
282
  private refreshInFlight;
275
283
  private readonly debug?;
@@ -293,6 +301,7 @@ declare class TopoloClient {
293
301
  * use and for the generic `topolo api` / MCP passthrough tool.
294
302
  */
295
303
  request<T = unknown>(opts: RequestOptions): Promise<T>;
304
+ private loadCurrentCredential;
296
305
  private refreshRejectedAccessToken;
297
306
  private resolveRequestService;
298
307
  private resolveLiveCallableService;
@@ -430,6 +439,7 @@ declare const APP_API_URLS: {
430
439
  readonly auth: "https://auth.topolo.app";
431
440
  readonly backup: "https://backup.topolo.app";
432
441
  readonly books: "https://books.topolo.app";
442
+ readonly brand: "https://brand.topolo.app";
433
443
  readonly bugfix: "https://bugfix.topolo.app";
434
444
  readonly bytes: "https://bytes.topolo.app";
435
445
  readonly calendar: "https://calendar.topolo.app";
@@ -579,6 +589,29 @@ declare const APPLICATIONS: {
579
589
  readonly appId: null;
580
590
  }];
581
591
  };
592
+ readonly brand: {
593
+ readonly id: "brand";
594
+ readonly appDir: "TopoloBrand";
595
+ readonly name: "topolo-brand";
596
+ readonly packageName: "@topolo/topolo-brand";
597
+ readonly productionUrl: "https://brand.topolo.app";
598
+ readonly services: readonly ["brand"];
599
+ readonly deployTargets: readonly [{
600
+ readonly name: "topolo-brand";
601
+ readonly kind: "worker";
602
+ readonly apiUrl: "https://brand.topolo.app";
603
+ readonly domains: readonly ["brand.topolo.app"];
604
+ readonly routes: readonly ["brand.topolo.app"];
605
+ readonly appId: "brand";
606
+ }, {
607
+ readonly name: "topolo-brand-api";
608
+ readonly kind: "worker";
609
+ readonly apiUrl: null;
610
+ readonly domains: readonly [];
611
+ readonly routes: readonly [];
612
+ readonly appId: null;
613
+ }];
614
+ };
582
615
  readonly bugfix: {
583
616
  readonly id: "bugfix";
584
617
  readonly appDir: "TopoloBugFix";
package/dist/index.js CHANGED
@@ -68,6 +68,7 @@ var APP_API_URLS = {
68
68
  auth: "https://auth.topolo.app",
69
69
  backup: "https://backup.topolo.app",
70
70
  books: "https://books.topolo.app",
71
+ brand: "https://brand.topolo.app",
71
72
  bugfix: "https://bugfix.topolo.app",
72
73
  bytes: "https://bytes.topolo.app",
73
74
  calendar: "https://calendar.topolo.app",
@@ -250,6 +251,38 @@ var APPLICATIONS = {
250
251
  }
251
252
  ]
252
253
  },
254
+ "brand": {
255
+ "id": "brand",
256
+ "appDir": "TopoloBrand",
257
+ "name": "topolo-brand",
258
+ "packageName": "@topolo/topolo-brand",
259
+ "productionUrl": "https://brand.topolo.app",
260
+ "services": [
261
+ "brand"
262
+ ],
263
+ "deployTargets": [
264
+ {
265
+ "name": "topolo-brand",
266
+ "kind": "worker",
267
+ "apiUrl": "https://brand.topolo.app",
268
+ "domains": [
269
+ "brand.topolo.app"
270
+ ],
271
+ "routes": [
272
+ "brand.topolo.app"
273
+ ],
274
+ "appId": "brand"
275
+ },
276
+ {
277
+ "name": "topolo-brand-api",
278
+ "kind": "worker",
279
+ "apiUrl": null,
280
+ "domains": [],
281
+ "routes": [],
282
+ "appId": null
283
+ }
284
+ ]
285
+ },
253
286
  "bugfix": {
254
287
  "id": "bugfix",
255
288
  "appDir": "TopoloBugFix",
@@ -2372,6 +2405,8 @@ var TopoloClient = class _TopoloClient {
2372
2405
  requireConfirmForWrites;
2373
2406
  timeoutMs;
2374
2407
  fetchImpl;
2408
+ credentialProvider;
2409
+ credentialLoadInFlight = null;
2375
2410
  refreshCredential;
2376
2411
  refreshInFlight = null;
2377
2412
  debug;
@@ -2399,6 +2434,7 @@ var TopoloClient = class _TopoloClient {
2399
2434
  this.requireConfirmForWrites = options.requireConfirmForWrites !== false;
2400
2435
  this.timeoutMs = options.timeoutMs ?? 3e4;
2401
2436
  this.fetchImpl = options.fetch ?? fetch;
2437
+ this.credentialProvider = options.credentialProvider;
2402
2438
  this.refreshCredential = options.refreshCredential;
2403
2439
  this.debug = options.debug;
2404
2440
  }
@@ -2421,6 +2457,7 @@ var TopoloClient = class _TopoloClient {
2421
2457
  `Mutating ${method} requests require { confirm: true }. This guardrail prevents agents from issuing writes without an explicit human-in-the-loop acknowledgement.`
2422
2458
  );
2423
2459
  }
2460
+ await this.loadCurrentCredential();
2424
2461
  const resolvedService = opts.baseUrl ? { serviceKey: normalizeLookupKey(opts.service), baseUrl: requireHttpOrigin(opts.baseUrl) } : await this.resolveRequestService(opts.service);
2425
2462
  const baseUrl = resolvedService.baseUrl;
2426
2463
  const url = new URL(opts.path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
@@ -2532,6 +2569,19 @@ var TopoloClient = class _TopoloClient {
2532
2569
  });
2533
2570
  return parsed;
2534
2571
  }
2572
+ async loadCurrentCredential() {
2573
+ if (!this.credentialProvider) return;
2574
+ this.credentialLoadInFlight ??= this.credentialProvider().then((credential) => {
2575
+ if (!credential) {
2576
+ throw new TopoloAuthError("The configured Topolo credential is no longer available.");
2577
+ }
2578
+ this.credential = credential;
2579
+ return credential;
2580
+ }).finally(() => {
2581
+ this.credentialLoadInFlight = null;
2582
+ });
2583
+ await this.credentialLoadInFlight;
2584
+ }
2535
2585
  async refreshRejectedAccessToken(attemptedAccessToken) {
2536
2586
  if (this.credential.kind === "access_token" && this.credential.accessToken !== attemptedAccessToken) {
2537
2587
  return this.credential;
@@ -84,6 +84,7 @@ var APP_API_URLS = {
84
84
  auth: "https://auth.topolo.app",
85
85
  backup: "https://backup.topolo.app",
86
86
  books: "https://books.topolo.app",
87
+ brand: "https://brand.topolo.app",
87
88
  bugfix: "https://bugfix.topolo.app",
88
89
  bytes: "https://bytes.topolo.app",
89
90
  calendar: "https://calendar.topolo.app",
@@ -393,9 +394,9 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
393
394
  const profile = profileForEnvironment(config, environment);
394
395
  const cred = profile.credential;
395
396
  if (!cred || cred.kind !== "access_token") return cred ?? null;
396
- if (!cred.refreshToken || !cred.expiresAt || !profile.oauthClientId) return cred;
397
+ if (!cred.refreshToken || !profile.oauthClientId) return cred;
397
398
  const now = Math.floor(Date.now() / 1e3);
398
- if (!options.force && cred.expiresAt - REFRESH_SKEW_SECONDS > now) return cred;
399
+ if (!options.force && cred.expiresAt && cred.expiresAt - REFRESH_SKEW_SECONDS > now) return cred;
399
400
  try {
400
401
  const oauth = new TopoloOAuth({
401
402
  serviceUrls: resolveServiceUrls(profile.serviceUrls, environment)
@@ -436,9 +437,9 @@ async function refreshContextCredentialIfNeeded(environment, key, options = {})
436
437
  const credential = context?.credential;
437
438
  if (!credential || credential.kind !== "access_token") return credential ?? null;
438
439
  const oauthClientId = context.oauthClientId ?? profile.oauthClientId;
439
- if (!credential.refreshToken || !credential.expiresAt || !oauthClientId) return credential;
440
+ if (!credential.refreshToken || !oauthClientId) return credential;
440
441
  const now = Math.floor(Date.now() / 1e3);
441
- if (!options.force && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
442
+ if (!options.force && credential.expiresAt && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
442
443
  try {
443
444
  const oauth = new TopoloOAuth({
444
445
  serviceUrls: resolveServiceUrls(profile.serviceUrls, environment)
@@ -40,6 +40,7 @@ var APP_API_URLS = {
40
40
  auth: "https://auth.topolo.app",
41
41
  backup: "https://backup.topolo.app",
42
42
  books: "https://books.topolo.app",
43
+ brand: "https://brand.topolo.app",
43
44
  bugfix: "https://bugfix.topolo.app",
44
45
  bytes: "https://bytes.topolo.app",
45
46
  calendar: "https://calendar.topolo.app",
@@ -349,9 +350,9 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
349
350
  const profile = profileForEnvironment(config, environment);
350
351
  const cred = profile.credential;
351
352
  if (!cred || cred.kind !== "access_token") return cred ?? null;
352
- if (!cred.refreshToken || !cred.expiresAt || !profile.oauthClientId) return cred;
353
+ if (!cred.refreshToken || !profile.oauthClientId) return cred;
353
354
  const now = Math.floor(Date.now() / 1e3);
354
- if (!options.force && cred.expiresAt - REFRESH_SKEW_SECONDS > now) return cred;
355
+ if (!options.force && cred.expiresAt && cred.expiresAt - REFRESH_SKEW_SECONDS > now) return cred;
355
356
  try {
356
357
  const oauth = new TopoloOAuth({
357
358
  serviceUrls: resolveServiceUrls(profile.serviceUrls, environment)
@@ -392,9 +393,9 @@ async function refreshContextCredentialIfNeeded(environment, key, options = {})
392
393
  const credential = context?.credential;
393
394
  if (!credential || credential.kind !== "access_token") return credential ?? null;
394
395
  const oauthClientId = context.oauthClientId ?? profile.oauthClientId;
395
- if (!credential.refreshToken || !credential.expiresAt || !oauthClientId) return credential;
396
+ if (!credential.refreshToken || !oauthClientId) return credential;
396
397
  const now = Math.floor(Date.now() / 1e3);
397
- if (!options.force && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
398
+ if (!options.force && credential.expiresAt && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
398
399
  try {
399
400
  const oauth = new TopoloOAuth({
400
401
  serviceUrls: resolveServiceUrls(profile.serviceUrls, environment)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.9.0",
4
- "topoloPublishedVersion": "0.9.0",
3
+ "version": "0.9.2",
4
+ "topoloPublishedVersion": "0.9.2",
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",