@zackbart/connecta 0.18.3 → 0.20.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +131 -4
  2. package/dist/apps-shell.d.ts +10 -12
  3. package/dist/apps-shell.js +29 -220
  4. package/dist/catalog-service.d.ts +16 -13
  5. package/dist/catalog-service.js +106 -115
  6. package/dist/catalog.js +29 -46
  7. package/dist/connector-scope.js +2 -7
  8. package/dist/connectors/api.d.ts +4 -16
  9. package/dist/connectors/api.js +19 -46
  10. package/dist/connectors/guarded-fetch.d.ts +9 -23
  11. package/dist/connectors/guarded-fetch.js +38 -76
  12. package/dist/connectors/remote-mcp.js +36 -79
  13. package/dist/errors.d.ts +6 -27
  14. package/dist/errors.js +8 -5
  15. package/dist/execute.d.ts +23 -28
  16. package/dist/execute.js +101 -257
  17. package/dist/executor-result.d.ts +1 -0
  18. package/dist/executor-result.js +4 -11
  19. package/dist/executors/quickjs-child.js +1 -3
  20. package/dist/executors/quickjs-runtime.js +1 -3
  21. package/dist/executors/quickjs.js +1 -3
  22. package/dist/index.js +134 -123
  23. package/dist/invocation.d.ts +1 -1
  24. package/dist/invocation.js +113 -183
  25. package/dist/meta-tools.d.ts +15 -29
  26. package/dist/meta-tools.js +41 -582
  27. package/dist/operator-ui/generated.d.ts +2 -2
  28. package/dist/providers/cloudflare.d.ts +2 -18
  29. package/dist/providers/cloudflare.js +1460 -2451
  30. package/dist/providers/linear.d.ts +4 -41
  31. package/dist/providers/linear.js +8 -39
  32. package/dist/providers/mixpanel.d.ts +3 -25
  33. package/dist/providers/mixpanel.js +7 -22
  34. package/dist/providers/notion.d.ts +1 -15
  35. package/dist/providers/notion.js +44 -173
  36. package/dist/providers/revenuecat.d.ts +4 -57
  37. package/dist/providers/revenuecat.js +10 -93
  38. package/dist/providers/stripe.d.ts +1 -12
  39. package/dist/providers/stripe.js +7 -45
  40. package/dist/registry.d.ts +9 -34
  41. package/dist/registry.js +9 -103
  42. package/dist/routes/mcp.js +1 -1
  43. package/dist/routes/oauth.js +3 -3
  44. package/dist/routes/shared.d.ts +15 -15
  45. package/dist/routes/shared.js +1 -3
  46. package/dist/skills.d.ts +1 -1
  47. package/dist/skills.js +5 -5
  48. package/dist/timeout.d.ts +8 -7
  49. package/dist/timeout.js +47 -38
  50. package/dist/types.d.ts +3 -3
  51. package/dist/ui.d.ts +1 -25
  52. package/dist/ui.js +18 -45
  53. package/dist/version.d.ts +1 -1
  54. package/dist/version.js +1 -1
  55. package/documentation/call-admission.md +1 -1
  56. package/documentation/cloudflare.md +1 -1
  57. package/documentation/code-mode.md +25 -25
  58. package/documentation/connectors.md +24 -1
  59. package/documentation/linear.md +1 -1
  60. package/documentation/meta-tools.md +4 -30
  61. package/documentation/mixpanel.md +1 -1
  62. package/documentation/notion.md +1 -1
  63. package/documentation/operations.md +29 -25
  64. package/documentation/provider-conventions.md +4 -5
  65. package/documentation/revenuecat.md +1 -1
  66. package/documentation/stripe.md +1 -1
  67. package/documentation/upgrading.md +43 -8
  68. package/ethos.md +75 -121
  69. package/package.json +3 -4
  70. package/templates/node/package.json +1 -1
  71. package/documentation/code-first-exploration.md +0 -292
  72. package/documentation/mcp-2026-07-28.md +0 -46
  73. package/documentation/mcp-ui-design.md +0 -382
  74. package/documentation/program-ui-read-calls.md +0 -213
  75. package/documentation/provider-audit.md +0 -198
  76. package/documentation/rich-output-design.md +0 -211
package/dist/index.js CHANGED
@@ -42,71 +42,116 @@ function normalizeAuth(auth) {
42
42
  return rank(a) - rank(b);
43
43
  });
44
44
  }
45
- const LEGACY_CONFIG_MIGRATIONS = [
46
- ["activityReadGate", "activity.readGate"],
47
- ["activityDeploymentId", "activity.deploymentId"],
48
- ["credentialEncryptionKey", "credentials.encryptionKey"],
49
- ["toolCacheTtlSeconds", "discovery.catalogTtlSeconds"],
50
- ["persistToolCatalog", "discovery.persistCatalog"],
51
- ["toolCatalogStaleSeconds", "discovery.staleCatalogSeconds"],
52
- ["probeTimeoutMs", "discovery.probeTimeoutMs"],
53
- ["defaultToolTimeoutMs", "calls.defaultTimeoutMs"],
54
- ["maxResultBytes", "calls.maxResultBytes"],
55
- ];
56
- const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
57
- /**
58
- * Fail closed at the public boundary: a JavaScript caller on the v0.6 shape
59
- * must receive one complete migration error, never silently lose an option to
60
- * a default. This runs before createConnecta reads any other config field.
61
- */
62
- function assertNoLegacyConfig(config) {
63
- const candidate = config;
64
- if (hasOwn(candidate, "toolkits")) {
65
- throw new Error("ConnectaConfig.toolkits was removed in issue #178. Deploy one " +
66
- "connecta instance per audience instead; see ethos.md.");
67
- }
68
- const credentials = candidate.credentials;
69
- const hasNestedHealth = typeof credentials === "object" &&
70
- credentials !== null &&
71
- hasOwn(credentials, "health");
72
- if (hasOwn(candidate, "credentialHealth") || hasNestedHealth) {
73
- throw new Error("`credentials.health` and legacy `credentialHealth` were removed in " +
74
- "issue #179. Credentials now fail at use; see ethos.md.");
75
- }
76
- const calls = candidate.calls;
77
- if (typeof calls === "object" &&
78
- calls !== null &&
79
- hasOwn(calls, "maxBatchResultBytes")) {
80
- throw new Error("`calls.maxBatchResultBytes` was removed in issue #273 along with " +
81
- "batch_call. Remove it; a program's batching is bounded by " +
82
- "execute_code's own limits — connecta.batch's per-run call ceiling " +
83
- "and the executor result cap — while each call inside it still honours " +
84
- "calls.maxResultBytes and any per-connector override.");
85
- }
86
- const found = [];
87
- if (hasOwn(candidate, "activity")) {
88
- const activity = candidate.activity;
89
- const isObject = typeof activity === "object" && activity !== null;
90
- // A valid v0.6 ActivityStore can itself own a backend field named `store`.
91
- // Its required `record` method (including a prototype method) therefore
92
- // takes precedence over the otherwise-new wrapper shape.
93
- const hasLegacyRecord = isObject &&
94
- typeof activity.record === "function";
95
- if (activity !== undefined &&
96
- (!isObject ||
97
- hasLegacyRecord ||
98
- !hasOwn(activity, "store"))) {
99
- found.push(["activity", "activity.store"]);
100
- }
45
+ const admissionPoolSchema = {
46
+ concurrency: null,
47
+ maxQueueSize: null,
48
+ queueTimeoutMs: null,
49
+ retryAfterMs: null,
50
+ };
51
+ const CONFIG_SCHEMA = {
52
+ connectors: null,
53
+ auth: null,
54
+ storage: null,
55
+ publicUrl: null,
56
+ activity: {
57
+ store: null,
58
+ readGate: null,
59
+ deploymentId: null,
60
+ },
61
+ credentials: {
62
+ encryptionKey: null,
63
+ },
64
+ accessTokens: {
65
+ maxActive: null,
66
+ },
67
+ discovery: {
68
+ concurrency: null,
69
+ catalogTtlSeconds: null,
70
+ persistCatalog: null,
71
+ staleCatalogSeconds: null,
72
+ probeTimeoutMs: null,
73
+ },
74
+ calls: {
75
+ defaultTimeoutMs: null,
76
+ maxResultBytes: null,
77
+ },
78
+ execute: {
79
+ maxEmittedBytes: null,
80
+ maxEmittedBlocks: null,
81
+ },
82
+ admission: {
83
+ requests: admissionPoolSchema,
84
+ code: admissionPoolSchema,
85
+ },
86
+ branding: {
87
+ productName: null,
88
+ productUrl: null,
89
+ ownerName: null,
90
+ ownerUrl: null,
91
+ description: null,
92
+ pageTitle: null,
93
+ favicon: {
94
+ svg: null,
95
+ ico: null,
96
+ href: null,
97
+ },
98
+ themeColor: null,
99
+ },
100
+ logger: null,
101
+ serverInfo: {
102
+ name: null,
103
+ version: null,
104
+ title: null,
105
+ websiteUrl: null,
106
+ icons: [
107
+ {
108
+ src: null,
109
+ mimeType: null,
110
+ sizes: null,
111
+ },
112
+ ],
113
+ },
114
+ deploymentInfo: null,
115
+ executor: null,
116
+ };
117
+ function unknownOptionPaths(value, path, schema) {
118
+ if (schema === null)
119
+ return [];
120
+ if (Array.isArray(schema)) {
121
+ if (!Array.isArray(value))
122
+ return [];
123
+ return value.flatMap((entry, index) => unknownOptionPaths(entry, `${path}[${index}]`, schema[0]));
101
124
  }
102
- for (const migration of LEGACY_CONFIG_MIGRATIONS) {
103
- if (hasOwn(candidate, migration[0]))
104
- found.push(migration);
125
+ if (typeof value !== "object" || value === null)
126
+ return [];
127
+ const known = new Set(Object.keys(schema));
128
+ const unknown = Reflect.ownKeys(value)
129
+ .filter((key) => typeof key !== "string" || !known.has(key))
130
+ .map((key) => `${path}.${String(key)}`)
131
+ .sort();
132
+ if (unknown.length > 0)
133
+ return unknown;
134
+ for (const [key, childSchema] of Object.entries(schema)) {
135
+ unknown.push(...unknownOptionPaths(value[key], `${path}.${key}`, childSchema));
105
136
  }
106
- if (found.length === 0)
137
+ return unknown;
138
+ }
139
+ function rejectUnknownOptions(paths) {
140
+ if (paths.length === 0)
107
141
  return;
108
- throw new Error("Unsupported v0.6.x ConnectaConfig options. Migrate each path for v0.7.0:\n" +
109
- found.map(([oldPath, newPath]) => `- ${oldPath} -> ${newPath}`).join("\n"));
142
+ throw new Error(`Unknown Connecta configuration option${paths.length === 1 ? "" : "s"}:\n` +
143
+ paths.map((path) => `- ${path}`).join("\n"));
144
+ }
145
+ /** Reject JavaScript typos and removed options before construction does work. */
146
+ function assertKnownConfig(config) {
147
+ rejectUnknownOptions(unknownOptionPaths(config, "ConnectaConfig", CONFIG_SCHEMA));
148
+ const activity = config.activity;
149
+ if (activity !== undefined &&
150
+ (typeof activity !== "object" ||
151
+ activity === null ||
152
+ typeof activity.store?.record !== "function")) {
153
+ throw new Error("ConnectaConfig.activity.store must implement record(event)");
154
+ }
110
155
  }
111
156
  /**
112
157
  * One-time construction warnings for deployment shapes that run fine but are
@@ -193,11 +238,7 @@ function warnInsecureConfig(config, inboundAuth, logger) {
193
238
  }
194
239
  }
195
240
  export function createConnecta(config) {
196
- assertNoLegacyConfig(config);
197
- if (Object.prototype.hasOwnProperty.call(config, "surface")) {
198
- throw new Error("ConnectaConfig.surface was removed in issue #273. Remove it; connecta " +
199
- "now serves one seven-tool surface.");
200
- }
241
+ assertKnownConfig(config);
201
242
  if (!config.executor) {
202
243
  throw new Error("ConnectaConfig.executor is required. Configure quickJsExecutor() from " +
203
244
  '"@zackbart/connecta/quickjs" on Node, or ' +
@@ -233,30 +274,20 @@ export function createConnecta(config) {
233
274
  const registry = new Registry(config.connectors, {
234
275
  storage,
235
276
  logger,
236
- ...(credentialVault !== undefined ? { credentialVault } : {}),
237
- ...(config.activity?.store !== undefined
277
+ credentialVault,
278
+ catalogDriftActivity: config.activity?.store
238
279
  ? {
239
- catalogDriftActivity: {
240
- sink: config.activity.store,
241
- serverInfo,
242
- ...(config.activity.deploymentId !== undefined
243
- ? { deploymentId: config.activity.deploymentId }
244
- : {}),
245
- },
280
+ sink: config.activity.store,
281
+ serverInfo,
282
+ ...(config.activity.deploymentId !== undefined
283
+ ? { deploymentId: config.activity.deploymentId }
284
+ : {}),
246
285
  }
247
- : {}),
248
- ...(config.discovery?.catalogTtlSeconds !== undefined
249
- ? { toolCacheTtlSeconds: config.discovery.catalogTtlSeconds }
250
- : {}),
251
- ...(config.discovery?.persistCatalog !== undefined
252
- ? { persistToolCatalog: config.discovery.persistCatalog }
253
- : {}),
254
- ...(config.discovery?.staleCatalogSeconds !== undefined
255
- ? { toolCatalogStaleSeconds: config.discovery.staleCatalogSeconds }
256
- : {}),
257
- ...(config.calls?.maxResultBytes !== undefined
258
- ? { maxResultBytes: config.calls.maxResultBytes }
259
- : {}),
286
+ : undefined,
287
+ toolCacheTtlSeconds: config.discovery?.catalogTtlSeconds,
288
+ persistToolCatalog: config.discovery?.persistCatalog,
289
+ toolCatalogStaleSeconds: config.discovery?.staleCatalogSeconds,
290
+ maxResultBytes: config.calls?.maxResultBytes,
260
291
  });
261
292
  const inboundAuth = normalizeAuth(accessTokens ? [accessTokens.auth, ...configuredAuth] : configuredAuth);
262
293
  warnInsecureConfig(config, inboundAuth, logger);
@@ -279,44 +310,24 @@ export function createConnecta(config) {
279
310
  const handler = createFetchHandler({
280
311
  registry,
281
312
  auth: inboundAuth,
282
- ...(config.publicUrl !== undefined ? { publicUrl: config.publicUrl } : {}),
313
+ publicUrl: config.publicUrl,
283
314
  serverInfo,
284
315
  logger,
285
- ...(config.activity?.store !== undefined
286
- ? { activity: config.activity.store }
287
- : {}),
288
- ...(config.activity?.readGate !== undefined
289
- ? { activityReadGate: config.activity.readGate }
290
- : {}),
291
- ...(config.activity?.deploymentId !== undefined
292
- ? { activityDeploymentId: config.activity.deploymentId }
293
- : {}),
316
+ activity: config.activity?.store,
317
+ activityReadGate: config.activity?.readGate,
318
+ activityDeploymentId: config.activity?.deploymentId,
294
319
  executor,
295
- ...(configuredExecutorName !== undefined
296
- ? { executorName: configuredExecutorName }
297
- : {}),
320
+ executorName: configuredExecutorName,
298
321
  requestAdmission,
299
- ...(config.calls?.defaultTimeoutMs !== undefined
300
- ? { defaultToolTimeoutMs: config.calls.defaultTimeoutMs }
301
- : {}),
302
- ...(config.discovery?.probeTimeoutMs !== undefined
303
- ? { probeTimeoutMs: config.discovery.probeTimeoutMs }
304
- : {}),
305
- ...(config.discovery?.concurrency !== undefined
306
- ? { discoveryConcurrency: config.discovery.concurrency }
307
- : {}),
308
- ...(config.execute?.maxEmittedBytes !== undefined
309
- ? { maxEmittedBytes: config.execute.maxEmittedBytes }
310
- : {}),
311
- ...(config.execute?.maxEmittedBlocks !== undefined
312
- ? { maxEmittedBlocks: config.execute.maxEmittedBlocks }
313
- : {}),
314
- ...(credentialVault !== undefined ? { credentialVault } : {}),
315
- ...(accessTokens !== undefined ? { accessTokens } : {}),
316
- ...(config.deploymentInfo !== undefined
317
- ? { deploymentInfo: config.deploymentInfo }
318
- : {}),
319
- ...(config.branding !== undefined ? { branding: config.branding } : {}),
322
+ defaultToolTimeoutMs: config.calls?.defaultTimeoutMs,
323
+ probeTimeoutMs: config.discovery?.probeTimeoutMs,
324
+ discoveryConcurrency: config.discovery?.concurrency,
325
+ maxEmittedBytes: config.execute?.maxEmittedBytes,
326
+ maxEmittedBlocks: config.execute?.maxEmittedBlocks,
327
+ credentialVault,
328
+ accessTokens,
329
+ deploymentInfo: config.deploymentInfo,
330
+ branding: config.branding,
320
331
  });
321
332
  let closePromise;
322
333
  return {
@@ -57,7 +57,7 @@ export interface InvocationContext<T> {
57
57
  requestSignal?: AbortSignal;
58
58
  unwrapResult?: boolean;
59
59
  /**
60
- * Caller-owned result policy. MCP passes fields + paging here; code mode
60
+ * Caller-owned result policy. MCP applies result paging here; code mode
61
61
  * normally accepts the already-unwrapped value unchanged.
62
62
  */
63
63
  processResult?: (value: unknown, resolved: ResolvedCatalogTool) => T | Promise<T>;