@zackbart/connecta 0.18.2 → 0.19.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 (75) hide show
  1. package/CHANGELOG.md +100 -4
  2. package/README.md +4 -0
  3. package/dist/catalog-service.d.ts +20 -13
  4. package/dist/catalog-service.js +123 -116
  5. package/dist/catalog.js +29 -46
  6. package/dist/connector-scope.js +2 -7
  7. package/dist/connectors/api.d.ts +4 -16
  8. package/dist/connectors/api.js +19 -46
  9. package/dist/connectors/guarded-fetch.d.ts +9 -23
  10. package/dist/connectors/guarded-fetch.js +38 -76
  11. package/dist/connectors/remote-mcp.js +36 -79
  12. package/dist/errors.d.ts +6 -27
  13. package/dist/errors.js +8 -5
  14. package/dist/execute.d.ts +24 -22
  15. package/dist/execute.js +98 -145
  16. package/dist/executor-result.d.ts +1 -0
  17. package/dist/executor-result.js +4 -11
  18. package/dist/executors/quickjs-child.js +1 -3
  19. package/dist/executors/quickjs-runtime.js +1 -3
  20. package/dist/executors/quickjs.js +1 -3
  21. package/dist/index.js +27 -57
  22. package/dist/invocation.js +114 -178
  23. package/dist/meta-tools.d.ts +15 -28
  24. package/dist/meta-tools.js +33 -89
  25. package/dist/providers/cloudflare.d.ts +2 -18
  26. package/dist/providers/cloudflare.js +1460 -2451
  27. package/dist/providers/linear.d.ts +4 -41
  28. package/dist/providers/linear.js +8 -39
  29. package/dist/providers/mixpanel.d.ts +3 -25
  30. package/dist/providers/mixpanel.js +7 -22
  31. package/dist/providers/notion.d.ts +1 -15
  32. package/dist/providers/notion.js +44 -173
  33. package/dist/providers/revenuecat.d.ts +4 -57
  34. package/dist/providers/revenuecat.js +10 -93
  35. package/dist/providers/stripe.d.ts +1 -12
  36. package/dist/providers/stripe.js +7 -45
  37. package/dist/registry.d.ts +16 -34
  38. package/dist/registry.js +18 -103
  39. package/dist/result-shapes.d.ts +13 -0
  40. package/dist/result-shapes.js +331 -0
  41. package/dist/routes/mcp.js +1 -1
  42. package/dist/routes/oauth.js +3 -3
  43. package/dist/routes/shared.d.ts +15 -15
  44. package/dist/routes/shared.js +1 -3
  45. package/dist/skills.js +3 -3
  46. package/dist/timeout.d.ts +8 -7
  47. package/dist/timeout.js +47 -38
  48. package/dist/types.d.ts +3 -3
  49. package/dist/ui.d.ts +1 -25
  50. package/dist/ui.js +18 -45
  51. package/dist/version.d.ts +1 -1
  52. package/dist/version.js +1 -1
  53. package/documentation/architecture.md +5 -2
  54. package/documentation/call-admission.md +1 -1
  55. package/documentation/cloudflare.md +1 -1
  56. package/documentation/code-mode.md +13 -13
  57. package/documentation/connectors.md +34 -1
  58. package/documentation/linear.md +1 -1
  59. package/documentation/meta-tools.md +17 -3
  60. package/documentation/mixpanel.md +1 -1
  61. package/documentation/notion.md +1 -1
  62. package/documentation/operations.md +20 -15
  63. package/documentation/provider-conventions.md +1 -1
  64. package/documentation/revenuecat.md +1 -1
  65. package/documentation/stripe.md +1 -1
  66. package/documentation/upgrading.md +24 -4
  67. package/ethos.md +74 -120
  68. package/package.json +3 -4
  69. package/templates/node/package.json +1 -1
  70. package/documentation/code-first-exploration.md +0 -292
  71. package/documentation/mcp-2026-07-28.md +0 -46
  72. package/documentation/mcp-ui-design.md +0 -382
  73. package/documentation/program-ui-read-calls.md +0 -213
  74. package/documentation/provider-audit.md +0 -198
  75. package/documentation/rich-output-design.md +0 -211
@@ -3,15 +3,7 @@ import type { Connector, ConnectorCallAdmissionPolicy } from "../types.js";
3
3
  /** RevenueCat publishes one hosted MCP endpoint, streamable HTTP. */
4
4
  export declare const REVENUECAT_MCP_ENDPOINT = "https://mcp.revenuecat.ai/mcp";
5
5
  export interface RevenueCatOptions {
6
- /**
7
- * Human-readable display name; defaults to "RevenueCat" for OAuth and
8
- * "RevenueCat (single project)" for a static API v2 secret key. The scope
9
- * shape rides the title because it is the one routing fact connecta can
10
- * know at construction: an `sk_` key reaches exactly one project, an OAuth
11
- * session reaches every project the account can. *Which* project a key
12
- * reaches is not knowable here (P10 — no credential test), so the guide's
13
- * first line carries the operator's stated purpose instead.
14
- */
6
+ /** Display name; scope defaults are in `documentation/revenuecat.md`. */
15
7
  title?: string;
16
8
  /**
17
9
  * Which project this connector is for and what decisions it answers. With
@@ -19,61 +11,16 @@ export interface RevenueCatOptions {
19
11
  * so it goes in the guide's first line and its summary.
20
12
  */
21
13
  purpose: string;
22
- /**
23
- * OAuth by default; static headers support a RevenueCat API v2 secret key
24
- * as `Authorization: Bearer sk_…`. `{ type: "credential" }` is the same
25
- * single-project scope with the key pasted at `/credentials` instead — which
26
- * is what two projects on two keys wants, since each is its own connector.
27
- */
14
+ /** OAuth or a single-project API v2 key; see `documentation/revenuecat.md`. */
28
15
  auth?: RemoteMcpAuth;
29
16
  /** Project-specific conventions appended to the maintained provider guide. */
30
17
  instructions?: string;
31
18
  /** Connector-specific inline result limit; omit to inherit the deployment. */
32
19
  maxResultBytes?: number;
33
- /**
34
- * Optional per-runtime call-admission policy. Deliberately not defaulted,
35
- * even though RevenueCat does publish numbers.
36
- *
37
- * API v2 meters per *domain*, and the domains disagree by a factor of
38
- * nineteen: Customer Information 480/min, Virtual Currencies 480/min,
39
- * Subscription Transactions Refunds 480/min, Audiences 60/min, Project
40
- * Configuration 60/min, Charts & Metrics 25/min
41
- * (https://www.revenuecat.com/docs/api-v2#tag/Rate-Limit, read 2026-08-18).
42
- * A `ConnectorCallAdmissionPolicy` carries exactly one rule, so a
43
- * connector-wide budget has to pick one of those six numbers for all ninety-
44
- * five tools. Transcribing 25 would throttle a customer read loop to a
45
- * nineteenth of its documented allowance; transcribing 480 would leave a
46
- * chart sweep unprotected. Neither is the provider's limit, and both would
47
- * look like RevenueCat being flaky.
48
- *
49
- * The metering scope says the same thing again: the limit applies per API
50
- * key for app-level keys and per *developer* for developer-level keys, so
51
- * an OAuth session shares one budget with everything else that developer
52
- * does — which a per-runtime counter cannot approximate in either
53
- * direction. So the number stays with the operator who knows the account,
54
- * exactly as P12 prescribes; `documentation/revenuecat.md` shows how to
55
- * supply one.
56
- */
20
+ /** Optional per-runtime policy; see `documentation/revenuecat.md#rate-limits`. */
57
21
  callAdmission?: ConnectorCallAdmissionPolicy;
58
22
  }
59
- /**
60
- * The manifest this release reviewed: both lists in one place, which is what
61
- * makes the classification the connector applies and the drift check that runs
62
- * beside it the same fact (P13). Ninety-four of the ninety-five tools
63
- * RevenueCat's reference lists on 2026-08-18 are classified; the ninety-fifth,
64
- * `render-paywall-screenshot`, has no access column to classify from and fails
65
- * closed.
66
- *
67
- * No schema digests. No release has read RevenueCat's live schemas and written
68
- * them down — that needs a live project and a maintainer's own `sk_` key — and
69
- * an invented digest would report a change that never happened.
70
- * `npm run drift:check -- --record` reads them from a live catalog and prints
71
- * the block to paste in
72
- * ([#351](https://github.com/zackbart/connecta/issues/351)).
73
- *
74
- * Exported because the maintainer-run check compares against this manifest and
75
- * *names* what moved, which the runtime check deliberately cannot.
76
- */
23
+ /** Release-reviewed manifest; see provider conventions P5 and P13. */
77
24
  export declare const REVENUECAT_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
78
25
  /** A maintained RevenueCat hosted-MCP connection. */
79
26
  export declare function revenuecat(id: string, options: RevenueCatOptions): Connector;
@@ -1,16 +1,9 @@
1
1
  import { remoteMcp, withCredentialDefaults, } from "../connectors/remote-mcp.js";
2
2
  import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
3
+ import { defined } from "../connectors/api.js";
3
4
  /** RevenueCat publishes one hosted MCP endpoint, streamable HTTP. */
4
5
  export const REVENUECAT_MCP_ENDPOINT = "https://mcp.revenuecat.ai/mcp";
5
- /**
6
- * Tools whose official contract is observational rather than mutating.
7
- *
8
- * Every name here carries `Read` in RevenueCat's own tool reference
9
- * (https://www.revenuecat.com/docs/tools/mcp/tools-reference, read
10
- * 2026-08-18). The list is a superset by design (P5): a name a project never
11
- * serves costs nothing, while an unclassified new one fails closed onto
12
- * `call_destructive_tool`.
13
- */
6
+ /** Reviewed reads; see `documentation/revenuecat.md` and convention P5. */
14
7
  const READ_ONLY_TOOLS = new Set([
15
8
  // Projects and apps
16
9
  "get-account-billing",
@@ -76,65 +69,26 @@ const READ_ONLY_TOOLS = new Set([
76
69
  // *start* one are writes and sit below.
77
70
  "get-paywall-ai-task",
78
71
  ]);
79
- /**
80
- * The maintained write catalog. `"destructive"` tools modify or remove state
81
- * that already exists; `"additive"` ones only bring something new into being.
82
- * Both leave the read-only path — the distinction only decides whether the
83
- * connection asserts `destructiveHint`, which shapes the host's approval copy.
84
- *
85
- * Every name here carries `Write` in RevenueCat's tool reference. The mass
86
- * verdicts follow the verb: `archive-*` and `unarchive-*` flip an existing
87
- * object's active state, `update-*` and `delete-*` and `publish-*` and
88
- * `unpublish-*` and `detach-*` change or remove something that already exists,
89
- * and a plain `create-*` brings a new object into being beside the old ones.
90
- *
91
- * Nine verdicts are not decided by the verb, and each is argued where it sits:
92
- * `create-product-prices`, `equalize-subscription-prices`,
93
- * `validate-app-credentials`, `upload-product-store-state-screenshot`,
94
- * `attach-products-to-entitlement`, `attach-products-to-package`,
95
- * `duplicate-paywall`, `create-paywall-ai`, and `edit-paywall-ai`.
96
- *
97
- * `render-paywall-screenshot` is deliberately on neither list. RevenueCat's
98
- * reference gives it no access column at all, and a tool nobody has classified
99
- * fails closed (P5) rather than being guessed into the read path because its
100
- * name sounds harmless.
101
- */
72
+ /** Reviewed writes and verb exceptions: `documentation/revenuecat.md`. */
102
73
  const WRITE_TOOLS = new Map([
103
74
  // Projects and apps
104
75
  ["create-app", "additive"],
105
76
  ["create-project", "additive"],
106
77
  ["update-app", "destructive"],
107
78
  ["update-project-ui-config", "destructive"],
108
- // "Checks one saved App Store or Google Play credential set." RevenueCat
109
- // files it Write, so it does not reach the read path — but it leaves the
110
- // credentials themselves alone and only records the outcome of a check.
111
- // Additive: a verdict comes into being, nothing existing is overwritten.
112
79
  ["validate-app-credentials", "additive"],
113
80
  // Products and prices
114
81
  ["archive-product", "destructive"],
115
82
  ["create-product", "additive"],
116
- // Named `create-`, described "Configure prices for a product". A product's
117
- // price set already exists, and configuring it replaces what is there
118
- // rather than adding a second price beside the first. Money-facing and
119
- // overwriting, so: destructive, whatever the verb says.
120
83
  ["create-product-prices", "destructive"],
121
- // "Fills missing App Store subscription territory prices." By RevenueCat's
122
- // own word it only writes where a price is absent, so nothing already set
123
- // is changed. Additive.
124
84
  ["equalize-subscription-prices", "additive"],
125
85
  ["set-product-store-state", "destructive"],
126
86
  ["submit-products-to-store", "destructive"],
127
87
  ["unarchive-product", "destructive"],
128
88
  ["update-product", "destructive"],
129
- // "Reserves an App Store Connect review screenshot slot." A new slot comes
130
- // into being; no existing screenshot is replaced by the reservation.
131
89
  ["upload-product-store-state-screenshot", "additive"],
132
90
  // Entitlements
133
91
  ["archive-entitlement", "destructive"],
134
- // Attach adds a product to a membership set and removes nothing;
135
- // `detach-products-from-entitlement` is its destructive counterpart. Filing
136
- // both destructive would make the pair read identically in the approval copy
137
- // a human is shown, which is exactly the inflation P5 warns about.
138
92
  ["attach-products-to-entitlement", "additive"],
139
93
  ["create-entitlement", "additive"],
140
94
  ["detach-products-from-entitlement", "destructive"],
@@ -142,7 +96,6 @@ const WRITE_TOOLS = new Map([
142
96
  ["update-entitlement", "destructive"],
143
97
  // Offerings and packages
144
98
  ["archive-offering", "destructive"],
145
- // The same attach/detach argument one level down.
146
99
  ["attach-products-to-package", "additive"],
147
100
  ["create-offering", "additive"],
148
101
  ["create-packages", "additive"],
@@ -154,19 +107,10 @@ const WRITE_TOOLS = new Map([
154
107
  ["create-audience", "additive"],
155
108
  ["update-audience", "destructive"],
156
109
  // Paywalls
157
- // "Duplicates an existing paywall's current draft." The original is
158
- // untouched and a new paywall appears beside it. Additive.
159
110
  ["duplicate-paywall", "additive"],
160
111
  ["publish-paywall", "destructive"],
161
112
  ["unpublish-paywall", "destructive"],
162
- // Customers and subscriptions. Neither verb is in the mass rule and neither
163
- // removes anything, so the file's own criterion would read them additive.
164
- // They are destructive on consequence, the way `create_refund` is in
165
- // `stripe.ts`: `assign-customer-offering` overrides which offering a live
166
- // customer's app serves, and `grant-customer-entitlement` opens paid access
167
- // to a real person without a store purchase (the promotional subscription it
168
- // creates is the mechanism, not the point). Both change what a customer
169
- // gets today, and both deserve the destructive approval copy.
113
+ // Customers and subscriptions
170
114
  ["assign-customer-offering", "destructive"],
171
115
  ["grant-customer-entitlement", "destructive"],
172
116
  // Virtual currencies
@@ -175,39 +119,14 @@ const WRITE_TOOLS = new Map([
175
119
  ["unarchive-virtual-currency", "destructive"],
176
120
  ["update-virtual-currency", "destructive"],
177
121
  // Integrations and webhooks
178
- // A new integration is a new object, but one that "starts delivering
179
- // RevenueCat events to the given url" — with filters omitted, every customer
180
- // event in the project, to a URL the caller typed. That is customer data
181
- // leaving the account on consequence, which is the `create_refund` argument
182
- // again: the verb says additive, the effect says destructive, and the
183
- // approval copy should say the latter.
184
122
  ["create-webhook-integration", "destructive"],
185
123
  ["delete-webhook-integration", "destructive"],
186
124
  ["update-webhook-integration", "destructive"],
187
- // Paywall editing. Both start an async task; what the task does decides the
188
- // verdict. Creating a paywall leaves every existing one alone (additive);
189
- // editing one rewrites a draft that already exists (destructive).
125
+ // Paywall editing
190
126
  ["create-paywall-ai", "additive"],
191
127
  ["edit-paywall-ai", "destructive"],
192
128
  ]);
193
- /**
194
- * The manifest this release reviewed: both lists in one place, which is what
195
- * makes the classification the connector applies and the drift check that runs
196
- * beside it the same fact (P13). Ninety-four of the ninety-five tools
197
- * RevenueCat's reference lists on 2026-08-18 are classified; the ninety-fifth,
198
- * `render-paywall-screenshot`, has no access column to classify from and fails
199
- * closed.
200
- *
201
- * No schema digests. No release has read RevenueCat's live schemas and written
202
- * them down — that needs a live project and a maintainer's own `sk_` key — and
203
- * an invented digest would report a change that never happened.
204
- * `npm run drift:check -- --record` reads them from a live catalog and prints
205
- * the block to paste in
206
- * ([#351](https://github.com/zackbart/connecta/issues/351)).
207
- *
208
- * Exported because the maintainer-run check compares against this manifest and
209
- * *names* what moved, which the runtime check deliberately cannot.
210
- */
129
+ /** Release-reviewed manifest; see provider conventions P5 and P13. */
211
130
  export const REVENUECAT_VETTED_CATALOG = vettedCatalog({
212
131
  reads: READ_ONLY_TOOLS,
213
132
  writes: WRITE_TOOLS,
@@ -312,12 +231,10 @@ export function revenuecat(id, options) {
312
231
  // carries the project-resolution sequence, which is worth reading before
313
232
  // a run rather than before every call.
314
233
  },
315
- ...(options.callAdmission !== undefined
316
- ? { callAdmission: options.callAdmission }
317
- : {}),
318
- ...(options.maxResultBytes !== undefined
319
- ? { maxResultBytes: options.maxResultBytes }
320
- : {}),
234
+ ...defined({
235
+ callAdmission: options.callAdmission,
236
+ maxResultBytes: options.maxResultBytes,
237
+ }),
321
238
  });
322
239
  return withVettedCatalog(connector, REVENUECAT_VETTED_CATALOG);
323
240
  }
@@ -38,18 +38,7 @@ export interface StripeHeaderOptions extends StripeCommonOptions {
38
38
  connectedAccount?: string;
39
39
  }
40
40
  export type StripeOptions = StripeOAuthOptions | StripeHeaderOptions;
41
- /**
42
- * The manifest this release reviewed: both lists in one place, which is what
43
- * makes the classification the connector applies and the drift check that runs
44
- * beside it the same fact (P13). No schema digests yet — no release has read
45
- * Stripe's live schemas and written them down, and an invented digest would
46
- * report a change that never happened. `npm run drift:check -- --record` reads
47
- * them from a live account and prints the block to paste in
48
- * ([#351](https://github.com/zackbart/connecta/issues/351)).
49
- *
50
- * Exported because the maintainer-run check compares against this manifest and
51
- * *names* what moved, which the runtime check deliberately cannot.
52
- */
41
+ /** Release-reviewed manifest; see provider conventions P5 and P13. */
53
42
  export declare const STRIPE_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
54
43
  /** A maintained Stripe hosted-MCP connection. */
55
44
  export declare function stripe(id: string, options: StripeOptions): Connector;
@@ -1,17 +1,9 @@
1
1
  import { remoteMcp, withCredentialDefaults, } from "../connectors/remote-mcp.js";
2
2
  import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
3
+ import { defined } from "../connectors/api.js";
3
4
  /** Stripe publishes one hosted MCP endpoint for every account and mode. */
4
5
  export const STRIPE_MCP_ENDPOINT = "https://mcp.stripe.com/";
5
- /**
6
- * Stripe documents no MCP-specific rate limit, so this transcribes the account
7
- * limit the MCP server spends: 100 requests per second in live mode, 25 in a
8
- * sandbox (https://docs.stripe.com/rate-limits). The concurrency bound is
9
- * connecta's own conservative choice — Stripe documents that per-account and
10
- * per-endpoint concurrency limits exist and surface as `429` with a
11
- * `Stripe-Rate-Limited-Reason` of `global-concurrency` or
12
- * `endpoint-concurrency`, but publishes no number. Declaring `maxConcurrency`
13
- * is also what earns the right to the queue settings beside it.
14
- */
6
+ /** Account limits and local concurrency rationale: `documentation/stripe.md`. */
15
7
  const STRIPE_ADMISSION = {
16
8
  production: {
17
9
  rules: [
@@ -50,34 +42,14 @@ const READ_ONLY_TOOLS = new Set([
50
42
  "search_stripe_documentation",
51
43
  "stripe_implementation_planner",
52
44
  ]);
53
- /**
54
- * The maintained write catalog. `"destructive"` tools modify or remove state
55
- * that already exists; `"additive"` ones only bring something new into being.
56
- * Both leave the read-only path — the distinction only decides whether the
57
- * connection asserts `destructiveHint`, which shapes the host's approval copy.
58
- *
59
- * `create_refund` is filed destructive despite its name: it reverses a
60
- * settled charge and moves money back out, which is a mutation of something
61
- * that already exists, not a fresh object appearing beside it.
62
- */
45
+ /** Reviewed writes, including refund rationale: `documentation/stripe.md`. */
63
46
  const WRITE_TOOLS = new Map([
64
47
  ["stripe_api_write", "destructive"],
65
48
  ["create_refund", "destructive"],
66
49
  ["stripe_report", "additive"],
67
50
  ["send_stripe_mcp_feedback", "additive"],
68
51
  ]);
69
- /**
70
- * The manifest this release reviewed: both lists in one place, which is what
71
- * makes the classification the connector applies and the drift check that runs
72
- * beside it the same fact (P13). No schema digests yet — no release has read
73
- * Stripe's live schemas and written them down, and an invented digest would
74
- * report a change that never happened. `npm run drift:check -- --record` reads
75
- * them from a live account and prints the block to paste in
76
- * ([#351](https://github.com/zackbart/connecta/issues/351)).
77
- *
78
- * Exported because the maintainer-run check compares against this manifest and
79
- * *names* what moved, which the runtime check deliberately cannot.
80
- */
52
+ /** Release-reviewed manifest; see provider conventions P5 and P13. */
81
53
  export const STRIPE_VETTED_CATALOG = vettedCatalog({
82
54
  reads: READ_ONLY_TOOLS,
83
55
  writes: WRITE_TOOLS,
@@ -85,14 +57,7 @@ export const STRIPE_VETTED_CATALOG = vettedCatalog({
85
57
  /** Stripe key prefixes carry their own mode; only a clear reading counts. */
86
58
  const LIVE_KEY = /\b(?:sk|rk|pk)_live_/;
87
59
  const TEST_KEY = /\b(?:sk|rk|pk)_test_/;
88
- /**
89
- * Refuse a deployment whose declared mode and supplied key disagree.
90
- *
91
- * This is the one half of production/sandbox routing connecta can actually
92
- * enforce. Nothing here reads or reports key material: an unrecognizable key
93
- * shape is left alone rather than guessed at, and a mismatch names only the
94
- * two modes.
95
- */
60
+ /** Refuse a recognizable key/mode mismatch; see `documentation/stripe.md`. */
96
61
  function assertModeMatchesKey(id, mode, auth) {
97
62
  if (auth.type !== "headers")
98
63
  return;
@@ -139,7 +104,6 @@ function resolveAuth(id, options) {
139
104
  headers: { ...auth.headers, "Stripe-Account": connectedAccount },
140
105
  };
141
106
  }
142
- const OAUTH_ADMISSION = STRIPE_ADMISSION.sandbox;
143
107
  function oauthUsageGuide(purpose, instructions) {
144
108
  const accountInstructions = instructions?.trim();
145
109
  return `# Stripe usage
@@ -233,7 +197,7 @@ export function stripe(id, options) {
233
197
  : `Stripe payments (${copy?.blurb}) — ${purpose}`,
234
198
  auth,
235
199
  requireHttps: true,
236
- callAdmission: mode === undefined ? OAUTH_ADMISSION : STRIPE_ADMISSION[mode],
200
+ callAdmission: STRIPE_ADMISSION[mode ?? "sandbox"],
237
201
  usageGuide: {
238
202
  content: mode === undefined
239
203
  ? oauthUsageGuide(purpose, options.instructions)
@@ -248,9 +212,7 @@ export function stripe(id, options) {
248
212
  // Not `required`. The four generic tools are the routing decision; a
249
213
  // guide forced into every call would pay for the same prose repeatedly.
250
214
  },
251
- ...(options.maxResultBytes !== undefined
252
- ? { maxResultBytes: options.maxResultBytes }
253
- : {}),
215
+ ...defined({ maxResultBytes: options.maxResultBytes }),
254
216
  });
255
217
  return withVettedCatalog(connector, STRIPE_VETTED_CATALOG);
256
218
  }
@@ -43,32 +43,25 @@ export declare function isValidMaxResultBytes(value: number): boolean;
43
43
  * a broken cap.
44
44
  */
45
45
  export declare function resolveMaxResultBytes(value: number | undefined, inherited: number): number;
46
- export interface HealthObservation {
47
- lastSuccessAt?: string;
48
- lastFailureAt?: string;
49
- lastLatencyMs?: number;
50
- consecutiveFailures: number;
51
- lastError?: string;
52
- }
53
46
  export interface RegistryOptions {
54
47
  storage: KVStorage;
55
48
  logger: Logger;
56
- credentialVault?: CredentialVault;
57
- toolCacheTtlSeconds?: number;
58
- persistToolCatalog?: boolean;
59
- toolCatalogStaleSeconds?: number;
49
+ credentialVault?: CredentialVault | undefined;
50
+ toolCacheTtlSeconds?: number | undefined;
51
+ persistToolCatalog?: boolean | undefined;
52
+ toolCatalogStaleSeconds?: number | undefined;
60
53
  /**
61
54
  * Cap on inline result size before truncation + get_result paging. Must be a
62
55
  * whole number of bytes >= 1; anything else warns at startup and falls back
63
56
  * to the default 50_000.
64
57
  */
65
- maxResultBytes?: number;
58
+ maxResultBytes?: number | undefined;
66
59
  /**
67
60
  * Where payload-free catalog-drift observations go. Present only when the
68
61
  * deployment configured an activity store; drift is reported through
69
62
  * connector status either way.
70
63
  */
71
- catalogDriftActivity?: Omit<CatalogDriftActivityContext, "logger">;
64
+ catalogDriftActivity?: Omit<CatalogDriftActivityContext, "logger"> | undefined;
72
65
  }
73
66
  export type ConnectorOperationOptions = Pick<ConnectorContext, "signal" | "timeoutMs">;
74
67
  /** Agent-only catalog behavior. This never enters a ConnectorContext. */
@@ -96,8 +89,6 @@ export interface RegistryView {
96
89
  toolName: string;
97
90
  } | null;
98
91
  getTools(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions, readOptions?: CatalogReadOptions): Promise<ToolDef[]>;
99
- refreshTools(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions): Promise<ToolDef[]>;
100
- peekTools(id: string): ToolDef[] | undefined;
101
92
  contextFor(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions): ConnectorContext;
102
93
  /** Acquire the connector's shared downstream-call permit. */
103
94
  admitCall(id: string, input: {
@@ -106,13 +97,12 @@ export interface RegistryView {
106
97
  signal?: AbortSignal;
107
98
  }): Promise<CallAdmissionPermit>;
108
99
  resultsStorage(): KVStorage;
109
- recordSuccess(id: string, latencyMs: number): void;
110
- recordFailure(id: string, latencyMs: number, error: unknown): void;
111
- healthFor(id: string): HealthObservation | undefined;
112
- hasObservedSuccess(id: string): boolean;
113
- observedSuccessAt(id: string): string | undefined;
114
100
  /** Local declared-vs-stored credential mismatch, with no downstream I/O. */
115
101
  credentialDriftFor(id: string): Promise<string | undefined>;
102
+ /** Value-free shape learned from successful calls, never a provider declaration. */
103
+ observedOutputSchema(connectorId: string, definition: ToolDef): ToolDef["outputSchema"] | undefined;
104
+ /** Passively learn one successful unwrapped result; failures stay isolated. */
105
+ observeOutputShape(connectorId: string, definition: ToolDef, value: unknown): void;
116
106
  statusFor(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions): Promise<ConnectorStatus>;
117
107
  invalidateStored(id: string): Promise<void>;
118
108
  }
@@ -131,16 +121,16 @@ export declare class Registry implements RegistryView {
131
121
  private readonly catalogGenerations;
132
122
  /** Serialize persisted catalog set/delete operations within this isolate. */
133
123
  private readonly catalogMutations;
134
- /** Same-request cold loads share one promise without retaining the request. */
124
+ /** Same-request cold loads share one promise without retaining the request.
125
+ * See documentation/architecture.md#the-two-lifetimes. */
135
126
  private readonly requestCatalogLoads;
136
127
  /** One live refresh per connector across agent and operator requests. */
137
128
  private readonly catalogRefreshes;
138
129
  /** Last payload-free agent catalog access in this runtime. */
139
130
  private readonly catalogAccess;
140
- /** Deployment-wide observations — every call, whatever view made it. */
141
- private readonly health;
142
131
  /** Last drift counts reported to activity, per connector, in this runtime. */
143
132
  private readonly reportedDrift;
133
+ private readonly observedOutputSchemas;
144
134
  private readonly ttlMs;
145
135
  private readonly staleMs;
146
136
  private readonly persistToolCatalog;
@@ -203,6 +193,8 @@ export declare class Registry implements RegistryView {
203
193
  * separate from any connector's `conn:<id>:` namespace. Backs get_result.
204
194
  */
205
195
  resultsStorage(): KVStorage;
196
+ observedOutputSchema(connectorId: string, definition: ToolDef): ToolDef["outputSchema"] | undefined;
197
+ observeOutputShape(connectorId: string, definition: ToolDef, value: unknown): void;
206
198
  /** Resolve "<connectorId>.<toolName>" → connector + tool name. */
207
199
  resolveAddress(address: string): {
208
200
  connector: Connector;
@@ -210,7 +202,6 @@ export declare class Registry implements RegistryView {
210
202
  } | null;
211
203
  private catalogKey;
212
204
  private catalogChunkKey;
213
- private validLegacyCatalog;
214
205
  private validCatalogTools;
215
206
  private validCatalogManifest;
216
207
  private parseCatalogManifest;
@@ -234,7 +225,7 @@ export declare class Registry implements RegistryView {
234
225
  */
235
226
  private startCatalogRefresh;
236
227
  /** Force a live listTools refresh and replace both catalog cache layers. */
237
- refreshTools(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions): Promise<ToolDef[]>;
228
+ private refreshTools;
238
229
  private observeCatalogAccess;
239
230
  /**
240
231
  * Start or join one shared refresh. A newly deferred task owns its scope,
@@ -253,15 +244,6 @@ export declare class Registry implements RegistryView {
253
244
  * later callers join only its result, never its request scope.
254
245
  */
255
246
  getTools(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions, readOptions?: CatalogReadOptions): Promise<ToolDef[]>;
256
- /** Return a cached catalog without performing storage or network I/O. */
257
- peekTools(id: string): ToolDef[] | undefined;
258
- recordSuccess(id: string, latencyMs: number): void;
259
- recordFailure(id: string, latencyMs: number, error: unknown): void;
260
- healthFor(id: string): HealthObservation | undefined;
261
- /** Whether this deployment has seen a successful call to `id`. */
262
- hasObservedSuccess(id: string): boolean;
263
- /** The timestamp behind `hasObservedSuccess`. */
264
- observedSuccessAt(id: string): string | undefined;
265
247
  credentialDriftFor(id: string): Promise<string | undefined>;
266
248
  /** Best-effort connector status for the operator UI. */
267
249
  statusFor(id: string, baseUrl: string, requestScope?: object, callOptions?: ConnectorOperationOptions): Promise<ConnectorStatus>;