@topolo/sdk 0.9.10 → 0.10.0

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/README.md CHANGED
@@ -97,22 +97,27 @@ traceable to a specific agent invocation.
97
97
  Agents should use the action catalog for app-specific operations so new
98
98
  services and actions become usable without an SDK, CLI, or MCP release.
99
99
 
100
- ## Application catalog
101
-
102
- `APPLICATIONS` describes every Topolo platform application discovered from the
103
- PlatformApplications metadata, including Worker apps that do not expose a
104
- callable app API. `DEFAULT_APP_URLS` is the bundled callable API service
105
- snapshot generated from `topolo.cloudcontrol.json`.
106
-
107
- For agent-scale fleets, the bundle is packaging metadata, not an authorization
108
- source. `TopoloClient.listServices()` always calls the live TopoloAuth catalog
109
- with the current credential and returns only services that credential can use in
110
- its organization, including the granted permissions. `TopoloClient.request()`
111
- uses that credential-scoped catalog before routing any non-Auth service, so a
112
- bundled app ID is only a convenient alias after Auth confirms access.
113
-
114
- `listBundledServices()` is available for packaging/audit tooling that needs the
115
- generated snapshot. Do not use it to decide what an end user or agent may call.
100
+ ## Application directory (live registry)
101
+
102
+ The platform scales to millions of constantly-changing applications, so the
103
+ SDK ships NO compiled application map that decides behavior. The live
104
+ credential-scoped registry is the source of truth:
105
+
106
+ - `TopoloClient.searchServices()` / `getService()` enumerate and resolve
107
+ applications for the current credential.
108
+ - `listApplicationDirectory(client)` walks the registry to exhaustion and
109
+ returns friendly ids derived from live slugs (`topolo-notify` → `notify`).
110
+ - `resolveApplicationDirectoryEntry(client, application)` resolves one app by
111
+ id, slug, or name — including apps registered after this package was built.
112
+ - `friendlyAppId(entry)` derives the display id from a live catalog entry.
113
+
114
+ `DEFAULT_APP_URLS` now contains ONLY the `auth` and `developers` bootstrap
115
+ seeds — the endpoints that must be reachable before the registry can be
116
+ consulted. `APPLICATIONS` remains as a frozen static fallback snapshot used
117
+ only when the registry is unreachable (it can enrich repo/deploy metadata for
118
+ registry-confirmed apps, but never gates or rejects a registry-known app).
119
+ `listBundledServices()` reads that snapshot and is deprecated for anything
120
+ behavior-deciding.
116
121
 
117
122
  ## Action catalog
118
123
 
package/dist/index.cjs CHANGED
@@ -39,8 +39,10 @@ __export(index_exports, {
39
39
  TopoloSdkError: () => TopoloSdkError,
40
40
  WorkspacesModule: () => WorkspacesModule,
41
41
  actionContractCompleteness: () => actionContractCompleteness,
42
+ applicationEntryFromCatalog: () => applicationEntryFromCatalog,
42
43
  applicationRequirementScopes: () => applicationRequirementScopes,
43
44
  auditAllApplicationRequirements: () => auditAllApplicationRequirements,
45
+ auditApplicationEntries: () => auditApplicationEntries,
44
46
  auditApplicationRequirements: () => auditApplicationRequirements,
45
47
  createTopolo: () => createTopolo,
46
48
  createTopoloWidgetError: () => createTopoloWidgetError,
@@ -52,12 +54,17 @@ __export(index_exports, {
52
54
  defineTopoloStatsWidget: () => defineTopoloStatsWidget,
53
55
  digestTopoloActionCatalog: () => digestTopoloActionCatalog,
54
56
  enrichActionContract: () => enrichActionContract,
57
+ formatDirectoryApplicationIds: () => formatDirectoryApplicationIds,
58
+ friendlyAppId: () => friendlyAppId,
59
+ listApplicationDirectory: () => listApplicationDirectory,
55
60
  parseTopoloActionUploadContract: () => parseTopoloActionUploadContract,
56
61
  prepareTopoloActionBase64UploadInput: () => prepareTopoloActionBase64UploadInput,
57
62
  prepareTopoloActionUploadInput: () => prepareTopoloActionUploadInput,
58
63
  requirementsForApplication: () => requirementsForApplication,
64
+ resolveApplicationDirectoryEntry: () => resolveApplicationDirectoryEntry,
59
65
  resolveCatalogServiceUrl: () => resolveCatalogServiceUrl,
60
66
  resolveServiceUrl: () => resolveServiceUrl,
67
+ staticApplicationDirectory: () => staticApplicationDirectory,
61
68
  validateTopoloActionInput: () => validateTopoloActionInput,
62
69
  validateTopoloWidgetResponse: () => validateTopoloWidgetResponse
63
70
  });
@@ -166,62 +173,13 @@ var TopoloHttpError = class extends TopoloSdkError {
166
173
  }
167
174
  };
168
175
 
169
- // src/services.generated.ts
176
+ // src/bootstrap-services.ts
170
177
  var APP_API_URLS = {
171
- agent: "https://agent.topolo.app",
172
178
  auth: "https://auth.topolo.app",
173
- backup: "https://backup.topolo.app",
174
- blog: "https://blog.topolo.app",
175
- books: "https://books.topolo.app",
176
- brand: "https://brand.topolo.app",
177
- bugfix: "https://bugfix.topolo.app",
178
- bytes: "https://bytes.topolo.app",
179
- calendar: "https://calendar.topolo.app",
180
- campaigns: "https://campaigns.topolo.app",
181
- capacity: "https://capacity.topolo.app",
182
- chat: "https://chat.topolo.app",
183
- commerce: "https://commerce.topolo.app",
184
- compose: "https://compose.topolo.app",
185
- consent: "https://consent.topolo.app",
186
- crm: "https://crm.topolo.app",
187
- design: "https://design.topolo.app",
188
- developers: "https://developers.topolo.app",
189
- director: "https://director.topolo.app",
190
- feed: "https://feed.topolo.app",
191
- flow: "https://flow.topolo.app",
192
- forecast: "https://forecast.topolo.app",
193
- forms: "https://forms.topolo.app",
194
- home: "https://home.topolo.app",
195
- insights: "https://insights.topolo.app",
196
- inventory: "https://inventory.topolo.app",
197
- learn: "https://learn.topolo.app",
198
- localize: "https://localize.topolo.app",
199
- mail: "https://mail.topolo.app",
200
- mdm: "https://mdm.topolo.app",
201
- messages: "https://messages.topolo.app",
202
- nexus: "https://nexus.topolo.app",
203
- notify: "https://notify.topolo.app",
204
- observability_watch: "https://observability-watch.topolo.app",
205
- one: "https://www.topolo.app",
206
- p2p: "https://p2p.topolo.app",
207
- pay: "https://pay.topolo.app",
208
- people: "https://people.topolo.app",
209
- "quro.api": "https://api.ol0.me",
210
- "quro.redirect": "https://ol0.me",
211
- roadmapper: "https://roadmapper.topolo.app",
212
- sign: "https://sign.topolo.app",
213
- social_studio: "https://studio.topolo.app",
214
- socialize: "https://socialize.topolo.app",
215
- spaces: "https://spaces.topolo.app",
216
- status: "https://status.topolo.app",
217
- success: "https://success.topolo.app",
218
- support: "https://support.topolo.app",
219
- survey: "https://survey.topolo.app",
220
- voice: "https://voice.topolo.app",
221
- web: "https://web.topolo.app"
179
+ developers: "https://developers.topolo.app"
222
180
  };
223
181
 
224
- // src/applications.generated.ts
182
+ // src/applications-fallback.ts
225
183
  var APPLICATIONS = {
226
184
  "admin": {
227
185
  "id": "admin",
@@ -1947,8 +1905,148 @@ var APPLICATIONS = {
1947
1905
  }
1948
1906
  };
1949
1907
 
1908
+ // src/application-directory.ts
1909
+ function friendlyAppId(entry) {
1910
+ for (const value of [entry.slug, entry.name, entry.appId]) {
1911
+ if (typeof value !== "string" || !value.trim()) continue;
1912
+ const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
1913
+ const withoutPrefix = normalized.replace(/^(?:app[_-])?topolo[-_]+/, "");
1914
+ if (withoutPrefix) return withoutPrefix;
1915
+ }
1916
+ return entry.appId;
1917
+ }
1918
+ function idVariants(value) {
1919
+ const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
1920
+ return [.../* @__PURE__ */ new Set([
1921
+ normalized,
1922
+ normalized.replace(/-/g, "_"),
1923
+ normalized.replace(/_/g, "-")
1924
+ ])].filter(Boolean);
1925
+ }
1926
+ var STATIC_APPLICATIONS = APPLICATIONS;
1927
+ function staticApplicationForId(id) {
1928
+ for (const variant of idVariants(id)) {
1929
+ const entry = STATIC_APPLICATIONS[variant];
1930
+ if (entry) return entry;
1931
+ }
1932
+ return null;
1933
+ }
1934
+ function applicationEntryFromCatalog(live) {
1935
+ const id = friendlyAppId(live);
1936
+ return {
1937
+ id,
1938
+ appDir: "-",
1939
+ name: live.name ?? live.slug ?? live.appId,
1940
+ packageName: null,
1941
+ productionUrl: live.launchUrl ?? live.apiBaseUrl ?? null,
1942
+ services: live.apiBaseUrl ? [id] : [],
1943
+ deployTargets: []
1944
+ };
1945
+ }
1946
+ var DIRECTORY_PAGE_LIMIT = 100;
1947
+ var DIRECTORY_MAX_PAGES = 100;
1948
+ function staticApplicationDirectory() {
1949
+ const applications = Object.entries(STATIC_APPLICATIONS).map(([id, application]) => ({
1950
+ id,
1951
+ application,
1952
+ source: "static",
1953
+ live: null
1954
+ })).sort((left, right) => left.id.localeCompare(right.id));
1955
+ return { source: "static_fallback", applications };
1956
+ }
1957
+ function directoryApplicationFromLive(live) {
1958
+ const id = friendlyAppId(live);
1959
+ return {
1960
+ id,
1961
+ // Prefer the static snapshot's richer repo/deploy metadata when the live
1962
+ // registry confirms the app; synthesize from the live entry otherwise.
1963
+ application: staticApplicationForId(id) ?? applicationEntryFromCatalog(live),
1964
+ source: "live",
1965
+ live
1966
+ };
1967
+ }
1968
+ async function listApplicationDirectory(client) {
1969
+ if (!client) return staticApplicationDirectory();
1970
+ let services;
1971
+ try {
1972
+ services = [];
1973
+ let cursor;
1974
+ for (let page = 0; page < DIRECTORY_MAX_PAGES; page += 1) {
1975
+ const result = await client.searchServices({
1976
+ ...cursor ? { cursor } : {},
1977
+ limit: DIRECTORY_PAGE_LIMIT
1978
+ });
1979
+ services.push(...result.services);
1980
+ if (!result.page.nextCursor) break;
1981
+ cursor = result.page.nextCursor;
1982
+ }
1983
+ } catch {
1984
+ return staticApplicationDirectory();
1985
+ }
1986
+ const seen = /* @__PURE__ */ new Map();
1987
+ for (const live of services) {
1988
+ const entry = directoryApplicationFromLive(live);
1989
+ if (!seen.has(entry.id)) seen.set(entry.id, entry);
1990
+ }
1991
+ return {
1992
+ source: "live",
1993
+ applications: [...seen.values()].sort((left, right) => left.id.localeCompare(right.id))
1994
+ };
1995
+ }
1996
+ function matchesDirectoryApplication(app, needle) {
1997
+ const candidates = new Set(idVariants(needle));
1998
+ const keys = [
1999
+ app.id,
2000
+ app.application.id,
2001
+ app.application.name,
2002
+ app.live?.appId,
2003
+ app.live?.slug,
2004
+ app.live?.name
2005
+ ];
2006
+ for (const key of keys) {
2007
+ if (typeof key !== "string" || !key.trim()) continue;
2008
+ for (const variant of idVariants(key)) {
2009
+ if (candidates.has(variant)) return true;
2010
+ }
2011
+ for (const variant of idVariants(friendlyAppId({ appId: key }))) {
2012
+ if (candidates.has(variant)) return true;
2013
+ }
2014
+ }
2015
+ return false;
2016
+ }
2017
+ function formatDirectoryApplicationIds(directory) {
2018
+ const ids = directory.applications.map((app) => app.id).sort();
2019
+ const preview = ids.slice(0, 50).join(", ");
2020
+ const suffix = ids.length > 50 ? `, ... +${ids.length - 50} more` : "";
2021
+ const label = directory.source === "live" ? "Applications available to this credential" : "Applications in the bundled static snapshot (live registry unreachable)";
2022
+ return `${label}: ${preview}${suffix}`;
2023
+ }
2024
+ async function resolveApplicationDirectoryEntry(client, application) {
2025
+ const needle = typeof application === "string" ? application.trim() : "";
2026
+ if (!needle) {
2027
+ throw new TopoloSdkError("unknown_application", "application is required");
2028
+ }
2029
+ if (client) {
2030
+ let live = null;
2031
+ try {
2032
+ live = await client.getService(needle);
2033
+ } catch {
2034
+ live = null;
2035
+ }
2036
+ if (live) return directoryApplicationFromLive(live);
2037
+ }
2038
+ const directory = await listApplicationDirectory(client);
2039
+ const match = directory.applications.find((app) => matchesDirectoryApplication(app, needle));
2040
+ if (match) return match;
2041
+ throw new TopoloSdkError(
2042
+ "unknown_application",
2043
+ `Unknown application "${application}". ${formatDirectoryApplicationIds(directory)}`
2044
+ );
2045
+ }
2046
+
1950
2047
  // src/application-requirements.ts
1951
- var APPLICATION_REQUIREMENTS_VERSION = "2026-06-07.1";
2048
+ var STATIC_APPLICATIONS2 = APPLICATIONS;
2049
+ var APPLICATION_REQUIREMENTS_VERSION = "2026-08-11.1";
1952
2050
  var APPLICATION_REQUIREMENTS = [
1953
2051
  {
1954
2052
  id: "platform-metadata",
@@ -1958,10 +2056,10 @@ var APPLICATION_REQUIREMENTS = [
1958
2056
  evidence: [
1959
2057
  "topolo.cloudcontrol.json exists for every deployed app surface",
1960
2058
  "package.json names the package or app when the repo ships code",
1961
- "The SDK application catalog exposes the app through topolo apps and MCP discovery"
2059
+ "The live platform registry exposes the app through topolo apps and MCP discovery"
1962
2060
  ],
1963
2061
  implementation: [
1964
- "Add the app to the SDK application catalog generator before exposing it to agents",
2062
+ "Register the app in the live platform registry (Auth service catalog) before exposing it to agents",
1965
2063
  "Keep production URLs, Worker names, Pages projects, routes, domains, and bindings current in CloudControl metadata",
1966
2064
  "Do not leave a new Topolo* app directory without an explicit application ID"
1967
2065
  ]
@@ -2036,7 +2134,7 @@ var APPLICATION_REQUIREMENTS = [
2036
2134
  implementation: [
2037
2135
  "Add production Worker api_url metadata and sdk_app_id for every agent-callable API target",
2038
2136
  "Mark browser, documentation, and runtime-only Worker targets with agent_callable:false",
2039
- "Expose stable app IDs through generated DEFAULT_APP_URLS and live catalog discovery",
2137
+ "Expose stable app IDs through live catalog discovery",
2040
2138
  "Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes"
2041
2139
  ]
2042
2140
  },
@@ -2156,15 +2254,24 @@ function applicationRequirementScopes(application) {
2156
2254
  }
2157
2255
  return Array.from(scopes);
2158
2256
  }
2257
+ function fallbackApplication(id) {
2258
+ const entry = STATIC_APPLICATIONS2[id];
2259
+ if (!entry) {
2260
+ throw new Error(
2261
+ `Unknown application "${id}" in the static fallback snapshot. Resolve applications from the live registry (resolveApplicationDirectoryEntry) and pass the entry directly.`
2262
+ );
2263
+ }
2264
+ return entry;
2265
+ }
2159
2266
  function requirementsForApplication(applicationOrId) {
2160
- const application = typeof applicationOrId === "string" ? APPLICATIONS[applicationOrId] : applicationOrId;
2267
+ const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
2161
2268
  const scopes = new Set(applicationRequirementScopes(application));
2162
2269
  return APPLICATION_REQUIREMENTS.filter(
2163
2270
  (requirement) => requirement.appliesTo.some((scope) => scopes.has(scope))
2164
2271
  );
2165
2272
  }
2166
2273
  function auditApplicationRequirements(applicationOrId) {
2167
- const application = typeof applicationOrId === "string" ? APPLICATIONS[applicationOrId] : applicationOrId;
2274
+ const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
2168
2275
  const scopes = applicationRequirementScopes(application);
2169
2276
  const findings = requirementsForApplication(application).map(
2170
2277
  (requirement) => evaluateRequirement(application, requirement)
@@ -2177,10 +2284,17 @@ function auditApplicationRequirements(applicationOrId) {
2177
2284
  findings
2178
2285
  };
2179
2286
  }
2287
+ function auditApplicationEntries(applications) {
2288
+ return buildAuditReport(
2289
+ applications.map((application) => auditApplicationRequirements(application))
2290
+ );
2291
+ }
2180
2292
  function auditAllApplicationRequirements(applicationIds = Object.keys(APPLICATIONS).sort()) {
2181
- const applications = applicationIds.map(
2182
- (applicationId) => auditApplicationRequirements(applicationId)
2293
+ return buildAuditReport(
2294
+ applicationIds.map((applicationId) => auditApplicationRequirements(applicationId))
2183
2295
  );
2296
+ }
2297
+ function buildAuditReport(applications) {
2184
2298
  const migrationQueue = applications.flatMap(
2185
2299
  (audit) => audit.findings.filter((finding2) => finding2.status !== "met").map((finding2) => ({
2186
2300
  applicationId: audit.application.id,
@@ -3491,8 +3605,9 @@ var TopoloClient = class _TopoloClient {
3491
3605
  });
3492
3606
  }
3493
3607
  /**
3494
- * Bundled generated registry for tooling that audits platform packaging, not
3495
- * for deciding what the current credential may use.
3608
+ * @deprecated Static fallback snapshot only. Use `searchServices()` (the
3609
+ * live credential-scoped registry) for anything that decides behavior; this
3610
+ * exists for offline packaging audits when the registry is unreachable.
3496
3611
  */
3497
3612
  listBundledServices() {
3498
3613
  const apps = Object.values(APPLICATIONS);
@@ -4832,8 +4947,10 @@ function createTopolo(options) {
4832
4947
  TopoloSdkError,
4833
4948
  WorkspacesModule,
4834
4949
  actionContractCompleteness,
4950
+ applicationEntryFromCatalog,
4835
4951
  applicationRequirementScopes,
4836
4952
  auditAllApplicationRequirements,
4953
+ auditApplicationEntries,
4837
4954
  auditApplicationRequirements,
4838
4955
  createTopolo,
4839
4956
  createTopoloWidgetError,
@@ -4845,12 +4962,17 @@ function createTopolo(options) {
4845
4962
  defineTopoloStatsWidget,
4846
4963
  digestTopoloActionCatalog,
4847
4964
  enrichActionContract,
4965
+ formatDirectoryApplicationIds,
4966
+ friendlyAppId,
4967
+ listApplicationDirectory,
4848
4968
  parseTopoloActionUploadContract,
4849
4969
  prepareTopoloActionBase64UploadInput,
4850
4970
  prepareTopoloActionUploadInput,
4851
4971
  requirementsForApplication,
4972
+ resolveApplicationDirectoryEntry,
4852
4973
  resolveCatalogServiceUrl,
4853
4974
  resolveServiceUrl,
4975
+ staticApplicationDirectory,
4854
4976
  validateTopoloActionInput,
4855
4977
  validateTopoloWidgetResponse
4856
4978
  });