@topolo/sdk 0.4.5 → 0.4.6

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
@@ -137,7 +137,7 @@ var SERVICES = {
137
137
  inventory: "https://inventory.topolo.app",
138
138
  learn: "https://learn-api.topolo.app",
139
139
  localize: "https://localize.topolo.app",
140
- mail: "https://mail.topolo.app",
140
+ mail: "https://mail-api.topolo.app",
141
141
  mdm: "https://mdm-api.topolo.app",
142
142
  messages: "https://messages.topolo.app",
143
143
  nexus: "https://nexus-api.topolo.app",
@@ -975,15 +975,17 @@ var APPLICATIONS = {
975
975
  "mail.topolo.app"
976
976
  ],
977
977
  "routes": [],
978
- "serviceId": "mail"
978
+ "serviceId": null
979
979
  },
980
980
  {
981
981
  "name": "topolo-mail-api",
982
982
  "kind": "worker",
983
- "apiUrl": null,
984
- "domains": [],
983
+ "apiUrl": "https://mail-api.topolo.app",
984
+ "domains": [
985
+ "mail-api.topolo.app"
986
+ ],
985
987
  "routes": [],
986
- "serviceId": null
988
+ "serviceId": "mail"
987
989
  }
988
990
  ]
989
991
  },
@@ -2106,10 +2108,7 @@ function resolveCatalogServiceUrl(entry, options = {}) {
2106
2108
  if (override) return override;
2107
2109
  const apiBaseUrl = firstString(entry.apiBaseUrl, entry.api_base_url);
2108
2110
  if (apiBaseUrl) return apiBaseUrl;
2109
- const bundledUrl = firstBundledServiceUrl(keys);
2110
- const liveUrl = firstString(entry.baseUrl);
2111
- if (bundledUrl && (!liveUrl || sameUrlEnvironment(bundledUrl, liveUrl))) return bundledUrl;
2112
- return liveUrl ?? bundledUrl ?? null;
2111
+ return null;
2113
2112
  }
2114
2113
  function resolveServiceUrl(service, overrides) {
2115
2114
  const override = resolveServiceUrlOverride([service], overrides);
@@ -2151,34 +2150,12 @@ function resolveServiceUrlOverride(keys, overrides) {
2151
2150
  }
2152
2151
  return null;
2153
2152
  }
2154
- function firstBundledServiceUrl(keys) {
2155
- for (const key of keys) {
2156
- const url = DEFAULT_SERVICE_URLS[key];
2157
- if (url) return url;
2158
- }
2159
- return null;
2160
- }
2161
2153
  function firstString(...values) {
2162
2154
  for (const value of values) {
2163
2155
  if (typeof value === "string" && value.trim()) return value.trim();
2164
2156
  }
2165
2157
  return null;
2166
2158
  }
2167
- function sameUrlEnvironment(left, right) {
2168
- return urlEnvironment(left) === urlEnvironment(right);
2169
- }
2170
- function urlEnvironment(value) {
2171
- try {
2172
- const url = new URL(value);
2173
- const host = url.hostname.toLowerCase();
2174
- if (host === "localhost" || host === "127.0.0.1") return "local";
2175
- if (host.endsWith(".stg.topolo.us") || host.includes("topolo-staging")) return "staging";
2176
- if (host.endsWith(".topolo.app") || host.endsWith(".topolo.us")) return "production";
2177
- return "external";
2178
- } catch {
2179
- return "external";
2180
- }
2181
- }
2182
2159
 
2183
2160
  // src/client.ts
2184
2161
  var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
@@ -2351,7 +2328,7 @@ var TopoloClient = class _TopoloClient {
2351
2328
  async resolveLiveCallableService(serviceKey) {
2352
2329
  const catalog = await this.listServices();
2353
2330
  const match = catalog.find((entry) => catalogEntryMatches(entry, serviceKey));
2354
- if (!match || !isCallableCatalogEntry(match)) return null;
2331
+ if (!match) return null;
2355
2332
  const baseUrl = resolveCatalogServiceUrl(match, {
2356
2333
  serviceKey,
2357
2334
  overrides: this.serviceUrls
@@ -2449,7 +2426,6 @@ var TopoloClient = class _TopoloClient {
2449
2426
  slug: typeof s.app_slug === "string" ? s.app_slug : null,
2450
2427
  name: typeof s.name === "string" ? s.name : null,
2451
2428
  description: typeof s.description === "string" ? s.description : null,
2452
- baseUrl: typeof s.base_url === "string" ? s.base_url : null,
2453
2429
  apiBaseUrl: typeof s.api_base_url === "string" ? s.api_base_url : typeof s.apiBaseUrl === "string" ? s.apiBaseUrl : null,
2454
2430
  launchUrl: typeof s.launch_url === "string" ? s.launch_url : typeof s.launchUrl === "string" ? s.launchUrl : null,
2455
2431
  status: typeof s.status === "string" ? s.status : null,
@@ -2536,7 +2512,6 @@ var TopoloClient = class _TopoloClient {
2536
2512
  slug: app.id,
2537
2513
  name: app.name ?? app.id,
2538
2514
  description: null,
2539
- baseUrl: app.productionUrl ?? null,
2540
2515
  apiBaseUrl: null,
2541
2516
  launchUrl: app.productionUrl ?? null,
2542
2517
  status: "bundled",
@@ -2629,13 +2604,6 @@ function catalogEntryLookupKeys(entry) {
2629
2604
  }
2630
2605
  return [...keys];
2631
2606
  }
2632
- function isCallableCatalogEntry(entry) {
2633
- const kind = normalizeLookupKey(entry.surfaceKind || "");
2634
- if (kind === "api" || kind === "technical_service" || kind === "service") return true;
2635
- return Boolean(
2636
- (entry.baseUrl || entry.apiBaseUrl) && catalogEntryLookupKeys(entry).some((key) => Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, key))
2637
- );
2638
- }
2639
2607
  function normalizeActionCatalogEntry(item) {
2640
2608
  if (!item || typeof item !== "object" || Array.isArray(item)) return null;
2641
2609
  const a = item;
package/dist/index.d.cts CHANGED
@@ -104,7 +104,6 @@ interface TopoloServiceCatalogEntry {
104
104
  slug: string | null;
105
105
  name: string | null;
106
106
  description: string | null;
107
- baseUrl: string | null;
108
107
  apiBaseUrl?: string | null;
109
108
  launchUrl?: string | null;
110
109
  status: string | null;
@@ -259,7 +258,7 @@ declare const SERVICES: {
259
258
  readonly inventory: "https://inventory.topolo.app";
260
259
  readonly learn: "https://learn-api.topolo.app";
261
260
  readonly localize: "https://localize.topolo.app";
262
- readonly mail: "https://mail.topolo.app";
261
+ readonly mail: "https://mail-api.topolo.app";
263
262
  readonly mdm: "https://mdm-api.topolo.app";
264
263
  readonly messages: "https://messages.topolo.app";
265
264
  readonly nexus: "https://nexus-api.topolo.app";
@@ -891,14 +890,14 @@ declare const APPLICATIONS: {
891
890
  readonly apiUrl: "https://mail.topolo.app";
892
891
  readonly domains: readonly ["mail.topolo.app"];
893
892
  readonly routes: readonly [];
894
- readonly serviceId: "mail";
893
+ readonly serviceId: null;
895
894
  }, {
896
895
  readonly name: "topolo-mail-api";
897
896
  readonly kind: "worker";
898
- readonly apiUrl: null;
899
- readonly domains: readonly [];
897
+ readonly apiUrl: "https://mail-api.topolo.app";
898
+ readonly domains: readonly ["mail-api.topolo.app"];
900
899
  readonly routes: readonly [];
901
- readonly serviceId: null;
900
+ readonly serviceId: "mail";
902
901
  }];
903
902
  };
904
903
  readonly mdm: {
@@ -1585,7 +1584,6 @@ interface ServiceCatalogUrlEntry {
1585
1584
  serviceId?: string | null;
1586
1585
  slug?: string | null;
1587
1586
  name?: string | null;
1588
- baseUrl?: string | null;
1589
1587
  apiBaseUrl?: string | null;
1590
1588
  launchUrl?: string | null;
1591
1589
  api_base_url?: string | null;
package/dist/index.d.ts CHANGED
@@ -104,7 +104,6 @@ interface TopoloServiceCatalogEntry {
104
104
  slug: string | null;
105
105
  name: string | null;
106
106
  description: string | null;
107
- baseUrl: string | null;
108
107
  apiBaseUrl?: string | null;
109
108
  launchUrl?: string | null;
110
109
  status: string | null;
@@ -259,7 +258,7 @@ declare const SERVICES: {
259
258
  readonly inventory: "https://inventory.topolo.app";
260
259
  readonly learn: "https://learn-api.topolo.app";
261
260
  readonly localize: "https://localize.topolo.app";
262
- readonly mail: "https://mail.topolo.app";
261
+ readonly mail: "https://mail-api.topolo.app";
263
262
  readonly mdm: "https://mdm-api.topolo.app";
264
263
  readonly messages: "https://messages.topolo.app";
265
264
  readonly nexus: "https://nexus-api.topolo.app";
@@ -891,14 +890,14 @@ declare const APPLICATIONS: {
891
890
  readonly apiUrl: "https://mail.topolo.app";
892
891
  readonly domains: readonly ["mail.topolo.app"];
893
892
  readonly routes: readonly [];
894
- readonly serviceId: "mail";
893
+ readonly serviceId: null;
895
894
  }, {
896
895
  readonly name: "topolo-mail-api";
897
896
  readonly kind: "worker";
898
- readonly apiUrl: null;
899
- readonly domains: readonly [];
897
+ readonly apiUrl: "https://mail-api.topolo.app";
898
+ readonly domains: readonly ["mail-api.topolo.app"];
900
899
  readonly routes: readonly [];
901
- readonly serviceId: null;
900
+ readonly serviceId: "mail";
902
901
  }];
903
902
  };
904
903
  readonly mdm: {
@@ -1585,7 +1584,6 @@ interface ServiceCatalogUrlEntry {
1585
1584
  serviceId?: string | null;
1586
1585
  slug?: string | null;
1587
1586
  name?: string | null;
1588
- baseUrl?: string | null;
1589
1587
  apiBaseUrl?: string | null;
1590
1588
  launchUrl?: string | null;
1591
1589
  api_base_url?: string | null;
package/dist/index.js CHANGED
@@ -82,7 +82,7 @@ var SERVICES = {
82
82
  inventory: "https://inventory.topolo.app",
83
83
  learn: "https://learn-api.topolo.app",
84
84
  localize: "https://localize.topolo.app",
85
- mail: "https://mail.topolo.app",
85
+ mail: "https://mail-api.topolo.app",
86
86
  mdm: "https://mdm-api.topolo.app",
87
87
  messages: "https://messages.topolo.app",
88
88
  nexus: "https://nexus-api.topolo.app",
@@ -920,15 +920,17 @@ var APPLICATIONS = {
920
920
  "mail.topolo.app"
921
921
  ],
922
922
  "routes": [],
923
- "serviceId": "mail"
923
+ "serviceId": null
924
924
  },
925
925
  {
926
926
  "name": "topolo-mail-api",
927
927
  "kind": "worker",
928
- "apiUrl": null,
929
- "domains": [],
928
+ "apiUrl": "https://mail-api.topolo.app",
929
+ "domains": [
930
+ "mail-api.topolo.app"
931
+ ],
930
932
  "routes": [],
931
- "serviceId": null
933
+ "serviceId": "mail"
932
934
  }
933
935
  ]
934
936
  },
@@ -2051,10 +2053,7 @@ function resolveCatalogServiceUrl(entry, options = {}) {
2051
2053
  if (override) return override;
2052
2054
  const apiBaseUrl = firstString(entry.apiBaseUrl, entry.api_base_url);
2053
2055
  if (apiBaseUrl) return apiBaseUrl;
2054
- const bundledUrl = firstBundledServiceUrl(keys);
2055
- const liveUrl = firstString(entry.baseUrl);
2056
- if (bundledUrl && (!liveUrl || sameUrlEnvironment(bundledUrl, liveUrl))) return bundledUrl;
2057
- return liveUrl ?? bundledUrl ?? null;
2056
+ return null;
2058
2057
  }
2059
2058
  function resolveServiceUrl(service, overrides) {
2060
2059
  const override = resolveServiceUrlOverride([service], overrides);
@@ -2096,34 +2095,12 @@ function resolveServiceUrlOverride(keys, overrides) {
2096
2095
  }
2097
2096
  return null;
2098
2097
  }
2099
- function firstBundledServiceUrl(keys) {
2100
- for (const key of keys) {
2101
- const url = DEFAULT_SERVICE_URLS[key];
2102
- if (url) return url;
2103
- }
2104
- return null;
2105
- }
2106
2098
  function firstString(...values) {
2107
2099
  for (const value of values) {
2108
2100
  if (typeof value === "string" && value.trim()) return value.trim();
2109
2101
  }
2110
2102
  return null;
2111
2103
  }
2112
- function sameUrlEnvironment(left, right) {
2113
- return urlEnvironment(left) === urlEnvironment(right);
2114
- }
2115
- function urlEnvironment(value) {
2116
- try {
2117
- const url = new URL(value);
2118
- const host = url.hostname.toLowerCase();
2119
- if (host === "localhost" || host === "127.0.0.1") return "local";
2120
- if (host.endsWith(".stg.topolo.us") || host.includes("topolo-staging")) return "staging";
2121
- if (host.endsWith(".topolo.app") || host.endsWith(".topolo.us")) return "production";
2122
- return "external";
2123
- } catch {
2124
- return "external";
2125
- }
2126
- }
2127
2104
 
2128
2105
  // src/client.ts
2129
2106
  var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
@@ -2296,7 +2273,7 @@ var TopoloClient = class _TopoloClient {
2296
2273
  async resolveLiveCallableService(serviceKey) {
2297
2274
  const catalog = await this.listServices();
2298
2275
  const match = catalog.find((entry) => catalogEntryMatches(entry, serviceKey));
2299
- if (!match || !isCallableCatalogEntry(match)) return null;
2276
+ if (!match) return null;
2300
2277
  const baseUrl = resolveCatalogServiceUrl(match, {
2301
2278
  serviceKey,
2302
2279
  overrides: this.serviceUrls
@@ -2394,7 +2371,6 @@ var TopoloClient = class _TopoloClient {
2394
2371
  slug: typeof s.app_slug === "string" ? s.app_slug : null,
2395
2372
  name: typeof s.name === "string" ? s.name : null,
2396
2373
  description: typeof s.description === "string" ? s.description : null,
2397
- baseUrl: typeof s.base_url === "string" ? s.base_url : null,
2398
2374
  apiBaseUrl: typeof s.api_base_url === "string" ? s.api_base_url : typeof s.apiBaseUrl === "string" ? s.apiBaseUrl : null,
2399
2375
  launchUrl: typeof s.launch_url === "string" ? s.launch_url : typeof s.launchUrl === "string" ? s.launchUrl : null,
2400
2376
  status: typeof s.status === "string" ? s.status : null,
@@ -2481,7 +2457,6 @@ var TopoloClient = class _TopoloClient {
2481
2457
  slug: app.id,
2482
2458
  name: app.name ?? app.id,
2483
2459
  description: null,
2484
- baseUrl: app.productionUrl ?? null,
2485
2460
  apiBaseUrl: null,
2486
2461
  launchUrl: app.productionUrl ?? null,
2487
2462
  status: "bundled",
@@ -2574,13 +2549,6 @@ function catalogEntryLookupKeys(entry) {
2574
2549
  }
2575
2550
  return [...keys];
2576
2551
  }
2577
- function isCallableCatalogEntry(entry) {
2578
- const kind = normalizeLookupKey(entry.surfaceKind || "");
2579
- if (kind === "api" || kind === "technical_service" || kind === "service") return true;
2580
- return Boolean(
2581
- (entry.baseUrl || entry.apiBaseUrl) && catalogEntryLookupKeys(entry).some((key) => Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, key))
2582
- );
2583
- }
2584
2552
  function normalizeActionCatalogEntry(item) {
2585
2553
  if (!item || typeof item !== "object" || Array.isArray(item)) return null;
2586
2554
  const a = item;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -813,15 +813,17 @@ export const APPLICATIONS = {
813
813
  "mail.topolo.app"
814
814
  ],
815
815
  "routes": [],
816
- "serviceId": "mail"
816
+ "serviceId": null
817
817
  },
818
818
  {
819
819
  "name": "topolo-mail-api",
820
820
  "kind": "worker",
821
- "apiUrl": null,
822
- "domains": [],
821
+ "apiUrl": "https://mail-api.topolo.app",
822
+ "domains": [
823
+ "mail-api.topolo.app"
824
+ ],
823
825
  "routes": [],
824
- "serviceId": null
826
+ "serviceId": "mail"
825
827
  }
826
828
  ]
827
829
  },
@@ -25,7 +25,8 @@ const MAIL_CATALOG = {
25
25
  service_id: 'srv_mail',
26
26
  app_slug: 'topolo-mail',
27
27
  name: 'Topolo Mail',
28
- base_url: 'https://mail-api.topolo.app',
28
+ api_base_url: 'https://mail-api.topolo.app',
29
+ launch_url: 'https://mail.topolo.app',
29
30
  surface_kind: 'api',
30
31
  status: 'active',
31
32
  granted_permissions: ['srv_mail.messages:read'],
@@ -376,7 +377,7 @@ describe('TopoloClient.getServiceIdBySlug', () => {
376
377
 
377
378
  it('falls back to /api/services/by-slug/:slug for unknown slugs', async () => {
378
379
  const { impl, calls } = stubFetch([
379
- { body: { success: true, data: { service_id: 'service_abc123', base_url: 'https://x' } } },
380
+ { body: { success: true, data: { service_id: 'service_abc123', api_base_url: 'https://x-api' } } },
380
381
  ]);
381
382
  const client = freshClient(impl, { auth: 'https://auth.example.com' });
382
383
  const id = await client.getServiceIdBySlug('external-service');
@@ -452,7 +453,8 @@ describe('TopoloClient.listServices', () => {
452
453
  app_slug: 'topolo-director',
453
454
  name: 'Topolo Director',
454
455
  description: 'Demo control plane',
455
- base_url: 'https://director.topolo.app',
456
+ api_base_url: 'https://director-api.topolo.app',
457
+ launch_url: 'https://director.topolo.app',
456
458
  status: 'active',
457
459
  surface_kind: 'application',
458
460
  launchable: true,
@@ -476,9 +478,8 @@ describe('TopoloClient.listServices', () => {
476
478
  slug: 'topolo-director',
477
479
  name: 'Topolo Director',
478
480
  description: 'Demo control plane',
479
- baseUrl: 'https://director.topolo.app',
480
- apiBaseUrl: null,
481
- launchUrl: null,
481
+ apiBaseUrl: 'https://director-api.topolo.app',
482
+ launchUrl: 'https://director.topolo.app',
482
483
  status: 'active',
483
484
  surfaceKind: 'application',
484
485
  launchable: true,
@@ -514,7 +515,8 @@ describe('TopoloClient.listServices', () => {
514
515
  service_id: 'srv_mail',
515
516
  app_slug: 'topolo-mail',
516
517
  name: 'Topolo Mail',
517
- base_url: 'https://mail.topolo.app',
518
+ api_base_url: 'https://mail-api.topolo.app',
519
+ launch_url: 'https://mail.topolo.app',
518
520
  surface_kind: 'application',
519
521
  status: 'active',
520
522
  granted_permissions: ['srv_mail.messages:read'],
@@ -535,7 +537,7 @@ describe('TopoloClient.listServices', () => {
535
537
  await client.request({ service: 'mail', path: '/api/health' });
536
538
 
537
539
  expect(calls[0]!.url).toBe('https://auth.example.com/api/services/catalog');
538
- expect(calls[1]!.url).toBe('https://mail.topolo.app/api/health');
540
+ expect(calls[1]!.url).toBe('https://mail-api.topolo.app/api/health');
539
541
  });
540
542
 
541
543
  it('routes known split-surface services to the callable API URL', async () => {
@@ -548,7 +550,8 @@ describe('TopoloClient.listServices', () => {
548
550
  service_id: 'srv_crm',
549
551
  app_slug: 'topolo-crm',
550
552
  name: 'Topolo CRM',
551
- base_url: 'https://crm.topolo.app',
553
+ api_base_url: 'https://crm-api.topolo.app',
554
+ launch_url: 'https://crm.topolo.app',
552
555
  surface_kind: 'application',
553
556
  status: 'active',
554
557
  granted_permissions: ['srv_crm.contacts:read'],
@@ -582,8 +585,8 @@ describe('TopoloClient.listServices', () => {
582
585
  service_id: 'srv_future',
583
586
  app_slug: 'topolo-future',
584
587
  name: 'Future',
585
- base_url: 'https://future.topolo.app',
586
588
  api_base_url: 'https://future-api.topolo.app',
589
+ launch_url: 'https://future.topolo.app',
587
590
  surface_kind: 'api',
588
591
  status: 'active',
589
592
  granted_permissions: ['srv_future.read:all'],
@@ -616,7 +619,8 @@ describe('TopoloClient.listServices', () => {
616
619
  service_id: 'srv_crm',
617
620
  app_slug: 'topolo-crm',
618
621
  name: 'Topolo CRM',
619
- base_url: 'https://crm-api.topolo.app',
622
+ api_base_url: 'https://crm-api.topolo.app',
623
+ launch_url: 'https://crm.topolo.app',
620
624
  surface_kind: 'api',
621
625
  status: 'active',
622
626
  granted_permissions: ['srv_crm.contacts:read'],
@@ -649,7 +653,7 @@ describe('TopoloClient.listServices', () => {
649
653
  service_id: 'srv_future_app',
650
654
  app_slug: 'topolo-future-app',
651
655
  name: 'Future App',
652
- base_url: 'https://future-app.topolo.app',
656
+ launch_url: 'https://future-app.topolo.app',
653
657
  surface_kind: 'application',
654
658
  status: 'active',
655
659
  granted_permissions: ['srv_future_app.launch:read'],
@@ -682,7 +686,8 @@ describe('TopoloClient.listServices', () => {
682
686
  service_id: 'srv_future',
683
687
  app_slug: 'topolo-warehouse',
684
688
  name: 'Warehouse',
685
- base_url: 'https://warehouse.topolo.app',
689
+ api_base_url: 'https://warehouse.topolo.app',
690
+ launch_url: 'https://warehouse.topolo.app',
686
691
  surface_kind: 'api',
687
692
  status: 'active',
688
693
  granted_permissions: ['srv_future.read:all'],
@@ -741,7 +746,7 @@ describe('TopoloClient action catalog', () => {
741
746
  await client.callAction('messages.list', { mailboxId: 'primary', q: 'Ada', page: 2 });
742
747
  const call = requestCalls(calls)[0]!;
743
748
  const url = new URL(call.url);
744
- expect(url.toString()).toBe('https://mail.topolo.app/api/mail/mailboxes/primary/messages?q=Ada&page=2');
749
+ expect(url.toString()).toBe('https://mail-api.topolo.app/api/mail/mailboxes/primary/messages?q=Ada&page=2');
745
750
  expect(call.init.method).toBe('GET');
746
751
  const headers = new Headers(call.init.headers);
747
752
  expect(headers.get('X-Topolo-Action-Id')).toBe('srv_mail.messages.list');
package/src/client.ts CHANGED
@@ -106,7 +106,6 @@ export interface TopoloServiceCatalogEntry {
106
106
  slug: string | null;
107
107
  name: string | null;
108
108
  description: string | null;
109
- baseUrl: string | null;
110
109
  apiBaseUrl?: string | null;
111
110
  launchUrl?: string | null;
112
111
  status: string | null;
@@ -328,7 +327,7 @@ export class TopoloClient {
328
327
  private async resolveLiveCallableService(serviceKey: string): Promise<{ serviceKey: string; baseUrl: string } | null> {
329
328
  const catalog = await this.listServices();
330
329
  const match = catalog.find((entry) => catalogEntryMatches(entry, serviceKey));
331
- if (!match || !isCallableCatalogEntry(match)) return null;
330
+ if (!match) return null;
332
331
  const baseUrl = resolveCatalogServiceUrl(match, {
333
332
  serviceKey,
334
333
  overrides: this.serviceUrls,
@@ -454,7 +453,6 @@ export class TopoloClient {
454
453
  name: typeof s.name === 'string' ? s.name : null,
455
454
  description:
456
455
  typeof s.description === 'string' ? s.description : null,
457
- baseUrl: typeof s.base_url === 'string' ? s.base_url : null,
458
456
  apiBaseUrl:
459
457
  typeof s.api_base_url === 'string'
460
458
  ? s.api_base_url
@@ -573,7 +571,6 @@ export class TopoloClient {
573
571
  slug: app.id,
574
572
  name: app.name ?? app.id,
575
573
  description: null,
576
- baseUrl: app.productionUrl ?? null,
577
574
  apiBaseUrl: null,
578
575
  launchUrl: app.productionUrl ?? null,
579
576
  status: 'bundled',
@@ -695,15 +692,6 @@ function catalogEntryLookupKeys(entry: TopoloServiceCatalogEntry): string[] {
695
692
  return [...keys];
696
693
  }
697
694
 
698
- function isCallableCatalogEntry(entry: TopoloServiceCatalogEntry): boolean {
699
- const kind = normalizeLookupKey(entry.surfaceKind || '');
700
- if (kind === 'api' || kind === 'technical_service' || kind === 'service') return true;
701
- return Boolean(
702
- (entry.baseUrl || entry.apiBaseUrl) &&
703
- catalogEntryLookupKeys(entry).some((key) => Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, key)),
704
- );
705
- }
706
-
707
695
  function normalizeActionCatalogEntry(item: unknown): TopoloActionCatalogEntry | null {
708
696
  if (!item || typeof item !== 'object' || Array.isArray(item)) return null;
709
697
  const a = item as Record<string, unknown>;
@@ -22,7 +22,8 @@ function stubFetch(responses: Array<{ status?: number; body?: unknown }>) {
22
22
  service_id: 'srv_p2p',
23
23
  app_slug: 'topolo-p2p',
24
24
  name: 'Topolo P2P',
25
- base_url: 'https://p2p.topolo.app',
25
+ api_base_url: 'https://p2p.topolo.app',
26
+ launch_url: 'https://p2p.topolo.app',
26
27
  surface_kind: 'api',
27
28
  status: 'active',
28
29
  granted_permissions: ['srv_p2p.directory:read'],
@@ -27,7 +27,7 @@ export const SERVICES = {
27
27
  inventory: "https://inventory.topolo.app",
28
28
  learn: "https://learn-api.topolo.app",
29
29
  localize: "https://localize.topolo.app",
30
- mail: "https://mail.topolo.app",
30
+ mail: "https://mail-api.topolo.app",
31
31
  mdm: "https://mdm-api.topolo.app",
32
32
  messages: "https://messages.topolo.app",
33
33
  nexus: "https://nexus-api.topolo.app",
@@ -70,7 +70,7 @@ describe('service registry', () => {
70
70
  books: 'https://books.topolo.app',
71
71
  consent: 'https://consent.topolo.app',
72
72
  feed: 'https://feed-api.topolo.app',
73
- mail: 'https://mail.topolo.app',
73
+ mail: 'https://mail-api.topolo.app',
74
74
  one: 'https://one.topolo.app',
75
75
  web: 'https://web-api.topolo.app',
76
76
  });
@@ -99,30 +99,31 @@ describe('service registry', () => {
99
99
  }
100
100
  });
101
101
 
102
- it('resolves known split-surface services to the generated callable URL', () => {
102
+ it('resolves services from explicit catalog API URLs', () => {
103
103
  expect(resolveCatalogServiceUrl({
104
104
  serviceId: 'srv_crm',
105
105
  slug: 'topolo-crm',
106
106
  name: 'Topolo CRM',
107
- baseUrl: 'https://crm.topolo.app',
107
+ launchUrl: 'https://crm.topolo.app',
108
+ apiBaseUrl: 'https://crm-api.topolo.app',
108
109
  }, { serviceKey: 'crm' })).toBe('https://crm-api.topolo.app');
109
110
  });
110
111
 
111
- it('uses a live staging URL instead of a production bundled default', () => {
112
+ it('does not infer callable URLs from launcher URLs', () => {
112
113
  expect(resolveCatalogServiceUrl({
113
114
  serviceId: 'srv_crm',
114
115
  slug: 'topolo-crm',
115
116
  name: 'Topolo CRM',
116
- baseUrl: 'https://crm.stg.topolo.us',
117
- }, { serviceKey: 'crm' })).toBe('https://crm.stg.topolo.us');
117
+ launchUrl: 'https://crm.stg.topolo.us',
118
+ }, { serviceKey: 'crm' })).toBeNull();
118
119
  });
119
120
 
120
- it('prefers explicit catalog API URLs over launcher URLs', () => {
121
+ it('prefers explicit catalog API URLs over launch URLs', () => {
121
122
  expect(resolveCatalogServiceUrl({
122
123
  serviceId: 'srv_future',
123
124
  slug: 'topolo-future',
124
125
  name: 'Future',
125
- baseUrl: 'https://future.topolo.app',
126
+ launchUrl: 'https://future.topolo.app',
126
127
  apiBaseUrl: 'https://future-api.topolo.app',
127
128
  })).toBe('https://future-api.topolo.app');
128
129
  });
package/src/services.ts CHANGED
@@ -51,7 +51,6 @@ export interface ServiceCatalogUrlEntry {
51
51
  serviceId?: string | null;
52
52
  slug?: string | null;
53
53
  name?: string | null;
54
- baseUrl?: string | null;
55
54
  apiBaseUrl?: string | null;
56
55
  launchUrl?: string | null;
57
56
  api_base_url?: string | null;
@@ -72,11 +71,7 @@ export function resolveCatalogServiceUrl(
72
71
  const apiBaseUrl = firstString(entry.apiBaseUrl, entry.api_base_url);
73
72
  if (apiBaseUrl) return apiBaseUrl;
74
73
 
75
- const bundledUrl = firstBundledServiceUrl(keys);
76
- const liveUrl = firstString(entry.baseUrl);
77
- if (bundledUrl && (!liveUrl || sameUrlEnvironment(bundledUrl, liveUrl))) return bundledUrl;
78
-
79
- return liveUrl ?? bundledUrl ?? null;
74
+ return null;
80
75
  }
81
76
 
82
77
  export function resolveServiceUrl(
@@ -135,34 +130,9 @@ function resolveServiceUrlOverride(
135
130
  return null;
136
131
  }
137
132
 
138
- function firstBundledServiceUrl(keys: string[]): string | null {
139
- for (const key of keys) {
140
- const url = DEFAULT_SERVICE_URLS[key as ServiceId];
141
- if (url) return url;
142
- }
143
- return null;
144
- }
145
-
146
133
  function firstString(...values: Array<string | null | undefined>): string | null {
147
134
  for (const value of values) {
148
135
  if (typeof value === 'string' && value.trim()) return value.trim();
149
136
  }
150
137
  return null;
151
138
  }
152
-
153
- function sameUrlEnvironment(left: string, right: string): boolean {
154
- return urlEnvironment(left) === urlEnvironment(right);
155
- }
156
-
157
- function urlEnvironment(value: string): 'staging' | 'production' | 'local' | 'external' {
158
- try {
159
- const url = new URL(value);
160
- const host = url.hostname.toLowerCase();
161
- if (host === 'localhost' || host === '127.0.0.1') return 'local';
162
- if (host.endsWith('.stg.topolo.us') || host.includes('topolo-staging')) return 'staging';
163
- if (host.endsWith('.topolo.app') || host.endsWith('.topolo.us')) return 'production';
164
- return 'external';
165
- } catch {
166
- return 'external';
167
- }
168
- }