@topolo/sdk 0.3.0 → 0.4.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
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",
@@ -25,10 +25,13 @@
25
25
  "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
26
26
  "typecheck": "node scripts/generate-services.mjs && tsc --noEmit",
27
27
  "test": "vitest run",
28
- "test:watch": "vitest"
28
+ "test:watch": "vitest",
29
+ "prepublishOnly": "npm run build",
30
+ "coverage": "vitest run --coverage"
29
31
  },
30
32
  "devDependencies": {
31
33
  "@types/node": "^20.19.39",
34
+ "@vitest/coverage-v8": "^2.1.0",
32
35
  "tsup": "^8.0.0",
33
36
  "typescript": "^5.4.0",
34
37
  "vitest": "^2.1.0"
@@ -108,12 +108,12 @@ export const APPLICATION_REQUIREMENTS = [
108
108
  'Applications must derive identity, organization, scopes, and service entitlement from TopoloAuth rather than inventing parallel auth state.',
109
109
  appliesTo: ['browser', 'api', 'tooling', 'agent_surface'],
110
110
  evidence: [
111
- '@topolo/auth-client or @topolo/auth-middleware is used where applicable',
111
+ '@topolo/auth-client or @topolo-io/worker-runtime is used where applicable',
112
112
  'No public command, tool, or SDK method accepts orgId',
113
113
  'Service slug and Auth service registration are documented for protected services',
114
114
  ],
115
115
  implementation: [
116
- 'Use shared auth packages instead of copying token parsing or browser storage flows',
116
+ 'Use shared auth/runtime packages instead of copying token parsing, gateway, or browser storage flows',
117
117
  'Derive organization from the credential on every request',
118
118
  'Route OAuth, refresh, logout, and SSO paths according to the shared Auth contract',
119
119
  ],
@@ -149,10 +149,12 @@ export const APPLICATION_REQUIREMENTS = [
149
149
  'Auth service catalog contains the service ID and slug',
150
150
  'Permissions, role bundles, and API-key scopes exist for the service',
151
151
  'SDK, CLI, and MCP service discovery include the callable production API',
152
+ 'CloudControl production HTTP targets classify agent reachability with sdk_service_id or agent_callable:false',
152
153
  ],
153
154
  implementation: [
154
- 'Add production Worker api_url metadata before adding an SDK service ID',
155
- 'Expose stable service IDs through DEFAULT_SERVICE_URLS',
155
+ 'Add production Worker api_url metadata and sdk_service_id for every agent-callable API target',
156
+ 'Mark browser, documentation, and runtime-only Worker targets with agent_callable:false',
157
+ 'Expose stable service IDs through generated DEFAULT_SERVICE_URLS and live catalog discovery',
156
158
  'Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes',
157
159
  ],
158
160
  },
@@ -264,18 +266,28 @@ export function applicationRequirementScopes(
264
266
  application: ApplicationCatalogEntry,
265
267
  ): ApplicationRequirementScope[] {
266
268
  const scopes = new Set<ApplicationRequirementScope>(['all']);
269
+ // id is checked by value: tooling ids (cli/mcp) are intentionally not in
270
+ // the deploy catalog union, so compare as string rather than assert overlap.
271
+ const appId: string = application.id;
267
272
  const hasBrowserSurface =
268
- Boolean(application.productionUrl) || application.deployTargets.some((target) => target.kind === 'pages');
273
+ Boolean(application.productionUrl) ||
274
+ // String() keeps this guard valid after the Pages->Worker migration narrowed
275
+ // the generated kind union to "worker" (no "pages" literal remains).
276
+ application.deployTargets.some((target) => String(target.kind) === 'pages');
277
+ // An API surface means an agent-callable service — keyed on a resolved
278
+ // serviceId, NOT a bare apiUrl. After the Pages->Worker migration every
279
+ // frontend shell carries an apiUrl (its own serving domain), so apiUrl is no
280
+ // longer a signal for "exposes a callable API"; serviceId is.
269
281
  const hasApiSurface =
270
282
  application.services.length > 0 ||
271
- application.deployTargets.some((target) => Boolean(target.apiUrl));
283
+ application.deployTargets.some((target) => Boolean(target.serviceId));
272
284
 
273
285
  if (hasBrowserSurface) scopes.add('browser');
274
286
  if (hasApiSurface) scopes.add('api');
275
- if (application.id === 'cli' || application.id === 'mcp' || application.id === 'cloudcontrol') {
287
+ if (appId === 'cli' || appId === 'mcp' || appId === 'cloudcontrol') {
276
288
  scopes.add('tooling');
277
289
  }
278
- if (application.id === 'cli' || application.id === 'mcp' || hasApiSurface) {
290
+ if (appId === 'cli' || appId === 'mcp' || hasApiSurface) {
279
291
  scopes.add('agent_surface');
280
292
  }
281
293
 
@@ -412,7 +424,9 @@ function evaluateRequirement(
412
424
  evidence,
413
425
  );
414
426
  case 'cloudflare-deployment-contract': {
415
- if (application.deployTargets.length === 0) {
427
+ // `< 1` rather than `=== 0`: every catalogued app now has >=1 deploy target,
428
+ // so the generated tuple-length union excludes 0 and `=== 0` fails typecheck.
429
+ if (application.deployTargets.length < 1) {
416
430
  return finding(requirement, 'missing', 'No CloudControl deploy targets are registered.', evidence);
417
431
  }
418
432
  evidence.push(`deployTargets=${application.deployTargets.length}`);
@@ -420,12 +434,13 @@ function evaluateRequirement(
420
434
  return finding(requirement, 'met', 'CloudControl deploy target metadata is present.', evidence);
421
435
  }
422
436
  case 'agent-and-operator-surfaces': {
437
+ const appId: string = application.id;
423
438
  if (application.services.length > 0) {
424
439
  evidence.push(`services=${application.services.join(',')}`);
425
440
  return finding(requirement, 'partial', 'SDK service discovery exists; typed SDK/CLI/MCP workflow coverage should be checked as APIs stabilize.', evidence);
426
441
  }
427
- if (application.id === 'cli' || application.id === 'mcp' || application.id === 'cloudcontrol') {
428
- evidence.push(`tooling=${application.id}`);
442
+ if (appId === 'cli' || appId === 'mcp' || appId === 'cloudcontrol') {
443
+ evidence.push(`tooling=${appId}`);
429
444
  return finding(requirement, 'met', 'This application is itself an agent/operator surface.', evidence);
430
445
  }
431
446
  return finding(requirement, 'missing', 'No SDK service or tooling surface is registered.', evidence);