@zackbart/connecta 0.29.0 → 0.31.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 (116) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/README.md +126 -134
  3. package/bin/connecta.mjs +13 -2
  4. package/bin/version.mjs +1 -1
  5. package/dist/argument-redaction.js +230 -0
  6. package/dist/auth-elicitation.js +14 -9
  7. package/dist/authorization-handoff.js +111 -0
  8. package/dist/call-recovery.js +25 -0
  9. package/dist/catalog-cache.js +2 -2
  10. package/dist/catalog-service.js +103 -63
  11. package/dist/config-schema.d.ts +14 -7
  12. package/dist/config-schema.js +29 -10
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.js +12 -7
  15. package/dist/connectors/guarded-fetch.d.ts +9 -1
  16. package/dist/connectors/guarded-fetch.js +17 -5
  17. package/dist/connectors/negotiation-cache.js +1 -1
  18. package/dist/downstream-input-context.js +9 -0
  19. package/dist/downstream-input.js +13 -11
  20. package/dist/errors.d.ts +38 -12
  21. package/dist/errors.js +19 -9
  22. package/dist/execute.js +375 -43
  23. package/dist/executor-result.js +11 -9
  24. package/dist/executors/quickjs-child.js +12 -5
  25. package/dist/executors/quickjs-protocol.js +5 -6
  26. package/dist/executors/quickjs-runtime.js +6 -1
  27. package/dist/executors/quickjs.js +20 -4
  28. package/dist/guest-runtime.js +52 -2
  29. package/dist/guest-types.d.ts +47 -5
  30. package/dist/index.d.ts +1 -1
  31. package/dist/invocation.js +72 -14
  32. package/dist/meta-output.js +0 -15
  33. package/dist/meta-tools.js +166 -95
  34. package/dist/oauth-handoff.js +88 -11
  35. package/dist/operator-ui/generated.js +2 -2
  36. package/dist/operator-ui/view.d.ts +9 -0
  37. package/dist/operator-ui/view.js +11 -0
  38. package/dist/program-result.js +5 -0
  39. package/dist/program-writes.js +7 -48
  40. package/dist/provider.d.ts +8 -6
  41. package/dist/provider.js +3 -4
  42. package/dist/providers/_shared/google/workspace.d.ts +1 -1
  43. package/dist/providers/_shared/request-token.js +83 -0
  44. package/dist/providers/_shared/rest/dispatch.js +41 -0
  45. package/dist/providers/_shared/rest/operation-index.d.ts +133 -0
  46. package/dist/providers/_shared/rest/operation-index.js +527 -0
  47. package/dist/providers/_shared/rest/tools.d.ts +141 -0
  48. package/dist/providers/_shared/rest/tools.js +569 -0
  49. package/dist/providers/_shared/rest/value-safety.d.ts +151 -0
  50. package/dist/providers/_shared/rest/value-safety.js +580 -0
  51. package/dist/providers/cloudflare/graphql.js +385 -0
  52. package/dist/providers/cloudflare/index.d.ts +47 -51
  53. package/dist/providers/cloudflare/index.js +188 -1997
  54. package/dist/providers/cloudflare/openapi.generated.js +3347 -0
  55. package/dist/providers/cloudflare/rest.d.ts +37 -0
  56. package/dist/providers/cloudflare/rest.js +1056 -0
  57. package/dist/providers/cloudflare/skill.generated.js +7 -4
  58. package/dist/providers/cloudflare/value-safety.js +1247 -0
  59. package/dist/providers/infisical/index.d.ts +7 -0
  60. package/dist/providers/infisical/index.js +713 -0
  61. package/dist/providers/infisical/skill.generated.js +8 -0
  62. package/dist/providers/notion/index.d.ts +35 -31
  63. package/dist/providers/notion/index.js +60 -1499
  64. package/dist/providers/notion/openapi.generated.js +75 -0
  65. package/dist/providers/notion/rest.d.ts +24 -0
  66. package/dist/providers/notion/rest.js +1067 -0
  67. package/dist/providers/notion/skill.generated.js +5 -4
  68. package/dist/providers/notion/value-safety.js +31 -0
  69. package/dist/providers/stripe/index.d.ts +26 -20
  70. package/dist/providers/stripe/index.js +103 -130
  71. package/dist/providers/stripe/openapi.generated.js +649 -0
  72. package/dist/providers/stripe/rest.d.ts +14 -0
  73. package/dist/providers/stripe/rest.js +395 -0
  74. package/dist/providers/stripe/skill.generated.js +7 -5
  75. package/dist/providers/stripe/value-safety.js +705 -0
  76. package/dist/providers/vercel/index.d.ts +31 -22
  77. package/dist/providers/vercel/index.js +96 -853
  78. package/dist/providers/vercel/openapi.generated.js +456 -0
  79. package/dist/providers/vercel/rest.d.ts +20 -0
  80. package/dist/providers/vercel/rest.js +1002 -0
  81. package/dist/providers/vercel/skill.generated.js +4 -5
  82. package/dist/providers/vercel/value-safety.js +328 -0
  83. package/dist/registry.d.ts +8 -6
  84. package/dist/registry.js +134 -61
  85. package/dist/resource-read.js +4 -1
  86. package/dist/routes/mcp.js +11 -2
  87. package/dist/sent-secrets.d.ts +54 -13
  88. package/dist/sent-secrets.js +770 -231
  89. package/dist/skills.js +26 -16
  90. package/dist/sqlite.js +21 -6
  91. package/dist/storage/keys.js +20 -5
  92. package/dist/storage/memory.js +9 -4
  93. package/dist/storage/sql.js +18 -9
  94. package/dist/types.d.ts +17 -3
  95. package/dist/usage-guide.js +49 -40
  96. package/dist/version.d.ts +1 -1
  97. package/dist/version.js +1 -1
  98. package/dist/worker.js +2 -1
  99. package/dist/write-outcome.js +47 -0
  100. package/documentation/README.md +64 -0
  101. package/documentation/architecture.md +241 -97
  102. package/documentation/auth.md +138 -5
  103. package/documentation/code-mode.md +224 -107
  104. package/documentation/deploying.md +146 -0
  105. package/documentation/integrating.md +170 -0
  106. package/documentation/meta-tools.md +142 -30
  107. package/documentation/operating.md +135 -0
  108. package/documentation/operator-tests.md +4 -0
  109. package/documentation/operator-ui.md +132 -0
  110. package/documentation/provider-auth-migration.md +307 -0
  111. package/documentation/provider-migration-0.29.md +22 -5
  112. package/examples/worker/README.md +9 -2
  113. package/package.json +9 -2
  114. package/templates/node/README.md +9 -2
  115. package/templates/node/package.json +1 -1
  116. package/dist/providers/vercel/mcp-ownership.js +0 -212
@@ -0,0 +1,135 @@
1
+ # Operating an endpoint
2
+
3
+ Use this guide as an agent connected to an existing Connecta endpoint. Setup
4
+ and credentials are the deployment operator's responsibility; use
5
+ [Deploying Connecta](./deploying.md) if you are that operator.
6
+ [All agent routes](./README.md) are in the index.
7
+
8
+ ## Choose the call path
9
+
10
+ Connecta exposes six top-level tools. Read [the tool table](./meta-tools.md#the-six-tools)
11
+ for exact arguments and result envelopes. Follow the endpoint's supplied
12
+ instructions and `skills` usage guide for deployment-specific context.
13
+
14
+ | Work | Use |
15
+ | ------------------------------------------------------------------ | --------------------------------------------------------- |
16
+ | One known read, with usable arguments and a small result | `call_tool` |
17
+ | Discover a tool, chain calls, combine services, or reduce a result | `execute_code` |
18
+ | One write on a read-only endpoint | `call_destructive_tool` |
19
+ | Obtain connector instructions | `skills` with the returned guide name |
20
+ | Start a required authentication handoff | `authorize_connector`, using the returned recovery action |
21
+
22
+ The endpoint's trust is part of its tool descriptions. On a `trusted` endpoint,
23
+ programs may write within the caller's grants, and `execute_code` is annotated
24
+ as a write. On `read-only`, every write is a separate top-level call. The host
25
+ controls approval. Never change pool, identity, or trust to work around a refusal.
26
+ [Routing between the call surfaces](./meta-tools.md#routing-between-the-call-surfaces)
27
+ owns the full decision rules.
28
+
29
+ ## Discover before guessing
30
+
31
+ Use two to four distinctive action/object terms for each operation, and name
32
+ the connector when it is obvious. Read `catalogErrors`, `absence`, classification,
33
+ and required inputs before selecting a result. An empty search may mean a
34
+ failed catalog or a service outside the caller's grants.
35
+
36
+ For normal reads, keep discovery, calls, and reduction in one program when the
37
+ schemas suffice; return the answer rather than catalog matches. Use top-level
38
+ `search_tools` for catalog inspection or to discover a write on a read-only
39
+ endpoint, then dispatch each write with `call_destructive_tool`. An unfamiliar
40
+ read result may return a bounded sample for inspection before the next program.
41
+
42
+ Use the exact returned `address`, including punctuation. A TypeScript signature
43
+ is guidance for writing JavaScript; do not paste types into executable code.
44
+ If a schema is truncated or exact constraints matter, describe the address with
45
+ `format: "json"`. Read a returned `guide` through `skills` or
46
+ `connecta.skill` before relying on provider-specific conventions.
47
+ [Discovery context](./meta-tools.md#discovery-context) and
48
+ [guest search](./code-mode.md#connectasearch) define these results.
49
+
50
+ ## Call, combine, and reduce
51
+
52
+ A program is one JavaScript `async` arrow expression. It has the `connecta`
53
+ guest API and captured console output, with no portable imports, filesystem,
54
+ network access, or credentials. Downstream calls return an envelope; read its
55
+ `data` rather than treating the envelope as the provider's result.
56
+
57
+ This illustrative tracker has a `list_issues` read accepting `state` and
58
+ returning `data.nodes`. Discover its address, call it, and group the identifiers
59
+ in one program:
60
+
61
+ ```js
62
+ async () => {
63
+ const page = await connecta.search({
64
+ connector: "tracker",
65
+ query: "list issues",
66
+ safety: "readOnly",
67
+ });
68
+ if (page.catalogErrors.length || page.absence) {
69
+ return { gap: page.catalogErrors, absence: page.absence };
70
+ }
71
+ const tool = page.tools.find(t => t.name === "list_issues");
72
+ if (!tool) return { gap: "list_issues unavailable" };
73
+ const { data, format } = await connecta.call(tool.address, {
74
+ state: "started",
75
+ });
76
+ if (format !== "json" || !Array.isArray(data?.nodes)) {
77
+ return { gap: "Expected a JSON issues collection" };
78
+ }
79
+ const byOwner = Object.create(null);
80
+ for (const issue of data.nodes) {
81
+ const owner = issue.assignee?.name ?? "unassigned";
82
+ (byOwner[owner] ??= []).push(issue.identifier);
83
+ }
84
+ return byOwner;
85
+ }
86
+ ```
87
+
88
+ `tracker.list_issues` is illustrative, not a built-in address. Discover the real
89
+ connector's schemas and pagination before adapting this program. Keep loops and
90
+ parallel work bounded. [Parallel calls](./code-mode.md#parallel-calls),
91
+ [results and projection](./code-mode.md#results-and-projection), and
92
+ [cancellation and limits](./code-mode.md#cancellation-and-limits) own those rules.
93
+
94
+ Discovery may label an output schema `observed`. It records field names and
95
+ broad types from successful reads in bounded runtime memory, with no scalar
96
+ values. Treat it as evidence, not a provider contract; handle missing fields.
97
+
98
+ ## Large results and resources
99
+
100
+ Direct calls may return a preview and a result handle. Page the handle through
101
+ `connecta.result` in a program using the returned offset and byte limits, or
102
+ reduce the data in the original program. Handles are short-lived and bound to
103
+ the admitted caller, endpoint/pool, and current grants. Never invent one or pass
104
+ it between identities. [Paging](./meta-tools.md#paging-with-connectaresult)
105
+ owns the envelope and expiry rules.
106
+
107
+ For resources, use the exposed resource inventory and `connecta.read`; do not
108
+ fetch an arbitrary URL. [Resource reads](./code-mode.md#connectaread) describe
109
+ which URIs may be read. Connector guides and native skills are described in
110
+ [skills](./meta-tools.md#connector-guides-and-skills).
111
+
112
+ ## Recover without replaying a write
113
+
114
+ Read typed failures and their `nextAction`. Authorization recovery can point
115
+ to consent, operator credential setup, or deployment configuration. Discovery
116
+ and status do not begin consent on their own. Follow
117
+ [authorization recovery](./meta-tools.md#authorization-recovery),
118
+ [routing recovery](./meta-tools.md#routing-recovery), and
119
+ [argument recovery](./meta-tools.md#argument-recovery) for the specific failure.
120
+
121
+ A dispatched write is never automatically replayed. An ambiguous timeout may
122
+ mean the provider applied it; inspect state or ask for the missing decision
123
+ before issuing it again. [Retry semantics](./code-mode.md#retry-semantics) and
124
+ [writes](./code-mode.md#writes) describe program outcomes and write accounting.
125
+
126
+ ## Implementation and evidence
127
+
128
+ The endpoint's built-in [usage skill](https://github.com/zackbart/connecta/blob/main/src/skills.ts)
129
+ is maintained alongside [meta-tools](https://github.com/zackbart/connecta/blob/main/src/meta-tools.ts)
130
+ and [execution](https://github.com/zackbart/connecta/blob/main/src/execute.ts).
131
+ [Usage-guide tests](https://github.com/zackbart/connecta/blob/main/test/usage-guide.test.ts),
132
+ [direct-call tests](https://github.com/zackbart/connecta/blob/main/test/meta-tools-call.test.ts),
133
+ and [guest-contract tests](https://github.com/zackbart/connecta/blob/main/test/guest-api-contract.test.ts)
134
+ check the contracts. Executor-specific evidence is indexed in
135
+ [code-mode verification](./code-mode.md#verification).
@@ -1,5 +1,9 @@
1
1
  # Operator UI tests
2
2
 
3
+ Use this repository-maintenance guide when changing operator pages, data routes,
4
+ or browser evidence. Read the [operator UI contract](./operator-ui.md) first.
5
+ [The agent index](./README.md) routes deployment and endpoint tasks.
6
+
3
7
  `test/fixtures/operator-visual.ts` owns the visual data. It builds the config,
4
8
  live overlay, viewer, and legacy auth details through the current server routes,
5
9
  using the types in `src/operator-ui/contract.ts` and `model.ts`. Collections use
@@ -0,0 +1,132 @@
1
+ # Operator UI
2
+
3
+ Use this guide to enable or maintain the optional operator interface. For
4
+ client tool calls use [Operating an endpoint](./operating.md); for identities,
5
+ credential ownership, and grants use [Auth](./auth.md).
6
+ [All agent routes](./README.md) are in the index.
7
+
8
+ ## Task routes
9
+
10
+ | Task | Read |
11
+ | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
12
+ | Enable UI, vault, or history in a deployment | [Setup](#setup), then the platform template |
13
+ | Consume config, provenance, status, or activity | [Operator data contract](#operator-data-contract) |
14
+ | Change a UI page or data route | [Source and tests](#source-and-tests), [browser verification](./operator-tests.md) |
15
+ | Diagnose permission refusals | [Management permissions](./auth.md#management-permissions), [activity disclosure below](#operator-data-contract) |
16
+
17
+ ## Setup
18
+
19
+ Set `ui: operatorUi()` using `@zackbart/connecta/ui`. Branding belongs in
20
+ `operatorUi({ branding })`; the [Node template](../templates/node/README.md#select-optional-modules)
21
+ and [Worker example](../examples/worker/README.md#select-optional-modules)
22
+ own the runnable configuration, variables, and branding shape. The UI is an
23
+ explicit optional import and stays outside the root package import graph.
24
+
25
+ Overview, Connectors, Tools, Access, Activity, and Config show only what the
26
+ caller may inspect. Connector detail tabs cover configuration, schemas,
27
+ authentication, activity, and diagnostics. Config labels values as default or
28
+ configured. Deployment code owns connectors, grants, pools, and classification;
29
+ the UI changes only authorized authentication material.
30
+
31
+ Install the vault for declared credential slots and activity history for
32
+ persisted call records. Neither module grants permission to manage or read
33
+ it. Credential administration, personal connection, access-token management,
34
+ and activity access are separate identity decisions, denied by default where
35
+ specified in [auth](./auth.md#management-permissions). Machine tokens never
36
+ grant interactive credential or token management authority.
37
+
38
+ ## Operator data contract
39
+
40
+ `GET /ui/api/config`, owned by `operatorUi()`, returns `OperatorUiContract`
41
+ from `connecta/ui`. `src/operator-ui/contract.ts` is also the browser's type
42
+ source. The response has `schemaVersion: 1`, `config`, `configSources`, `live`, and `you`.
43
+ `config` is the construction-time `describeConfig()` snapshot, filtered to
44
+ visible connectors, granted tools, classification overrides, and admitted
45
+ pools. Pool tools are the intersection with the caller's identity grants.
46
+ `configSources` labels each serialized leaf as `default` or `config`, based on
47
+ option presence rather than equality with the default. Factory descriptions carry
48
+ relative `optionSources` paths so resolved module and transport defaults retain
49
+ their provenance. The snapshot copies only resolved values; the UI consumes
50
+ these presence facts separately. Its paths use connector
51
+ ids and pool names and are filtered after disclosure; hidden values leave no
52
+ provenance keys. It contains no source code or credential material.
53
+ Every response is private, `no-store` JSON. Only GET is allowed, with the
54
+ same auth gate and identity partition as `/ui/data` and `/ui/connectors/:id`.
55
+
56
+ `live.connectors` carries status and problem codes, complete registry tools
57
+ with their final read/write classification, catalog age in milliseconds, and
58
+ last-call time/outcome. Catalog descriptions and schemas are allowed for an
59
+ authenticated reader; grammar-failing names and addresses become `<withheld>`.
60
+ `auth.registrationPath` reports the selected downstream OAuth client mechanism when known.
61
+ Status prose, error text, credential values or suffixes, arguments, results,
62
+ and code are excluded. Static and unobserved catalogs have a null age;
63
+ persisted catalogs retain their original fetch time. Probes run with bounded
64
+ concurrency and the configured probe deadline, and release their scopes.
65
+
66
+ Last-call lookup requires the existing activity permission and read gate. It
67
+ scans up to 1,000 recent rows, filters connector/tool grants, and restricts
68
+ personal connectors to the caller's activity identity. Each retained fact
69
+ copies a validated timestamp and outcome only. A null call means unknown or
70
+ absent in that window, not proof of no calls. `live.activity` distinguishes
71
+ available, unconfigured, forbidden, and unavailable history. `you` names no
72
+ identity or auth material; it reports grants, root and admitted-pool trust,
73
+ and effective activity, token, and per-connector auth permissions.
74
+
75
+ `connecta doctor --config` fetches this authenticated contract and prints only
76
+ `config` as indented JSON. It requires the UI module and the existing doctor
77
+ authentication environment variables; it runs no diagnostic program, follows
78
+ no redirects, and prints no raw HTTP failure body.
79
+
80
+ The operator shell uses React, TanStack Router/Query/Table, Radix, cmdk and
81
+ Tailwind v4. Inter, CSS, JavaScript and dependency notices are hashed assets
82
+ under `/ui/assets/*`, served identically with immutable cache headers on Node
83
+ and Workers. HTML contains only mount points and escaped inert configuration;
84
+ it remains uncached. `generated.ts` is ignored and generated before build and
85
+ test; `check:operator-ui` detects stale assets and shared page styles. The UI
86
+ stays behind `./ui`, outside the root import graph. The identity-fenced store
87
+ owns authenticated reads and existing mutations. Overview, Connectors, connector
88
+ detail, Tools, Access and Config consume the typed contract. Activity retains
89
+ its authenticated data routes. Connector detail tabs live
90
+ in the URL hash; Activity filters live in the query string and apply to loaded
91
+ history. Both `/ui/activity` and `/ui/api/activity` require Activity access and
92
+ pass the optional activity `readGate`. Interactive operators and machine callers
93
+ admitted by `identity.activityAccess` share the same history disclosure rules.
94
+ Connector/tool grants and grants for the recorded pool filter each event. Shared
95
+ connector history can include other principals' events, with recorded request
96
+ IDs, validated client name/version and package version, and actor kind, ID and
97
+ namespace. Interactive reads may also add directory actor labels; machine reads
98
+ never add them. Personal connector history is owner-only: the event must have a
99
+ checked `principal` actor basis and actor ID/namespace matching the reader's
100
+ admitted principal. Rows without a provable personal owner are withheld. Activity
101
+ carries no arguments, results, code or raw downstream errors. The last-call
102
+ overlay uses the same event filter but returns only timestamp and outcome.
103
+ Calls group only by recorded request ids, with missing ids shown as
104
+ separate calls. Classification and result size are shown only when recorded. The verdict is
105
+ captured after registry resolution, and result size counts UTF-8 bytes of the
106
+ downstream value before paging or truncation. Nullable SQL columns preserve old
107
+ rows. Catalog changes use the same paging envelope with `kind: "catalog_drift"`,
108
+ `source: "catalog_refresh"` and a checked `catalog_changed` fact containing only
109
+ added, removed and changed tool counts. The first complete catalog is a baseline;
110
+ one refresh-publication hook emits each later change. It includes the request's
111
+ id and typed actor when available, otherwise a fresh id and system actor. No
112
+ names, descriptions or schemas enter the event. Private catalog changes require
113
+ a matching principal owner even when the connector uses shared auth. Empty credential declarations
114
+ report `credential_required` before running a connector status or catalog probe.
115
+ The Access adapter reports inbound provider kinds, admitted pools, grants, trust
116
+ and endpoint setup; token controls retain their existing permission gate.
117
+ Configuration remains in deployment code. The UI mutates only credentials,
118
+ OAuth connections and client tokens through the existing routes.
119
+
120
+ ## Source and tests
121
+
122
+ The contract type is [contract.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/contract.ts).
123
+ [UI routes](https://github.com/zackbart/connecta/blob/main/src/routes/ui.ts) and
124
+ [UI implementation](https://github.com/zackbart/connecta/blob/main/src/ui.ts)
125
+ serve the authenticated shell and data. The browser lives in
126
+ [src/operator-ui](https://github.com/zackbart/connecta/tree/main/src/operator-ui).
127
+ [UI tests](https://github.com/zackbart/connecta/blob/main/test/ui.test.ts),
128
+ [credential-route tests](https://github.com/zackbart/connecta/blob/main/test/ui-credentials.test.ts),
129
+ [config snapshot tests](https://github.com/zackbart/connecta/blob/main/test/describe-config.test.ts),
130
+ and [browser flows](https://github.com/zackbart/connecta/blob/main/test/browser/operator-ui.spec.ts)
131
+ defend filtering and behavior. Use [Operator UI tests](./operator-tests.md)
132
+ for the browser state matrix and Linux snapshot procedure.
@@ -0,0 +1,307 @@
1
+ # Provider auth migration
2
+
3
+ Use this upgrade guide when moving a Stripe, Notion, Vercel, or Cloudflare
4
+ deployment from 0.30 to 0.31, where `auth` selects each provider's
5
+ implementation ([#801](https://github.com/zackbart/connecta/issues/801)).
6
+ The [0.31.0 release notes](https://github.com/zackbart/connecta/blob/main/release-notes/0.31.0.md) summarize the change.
7
+ [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover other
8
+ version changes; [integrating services](./integrating.md) covers new connectors.
9
+
10
+ A dual provider requires `auth`. `{ type: "oauth" }` connects the vendor's
11
+ hosted MCP server, OAuth only. A key type connects Connecta's REST connector
12
+ with an operator-managed credential. There is no default, and one connector id
13
+ uses one implementation: configure two ids for both. The
14
+ [decision record](https://github.com/zackbart/connecta/blob/main/decisions/0005-auth-selects-implementation.md)
15
+ explains why.
16
+
17
+ ## Stripe
18
+
19
+ Stripe's hosted MCP server stops accepting secret keys and untagged
20
+ restricted keys on 2026-10-31; Stripe still documents agent-tagged restricted
21
+ keys for it. Connecta's hosted Stripe connection is OAuth only either way, and
22
+ every key, tagged or not, uses the REST connector. Every `stripe()` call must
23
+ now name `auth`:
24
+
25
+ ```ts
26
+ connectors: [
27
+ stripe("stripe", {
28
+ purpose: "Organization billing",
29
+ auth: { type: "oauth" },
30
+ }),
31
+ stripe("stripe_live", {
32
+ purpose: "Live billing",
33
+ auth: { type: "apiKey" },
34
+ mode: "production",
35
+ }),
36
+ stripe("stripe_sandbox", {
37
+ purpose: "Rehearsal",
38
+ auth: { type: "apiKey" },
39
+ mode: "sandbox",
40
+ }),
41
+ stripe("stripe_merchant", {
42
+ purpose: "One connected merchant",
43
+ auth: { type: "apiKey" },
44
+ mode: "production",
45
+ connectedAccount: "acct_…",
46
+ }),
47
+ ];
48
+ ```
49
+
50
+ | 0.30 configuration | Now |
51
+ | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
52
+ | No `auth`, or `auth: { type: "oauth" }` | `auth: { type: "oauth" }`. Same endpoint, reviewed catalog, guide conventions, and grant. |
53
+ | `auth: { type: "headers", headers }` with `mode` | `auth: { type: "apiKey" }` with `mode`. Paste the key into the connection in the operator UI; literal keys are gone. |
54
+ | `auth: { type: "credential" }` with `mode` | `auth: { type: "apiKey" }` with `mode`. A key stored for the same connector id carries over; run its Test action. |
55
+ | `connectedAccount` with `headers` auth | `connectedAccount` with `auth: { type: "apiKey" }`; it now works with an operator-managed key. |
56
+ | `mode` or `connectedAccount` with OAuth | Refused by name at construction, as before. |
57
+
58
+ The key connector keeps Stripe's tool names (`stripe_api_search`,
59
+ `stripe_api_details`, `stripe_api_read`, `stripe_api_write`,
60
+ `get_stripe_account_info`, and `get_balance_summary`) with Connecta's own
61
+ contracts: search finds operations in a pinned API index, every call is
62
+ checked against that index before it is sent, results arrive as
63
+ `{ status, data, page? }`, and POST writes send the caller's `idempotencyKey`
64
+ or a generated one as `Idempotency-Key` and return it (DELETE sends none).
65
+ Every request, v1 and v2, sends `Stripe-Version: 2026-09-30.endive`, the
66
+ version of the pinned index, whatever the account's default API version, so
67
+ response shapes and accepted parameters follow that version. Check fields
68
+ your programs rely on with `stripe_api_details`.
69
+ A key whose `sk_live_`/`rk_live_` or `sk_test_`/`rk_test_` prefix contradicts
70
+ `mode` is refused before any request. Organization keys (`sk_org_…`) need a
71
+ `Stripe-Context` header the connector does not send; use an account key.
72
+
73
+ Lost on the key path: natural-language Sigma (`stripe_analytics`), metrics,
74
+ documentation search, the implementation planner, reports, and feedback exist
75
+ only on the hosted OAuth connection. Programs calling those tools on a key
76
+ connector need an OAuth connector beside it. The
77
+ [Stripe skill](https://github.com/zackbart/connecta/blob/main/src/providers/stripe/SKILL.md)
78
+ owns the conventions for both.
79
+
80
+ ## Notion
81
+
82
+ Every `notion()` call must now name `auth`. 0.30 defaulted to hosted MCP and
83
+ selected the REST interface with `surface: "api"`; `surface` is gone:
84
+
85
+ ```ts
86
+ connectors: [
87
+ notion("notion", { purpose: "Workspace content as the signed-in user", auth: { type: "oauth" } }),
88
+ notion("notion_bot", { purpose: "Internal integration content", auth: { type: "token" } }),
89
+ ]
90
+ ```
91
+
92
+ | 0.30 configuration | Now |
93
+ | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
94
+ | No `surface`, or `surface: "mcp"` | `auth: { type: "oauth" }`. Same endpoint, reviewed catalog, grant, and optional `callAdmission`. |
95
+ | `surface: "api"` | `auth: { type: "token" }`. The integration token stored for the same connector id carries over; run its Test action. |
96
+ | `credentialLabel` or `defaultPageSize` | Token only, as before. Under OAuth they are refused by name at construction. |
97
+ | `integration_search`, `_get_page`, `_get_page_content`, `_get_data_source_schema`, `_query_data_source`, `_create_page`, `_append_blocks` | Unchanged names and contracts. `integration_append_blocks` also takes `checklist`. |
98
+ | `integration_get_database` | `notion_api_read` `GET /v1/databases/{database_id}`. |
99
+ | `integration_get_page_property` | `notion_api_read` `GET /v1/pages/{page_id}/properties/{property_id}`; `truncated_properties` names it. |
100
+ | `integration_list_users`, `integration_get_self` | `notion_api_read` `GET /v1/users` or `GET /v1/users/me`. |
101
+ | `integration_list_comments`, `integration_add_comment` | `notion_api_read` `GET /v1/comments`; `notion_api_write` `POST /v1/comments`. |
102
+ | `integration_update_page_properties`, `integration_trash_page` | `notion_api_write` `PATCH /v1/pages/{page_id}` with `properties`, or `in_trash` to trash or restore. |
103
+
104
+ The token connector gains Connecta's generic REST tools over Notion's pinned
105
+ API index (`notion_api_search`, `notion_api_details`, `notion_api_read`,
106
+ `notion_api_write`), so every public operation is reachable with the bot's
107
+ token: views, page moves and Markdown, meeting notes, custom agents and
108
+ sessions, file uploads by `external_url`, and data source changes. Every call
109
+ is checked against the index before it is sent, and results arrive as
110
+ `{ status, data, page? }`. The read-only POST queries (search, data source,
111
+ meeting notes, agents, sessions, and session events) use `notion_api_read`;
112
+ `page.in: "body"` says their cursor goes back in the body. Notion's OAuth token
113
+ endpoints and multipart file sends are refused. The 0.29 reconciliation table
114
+ and the `surface: "api"` complement rules no longer apply to Notion.
115
+
116
+ Lost per mode. A token connector acts as the integration bot, never as a
117
+ person, and has none of the hosted MCP's search across connected apps, page
118
+ duplication, team and skill search, attachment downloads, or page-to-skill
119
+ conversion. An OAuth connector acts as the user, and has none of the generic
120
+ REST tools or the `integration_*` projections and authoring helpers. Configure
121
+ both ids when a deployment needs both; a failed call is never retried on the
122
+ other. The [Notion skill](https://github.com/zackbart/connecta/blob/main/src/providers/notion/SKILL.md)
123
+ owns the conventions for both.
124
+
125
+ ## Vercel
126
+
127
+ Every `vercel()` call must now name `auth`. `surface` is gone, and so are the
128
+ 0.29 ownership rules that made the REST complement refuse whatever the hosted
129
+ server also covered: each implementation is complete on its own.
130
+
131
+ ```ts
132
+ connectors: [
133
+ vercel("vercel", { purpose: "Deployment diagnosis", auth: { type: "oauth" } }),
134
+ vercel("vercel_rest", { purpose: "Production apps", auth: { type: "token" }, teamId: "team_…" }),
135
+ ]
136
+ ```
137
+
138
+ | 0.30 configuration | Now |
139
+ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
140
+ | No `surface`, or `surface: "mcp"` | `auth: { type: "oauth" }`. Same endpoint, reviewed catalog, and grant. |
141
+ | `surface: "api"` with `teamId` or `baseUrl` | `auth: { type: "token" }` with the same options. A token stored for the same connector id carries over; run its Test action. |
142
+ | `defaultPageSize` | Removed (it already had no effect). Pass `limit` in `query`, and follow `page.next` as `page.param`. |
143
+ | `teamId` or `baseUrl` with OAuth | Refused by name at construction. |
144
+ | `vercel_api_get`, `vercel_api_mutate` | `vercel_api_read` and `vercel_api_write`: `query` is a JSON object, not name/value pairs, and `teamId: null` replaces `personalAccount: true`. |
145
+ | `verify_project_domain`, `remove_project_domain`, `delete_deployment` | `vercel_api_write` with the operation from `vercel_api_search`, such as `DELETE /v13/deployments/{id}`. |
146
+ | `vercel_api_upload` with any path and headers | `vercel_api_upload` on octet-stream operations in the index (`POST /v2/files`, project avatars, Remote Cache artifacts); Connecta computes `x-vercel-digest`. |
147
+
148
+ The token connector serves `vercel_api_search`, `vercel_api_details`,
149
+ `vercel_api_read`, and `vercel_api_write` over Vercel's OpenAPI document,
150
+ pinned by content hash because Vercel does not version it. Every call is
151
+ checked against the pinned index before it is sent, and results arrive as
152
+ `{ status, data, page? }`. It adds `list_teams`, the value-safe environment
153
+ variable tools (`list_project_env_vars`, `upsert_project_env_var`,
154
+ `update_project_env_var`, `delete_project_env_var`),
155
+ `get_deployment_build_logs` (build events, never following), `get_runtime_logs`
156
+ (the runtime stream, stopped after `waitMs` or `maxRows`), and
157
+ `vercel_api_upload`.
158
+
159
+ Value safety follows a reviewed table (`src/providers/vercel/value-safety.ts`).
160
+ Every operation whose response schema in the pinned spec may carry a credential
161
+ or a stored secret has a verdict: refused (credential minting, Connect
162
+ authorization, decrypted environment values, Global Config items and tokens,
163
+ domain transfer codes, KMS signing), redacted at reviewed field paths
164
+ (environment values, protection-bypass secrets, deploy hook URLs, drain and
165
+ webhook headers and destination URLs beyond their origin, external route and
166
+ redirect destinations beyond their origin, the args and values of every header,
167
+ cookie, and query rule (route transforms and conditions, firewall conditions), team invite codes, synced Global Config items, URL credentials, and signing
168
+ secrets, including the one a new webhook or drain returns at creation), or
169
+ safe with a reason. Detection reads field names, field descriptions, and
170
+ operation descriptions, so a project transfer request (whose code lets another
171
+ team claim the project) is refused too. A test fails when
172
+ a newly flagged operation has no verdict. A key-name heuristic covers every
173
+ other body as defense in depth. Secret-family failures carry fixed messages
174
+ instead of Vercel's text, and every other reviewed operation also withholds that
175
+ text ([value safety](#value-safety-on-every-key-connector)). Read or rotate withheld secrets in the Vercel
176
+ dashboard. A domain move-out is refused because its answer is a transfer token.
177
+
178
+ Lost on the token path: documentation search, runtime error clusters, toolbar
179
+ threads, agent runs, web analytics summaries, purchase quotes and guided
180
+ purchases, `deploy_to_vercel`, and access grants for protected URLs exist only
181
+ on the hosted OAuth connection. Programs calling those tools need an OAuth
182
+ connector beside the token connector.
183
+
184
+ The hosted connection now lists `filter_project_envs`, `get_project_env`,
185
+ `create_project_env`, and `edit_project_env`, which 0.29 hid. The two reads can
186
+ return decrypted values, so they are reviewed as writes and the pool trust
187
+ policy gates them. Vercel admits only reviewed and approved MCP clients to its
188
+ hosted server; if authorization is refused for that reason, the deployment
189
+ needs Vercel's approval or a token connector. The
190
+ [Vercel skill](https://github.com/zackbart/connecta/blob/main/src/providers/vercel/SKILL.md)
191
+ owns the conventions for both.
192
+
193
+ ## Cloudflare
194
+
195
+ Every `cloudflare()` call must now name `auth`. 0.30 defaulted to hosted MCP
196
+ when `surface` was omitted; that default is gone with `surface` itself:
197
+
198
+ ```ts
199
+ connectors: [
200
+ cloudflare("cloudflare", {
201
+ purpose: "Estate changes",
202
+ auth: { type: "oauth" },
203
+ }),
204
+ cloudflare("cloudflare_api", {
205
+ purpose: "Production DNS and Workers",
206
+ auth: { type: "apiToken" },
207
+ accountId: "<account id>",
208
+ zoneId: "<zone id>",
209
+ pin: { accountIds: ["<account id>"] },
210
+ }),
211
+ cloudflare("cloudflare_legacy", {
212
+ purpose: "Legacy zones behind a user key",
213
+ auth: { type: "globalApiKey" },
214
+ pin: { zoneIds: ["<zone id>"] },
215
+ }),
216
+ ];
217
+ ```
218
+
219
+ | 0.30 configuration | Now |
220
+ | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
221
+ | No `surface`, or `surface: "mcp"`, with OAuth | `auth: { type: "oauth" }`. Same endpoint, catalog, and grant. |
222
+ | `surface: "mcp"` with `auth: { type: "credential" }` | `auth: { type: "apiToken" }`: bearer tokens no longer reach `mcp.cloudflare.com`. A token stored for the same connector id carries over. |
223
+ | `surface: "api"` (API token) | `auth: { type: "apiToken" }` with the same `accountId`, `zoneId`, `baseUrl`, and `maxConcurrency`. |
224
+ | `surface: "api"`, `authentication: "globalApiKey"` | `auth: { type: "globalApiKey" }` plus `pin: { accountIds, zoneIds }`, or `unpinned: true` to accept the user's whole estate. |
225
+ | `credential` override | Removed; the credential slot's copy is fixed. |
226
+ | `callAdmission` with hosted MCP | Unchanged under `auth: { type: "oauth" }`. |
227
+
228
+ The key connector is complete on its own. JSON writes that 0.30 refused on an
229
+ API token (they belonged to hosted `execute`) go through
230
+ `cloudflare_api_write`, checked against a pinned API index before they are
231
+ sent. The 23 hand-written reads (`get_zone`, `list_dns_records`,
232
+ `list_r2_objects`, `list_pages_deployments`, and the rest) are replaced by
233
+ `cloudflare_api_read` on the same paths; results are Cloudflare's own
234
+ `result`, unprojected, so programs pass `select` instead of reading the old
235
+ projections. `list_accounts`, `list_zones`, and `cloudflare_api_upload` keep
236
+ their names (upload now takes `parts` for multipart); `verify_api_token` and
237
+ `verify_global_api_key` become `verify_credential`; `cloudflare_api_get` and
238
+ `cloudflare_api_mutate` become `cloudflare_api_read` and `cloudflare_api_write`.
239
+ `graphql_query` is new.
240
+
241
+ Credentials stay in the dashboard. The key connector refuses every operation
242
+ that mints, rotates, or returns a credential (API tokens, Access service
243
+ tokens, R2 temporary credentials, signing keys, direct-upload URLs, deploy
244
+ hooks) and redacts stored secrets on every result. A pinned connector refuses
245
+ operations that name no account or zone unless they are reviewed safe, such
246
+ as `/certificates` and `/memberships/{id}`.
247
+
248
+ Read-only pools: hosted `execute` is always a write, even for a program that
249
+ only reads, so a read-only pool on an OAuth connector reaches only `search`.
250
+ Use an API-token connector for read-only API access.
251
+
252
+ Lost on each path. OAuth has no index validation, named tools, GraphQL tool,
253
+ upload tool, or pin; Cloudflare's OAuth grant is the only boundary. A key has
254
+ no hosted `search` over Cloudflare's live OpenAPI document; the pinned index
255
+ replaces it and `providers:check` reports when it falls behind. A Global API
256
+ Key cannot reach R2, which accepts API tokens only. The
257
+ [Cloudflare skill](https://github.com/zackbart/connecta/blob/main/src/providers/cloudflare/SKILL.md)
258
+ owns the conventions for both.
259
+
260
+ ## Value safety on every key connector
261
+
262
+ All four key connectors now share one value-safety mechanism: a reviewed
263
+ table per vendor over every operation the detector flags in the pinned spec,
264
+ one redaction pass on every result, and one error policy
265
+ ([architecture](./architecture.md#value-safety-for-rest-vendors)). Results
266
+ lose fields they returned before. A `"[redacted]"` value is never the real
267
+ one; read or rotate withheld secrets in the vendor's dashboard.
268
+
269
+ - **Stripe** refuses operations that hand out a credential: ephemeral keys,
270
+ Terminal connection tokens, account links, Express login links, account and
271
+ customer sessions, billing portal sessions, file link creation, Financial
272
+ Connections session creation, and the meter event session. Results redact
273
+ client secrets (PaymentIntents, SetupIntents, Checkout and Identity
274
+ sessions, Sources, Financial Connections, invoice confirmation secrets),
275
+ webhook and event destination signing secrets, Apps secret payloads,
276
+ app-install authorization codes, Terminal Wi-Fi passwords, forwarded
277
+ request header values, and Issuing card numbers and CVCs; webhook, file
278
+ link, and pre-signed import URLs keep only their scheme and host, and the
279
+ rules follow each object into expansions, lists, and events (an expanded
280
+ File's links, an event's `previous_attributes`). Identity verification
281
+ URLs are unchanged. A Checkout Session's URL is returned whole only for a
282
+ guest payment session (`mode: "payment"`, no `customer` or
283
+ `customer_account`, no customer creation, no saved payment method options);
284
+ any other session returns only its scheme and host, because its page can
285
+ show, reuse, or remove a customer's saved payment methods. v2 account
286
+ links and Terminal onboarding links are refused too. Issuing `number` and
287
+ `cvc` expansions are refused on every Issuing path, not only cards.
288
+ Failures of credential-bearing operations keep Stripe's type, code, and
289
+ param but not its message. Create client-side sessions and links from your
290
+ own server code.
291
+ - **Notion** results withhold the signature, credential, and security-token
292
+ parameters of pre-signed file URLs, so a returned file URL no longer
293
+ downloads; credential-named fields, including database properties named
294
+ like credentials, read as `"[redacted]"`. Failures of the OAuth, file
295
+ upload, bot user, and agent operations keep Notion's code but not its
296
+ message.
297
+ - **Vercel** replaces environment values with `"[redacted]"` instead of
298
+ dropping the field, and withholds Vercel's error text for every reviewed
299
+ operation and every operation whose request takes a credential-named
300
+ field, not only secret families. Audit event invite codes, integration
301
+ drain headers, and route header values are redacted too.
302
+ - **Cloudflare** redacts Hyperdrive database passwords, RealtimeKit storage
303
+ credentials, transform-rule header values, and dispatch binding values,
304
+ and reduces notification, RealtimeKit, and data security webhook
305
+ destinations to their scheme and host. A credential-named field now loses
306
+ its whole value, not only its strings (a `cookies` list, a variable named
307
+ `API_KEY`).
@@ -1,11 +1,21 @@
1
1
  # Notion, Vercel and Cloudflare migration for 0.29
2
2
 
3
+ Use this upgrade guide for an existing deployment.
4
+ [Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover other
5
+ version changes; [integrating services](./integrating.md) covers new connectors.
6
+ [The agent index](./README.md) routes package maintenance separately.
7
+
3
8
  This is the Phase 1 item 5d migration input for [Phase 5 release #709](https://github.com/zackbart/connecta/issues/709).
4
9
  Deploy it with the consolidated 0.29 release, not while the rework is in progress.
5
10
  BePresent and One&Many use Notion and Cloudflare; their actual grants and
6
11
  connector ids must be checked in deployment configuration before that release.
7
12
  The provider audit establishes available auth modes, not production OAuth grants.
8
13
 
14
+ Cloudflare's part of this guide is superseded: `cloudflare()` now selects its
15
+ implementation by `auth` and its key connector is complete on its own. Follow
16
+ the [provider auth migration](./provider-auth-migration.md#cloudflare) for
17
+ Cloudflare; the Cloudflare lines below record the 0.29 transition only.
18
+
9
19
  All three providers now default to hosted MCP. `surface: "api"` explicitly
10
20
  selects a REST complement and accepts only its API-specific options. The old
11
21
  Vercel/Cloudflare API modes are no longer complete alternatives; Notion retains
@@ -22,6 +32,11 @@ connectors: [
22
32
  ]
23
33
  ```
24
34
 
35
+ Notion has since moved to auth-selected implementations: `surface` is gone,
36
+ and `auth: { type: "oauth" }` or `{ type: "token" }` selects hosted MCP or the
37
+ REST connector. Upgrade with the
38
+ [provider auth migration](./provider-auth-migration.md#notion); the rest of
39
+ this paragraph records the 0.29 rules.
25
40
  Notion preserves headless/internal-integration capabilities. Add explicit
26
41
  `surface: "api"` to retain that identity and migrate old REST names to
27
42
  `integration_*`, for example `search` to `integration_search`, `create_page`
@@ -45,7 +60,9 @@ include `cf-r2-jurisdiction` only when the bucket needs it. This remains a write
45
60
  `execute` remains a write even when its program only calls GET.
46
61
  Trusted pools may execute writes; read-only pools use direct host-approved writes.
47
62
 
48
- For Vercel, authorize the owning teams in hosted OAuth, migrate discovery/logs,
63
+ Vercel's `surface` and ownership rules were later replaced: `auth` now selects
64
+ the implementation. See the [provider auth migration](./provider-auth-migration.md#vercel).
65
+ The 0.29 Vercel guidance follows for history. For Vercel, authorize the owning teams in hosted OAuth, migrate discovery/logs,
49
66
  domain listing/adding, deployment cancellation and file uploads to live MCP
50
67
  schemas, and keep the independently authorized REST complement for value-safe
51
68
  project environment variables (including `upsert: false` create-only writes), domain verification/removal and deployment
@@ -54,7 +71,7 @@ category. Raw hatches refuse all published REST counterparts, including project
54
71
  creation/update. Do not copy REST argument
55
72
  shapes into vendor tools, even when a tool name is unchanged.
56
73
 
57
- The per-provider tables map every removed name and explain retained API tools:
58
- [Notion](https://github.com/zackbart/connecta/blob/main/src/providers/notion/reconciliation.md),
59
- [Vercel](https://github.com/zackbart/connecta/blob/main/src/providers/vercel/reconciliation.md), and
60
- [Cloudflare](https://github.com/zackbart/connecta/blob/main/src/providers/cloudflare/reconciliation.md).
74
+ Every provider's table is retired with `surface`; the provider auth migration
75
+ maps their names ([Notion](./provider-auth-migration.md#notion),
76
+ [Cloudflare](./provider-auth-migration.md#cloudflare),
77
+ [Vercel](./provider-auth-migration.md#vercel)).