@zackbart/connecta 0.24.2 → 0.24.4

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 (97) hide show
  1. package/AGENTS.md +18 -20
  2. package/CHANGELOG.md +205 -1
  3. package/README.md +5 -6
  4. package/dist/auth/bearer.js +2 -0
  5. package/dist/auth/downstream-oauth.d.ts +12 -1
  6. package/dist/auth/downstream-oauth.js +147 -35
  7. package/dist/branding.d.ts +31 -2
  8. package/dist/branding.js +116 -8
  9. package/dist/call-admission.d.ts +4 -0
  10. package/dist/call-admission.js +26 -0
  11. package/dist/catalog-drift.js +9 -4
  12. package/dist/catalog-service.d.ts +2 -0
  13. package/dist/catalog-service.js +25 -8
  14. package/dist/catalog.d.ts +2 -0
  15. package/dist/catalog.js +246 -121
  16. package/dist/connectors/api.d.ts +1 -1
  17. package/dist/connectors/api.js +21 -3
  18. package/dist/connectors/guarded-fetch.d.ts +6 -2
  19. package/dist/connectors/guarded-fetch.js +61 -24
  20. package/dist/connectors/remote-mcp.js +92 -57
  21. package/dist/errors.d.ts +28 -3
  22. package/dist/errors.js +60 -1
  23. package/dist/execute.js +85 -23
  24. package/dist/executor-result.js +3 -1
  25. package/dist/executors/quickjs-child.js +5 -1
  26. package/dist/executors/quickjs-protocol.d.ts +4 -0
  27. package/dist/executors/quickjs-runtime.d.ts +1 -1
  28. package/dist/executors/quickjs-runtime.js +38 -21
  29. package/dist/executors/quickjs.js +68 -27
  30. package/dist/index.d.ts +15 -1
  31. package/dist/index.js +36 -4
  32. package/dist/invocation.js +134 -93
  33. package/dist/mcp-result.js +3 -2
  34. package/dist/meta-tools.js +191 -36
  35. package/dist/operator-ui/generated.js +2 -2
  36. package/dist/operator-ui/view.d.ts +38 -1
  37. package/dist/operator-ui/view.js +71 -0
  38. package/dist/providers/cloudflare.d.ts +14 -2
  39. package/dist/providers/cloudflare.js +107 -16
  40. package/dist/providers/linear.d.ts +26 -4
  41. package/dist/providers/linear.js +19 -4
  42. package/dist/providers/mixpanel.d.ts +16 -3
  43. package/dist/providers/mixpanel.js +13 -2
  44. package/dist/providers/notion.d.ts +8 -1
  45. package/dist/providers/notion.js +83 -10
  46. package/dist/providers/revenuecat.d.ts +30 -4
  47. package/dist/providers/revenuecat.js +42 -4
  48. package/dist/providers/stripe.d.ts +7 -1
  49. package/dist/providers/stripe.js +30 -4
  50. package/dist/providers/vercel.js +11 -1
  51. package/dist/registry.d.ts +22 -2
  52. package/dist/registry.js +101 -13
  53. package/dist/routes/mcp.d.ts +4 -1
  54. package/dist/routes/mcp.js +84 -13
  55. package/dist/routes/oauth.js +4 -0
  56. package/dist/routes/shared.d.ts +1 -0
  57. package/dist/routes/shared.js +4 -4
  58. package/dist/server.js +15 -3
  59. package/dist/skills.js +6 -5
  60. package/dist/storage/file.d.ts +6 -2
  61. package/dist/storage/file.js +312 -34
  62. package/dist/storage/memory.js +12 -1
  63. package/dist/types.d.ts +37 -0
  64. package/dist/ui.js +18 -10
  65. package/dist/validate.js +3 -3
  66. package/dist/version.d.ts +1 -1
  67. package/dist/version.js +1 -1
  68. package/documentation/architecture.md +193 -165
  69. package/documentation/auth.md +199 -145
  70. package/documentation/code-mode.md +433 -316
  71. package/documentation/meta-tools.md +363 -355
  72. package/examples/worker/AGENTS.md +2 -1
  73. package/examples/worker/README.md +12 -10
  74. package/examples/worker/src/index.ts +12 -15
  75. package/package.json +1 -2
  76. package/templates/node/.env.example +3 -3
  77. package/templates/node/AGENTS.md +5 -4
  78. package/templates/node/README.md +2 -1
  79. package/templates/node/package.json +1 -1
  80. package/templates/node/src/index.ts +23 -22
  81. package/documentation/call-admission.md +0 -142
  82. package/documentation/cloudflare.md +0 -471
  83. package/documentation/connector-guides.md +0 -176
  84. package/documentation/connectors.md +0 -389
  85. package/documentation/linear.md +0 -193
  86. package/documentation/mixpanel.md +0 -160
  87. package/documentation/notion.md +0 -308
  88. package/documentation/operations.md +0 -359
  89. package/documentation/operator-ui.md +0 -135
  90. package/documentation/optional-modules-upgrade.md +0 -243
  91. package/documentation/provider-conventions.md +0 -722
  92. package/documentation/request-admission.md +0 -170
  93. package/documentation/revenuecat.md +0 -305
  94. package/documentation/storage-and-credentials.md +0 -201
  95. package/documentation/stripe.md +0 -262
  96. package/documentation/upgrading.md +0 -754
  97. package/documentation/vercel.md +0 -241
@@ -1,754 +0,0 @@
1
- # Upgrading an existing deployment
2
-
3
- For the agent working *inside* a generated deployment rather than inside this
4
- repository. You did not create this project, you cannot re-run `connecta init`
5
- over it, and the thing you are holding is two files' worth of the owner's
6
- intent wrapped in eight files of template that has moved on without it.
7
-
8
- The shape of the job is fixed by two facts. A deployment is
9
- [config-as-code](../ethos.md): `src/index.ts` is the product, everything around
10
- it is scaffolding. And `connecta init` **refuses to merge into an existing
11
- path** — deliberately, because an initializer that overwrites is an initializer
12
- that eventually overwrites a connector set. So an upgrade is not a re-init. It
13
- is: read what you have, bump the pin, reconcile the scaffolding against the
14
- current template with the deployment's own generation as the base, migrate what
15
- the release notes broke, and prove it with `connecta doctor`.
16
-
17
- Work on a branch. Every step below is reversible until you delete the old
18
- lockfile, and you want the diff reviewable by whoever owns this deployment.
19
-
20
- ## 0.24.0 optional modules
21
-
22
- UI, encrypted credentials, activity history, and configured bearer auth now use
23
- explicit module imports. Core keeps the same seven tools and enforcement.
24
- Connecta-issued tokens are removed. Shared and personal auth management require
25
- separate explicit permissions, both denied by default; visibility alone grants
26
- neither. `activityAccess` replaces `operatorAccess` for global history reads.
27
-
28
- Follow the [optional-module migration](./optional-modules-upgrade.md) before
29
- upgrading. It includes the complete before-and-after configuration, team Worker
30
- and personal Node permission examples, issued-token client migration, disabling
31
- features, and verification. Preserve existing connector ids, identity namespaces,
32
- storage, and encryption key. Vault and OAuth records need no format migration;
33
- old issued-token records remain inert rather than being deleted automatically.
34
-
35
- ## 0.23.0 program API pruning
36
-
37
- This update removes MCP Apps rendering, connector shortcut globals,
38
- `connecta.batch`, automatic direct-call retries, and connector-owned HTTP routes. Refresh the client's MCP
39
- instructions and tool definitions after upgrading. The seven top-level tools,
40
- operator pages, credentials, result paging, and media emission remain.
41
-
42
- | Before | After |
43
- | --- | --- |
44
- | Connector `handleRequest(request, ctx)` | Move custom HTTP routes into the existing deployment fetch handler |
45
- | `await tracker.list_issues(args)` | `await connecta.call("tracker.list_issues", args)` using the exact address from discovery |
46
- | `await connecta.batch(calls)` | `Promise.all` over `connecta.call`, or `Promise.allSettled` to keep failures alongside successes |
47
- | `await connecta.ui(html)` | Return the data the client needs to render its own view |
48
- | `call_tool` or `call_destructive_tool` with `maxRetries` | Omit the removed argument; each call makes one attempt and returns typed failures with provider retry hints |
49
-
50
- A connector that still declares `handleRequest` refuses construction. Handle
51
- custom routes in the existing Node or Worker deployment before delegating other
52
- requests to `connecta.fetch`. The deployment owns authentication and security
53
- headers for its custom responses. Connecta returns 404 for unknown paths.
54
- Cloudflare Global API Key authentication and multi-field credentials remain
55
- supported; they need no migration.
56
-
57
- The direct-call schemas reject unknown arguments, including `maxRetries`, before
58
- invocation. Review stored programs and deployment-owned usage guides for the
59
- removed guest functions. Canonical addresses preserve punctuation; do not copy
60
- the old sanitized shortcut into the address string.
61
-
62
- ```js
63
- async () => {
64
- const outcomes = await Promise.allSettled([
65
- connecta.call("tracker.list_issues", { state: "started" }),
66
- connecta.call("tracker.list_projects", {}),
67
- ]);
68
- return outcomes.map((outcome) => outcome.status === "fulfilled"
69
- ? { ok: true, data: outcome.value }
70
- : { ok: false, code: outcome.reason.code, message: outcome.reason.message });
71
- }
72
- ```
73
-
74
- Reduce large successful values before returning. Promise rejection reasons are
75
- Error objects; explicitly select their fields for JSON output. Every call still
76
- passes through the existing read-only checks, admission limits, deadlines, and
77
- 20-call program budget. Rate-limited calls return `retryAfterMs` without waiting;
78
- the client can reissue after that delay. No storage migration is required.
79
-
80
- ## Read what you have first
81
-
82
- Three questions, in order. Answer all three before editing anything — the
83
- second and third are what stop you from "restoring" a file the owner changed on
84
- purpose.
85
-
86
- ### 1. What version is it pinned to
87
-
88
- ```sh
89
- node -p "require('./package.json').dependencies['@zackbart/connecta']"
90
- ```
91
-
92
- `init` writes that pin as an **exact** version, never a range, because the
93
- generated deployment and the package are separate release units
94
- ([operations](./operations.md#deployment-as-a-release-unit)). So the pin is
95
- also a fact about history: it is the version of the CLI that generated this
96
- project, unless someone has bumped it since — which `package-lock.json` will
97
- tell you.
98
-
99
- ```sh
100
- node -p "require('./package-lock.json').packages['node_modules/@zackbart/connecta'].version"
101
- ```
102
-
103
- Pin and lockfile agreeing means nobody has touched the dependency by hand. They
104
- disagreeing is the first thing to reconcile, and the lockfile is usually the
105
- truth about what has actually been running.
106
-
107
- A deployment with no `@zackbart/connecta` entry at all, or one carrying a range
108
- (`^0.14.0`), was not produced by `connecta init` — treat it as the pre-template
109
- case below.
110
-
111
- ### 2. Which template generation it came from
112
-
113
- The pin answers this, and the file layout corroborates it. Two generations
114
- exist so far:
115
-
116
- | Generation | Versions | Layout |
117
- | --- | --- | --- |
118
- | **pre-template** | before 0.10.2 | no `connecta init` existed; hand-written, or copied from the retired `examples/node` |
119
- | **A** | 0.10.2 – 0.15.1 | `.env.example`, `.gitignore`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `package.json`, `src/index.ts`, `tsconfig.json` |
120
- | **B** | 0.16.0 – 0.24.2 | adds `.dockerignore`, `Dockerfile`, `docker-compose.yml`, and `src/file-activity.ts`; `src/index.ts` grows the four commented operator blocks; `.env.example` ships `CONNECTA_TOKEN=` empty |
121
-
122
- Generation A is a decade in template years and identifying it precisely does
123
- not matter, because you are about to reconstruct it exactly rather than guess
124
- at it. What matters is the boundary: a project with no `Dockerfile` is a
125
- generation A project, and the whole container story is a change it has never
126
- seen.
127
-
128
- ### 3. What this deployment changed
129
-
130
- Regenerate the deployment's *own* starting point and diff against it. `init`
131
- pins from the CLI package's version, so an old CLI reproduces its own
132
- generation byte for byte:
133
-
134
- ```sh
135
- SCRATCH=$(mktemp -d) # keep this shell
136
- (cd "$SCRATCH" && npx @zackbart/connecta@0.15.1 init base) # ← the pin from step 1
137
- ```
138
-
139
- `$SCRATCH` is the one scratch path for the whole upgrade — the reconcile step
140
- below generates the current template into it too, and every later command
141
- resolves against it. Run the rest from the deployment root:
142
-
143
- ```sh
144
- diff -ru "$SCRATCH/base" . --exclude node_modules --exclude package-lock.json
145
- ```
146
-
147
- Everything that differs is deployment-owned and survives this upgrade
148
- unconditionally. Everything identical is scaffolding you may replace without
149
- asking. Expect the interesting half to be:
150
-
151
- - **`src/index.ts`** — the connector set, `auth`, `storage`, `publicUrl`, and
152
- whichever operator blocks were uncommented. This file is never overwritten,
153
- only edited.
154
- - **`package.json`** — extra dependencies (`@clerk/backend` if operator
155
- sign-in is on, provider SDKs the owner added, anything a handler imports)
156
- and extra scripts.
157
- - **`.env.example` / deployment docs** — variables the owner's connectors read.
158
- - Whole files that are not in any generation: extra `src/*.ts` modules behind
159
- `api()` handlers, CI workflows, infrastructure.
160
-
161
- Write the list down before you touch anything. You will use it twice: once to
162
- know what to preserve, once to know what to re-verify at the end.
163
-
164
- ## The upgrade
165
-
166
- ### Bump the pin and install
167
-
168
- ```sh
169
- npm pkg set dependencies.@zackbart/connecta=0.24.0
170
- npm install
171
- ```
172
-
173
- Exact, not a range. The reason `init` pins exactly applies just as much on the
174
- way up: a deployment whose connector safety classifications can move under it
175
- during an unrelated `npm install` is not reviewable.
176
-
177
- `quickjs-emscripten` is a direct dependency of the generated project and an
178
- optional peer of the package (`^0.32.0`), so npm will tell you if the pin the
179
- template ships has fallen out of range. Match the template's pin rather than
180
- inventing one. If operator sign-in is enabled, `@clerk/backend` (`^3.12.0`) is
181
- the other optional peer — also a direct dependency of the deployment, because
182
- optional peers never install with core.
183
-
184
- Do not run the build yet. Reconcile first, so a single typecheck answers for
185
- both the new package and the new scaffolding.
186
-
187
- ### Reconcile the scaffolding
188
-
189
- Generate the *current* template beside the base you already made, into the same
190
- `$SCRATCH`:
191
-
192
- ```sh
193
- (cd "$SCRATCH" && npx @zackbart/connecta@0.24.2 init current)
194
- ```
195
-
196
- You now have a three-way merge with a real base: `$SCRATCH/base` is what this
197
- deployment started as, `$SCRATCH/current` is what `init` produces today, and the
198
- deployment is the third leg. For every file:
199
-
200
- | base vs current | deployment vs base | Do |
201
- | --- | --- | --- |
202
- | unchanged | unchanged | nothing |
203
- | unchanged | changed | keep the deployment's version |
204
- | changed | unchanged | take `$SCRATCH/current`'s version |
205
- | changed | changed | merge by hand — this is the only file class that needs judgment |
206
-
207
- `diff3` or `git merge-file` will do the mechanical part. From the deployment
208
- root, with the deployment's file first, the base second, and the current
209
- template third:
210
-
211
- ```sh
212
- git merge-file -p src/index.ts "$SCRATCH/base/src/index.ts" \
213
- "$SCRATCH/current/src/index.ts" > "$SCRATCH/merged-index.ts"
214
- ```
215
-
216
- New files in `$SCRATCH/current` that exist in neither base nor deployment are
217
- pure additions — copy them in. For generation A that is the entire container story
218
- (`Dockerfile`, `docker-compose.yml`, `.dockerignore`) plus
219
- `src/file-activity.ts`.
220
-
221
- Two things are worth knowing before you accept the merge:
222
-
223
- - **`.env.example` is not decoration.** The 0.16.0 template ships
224
- `CONNECTA_TOKEN=` **empty** on purpose: both Compose and `src/index.ts`
225
- refuse to start until an operator sets it, where the old `replace-me` value
226
- started a healthy, port-published deployment whose bearer token was a string
227
- published in a public repository. Take the empty value. Adding the
228
- deployment's own variables underneath is the merge; restoring a placeholder
229
- bearer is not.
230
- - **`src/index.ts` is a merge, not a takeover.** What you are adopting from
231
- `$SCRATCH/current` is the environment reading (`PUBLIC_URL`, `CONNECTA_STATE_FILE`,
232
- treating empty as unset — that is what lets one source serve both `npm start`
233
- and the container) and the commented operator blocks. What you are keeping is
234
- every connector, every credential slot, every handler, and every operator
235
- block this deployment had already uncommented. If a block is live here and
236
- commented in the current template, live wins.
237
-
238
- `AGENTS.md` (and the `CLAUDE.md` symlink beside it) is the deployment's
239
- instruction file for the next agent. Take the current one, then re-append
240
- whatever the owner added — it is usually the only "template" file with real
241
- local content in it.
242
-
243
- ### The pre-template case
244
-
245
- A deployment older than 0.10.2 has no base to diff against. Do not try to
246
- manufacture one. Instead:
247
-
248
- 1. `SCRATCH=$(mktemp -d)`, then
249
- `(cd "$SCRATCH" && npx @zackbart/connecta@0.24.2 init current)` — there is no
250
- `base` leg here, only the current template to read from.
251
- 2. Copy `$SCRATCH/current` into the deployment file by file, **skipping
252
- `src/index.ts`**.
253
- 3. Port the deployment's existing configuration into the new `src/index.ts` by
254
- hand, one connector at a time, reading each version boundary below as you
255
- go.
256
-
257
- It is more work and it is honest work: a project of that vintage predates the
258
- executor requirement, the seven-tool surface, and the `api()` construction
259
- contract, so it needs a read anyway.
260
-
261
- ## Version boundaries
262
-
263
- Only what breaks an existing deployment is listed. Everything else in
264
- [`CHANGELOG.md`](../CHANGELOG.md) is additive, and a boundary absent from this
265
- list is a boundary you can cross with a version bump. The sections run newest
266
- first, so cross them bottom-up: start at the oldest one still above this
267
- deployment's pin and work back up the page, because each boundary assumes the
268
- older ones are already done.
269
-
270
- ### 0.23.0 → 0.24.2
271
-
272
- Use the [optional-module migration](./optional-modules-upgrade.md) to select
273
- modules, grant auth-management permissions, and migrate issued-token clients.
274
- Preserve storage, encryption keys, and identity namespaces. 0.24.1 adds two
275
- optional settings, `execute.maxHostCalls` and `execute.hostCallTimeoutMs`, for
276
- deployments whose providers legitimately run past the 20-call and 15-second
277
- `execute_code` defaults, and one bounded `warn` log line per failed connector
278
- call; neither needs migration. 0.24.2 adds tool-level
279
- `connectorAccess` grants and optional named pools at `/mcp/<pool>`; a
280
- deployment that declares neither is unchanged. See [pools](./auth.md#pools).
281
-
282
- ### 0.22.3 → 0.23.0
283
-
284
- Migrate stored programs and custom connector routes using the
285
- [0.23.0 migration](#0230-program-api-pruning). Refresh client instructions
286
- and tool definitions so account titles and the revised discovery guidance take
287
- effect. No storage migration is required.
288
-
289
- ### 0.21.2 → 0.22.3
290
-
291
- Connector and user policy remain config-as-code. If `identity.connectorAccess`
292
- is configured, every interactive human may now manage the authentication of
293
- each connector that resolver makes visible. A personal connector changes only
294
- that principal's partition; a shared connector changes the deployment-wide
295
- grant. Keep shared connectors out of a member's view, or change them to
296
- `authScope: "personal"`, when that member must not rotate the shared grant.
297
- `identity.operatorAccess` continues to govern deployment access tokens and
298
- global activity.
299
-
300
- Paged results also move under the authenticated subject's storage partition.
301
- Finish any important in-flight `get_result` sequence before upgrading; its old
302
- result id is not readable from the new partition after deployment. No persisted
303
- connector catalog or credential migration is required.
304
-
305
- ### 0.20.0 → 0.21.2
306
-
307
- 0.21.2 adds no deployment migration beyond 0.21.0. The boundary is additive
308
- for Node and existing Clerk deployments. The new Worker path
309
- uses Cloudflare Access identity directly and removes Clerk only after the edge
310
- cutover has been verified. An agent can perform every repository edit; a human
311
- must attach Access, choose its policy, create service credentials, and enable
312
- Managed OAuth in the Cloudflare dashboard.
313
-
314
- For a Worker currently using Clerk, keep rollback live through the cutover:
315
-
316
- 1. Bump and install 0.21.2. Add the new provider **before** the existing Clerk
317
- provider, but remove nothing:
318
-
319
- ```ts
320
- import { cloudflareAccessAuth } from
321
- "@zackbart/connecta/auth/cloudflare-access";
322
- import { clerkAuth } from "@zackbart/connecta/auth/clerk";
323
-
324
- auth: [
325
- cloudflareAccessAuth(),
326
- // Keep the deployment's existing options and secrets unchanged.
327
- clerkAuth({ /* existing configuration */ }),
328
- ],
329
- ```
330
-
331
- Before Access is attached, the new provider fails closed and the operator
332
- shell selects Clerk. Deploy this state and run doctor with the existing
333
- `CONNECTA_TOKEN`. This separates the package/code change from the edge
334
- change and proves the old path still works.
335
-
336
- 2. In Cloudflare, attach Access to the Worker itself, apply the intended human
337
- policy, and enable Managed OAuth. Through the API this is an Access
338
- application destination of `{ "type": "worker", "worker_id": "<script
339
- tag>" }`, not a hostname application for the `workers.dev` URL: the latter
340
- gates traffic but does not provide `ctx.access`. Create an Access service
341
- token and a **Service Auth** policy for doctor and fully unattended clients.
342
- In the application's Managed OAuth settings, enable Dynamic Client
343
- Registration and add these three **Allowed redirect URIs**:
344
-
345
- ```text
346
- https://claude.ai/api/mcp/auth_callback
347
- https://chatgpt.com/connector_platform_oauth_redirect
348
- https://chatgpt.com/connector/oauth/*
349
- ```
350
-
351
- They map to
352
- `oauth_configuration.dynamic_client_registration.allowed_uris` in the
353
- Access API, not to the identity policy. The two ChatGPT entries cover its
354
- stable and callback-id forms. An empty list fails client registration only
355
- after discovery, so do not treat a working `/.well-known/*` response as
356
- proof that this step is complete.
357
- Do not create a bypass for `/.well-known/*`; Managed OAuth owns that
358
- discovery surface.
359
-
360
- 3. Reconnect interactive MCP clients to `<PUBLIC_URL>/mcp`. Their old Clerk
361
- OAuth tokens are not Cloudflare credentials, so each client performs one new
362
- browser authorization. An agent can edit client configuration and start the
363
- flow; the user still completes the identity-provider prompt. Move CI, cron,
364
- and server-to-server callers from connecta bearers to the two Access service
365
- headers. The cutover warning is literal: once Access is attached, a static
366
- bearer or `cta_…` token by itself is stopped at the edge before connecta can
367
- inspect it.
368
-
369
- 4. Verify the edge path:
370
-
371
- ```sh
372
- CF_ACCESS_CLIENT_ID=… CF_ACCESS_CLIENT_SECRET=… \
373
- npx connecta doctor --url https://connecta.example.workers.dev
374
- ```
375
-
376
- Open `/` as a human and exercise any enabled credential, token, and OAuth
377
- controls. A service token may pass doctor and MCP but must receive 403 from
378
- operator mutations.
379
-
380
- 5. After an observation window, remove `clerkAuth`, its import,
381
- `@clerk/backend`, and the Clerk variables/secrets. Until then they are inert
382
- behind Access but preserve rollback. Rollback order matters: detach Access
383
- first, then the untouched Clerk sessions and connecta bearers reach the
384
- Worker again. Reverting code first cannot help a request the edge still
385
- blocks. There is no storage migration and no token-format conversion.
386
-
387
- If the Worker exposes an intentionally public connector route, create a
388
- more-specific hostname/path Access application with a Bypass policy for that
389
- route only. `/health`, downstream OAuth callbacks, operator shells, and MCP are
390
- private under the canonical whole-Worker shape; doctor knows how to authenticate
391
- its health request.
392
-
393
- ### 0.19.0 → 0.20.0
394
-
395
- Three intake paths become deliberately strict. None changes storage, the two
396
- deployment shapes, or the exact seven-tool MCP surface.
397
-
398
- - `createConnecta` now rejects every unknown own configuration property by its
399
- complete path. Remove typos and options retired before 0.19, including the
400
- top-level `toolkits`, `credentialHealth`, `surface`, and `maxResultBytes`,
401
- plus `credentials.health` and `calls.maxBatchResultBytes`. Connector, auth,
402
- storage, activity-store, logger, deployment-metadata, and executor
403
- implementations remain open objects; their implementation-specific fields
404
- are not configuration typos.
405
- - `call_tool` and `call_destructive_tool` no longer accept `fields`. Put
406
- projection in one `execute_code` program. For a legitimate oversized direct
407
- read, call without `fields` and follow the returned `get_result` action; that
408
- paging path remains part of the seven-tool surface.
409
- - `connecta.ui` accepts one HTML string and is display-only. Remove its second
410
- read-binding argument and any page calls to `connecta.read`. Fetch and shape
411
- data in the program before rendering, then return the same compact summary
412
- the view initially displays. Views cannot call any Connecta tool.
413
-
414
- The Node template layout remains generation B. Reconcile it as usual after the
415
- version bump; no new deployment file or environment variable is required.
416
-
417
- ### 0.18.3 → 0.19.0
418
-
419
- Nothing changes for a deployment. Bump the version and reconcile the template
420
- as usual; no configuration, storage, runtime, or model-facing boundary moved.
421
- The release deletes unreachable compatibility code and consolidates source and
422
- tests behind the same public behavior. Six design records also moved out of the
423
- npm package and now live only at their GitHub URLs. They were maintainer history,
424
- not deployment documentation.
425
-
426
- ### 0.18.2 → 0.18.3
427
-
428
- Nothing throws for an existing deployment, and the version bump alone crosses
429
- this boundary. Successful explicitly read-only calls whose provider declares
430
- no output schema now teach later discovery the result's field names and broad
431
- JSON types. The open optional-field shape is labeled
432
- `outputSchemaSource: "observed"`, lives only in a bounded runtime cache, and
433
- starts cold after 24 hours, a process restart, or Worker isolate eviction. No
434
- configuration or storage migration is involved, and discovery still never
435
- executes a tool.
436
-
437
- ### 0.18.1 → 0.18.2
438
-
439
- Nothing throws for an existing deployment, and the version bump alone crosses
440
- it. The release adds a third `auth` shape to `remoteMcp()` and every maintained
441
- hosted connection — `{ type: "credential" }` — under which the connector
442
- declares an operator slot on `/credentials` and reads the pasted value on each
443
- request. A deployment carrying a static key as a runtime secret
444
- (`auth: { type: "headers", headers: { Authorization: env.KEY } }`) keeps
445
- working unchanged; moving it behind `/credentials` is an edit to the connector's
446
- `auth` and one paste on the operator page, and needs `credentials.encryptionKey`
447
- configured — a deployment without a vault gets a startup warning and
448
- `recovery: "unavailable"` at use for that connector, not a boot failure. Two
449
- Linear notes: the `headers` example in `documentation/linear.md` now shows
450
- `Bearer ${key}` (Linear's MCP server documents that framing), and the credential
451
- shape sends `Bearer` by default; a `headers` connector already sending a bare
452
- key is untouched.
453
-
454
- ### 0.18.0 → 0.18.1
455
-
456
- Nothing throws, no option moves, and every deployment crosses this on the
457
- version bump alone. The release adds one provider subpath,
458
- `@zackbart/connecta/providers/revenuecat`, and rewrites guide text inside the
459
- `mixpanel()` and `stripe()` connections; a deployment that constructs neither
460
- sees no change, and one that does gets better first-line advice for the same
461
- constructor calls. Clients that cache connector guides should refresh them
462
- after upgrading.
463
-
464
- ### 0.17.0 → 0.18.0
465
-
466
- One floor moves and one always-loaded surface shrinks; neither changes a
467
- deployment's configuration.
468
-
469
- **Node 22 is the minimum supported release.** The published engine range and
470
- the Node template both declare `>=22.0.0`, matching the template's
471
- `node:22-slim` image. A Docker deployment already runs Node 22; a bare-metal
472
- deployment on Node 20 must upgrade its runtime before taking this version.
473
- Worker deployments are unaffected (#422).
474
-
475
- **Model-facing guidance is split by load cost.** MCP instructions and tool
476
- definitions now carry route selection, the fail-closed boundary, and minimum
477
- guest syntax. Detailed selection, repair, runtime, and example guidance moved
478
- to the existing `skills({ name: "usage" })` response. Clients that never fetch
479
- the skill keep the same routes and need no deployment change; clients that
480
- cache tool definitions should refresh them after upgrading (#418).
481
-
482
- ### 0.16.1 → 0.17.0
483
-
484
- Two construction rules need a deployment check.
485
-
486
- **A Dynamic Worker executor is loader-only.** The supported construction is
487
- exactly:
488
-
489
- ```ts
490
- new DynamicWorkerExecutor({ loader: env.LOADER })
491
- ```
492
-
493
- Remove `bindings`, `modules`, or `globalOutbound` from that options object.
494
- Those fields grant guest code ambient configuration, code, or egress. This is
495
- the supported sandbox boundary rather than a new Connecta-side inspection of
496
- the third-party executor object. The shipped Worker example was already
497
- loader-only, and Node deployments use `quickJsExecutor()`, so neither needs a
498
- change (#390).
499
-
500
- **An explicit guide summary must fit discovery.** Connecta normalizes
501
- whitespace in `usageGuide.summary` and refuses registry construction when the
502
- result is longer than 120 characters. Shorten it to 120 characters or fewer,
503
- or omit it and let Connecta derive a bounded summary from the guide's opening
504
- prose. A blank explicit summary still takes the derived-summary path (#392).
505
-
506
- ### 0.16.0 → 0.16.1
507
-
508
- Nothing throws, and a Node deployment crosses this on the version bump alone.
509
- The one thing that can stop the upgrade is npm, and only on a Worker:
510
- `@cloudflare/codemode` is now a declared optional peer at `^0.4.4 || ^0.5.0`,
511
- so a `package.json` holding it below that range fails `npm install` with an
512
- `ERESOLVE` conflict instead of installing. Move the pin into the range this
513
- release is tested against. Separately, `cloudflare()` no longer names
514
- `list_zone_settings` — read one setting with `get_zone_setting`, write one with
515
- `update_zone_setting` — and Cloudflare's 404 now arrives as `not_found` rather
516
- than `connector_call_failed`, which matters only to a program that branches on
517
- the code.
518
-
519
- ### 0.15.x → 0.16.0
520
-
521
- The largest one, and it fails loudly. Every item here throws at construction or
522
- fails a specific call; none of it degrades quietly.
523
-
524
- **`api()` enforces its construction contract.** Every hand-written tool now
525
- needs three things, checked when the connector is built:
526
-
527
- - a non-empty `description` — it is what an agent reads to choose the tool;
528
- - an explicit boolean `annotations.readOnlyHint` — `true` for a read, `false`
529
- for work that must cross `call_destructive_tool`;
530
- - an `inputSchema`, if it ships one, that the validator can actually compile.
531
-
532
- The throw names the failing address (`connectorId.toolName`), so this is a
533
- mechanical walk through `src/index.ts`. The one judgment call is the
534
- classification, and the safe answer is written down for you: **a tool that used
535
- to ship unannotated becomes `readOnlyHint: false`**, because unannotated
536
- already routed through `call_destructive_tool`. That is the routing it had.
537
- Writing `true` onto a tool you have not read is not an upgrade, it is a
538
- capability change.
539
-
540
- Connecta infers the classification from nothing — not a name, not a verb, not
541
- an HTTP method, not the other annotations. There is no flag that restores the
542
- old forgiving behavior.
543
-
544
- **`ApiOptions.strictValidation` is gone.** Delete it. Fail-closed schema
545
- handling is the only behavior left, so the option had nothing to switch. A
546
- schema that only reveals itself as unenforceable on first use — an unresolvable
547
- `$ref`, say — now fails that call as non-retryable `invalid_args` instead of
548
- forwarding raw arguments to the handler. `validateArgs: false` still exists and
549
- still means what it said: opting out of enforcement, not out of the schema
550
- being real.
551
-
552
- **`linear()` requires `access`.** Construction throws naming both options.
553
- `access: "read-write"` preserves an existing deployment's behavior exactly;
554
- `"read-only"` binds the connector to Linear's read-only endpoint, whose token
555
- cannot reach the write APIs at all. There is no default because neither guess
556
- is safe — one hands out writes nobody asked for, the other breaks a writing
557
- deployment at Linear, at runtime, where no agent can repair it
558
- ([linear](./linear.md)).
559
-
560
- **`mixpanel()` declares no call-admission budget.** The old hardcoded 600
561
- calls/hour transcribed a limit Mixpanel meters *per user*, which a per-runtime
562
- counter cannot approximate in either direction. Nothing throws — the ceiling is
563
- simply absent. If this deployment was relying on it, pass `callAdmission`
564
- explicitly ([call admission](./call-admission.md)). The default title also now
565
- carries the region (`Mixpanel (us)`), and an unknown `region` throws.
566
-
567
- **Three Cloudflare tools are gone; the connection ships 52.** `set_r2_cors`,
568
- `delete_r2_cors`, and `get_r2_metrics`. Grep the deployment — and any prompt,
569
- skill, or runbook around it — for those names. No capability is lost:
570
- `get_r2_cors` still reads a bucket's policy, CORS writes go through
571
- `cloudflare_api_mutate` at
572
- `PUT`/`DELETE /accounts/{accountId}/r2/buckets/{bucketName}/cors`, and metrics
573
- through `cloudflare_api_get` at `/accounts/{accountId}/r2/metrics`
574
- ([cloudflare](./cloudflare.md)).
575
-
576
- **`cloudflare()` checks an overridden `baseUrl` at construction.** A
577
- non-loopback plain-http origin, URL-embedded credentials, or a query or
578
- fragment now throws where the option is written rather than on the first call.
579
- A deployment pointing Cloudflare at an http proxy must move it to https or bind
580
- it to loopback. The default base is unaffected, so a deployment that never set
581
- `baseUrl` reads nothing here.
582
-
583
- **Cloudflare and Notion refuse redirects and bound their reads.** Both now send
584
- `redirect: "manual"`; a 3xx fails as non-retryable `connector_call_failed`
585
- rather than re-sending the connector's credential to whatever origin `Location`
586
- names. Both also cap the response they will read — 8 MiB for Cloudflare, 4 MiB
587
- for Notion — checked against a declared `Content-Length` and again while the
588
- body streams. Visible only to a deployment that was pulling something enormous
589
- through a tool call, such as a `cloudflare_api_get` on a large R2 object. These
590
- are ceilings on absurdity; anything near them was already past whatever
591
- `maxResultBytes` the deployment set.
592
-
593
- **The shipped defaults fail closed.** Covered under `.env.example` above, and
594
- repeated here because it is the item most likely to be "fixed" backwards: an
595
- empty `CONNECTA_TOKEN` that refuses to boot is the intended state of a fresh
596
- `.env.example`, not a regression.
597
-
598
- ### 0.13.x → 0.14.x
599
-
600
- No API breaks. One behavior change worth knowing: vetted annotations on a
601
- prebuilt connection no longer argue with an explicit downstream annotation in
602
- either direction, so a name the downstream explicitly marks `readOnlyHint:
603
- true` that no release has classified is now callable from `execute_code`
604
- instead of failing closed onto the approval path. Silence on an unclassified
605
- name still means not read-only. The one branch that still outranks the
606
- downstream is a name a release reviewed and filed destructive.
607
-
608
- ### 0.12.x → 0.13.0
609
-
610
- No API breaks; text changed under existing deployments. Served tool
611
- descriptions and the MCP `instructions` string were rewritten, and `skills({})`
612
- now summarizes a connector guide from its first body line rather than its
613
- heading — a guide opening `# Acme` that listed as "Acme" now lists as the
614
- sentence beneath it. If this deployment's connectors carry usage guides, read
615
- their first lines ([connector guides](./connector-guides.md)).
616
-
617
- ### 0.10.x → 0.11.0
618
-
619
- The executor boundary. **Every deployment must configure an executor** and
620
- serves exactly seven tools; construction refuses to boot without one. On Node
621
- that is `quickJsExecutor()` from `@zackbart/connecta/quickjs`; on Workers,
622
- `new DynamicWorkerExecutor({ loader: env.LOADER })` from
623
- `@cloudflare/codemode` plus its paid-plan Worker Loader binding.
624
-
625
- The top-level `list_connectors`, `describe_tools`, and `batch_call`
626
- registrations are gone. Their equivalents live inside `execute_code` as
627
- `connecta.search`, `connecta.describe`, and `connecta.batch`
628
- ([code mode](./code-mode.md)). Anything outside the deployment that called
629
- those three by name — a client config, a prompt, a script — is what actually
630
- breaks here; the deployment file itself only has to gain the executor and drop
631
- `surface`.
632
-
633
- ### 0.6.x → 0.7.0
634
-
635
- Only a pre-template deployment is still down here; every generation A project
636
- was born above this line. Three breaks, and the config one is in the table
637
- below.
638
-
639
- **A connector implementing `finishAuth` without `verifyState` can no longer
640
- complete OAuth** (#62). The callback refuses with the same opaque 400 as every
641
- other refusal, exchanges no code, and logs one operator-grade line naming the
642
- connector and the missing hook. `verifyState` is optional in the type system and
643
- required in practice wherever `finishAuth` is present, so nothing throws at
644
- construction — the flow simply stops completing, which is the one item in this
645
- guide you find by reading rather than by building. It reaches hand-written
646
- connectors only: the shipped `remoteMcp` OAuth provider has always implemented
647
- it. The old behavior was exchanging an authorization code with no CSRF guard at
648
- all, so this is not a hook to stub out with `() => true`.
649
-
650
- **`/`, `/credentials`, and `/activity` are core-owned routes** (#57). They
651
- previously fell through to connector `handleRequest` and then to a 404, so a
652
- connector that served any of the three is now shadowed without warning. `GET /`
653
- returns the operator shell where 0.6.1 returned 404, and a non-GET on those
654
- routes or on `/ui` returns 405 instead of falling through. For the current release, move custom handlers into the deployment: connector
655
- `handleRequest` is now removed. See the [current migration](#0230-program-api-pruning).
656
-
657
- ### Removed options that throw
658
-
659
- These fail at construction rather than falling back to a default, because
660
- silently ignoring a removed option is how a deployment runs a policy its config
661
- file says it has. Releases through 0.19 name the migration in the error. Version
662
- 0.20's strict configuration boundary names the unknown path; this table remains
663
- the migration map:
664
-
665
- | Option | Removed in | Do |
666
- | --- | --- | --- |
667
- | `accessTokens` | 0.24.0 | migrate issued-token clients to provider OAuth or configured bearer auth; old records become inert |
668
- | `credentials` | 0.24.0 | `vault: encryptedCredentialVault(storage, encryptionKey)` from `/credentials` |
669
- | `branding` | 0.24.0 | `ui: operatorUi({ branding })` from `/ui` |
670
- | `identity.operatorAccess` | 0.24.0 | `identity.activityAccess`; grant shared and personal auth management separately |
671
- | `toolkits`, `unscoped` | 0.8.1 (#178) | delete; deploy one instance per audience |
672
- | `credentials.health`, `credentialHealth` | 0.8.1 (#179) | delete; credentials fail at use |
673
- | `surface` | 0.11.0 (#273) | delete; there is one seven-tool surface |
674
- | `calls.maxBatchResultBytes` | 0.11.0 (#273) | delete; program batching is bounded by `execute_code`'s own limits |
675
- | flat v0.6 config paths | 0.7.0 | move into their groups ([operations](./operations.md#configuration)) |
676
-
677
- ## Verify
678
-
679
- In order, and do not skip the last one — the first three prove the package
680
- works, not that this deployment does.
681
-
682
- ```sh
683
- npm run typecheck # ships with the template
684
- CONNECTA_TOKEN=dev-token npm start # in one shell
685
- CONNECTA_TOKEN=dev-token npm run doctor # in another
686
- ```
687
-
688
- `connecta doctor` is the gate. It asserts `/health` reports ok, that
689
- `tools/list` is exactly the seven prescribed names — `authorize_connector`,
690
- `call_destructive_tool`, `call_tool`, `execute_code`, `get_result`,
691
- `search_tools`, `skills` — and that `execute_code` actually runs a program in
692
- the sandbox. It names the executor the deployment reports rather than assuming
693
- one: `QuickJS executed` on the Node template, `DynamicWorkerExecutor executed`
694
- on a Worker. It also *reports* catalog drift without failing on it; drifted
695
- counts here are a maintainer's next task, not a failed upgrade.
696
-
697
- Then exercise this deployment's own connectors, which doctor knows nothing
698
- about — it holds a bearer, and a client key does not get to learn a
699
- deployment's configuration topology. One program covers discovery and a call:
700
-
701
- ```js
702
- // execute_code — an empty query browses the catalog
703
- async () => {
704
- const page = await connecta.search({ query: "", limit: 100 });
705
- return {
706
- total: page.total,
707
- connectors: [...new Set(page.tools.map((t) => t.address.split(".")[0]))],
708
- };
709
- };
710
- ```
711
-
712
- Walk the list from the inventory you wrote down: every connector the owner
713
- configured should appear, every credential slot should still be listed at
714
- `/credentials`, and at least one real read per connector should return data.
715
- A connector whose catalog is empty after an upgrade is usually a credential
716
- that did not survive a state-file path change, not a broken release.
717
-
718
- If the container half is now in play, `cp .env.example .env`, set
719
- `CONNECTA_TOKEN`, and `docker compose up -d --build`, then point doctor at it.
720
- Commit the `package-lock.json` that `npm install` wrote on the host — that is
721
- what puts the image build on the reproducible `npm ci` path instead of
722
- resolving the pin again inside a layer.
723
-
724
- ## What not to do
725
-
726
- Five refusals. Each one is somebody's plausible shortcut, and each one produces
727
- a deployment that is quieter and wrong.
728
-
729
- - **Do not re-init over the top.** `connecta init` refuses to merge into an
730
- existing path and that refusal is load-bearing. Working around it — into a
731
- scratch directory and then `cp -r` over the deployment, or by deleting the
732
- project and regenerating — is how a connector set becomes a `time` connector.
733
- Scratch directories are for reading and diffing, never for copying wholesale.
734
- - **Do not weaken a fail-closed default to get green.** `readOnlyHint: true` on
735
- a tool you have not read, a restored `CONNECTA_TOKEN=replace-me`,
736
- `validateArgs: false` to silence a schema that will not compile, an
737
- annotation "corrected" to match what the downstream claims: all of these turn
738
- a construction error into a running deployment with a wider blast radius than
739
- it had yesterday. The construction throw is the feature. Fix the input.
740
- - **Do not pin back.** A deployment that boots on 0.15.1 and throws on 0.16.0
741
- is a deployment telling you which line to fix, with the address in the error
742
- message. Reverting the pin keeps the same defect and buries the report.
743
- - **Do not copy Connecta internals into the deployment.** If something the
744
- deployment needs is not exported, that is a package issue to file, not a file
745
- to vendor. A deployment that carries a copy of a provider cannot be upgraded
746
- by anyone, including you, next time.
747
- - **Do not add a second project shape.** No alternate entrypoint, no second
748
- container recipe, no parallel configuration path beside `src/index.ts`. There
749
- are exactly two deployment shapes — [`templates/node/`](../templates/node/)
750
- and the Worker example — and a third that is a diff away from one of them is
751
- a shape this repository has already deleted once.
752
-
753
- When something here disagrees with [`ethos.md`](../ethos.md), the ethos wins
754
- and this guide is what needs fixing.