@zackbart/connecta 0.19.0 → 0.21.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.
- package/CHANGELOG.md +107 -0
- package/README.md +3 -1
- package/bin/connecta.mjs +23 -6
- package/dist/apps-shell.d.ts +10 -12
- package/dist/apps-shell.js +29 -220
- package/dist/auth/bearer.d.ts +2 -2
- package/dist/auth/bearer.js +2 -2
- package/dist/auth/clerk.js +1 -0
- package/dist/auth/cloudflare-access.d.ts +8 -0
- package/dist/auth/cloudflare-access.js +66 -0
- package/dist/execute.d.ts +0 -7
- package/dist/execute.js +20 -123
- package/dist/index.d.ts +2 -2
- package/dist/index.js +110 -69
- package/dist/invocation.d.ts +1 -1
- package/dist/meta-tools.d.ts +0 -1
- package/dist/meta-tools.js +10 -495
- package/dist/operator-ui/generated.d.ts +2 -2
- package/dist/operator-ui/generated.js +1 -1
- package/dist/operator-ui/model.d.ts +3 -3
- package/dist/operator-ui/view.d.ts +1 -1
- package/dist/operator-ui/view.js +6 -3
- package/dist/routes/access-tokens.d.ts +1 -1
- package/dist/routes/access-tokens.js +2 -2
- package/dist/routes/activity.js +2 -2
- package/dist/routes/credentials.js +1 -1
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/oauth.js +1 -1
- package/dist/routes/shared.d.ts +4 -4
- package/dist/routes/shared.js +10 -10
- package/dist/routes/ui.js +12 -9
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +11 -8
- package/dist/types.d.ts +37 -22
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -4
- package/documentation/auth.md +71 -7
- package/documentation/code-mode.md +23 -23
- package/documentation/meta-tools.md +26 -50
- package/documentation/operations.md +36 -21
- package/documentation/operator-ui.md +21 -5
- package/documentation/provider-conventions.md +3 -4
- package/documentation/upgrading.md +106 -8
- package/ethos.md +3 -4
- package/examples/worker/README.md +52 -32
- package/examples/worker/src/index.ts +32 -38
- package/examples/worker/wrangler.jsonc +12 -4
- package/package.json +5 -1
- package/templates/node/package.json +1 -1
|
@@ -503,9 +503,9 @@ the security posture live in the [design record](https://github.com/zackbart/con
|
|
|
503
503
|
[#277](https://github.com/zackbart/connecta/issues/277)); this section is the
|
|
504
504
|
contract, and it wins where the two disagree.
|
|
505
505
|
|
|
506
|
-
**U1.** `connecta.ui(html
|
|
507
|
-
|
|
508
|
-
|
|
506
|
+
**U1.** `connecta.ui(html)` accepts exactly one non-empty HTML string. There is
|
|
507
|
+
no options parameter, read manifest, or sugar form. Every other shape throws
|
|
508
|
+
catchably and accepts nothing.
|
|
509
509
|
|
|
510
510
|
**U2.** At most one payload per run. A second call throws catchably, naming the
|
|
511
511
|
constraint; the first accepted payload stands. One tool result renders one view,
|
|
@@ -513,7 +513,7 @@ and last-wins would silently discard a payload the program deliberately
|
|
|
513
513
|
supplied.
|
|
514
514
|
|
|
515
515
|
**U3.** Delivered on success only, and out of model context: the tool result
|
|
516
|
-
gains `_meta["connecta/ui"] = { html
|
|
516
|
+
gains `_meta["connecta/ui"] = { html }` and the JSON envelope gains `ui: true`,
|
|
517
517
|
so the model learns a view rendered without seeing its bytes. `structuredContent`
|
|
518
518
|
stays the envelope alone. The single-label `connecta/ui` prefix is deliberate —
|
|
519
519
|
connecta has no domain to reverse, and fabricating one to satisfy MCP's
|
|
@@ -526,29 +526,31 @@ with `emittedDiscarded: N` when one failure discards both.
|
|
|
526
526
|
|
|
527
527
|
**U4.** The payload spends the aggregate emit byte budget
|
|
528
528
|
(`ConnectaConfig.execute.maxEmittedBytes`), measured at the call as the
|
|
529
|
-
serialized bytes of `{ html
|
|
529
|
+
serialized bytes of `{ html }` — `M5`'s measurement. Over budget throws
|
|
530
530
|
catchably, naming the budget and the room remaining, with nothing partially
|
|
531
531
|
accepted. It spends no block count (`maxEmittedBlocks`: it is not a block) and no
|
|
532
532
|
host-call budget (`L4`). One transport bound covers everything rich a program
|
|
533
533
|
delivers.
|
|
534
534
|
|
|
535
535
|
**U5.** One static shell: a connecta-authored HTML5 document at
|
|
536
|
-
`ui://connecta/program-ui/
|
|
536
|
+
`ui://connecta/program-ui/v3`, mimeType `text/html;profile=mcp-app`, declared on
|
|
537
537
|
`execute_code` via `_meta.ui.resourceUri` together with an explicit
|
|
538
|
-
`_meta.ui.visibility: ["model"]`.
|
|
539
|
-
|
|
540
|
-
|
|
538
|
+
`_meta.ui.visibility: ["model"]`. The other six tools declare the same
|
|
539
|
+
model-only visibility without a resource URI. Omission defaults to model and
|
|
540
|
+
app visibility, which would let a display-only view call them. A
|
|
541
|
+
`resources/read` handler answers exactly that URI and fails on any other;
|
|
542
|
+
`resources/list` is served and returns an empty list.
|
|
541
543
|
The version segment bumps whenever the shell's bytes change, because hosts cache
|
|
542
544
|
templates by URI.
|
|
543
545
|
|
|
544
546
|
**U6.** The shell renders the payload in a nested iframe
|
|
545
547
|
(`srcdoc`, `sandbox="allow-scripts"`, no `allow-same-origin`) and declares no CSP
|
|
546
548
|
domains, so the host applies its restrictive default and the `about:srcdoc` frame
|
|
547
|
-
inherits `default-src 'none'; connect-src 'none'`.
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
549
|
+
inherits `default-src 'none'; connect-src 'none'`. The shell offers no direct
|
|
550
|
+
network, tool calls, discovery, conversation messages, writes, or links. It
|
|
551
|
+
participates in the Apps lifecycle — initialize, tool-result, size-changed,
|
|
552
|
+
resource-teardown — and forwards no channel whatsoever from the inner frame to
|
|
553
|
+
the host. That isolation makes
|
|
552
554
|
program views fixed-height by construction: with no bridge there is no
|
|
553
555
|
content-height signal, the shell reports only its own box, and content taller
|
|
554
556
|
than that scrolls inside the inner frame rather than growing the view.
|
|
@@ -591,16 +593,14 @@ the same mistake as automatic host-side projection, refused in `ethos.md`
|
|
|
591
593
|
|
|
592
594
|
**U13.** The always-loaded MCP instructions locate `connecta.ui(html)` before an
|
|
593
595
|
agent chooses a route: it exists only inside `execute_code`, never in connector
|
|
594
|
-
search, and carries `U12`'s mirrored-return duty. The detailed call,
|
|
595
|
-
|
|
596
|
+
search, and carries `U12`'s mirrored-return duty. The detailed call, budget,
|
|
597
|
+
and repair rules live in the on-demand `usage` skill. The location
|
|
596
598
|
distinction rides `initialize`, under a 1,000-character ceiling for the complete
|
|
597
599
|
instructions string. This promotes existing contract, not capability: the
|
|
598
600
|
seven-tool surface, guest API, catalog, Apps delivery, and runtime do not change
|
|
599
601
|
([#286](https://github.com/zackbart/connecta/issues/286),
|
|
600
602
|
[#418](https://github.com/zackbart/connecta/issues/418)).
|
|
601
603
|
|
|
602
|
-
Bounded view reads follow normative [`V1`–`V8`](https://github.com/zackbart/connecta/blob/main/records/program-ui-read-calls.md) ([#287](https://github.com/zackbart/connecta/issues/287), [#289](https://github.com/zackbart/connecta/issues/289)).
|
|
603
|
-
|
|
604
604
|
## Retry semantics
|
|
605
605
|
|
|
606
606
|
**Y1.** Connecta retries nothing beneath a program. `call_tool` accepts an
|
|
@@ -878,7 +878,7 @@ the upstream `Executor` shape assignable.
|
|
|
878
878
|
| `U1`, `U2` | `test/guest-api-contract.test.ts` (invalid and repeated calls throw catchably, first payload stands), `test/execute-ui.test.ts` (every rejected shape) |
|
|
879
879
|
| `U3` | `test/guest-api-contract.test.ts` (`_meta` payload and `ui: true`, identical on both executors), `test/execute-ui.test.ts` (`structuredContent`, byte-for-byte no-call path, discard structured and plain, coexistence with `emittedDiscarded`), `test/quickjs-executor.test.ts` (mid-run shutdown) |
|
|
880
880
|
| `U4` | `test/execute-ui.test.ts` (one shared byte aggregate crossed in either order; block count and host-call budget untouched) |
|
|
881
|
-
| `U5`, `U10`, `U11` | `test/server.test.ts` (the shell URI, mimeType, and body; every other URI fails; empty listing;
|
|
881
|
+
| `U5`, `U10`, `U11` | `test/server.test.ts` (the shell URI, mimeType, and body; every other URI fails; empty listing; exact model-only `_meta.ui` on all seven tools; exactly one declared extension) |
|
|
882
882
|
| `U6` | `test/execute-ui.test.ts` (valid HTML5, `srcdoc` and sandbox attributes, no `allow-same-origin`, no path from the inner frame to the host) |
|
|
883
883
|
| `U7`, `U8` | two arms passing one case table, `test/codemode-compat.test.ts` |
|
|
884
884
|
| `U9` | `test/execute-ui.test.ts` (a `ui` byte aggregate distinct from `emitted`, absent when nothing was accepted) |
|
|
@@ -889,11 +889,11 @@ the upstream `Executor` shape assignable.
|
|
|
889
889
|
| `X6` | `test/quickjs-executor.test.ts` (never-settling await) |
|
|
890
890
|
| `X7` | `P3`'s tests; the Workers superset is deliberately unused |
|
|
891
891
|
|
|
892
|
-
The surface itself is checked by `test/server.test.ts` (the exact seven-tool
|
|
893
|
-
|
|
892
|
+
The surface itself is checked by `test/server.test.ts` (the exact seven-tool list)
|
|
893
|
+
and `test/code-first-surface.test.ts` (the fold's construction rules, the
|
|
894
894
|
required executor, the refusals a removed top-level tool now gets, copy, and
|
|
895
|
-
measured size).
|
|
895
|
+
measured size). The small whole-agent benchmark checks both read routes, provider semantics, and private pagination:
|
|
896
896
|
|
|
897
897
|
```sh
|
|
898
|
-
npm --prefix eval/current-version run
|
|
898
|
+
npm --prefix eval/current-version run benchmark
|
|
899
899
|
```
|
|
@@ -12,19 +12,19 @@ Every deployment requires an executor and `tools/list` is exactly seven:
|
|
|
12
12
|
batching live in `connecta.search`, `connecta.describe`, and `connecta.batch`
|
|
13
13
|
inside a program ([#273](https://github.com/zackbart/connecta/issues/273)).
|
|
14
14
|
|
|
15
|
-
Code-first is what a model sees.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
is what a program is promised.
|
|
21
|
-
|
|
22
|
-
The route is chosen before discovery.
|
|
23
|
-
whose arguments depend on an earlier result, or work with
|
|
24
|
-
starts with one `execute_code` call and keeps discovery,
|
|
25
|
-
inside it. Distinct operations get distinct short
|
|
26
|
-
that program.
|
|
27
|
-
`
|
|
15
|
+
Code-first is what a model sees. Read-only work has two routes: `call_tool` for
|
|
16
|
+
one known address, and `execute_code` when discovery or any wider work is
|
|
17
|
+
needed. Real hosted catalogs reversed the earlier synthetic result that made a
|
|
18
|
+
top-level cold search look cheaper. Keeping discovery inside the program avoids
|
|
19
|
+
returning every candidate schema to the model and removes a model round trip.
|
|
20
|
+
The [guest API contract](./code-mode.md) is what a program is promised.
|
|
21
|
+
|
|
22
|
+
The route is chosen before discovery. An unknown address, a result that will be
|
|
23
|
+
reduced, a call whose arguments depend on an earlier result, or work with
|
|
24
|
+
multiple operations starts with one `execute_code` call and keeps discovery,
|
|
25
|
+
calls, and reduction inside it. Distinct operations get distinct short
|
|
26
|
+
`connecta.search` queries in that program. A known address needs only
|
|
27
|
+
`call_tool`.
|
|
28
28
|
|
|
29
29
|
That routing is about read-only work, because that is the only work a program
|
|
30
30
|
can do. Anything unannotated, write-capable, or destructive is inadmissible
|
|
@@ -68,13 +68,15 @@ and a truncated line ends with the exact `+N more` count. This reads only the
|
|
|
68
68
|
configured registry: it loads no catalog, probes no credential, grants no
|
|
69
69
|
capability, and does not replace canonical discovery or addressing.
|
|
70
70
|
|
|
71
|
-
Start
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
Start a lookup with two to four distinctive action/object terms, not the full
|
|
72
|
+
request. Read-only lookup belongs in `connecta.search` inside the program.
|
|
73
|
+
Top-level `search_tools` remains available for explicit catalog inspection and
|
|
74
|
+
approval-required discovery. Omit `limit` initially so the default
|
|
75
|
+
eight-result page stays small. When the integration is obvious, set
|
|
76
|
+
`connector` to its id: a scoped search loads that catalog alone, while an
|
|
77
|
+
unscoped search must fan out across every configured connector. Leave the
|
|
78
|
+
search unscoped when the right integration is genuinely ambiguous. Set
|
|
79
|
+
`safety: "readOnly"` for generated code; `safety: "approvalRequired"` finds the
|
|
78
80
|
complementary set that must cross `call_destructive_tool`. Omitting `safety`,
|
|
79
81
|
or setting it to `"all"`, preserves the complete configured catalog. This is
|
|
80
82
|
only a discovery filter: it neither grants authority nor changes invocation admission.
|
|
@@ -192,36 +194,10 @@ offsets and totals refer to that exact compact text.
|
|
|
192
194
|
A `call_tool` truncation notice carries both the historical `resultId` and an
|
|
193
195
|
exact `nextAction: { tool: "get_result", arguments: { id, offset: 0 } }`. The
|
|
194
196
|
handle is therefore
|
|
195
|
-
directly actionable without copying an identifier out of prose
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
`fields` keeps its historical flat `{ "<path>": value }` result when every
|
|
201
|
-
requested dot-path resolves. Dot notation traverses objects; append `[]` to an
|
|
202
|
-
array field before continuing, as in `results[].id`. Empty arrays resolve to
|
|
203
|
-
empty arrays. An exact downstream
|
|
204
|
-
`$connecta` field is always escaped under `data`. If any path misses—or that
|
|
205
|
-
reserved name is selected—the result carries matches under `data` and reserves `$connecta` for a
|
|
206
|
-
`type: "field_projection"` recovery record naming each `unmatchedFields`
|
|
207
|
-
entry. A path that resolves for only some array elements stays in `data` and
|
|
208
|
-
appears in `partialFields`; its unresolved positions serialize as `null`, while
|
|
209
|
-
the recovery record distinguishes them from genuine downstream nulls. A path
|
|
210
|
-
that misses every element appears in `unmatchedFields` and is omitted from
|
|
211
|
-
`data`. Both lists scale with requested paths, never with array length. When a
|
|
212
|
-
miss matches a declared array path except for `[]`, the record also carries the
|
|
213
|
-
traversal hint. The discriminator means downstream fields
|
|
214
|
-
named `data`, `projection`,
|
|
215
|
-
or `$connecta` remain ordinary values nested under `data`, never apparent
|
|
216
|
-
metadata. A declared output schema contributes a bounded `availableFields`
|
|
217
|
-
list and a `schemaCoverage` verdict. Only a completely analyzed, closed schema
|
|
218
|
-
can label paths `invalidFields`; open, patterned, tuple, unresolvable, cyclic,
|
|
219
|
-
`$ref`-sibling, or traversal-limited shapes stay `partial`. Traversal bounds
|
|
220
|
-
depth, nodes, path count, individual path characters/bytes, and cumulative path
|
|
221
|
-
characters/bytes before sorting or rendering. Without a schema, Connecta
|
|
222
|
-
reports only observed misses and does not pretend it knows the complete runtime
|
|
223
|
-
shape. API values and JSON-parseable downstream MCP text blocks follow the same
|
|
224
|
-
rule.
|
|
197
|
+
directly actionable without copying an identifier out of prose. Program results
|
|
198
|
+
and oversized discovery responses carry no such route — paging a program's
|
|
199
|
+
return value is a refused shape, because a program can shrink anything before
|
|
200
|
+
it returns.
|
|
225
201
|
|
|
226
202
|
## Lexical discovery
|
|
227
203
|
|
|
@@ -45,6 +45,10 @@ one.
|
|
|
45
45
|
npx @zackbart/connecta init my-deployment
|
|
46
46
|
cd my-deployment && npm install && npm start
|
|
47
47
|
CONNECTA_TOKEN=… npx connecta doctor --url http://localhost:8787
|
|
48
|
+
|
|
49
|
+
# A Worker protected by Cloudflare Access
|
|
50
|
+
CF_ACCESS_CLIENT_ID=… CF_ACCESS_CLIENT_SECRET=… \
|
|
51
|
+
npx connecta doctor --url https://connecta.example.workers.dev
|
|
48
52
|
```
|
|
49
53
|
|
|
50
54
|
`init` copies the template, pins the generated deployment to the CLI package's
|
|
@@ -59,12 +63,17 @@ on the way out: `QuickJS` on the Node template, `DynamicWorkerExecutor` on the
|
|
|
59
63
|
Worker example, and `code executed` when an executor identifies as nothing —
|
|
60
64
|
a checker that asserts a sandbox it never saw is worse than one that says it
|
|
61
65
|
does not know ([#368](https://github.com/zackbart/connecta/issues/368)). It
|
|
62
|
-
refuses to send
|
|
66
|
+
refuses to send authentication credentials over remote plaintext HTTP, and it
|
|
63
67
|
*reports* catalog drift without failing on it — an unclassified downstream tool
|
|
64
68
|
already fails closed onto `call_destructive_tool`, so drift is a maintainer's
|
|
65
69
|
next task rather than a broken deployment
|
|
66
70
|
([#343](https://github.com/zackbart/connecta/issues/343)).
|
|
67
71
|
|
|
72
|
+
For an Access-protected Worker, doctor sends the service-token pair to both
|
|
73
|
+
`/health` and `/mcp`; Access authenticates those requests before connecta runs.
|
|
74
|
+
`CONNECTA_TOKEN` remains the Node and legacy Worker path, and may be supplied
|
|
75
|
+
alongside the Access pair during rollback testing. A partial pair is refused.
|
|
76
|
+
|
|
68
77
|
### Configuration
|
|
69
78
|
|
|
70
79
|
Structural seams stay top-level; tuning is grouped by subsystem. Every group is
|
|
@@ -74,7 +83,7 @@ optional.
|
|
|
74
83
|
| --- | --- | --- |
|
|
75
84
|
| `connectors` | — (required) | the connector set ([connectors](./connectors.md)) |
|
|
76
85
|
| `executor` | — (required) | the sandbox `execute_code` runs in ([code mode](./code-mode.md#what-an-executor-must-implement)) |
|
|
77
|
-
| `auth?` | none ⇒ open (dev only) | one `InboundAuth` or an array; bearer providers are checked before
|
|
86
|
+
| `auth?` | none ⇒ open (dev only) | one `InboundAuth` or an array; bearer providers are checked before interactive providers ([inbound auth](./auth.md)) |
|
|
78
87
|
| `storage?` | `memoryStorage()` | the one state seam for catalogs, result paging, credentials, and access tokens ([storage](./storage-and-credentials.md)) |
|
|
79
88
|
| `publicUrl?` | per-request origin | public base URL; an HTTPS value also redirects inbound HTTP |
|
|
80
89
|
| `logger?` | `console`, prefixed `[connecta]` | `{ debug, info, warn, error }` |
|
|
@@ -83,7 +92,7 @@ optional.
|
|
|
83
92
|
| `deploymentInfo?` | unset | arbitrary metadata exposed by `/health` |
|
|
84
93
|
| `activity?` | unset | `{ store, readGate?, deploymentId? }` — payload-free activity storage, an optional operator-read gate, and a stable event label |
|
|
85
94
|
| `credentials.encryptionKey?` | unset | base64 32-byte AES key for the connector vault. Without it, connectors declaring `credential` warn and their slots stay unmanageable |
|
|
86
|
-
| `accessTokens?` | unset | `{ maxActive? }` (default 100) for operator-issued MCP bearer tokens. Requires
|
|
95
|
+
| `accessTokens?` | unset | `{ maxActive? }` (default 100) for operator-issued MCP bearer tokens. Requires an interactive operator provider, or construction throws ([access tokens](./auth.md#operator-issued-access-tokens)) |
|
|
87
96
|
| `discovery.concurrency?` | 4 | connector catalogs/status probes in flight at once |
|
|
88
97
|
| `discovery.catalogTtlSeconds?` | 300 | fresh TTL for cached tool lists |
|
|
89
98
|
| `discovery.persistCatalog?` | true | persist serializable catalogs as a manifest plus revision-addressed chunks |
|
|
@@ -96,14 +105,14 @@ optional.
|
|
|
96
105
|
| `admission.requests?` | 16 active / 32 queued / 5 s / 1 s | global FIFO `/mcp` capacity, taken before auth ([request admission](./request-admission.md)) |
|
|
97
106
|
| `admission.code?` | 2 active / 8 queued / 5 s / 1 s | fallback pool for an executor that owns no `acquire()`; ignored with a warning when it does |
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`calls.maxBatchResultBytes
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
policy its config file
|
|
108
|
+
An unknown own option throws before construction does deployment work. The
|
|
109
|
+
check covers the top level, every configuration group, admission pools,
|
|
110
|
+
branding icons, and server icons; the error names the rejected path without
|
|
111
|
+
copying its value. Removed options such as `toolkits`, `credentials.health`,
|
|
112
|
+
`surface`, `calls.maxBatchResultBytes`, and the flat v0.6 paths now take that
|
|
113
|
+
same path. The [upgrade guide](./upgrading.md#removed-options-that-throw) keeps
|
|
114
|
+
their historical mappings. Silently ignoring either a typo or a removed option
|
|
115
|
+
is how a deployment runs a policy its config file does not describe.
|
|
107
116
|
|
|
108
117
|
### Deployment as a release unit
|
|
109
118
|
|
|
@@ -214,7 +223,7 @@ in.
|
|
|
214
223
|
|
|
215
224
|
| Suite | Covers |
|
|
216
225
|
| --- | --- |
|
|
217
|
-
| `access-tokens.test.ts` | the `AccessTokenManager` — a one-time secret created, authenticated, renamed, and revoked, bounded names and active count, enumerable storage required, a deployment with no
|
|
226
|
+
| `access-tokens.test.ts` | the `AccessTokenManager` — a one-time secret created, authenticated, renamed, and revoked, bounded names and active count, enumerable storage required, a deployment with no interactive operator refused — and the operator-only routes, down to historical activity still resolving a revoked token's name |
|
|
218
227
|
| `activity.test.ts` | payload-free delivery: a rejected async write attaches to `waitUntil` instead of throwing, approved destructive calls record under their real entry point, result-size friction records without retaining the result, and a hallucinated connector id or invented identity is clamped so the event still cannot carry a payload |
|
|
219
228
|
| `api-connector.test.ts` | `api()` — kind, description, tool defs, dispatch, default args, unknown tools, handler throws, argument validation, and the construction contract |
|
|
220
229
|
| `bearer.test.ts` | constant-time bearer compare, case-insensitive scheme, 401 challenges, and the retired audience options refusing rather than silently unbinding |
|
|
@@ -223,28 +232,29 @@ in.
|
|
|
223
232
|
| `catalog-drift.test.ts` | `vettedCatalog()`, `detectCatalogDrift()`, and `withVettedCatalog()`; drift on the registry surface and on `/health`; the connector seam projected rather than echoed; and the drift types being public |
|
|
224
233
|
| `catalog.test.ts` | lexical ranking and the compact schema renderer — `const`, `allOf` beside siblings, `$ref`, the depth limit, per-schema caching, and 2020-12 keyword compatibility |
|
|
225
234
|
| `clerk.test.ts` | protected-resource metadata, the browser sign-in config, OAuth and session tokens, cached best-effort activity labels with their caps, the hand-applied `azp` rejection, and the `allowedDomains` allowlist including every lookalike that must not be repaired into a match |
|
|
235
|
+
| `cloudflare-access-auth.test.ts` | trusted `ctx.access` human and service identities, absent/error fail-closed behavior, service-token MCP admission without operator mutation, human same-origin mutation, and the Clerk-to-ambient shell switch |
|
|
226
236
|
| `cloudflare-provider.test.ts` | `cloudflare()` construction, tool surface, request building, projections, typed failures, and credential test |
|
|
227
237
|
| `code-first-surface.test.ts` | the seven-tool surface itself — an executor required, every removed option and top-level tool refused, compact always-loaded routing pinned below 1,000 characters, complete on-demand usage served, and `connecta.ui` findable before connector search |
|
|
228
238
|
| `codemode-compat.test.ts` | the `Executor` seam staying structurally compatible with `@cloudflare/codemode`'s `DynamicWorkerExecutor`, enforced by `tsc` |
|
|
229
|
-
| `config.test.ts` | the grouped `ConnectaConfig` boundary — each group forwarding to its internals, malformed admission bounds failing construction, and
|
|
239
|
+
| `config.test.ts` | the grouped `ConnectaConfig` boundary — each group forwarding to its internals, malformed admission bounds failing construction, and unknown own-properties rejected by their complete path before construction does work |
|
|
230
240
|
| `credentials.test.ts` | the pure stored-shape classifier (containment, not equality) and the AES-GCM vault: round-trip, ciphertext bound to its connector id, named field sets, masked metadata, wrong-key rejection, deletion, coexistence with OAuth keys |
|
|
231
241
|
| `d1-activity-example.test.ts` | the Worker example's deployment-owned D1 activity store: actor namespace round-trip, payload-free friction reconstructed from the persisted code, and agreement with the package's friction table |
|
|
232
242
|
| `downstream-oauth.test.ts` | `KvOAuthProvider` round-trips and races, `auth_required` versus `error`, `startAuth`/`finishAuth`, callback refusal equality, bounded diagnostics, and HTML escaping |
|
|
233
243
|
| `errors.test.ts` | `ConnectorCallError` codes, retryable defaults and overrides, `retryAfterMs` round-trip, typed-over-heuristic classification, `AbortError` as a retryable timeout, and framing errors |
|
|
234
244
|
| `execute.test.ts` | the code-mode host bridge: identifier sanitization, MCP-result unwrapping, sandbox provider construction, authenticated thrown-failure framing, fail-closed filtering of destructive and unannotated tools, MCP/code-mode invocation parity, and payload-free describe diagnostics |
|
|
235
245
|
| `execute-emit.test.ts` | `connecta.emit` (M1–M10) — block validation, budgets, the provider, delivery after the result envelope on success only, and the defaults |
|
|
236
|
-
| `execute-ui.test.ts` | `connecta.ui` (U1–
|
|
246
|
+
| `execute-ui.test.ts` | display-only `connecta.ui` (U1–U13) — one-string validation, multiplicity and budget, the provider, `_meta` delivery, shell isolation, and the absence of a payload-to-host call path |
|
|
237
247
|
| `executor-admission.test.ts` | the portable bounded FIFO both pools use: active and queue ceilings, stable retryable overload, queue timeout, cancellation removal, idempotent release, shutdown |
|
|
238
248
|
| `guarded-fetch.test.ts` | the guarded transport — construction, request building, destination confinement, and response handling |
|
|
239
249
|
| `guest-api-contract.test.ts` | the shared guest contract on the Dynamic Worker, including caught call, typed inline describe recovery, discovery, utility, batch, and budget failure codes; plus the real authority boundary — local `data:` fetch, denied egress, unresolved DNS, empty environment paths, unavailable filesystem/HTTP builtins, and present runtime globals |
|
|
240
250
|
| `linear-provider.test.ts` | the Linear proxy's construction, classification, and guide |
|
|
241
|
-
| `meta-tools-call.test.ts` | registry-backed calls: structured errors,
|
|
251
|
+
| `meta-tools-call.test.ts` | registry-backed calls: structured errors, truncation and `get_result`, per-connector result bounds, JSON representation failures, MCP content bounds, and offset alignment |
|
|
242
252
|
| `meta-tools-search.test.ts` | registry-backed discovery: bounded search with page and address maxima, compact and JSON schemas with constraints, typed describe recovery and suggestions, and structured-result compatibility |
|
|
243
253
|
| `meta-tools.test.ts` | the remaining registry-backed meta-tools: the complete on-demand usage skill, connector-guide selection and summary bounds, stored-credential drift, catalog health, authorization, probe timeouts, and unavailable or unknown browse recovery |
|
|
244
254
|
| `mixpanel-provider.test.ts` | the Mixpanel proxy, its conditional-input guide and complete reviewed schema-digest manifest |
|
|
245
255
|
| `notion-provider.test.ts` | Notion's deliberate tool surface, including declined expanded page inputs, request construction, lean projections, both pagination conventions, error mapping, and writes |
|
|
246
256
|
| `operator-boundary.test.ts` | the operator row of the decisions table, after every mutation route: authentication material managed without moving a declared structure, and the one honest exception — a credential write making a remote catalog appear, which is discovery arriving, not an operator editing the deployment |
|
|
247
|
-
| `operator-store.test.ts` | `src/operator-ui/app/store.ts` against a fake browser: the Clerk listener, `gate()`, the generation fence, and the request path |
|
|
257
|
+
| `operator-store.test.ts` | `src/operator-ui/app/store.ts` against a fake browser: the Clerk listener, ambient Access requests without a browser-readable token, `gate()`, the generation fence, and the request path |
|
|
248
258
|
| `provider-conventions.test.ts` | the conventions a test can hold: hand-written providers refusing schemas they cannot enforce (H5), their compact discovery schemas staying complete (H7), Cloudflare stating its second pagination convention in the schema (H10), and Notion saying it has no escape hatch (H14) |
|
|
249
259
|
| `provider-registry.test.ts` | all six maintained providers inside real deployments: boot, description, address, catalog, storage, credential, admission, and activity isolation; plus provider-specific discovery and guide contracts |
|
|
250
260
|
| `registry.test.ts` | construction and id validation, startup warnings, address resolution, version 2 catalog TTL/persistence/completeness, agent-only stale-while-revalidate with cross-request single-flight shared with blocking reads in both start orders, owned teardown, invalidation/fingerprint guards, blocking diagnostics, and broken-connector isolation |
|
|
@@ -254,7 +264,7 @@ in.
|
|
|
254
264
|
| `request-admission.test.ts` | `/mcp` bounded before auth, the stable 503 and `Retry-After`, health and operator responsiveness under saturation, payload-free counters, queued cancellation, shutdown rejection while active work drains, and the separate fallback code pool |
|
|
255
265
|
| `result-shapes.test.ts` | passive output-shape learning: value-free bounded inference, merging, 256-entry LRU eviction, 24-hour expiry, runtime isolation, read-only admission, declared-schema precedence, definition-change invalidation, discovery provenance, and failure isolation |
|
|
256
266
|
| `revenuecat-provider.test.ts` | the RevenueCat proxy's per-project key scoping and account-wide OAuth guides, its purpose-bearing summary, the argued borderline verdicts in its digest-free manifest, and the deliberately unclassified `render-paywall-screenshot` |
|
|
257
|
-
| `server.test.ts` | end-to-end `/mcp` (401 → compact initialize instructions → seven compact definitions with bounded connector inventory → complete usage skill → `call_tool`), conditional guide pointers, open routes, Clerk `.well-known` metadata without network, code mode, and deferred catalog reads through both discovery surfaces |
|
|
267
|
+
| `server.test.ts` | end-to-end `/mcp` (401 → compact initialize instructions → seven compact definitions with bounded connector inventory and exact model-only Apps metadata → complete usage skill → `call_tool`), conditional guide pointers, open routes, Clerk `.well-known` metadata without network, code mode, and deferred catalog reads through both discovery surfaces |
|
|
258
268
|
| `server-route-contracts.test.ts` | the route contracts `server.ts` must keep byte-identical: every built-in answered ahead of connector routes inside the security wrapper, open data-free shells with framing denied, per-route auth and same-origin requirements with exact 401/403/405 bodies, and OAuth `verifyState`-before-`finishAuth` ordering |
|
|
259
269
|
| `startup-warnings.test.ts` | every construction-time `logger.warn` and, as importantly, the conditions that must *not* trigger one: open mode with a credential or OAuth connector, `publicUrl` unset beside OAuth, dropped branding and `uiAuth` URLs, a missing `verifyState`, a credential test-hook mismatch, and an unusable `calls.maxResultBytes` |
|
|
260
270
|
| `stripe-provider.test.ts` | the Stripe proxy's mixed-mode OAuth and fixed-mode header contracts, admission, exact account selectors, and no-guess rule |
|
|
@@ -272,13 +282,13 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
|
|
|
272
282
|
| --- | --- | --- |
|
|
273
283
|
| `deployment-shapes.test.ts` | the Worker as the only example with a loader-only sandbox, one Node template that is also its own container, the same source running locally and in the container, the Node template's pinned esbuild install-script approval, the full operator surface in both, a template that cannot start on its own `.env.example`, a Worker README naming every optional peer its entrypoint imports, and the initializer's `.gitignore` staying in step | walks the template and example trees with Node filesystem APIs |
|
|
274
284
|
| `doc-links.test.ts` | the documentation checker itself — local file and fragment resolution, repository URLs resolved back to the checkout, duplicate heading slugs, fenced-code exclusion, and useful failures | spawns the Node checker against filesystem fixtures |
|
|
275
|
-
| `doctor-cli.test.ts` | `connecta doctor`'s executor line end to end — the sandbox the deployment reports is the one named, an unidentifiable executor gets an executor-neutral line,
|
|
285
|
+
| `doctor-cli.test.ts` | `connecta doctor`'s executor line and credentials end to end — the sandbox the deployment reports is the one named, an unidentifiable executor gets an executor-neutral line, a hostile name is bounded, and a complete Cloudflare Access service-token pair is accepted while a partial pair is refused | spawns the CLI against a Node HTTP deployment over real sockets |
|
|
276
286
|
| `drift-check.test.ts` | the maintainer drift checker — hosted-provider credential framing, recorded touched endpoints, a quiet revision bump, clear failures for an unavailable spec/manifest/credential, `$ref` traversal, and one well-formed row per endpoint | spawns the Node checker against filesystem fixtures |
|
|
277
287
|
| `file-storage.test.ts` | `fileStorage()` across instances, logical TTL plus physical pruning without clobbering a newer value, and corrupt-file quarantine | exercises the Node filesystem storage adapter |
|
|
278
288
|
| `guest-api-contract-quickjs.test.ts` | the shared guest-contract cases on the real QuickJS executor, including identical caught failure codes and inline describe recovery, its exact absent globals, and blocked runtime imports | runs the contract cases on the Node QuickJS executor |
|
|
279
289
|
| `node.test.ts` | the `listen()` adapter propagating an HTTP client disconnect through the Web `Request` and the MCP handler into a program's connector call, releasing both admission permits | exercises the Node HTTP adapter over real TCP sockets |
|
|
280
290
|
| `packed-links.test.ts` | the packed-link gate itself — shipped targets and repository URLs accepted, relative links into unshipped paths and directories rejected with the citation to write instead, reference definitions seen, fenced examples ignored, the changelog exempt | spawns the Node packed-link gate against filesystem fixtures |
|
|
281
|
-
| `package-surface.test.ts` | the published boundary — built output shipped, the `exports` map carrying exactly the documented subpaths plus `./package.json`, only generic factories, platform storage kept in examples, Clerk and QuickJS behind optional subpaths, every provider independently importable, and the Cloudflare provider free of bare specifiers | walks the package tree with Node filesystem APIs |
|
|
291
|
+
| `package-surface.test.ts` | the published boundary — built output shipped, the `exports` map carrying exactly the documented subpaths plus `./package.json`, only generic factories, platform storage kept in examples, Clerk and QuickJS behind optional subpaths, dependency-free Cloudflare Access behind its Worker subpath, every provider independently importable, and the Cloudflare API provider free of bare specifiers | walks the package tree with Node filesystem APIs |
|
|
282
292
|
| `purity.test.ts` | the import-graph guardrail ([architecture](./architecture.md#import-graph-purity)) — the core stays Workers-clean | walks the source import graph with Node filesystem APIs |
|
|
283
293
|
| `quickjs-child-entry.test.ts` | a missing QuickJS child entry failing before `fork()`, with the expected path and the bundler-externalization constraint | mocks Node child-process and filesystem APIs |
|
|
284
294
|
| `quickjs-child-stderr.test.ts` | abnormal child exits retaining only an 8 KiB stderr tail, included in the parent-side diagnostic | mocks Node child-process streams |
|
|
@@ -294,7 +304,7 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
|
|
|
294
304
|
| Suite | Covers |
|
|
295
305
|
| --- | --- |
|
|
296
306
|
| `browser/operator-ui.spec.ts` | the operator wiring in a real browser: Clerk loader order across its version redirect and a real load failure, the shell staying open until authentication, credential and access-token and OAuth flows end to end, drift shown without naming a tool, and every failure and empty state |
|
|
297
|
-
| `browser/program-ui.spec.ts` | the Apps shell in a real browser:
|
|
307
|
+
| `browser/program-ui.spec.ts` | the display-only Apps shell in a real browser: local payload JavaScript runs, `connecta` stays absent, and forged payload messages never become host tool calls |
|
|
298
308
|
|
|
299
309
|
**The `_transportFactory` seam.** `RemoteMcpOptions._transportFactory` is
|
|
300
310
|
internal, not public API: when set, `remoteMcp()` uses that `Transport` instead
|
|
@@ -319,10 +329,15 @@ confinement does too.
|
|
|
319
329
|
- **A connector with no `verifyState` refuses every callback.** That is the
|
|
320
330
|
designed behavior, not a bug: handing an unverified code to `finishAuth` is
|
|
321
331
|
the vulnerability. The startup warning names the connector.
|
|
322
|
-
- **401 loops from a client that cannot discover auth.** The client must reach
|
|
332
|
+
- **401 loops from a Clerk client that cannot discover auth.** The client must reach
|
|
323
333
|
the open `/.well-known/oauth-protected-resource` (and the `/mcp` variant);
|
|
324
334
|
confirm CORS and the Clerk keys, and that DCR is enabled on the Clerk
|
|
325
335
|
instance.
|
|
336
|
+
- **An Access-protected MCP client receives redirects or loops.** Enable Managed
|
|
337
|
+
OAuth on the Access application and use an RFC 8707-capable client. Access,
|
|
338
|
+
not connecta, must answer the unauthenticated challenge and `/.well-known/`
|
|
339
|
+
metadata. Do not bypass those routes. For unattended automation, use an
|
|
340
|
+
Access Service Auth policy and service-token headers instead.
|
|
326
341
|
- **No sessions and no server push, by design.** The transport is stateless.
|
|
327
342
|
Scope resolves per request, which is also where the MCP spec has arrived.
|
|
328
343
|
- **A tool that should be callable from a program is not.** Only tools
|
|
@@ -39,10 +39,25 @@ their walkthrough, which is the honest version of the same page count.
|
|
|
39
39
|
| `src/operator-ui/browser.css` | One stylesheet, inlined into the shell. |
|
|
40
40
|
| `src/operator-ui/generated.ts` | The build output: the bundle and the stylesheet as two exported strings. |
|
|
41
41
|
|
|
42
|
-
The server renders a mount point, not a page. Branding, the Clerk
|
|
43
|
-
every operator-configured URL stay in `src/ui.ts`, where they are
|
|
44
|
-
they can become an attribute; the bundle renders everything that
|
|
45
|
-
Two roots share one store: `#operatorNav` and `#operatorContent`.
|
|
42
|
+
The server renders a mount point, not a page. Branding, the optional Clerk
|
|
43
|
+
loader, and every operator-configured URL stay in `src/ui.ts`, where they are
|
|
44
|
+
gated before they can become an attribute; the bundle renders everything that
|
|
45
|
+
has a state. Two roots share one store: `#operatorNav` and `#operatorContent`.
|
|
46
|
+
|
|
47
|
+
Cloudflare Access is ambient browser auth. When the current Worker invocation
|
|
48
|
+
has `ctx.access`, the shell selects the `cloudflare-access` UI mode, emits no
|
|
49
|
+
Clerk loader, and sends no browser-readable token. Same-origin fetch includes
|
|
50
|
+
the HttpOnly `CF_Authorization` cookie, Access admits it at the edge, and the
|
|
51
|
+
server reads the resulting runtime identity. Sign out navigates to
|
|
52
|
+
`/cdn-cgi/access/logout`. Mutations still require an exact same-origin
|
|
53
|
+
`Origin`; an ambient cookie does not weaken the CSRF boundary.
|
|
54
|
+
|
|
55
|
+
This runtime selection is the Clerk migration seam. A deployment may contain
|
|
56
|
+
both providers: before Worker-level Access is attached, the data-free shell
|
|
57
|
+
selects Clerk; after Access supplies `ctx.access`, it selects ambient auth. That
|
|
58
|
+
is not two same-hostname gates running in parallel. Access is upstream and a
|
|
59
|
+
request it rejects never reaches Clerk. Keeping Clerk in the array preserves a
|
|
60
|
+
code-level rollback after Access is detached.
|
|
46
61
|
|
|
47
62
|
The Clerk loader is intentionally blocking. The inline operator bundle calls
|
|
48
63
|
`boot()` as soon as the parser reaches the end of the body, so a deferred Clerk
|
|
@@ -58,7 +73,8 @@ the same ordering.
|
|
|
58
73
|
credential, token, and activity data arrives only through the authenticated
|
|
59
74
|
`/ui/*` APIs, and the shell is identical whether or not a caller is signed in.
|
|
60
75
|
- **One store, one identity.** `store.ts` is the only file that touches `fetch`,
|
|
61
|
-
`localStorage`, or
|
|
76
|
+
`localStorage`, Clerk, or the ambient Access mode. Every token-bearing request carries the current session's token,
|
|
77
|
+
while Access requests deliberately carry none,
|
|
62
78
|
and every response is dropped unless the identity that asked for it is still
|
|
63
79
|
the one on screen. `resetIdentity` replaces all identity-scoped state at once
|
|
64
80
|
and bumps a generation that work already in flight compares itself against.
|
|
@@ -183,10 +183,9 @@ tokens.
|
|
|
183
183
|
|
|
184
184
|
### H8 — Every tool declares an `outputSchema`
|
|
185
185
|
|
|
186
|
-
Declared outputs
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
tools on one real deployment and 3 of 30 on another
|
|
186
|
+
Declared outputs produce `outputKeys` and let a program reduce a result without
|
|
187
|
+
first fetching one to look at. Connecta measured *declared* output schemas at 0
|
|
188
|
+
of 30 tools on one real deployment and 3 of 30 on another
|
|
190
189
|
([#282](https://github.com/zackbart/connecta/issues/282)) — nearly every tool an
|
|
191
190
|
agent meets is a shape it can only learn by calling. A maintained provider has
|
|
192
191
|
no excuse to join that majority.
|
|
@@ -57,7 +57,7 @@ exist so far:
|
|
|
57
57
|
| --- | --- | --- |
|
|
58
58
|
| **pre-template** | before 0.10.2 | no `connecta init` existed; hand-written, or copied from the retired `examples/node` |
|
|
59
59
|
| **A** | 0.10.2 – 0.15.1 | `.env.example`, `.gitignore`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `package.json`, `src/index.ts`, `tsconfig.json` |
|
|
60
|
-
| **B** | 0.16.0 – 0.
|
|
60
|
+
| **B** | 0.16.0 – 0.21.0 | 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 |
|
|
61
61
|
|
|
62
62
|
Generation A is a decade in template years and identifying it precisely does
|
|
63
63
|
not matter, because you are about to reconstruct it exactly rather than guess
|
|
@@ -106,7 +106,7 @@ know what to preserve, once to know what to re-verify at the end.
|
|
|
106
106
|
### Bump the pin and install
|
|
107
107
|
|
|
108
108
|
```sh
|
|
109
|
-
npm pkg set dependencies.@zackbart/connecta=0.
|
|
109
|
+
npm pkg set dependencies.@zackbart/connecta=0.21.0
|
|
110
110
|
npm install
|
|
111
111
|
```
|
|
112
112
|
|
|
@@ -130,7 +130,7 @@ Generate the *current* template beside the base you already made, into the same
|
|
|
130
130
|
`$SCRATCH`:
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
|
-
(cd "$SCRATCH" && npx @zackbart/connecta@0.
|
|
133
|
+
(cd "$SCRATCH" && npx @zackbart/connecta@0.21.0 init current)
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
You now have a three-way merge with a real base: `$SCRATCH/base` is what this
|
|
@@ -186,7 +186,7 @@ A deployment older than 0.10.2 has no base to diff against. Do not try to
|
|
|
186
186
|
manufacture one. Instead:
|
|
187
187
|
|
|
188
188
|
1. `SCRATCH=$(mktemp -d)`, then
|
|
189
|
-
`(cd "$SCRATCH" && npx @zackbart/connecta@0.
|
|
189
|
+
`(cd "$SCRATCH" && npx @zackbart/connecta@0.21.0 init current)` — there is no
|
|
190
190
|
`base` leg here, only the current template to read from.
|
|
191
191
|
2. Copy `$SCRATCH/current` into the deployment file by file, **skipping
|
|
192
192
|
`src/index.ts`**.
|
|
@@ -207,6 +207,102 @@ first, so cross them bottom-up: start at the oldest one still above this
|
|
|
207
207
|
deployment's pin and work back up the page, because each boundary assumes the
|
|
208
208
|
older ones are already done.
|
|
209
209
|
|
|
210
|
+
### 0.20.0 → 0.21.0
|
|
211
|
+
|
|
212
|
+
This is additive for Node and existing Clerk deployments. The new Worker path
|
|
213
|
+
uses Cloudflare Access identity directly and removes Clerk only after the edge
|
|
214
|
+
cutover has been verified. An agent can perform every repository edit; a human
|
|
215
|
+
must attach Access, choose its policy, create service credentials, and enable
|
|
216
|
+
Managed OAuth in the Cloudflare dashboard.
|
|
217
|
+
|
|
218
|
+
For a Worker currently using Clerk, keep rollback live through the cutover:
|
|
219
|
+
|
|
220
|
+
1. Bump and install 0.21.0. Add the new provider **before** the existing Clerk
|
|
221
|
+
provider, but remove nothing:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import { cloudflareAccessAuth } from
|
|
225
|
+
"@zackbart/connecta/auth/cloudflare-access";
|
|
226
|
+
import { clerkAuth } from "@zackbart/connecta/auth/clerk";
|
|
227
|
+
|
|
228
|
+
auth: [
|
|
229
|
+
cloudflareAccessAuth(),
|
|
230
|
+
// Keep the deployment's existing options and secrets unchanged.
|
|
231
|
+
clerkAuth({ /* existing configuration */ }),
|
|
232
|
+
],
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Before Access is attached, the new provider fails closed and the operator
|
|
236
|
+
shell selects Clerk. Deploy this state and run doctor with the existing
|
|
237
|
+
`CONNECTA_TOKEN`. This separates the package/code change from the edge
|
|
238
|
+
change and proves the old path still works.
|
|
239
|
+
|
|
240
|
+
2. In Cloudflare, attach Access to the Worker itself, apply the intended human
|
|
241
|
+
policy, and enable Managed OAuth. Through the API this is an Access
|
|
242
|
+
application destination of `{ "type": "worker", "worker_id": "<script
|
|
243
|
+
tag>" }`, not a hostname application for the `workers.dev` URL: the latter
|
|
244
|
+
gates traffic but does not provide `ctx.access`. Create an Access service
|
|
245
|
+
token and a **Service Auth** policy for doctor and fully unattended clients.
|
|
246
|
+
Do not create a bypass for `/.well-known/*`; Managed OAuth owns that
|
|
247
|
+
discovery surface.
|
|
248
|
+
|
|
249
|
+
3. Reconnect interactive MCP clients to `<PUBLIC_URL>/mcp`. Their old Clerk
|
|
250
|
+
OAuth tokens are not Cloudflare credentials, so each client performs one new
|
|
251
|
+
browser authorization. An agent can edit client configuration and start the
|
|
252
|
+
flow; the user still completes the identity-provider prompt. Move CI, cron,
|
|
253
|
+
and server-to-server callers from connecta bearers to the two Access service
|
|
254
|
+
headers. The cutover warning is literal: once Access is attached, a static
|
|
255
|
+
bearer or `cta_…` token by itself is stopped at the edge before connecta can
|
|
256
|
+
inspect it.
|
|
257
|
+
|
|
258
|
+
4. Verify the edge path:
|
|
259
|
+
|
|
260
|
+
```sh
|
|
261
|
+
CF_ACCESS_CLIENT_ID=… CF_ACCESS_CLIENT_SECRET=… \
|
|
262
|
+
npx connecta doctor --url https://connecta.example.workers.dev
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Open `/` as a human and exercise any enabled credential, token, and OAuth
|
|
266
|
+
controls. A service token may pass doctor and MCP but must receive 403 from
|
|
267
|
+
operator mutations.
|
|
268
|
+
|
|
269
|
+
5. After an observation window, remove `clerkAuth`, its import,
|
|
270
|
+
`@clerk/backend`, and the Clerk variables/secrets. Until then they are inert
|
|
271
|
+
behind Access but preserve rollback. Rollback order matters: detach Access
|
|
272
|
+
first, then the untouched Clerk sessions and connecta bearers reach the
|
|
273
|
+
Worker again. Reverting code first cannot help a request the edge still
|
|
274
|
+
blocks. There is no storage migration and no token-format conversion.
|
|
275
|
+
|
|
276
|
+
If the Worker exposes an intentionally public connector route, create a
|
|
277
|
+
more-specific hostname/path Access application with a Bypass policy for that
|
|
278
|
+
route only. `/health`, downstream OAuth callbacks, operator shells, and MCP are
|
|
279
|
+
private under the canonical whole-Worker shape; doctor knows how to authenticate
|
|
280
|
+
its health request.
|
|
281
|
+
|
|
282
|
+
### 0.19.0 → 0.20.0
|
|
283
|
+
|
|
284
|
+
Three intake paths become deliberately strict. None changes storage, the two
|
|
285
|
+
deployment shapes, or the exact seven-tool MCP surface.
|
|
286
|
+
|
|
287
|
+
- `createConnecta` now rejects every unknown own configuration property by its
|
|
288
|
+
complete path. Remove typos and options retired before 0.19, including the
|
|
289
|
+
top-level `toolkits`, `credentialHealth`, `surface`, and `maxResultBytes`,
|
|
290
|
+
plus `credentials.health` and `calls.maxBatchResultBytes`. Connector, auth,
|
|
291
|
+
storage, activity-store, logger, deployment-metadata, and executor
|
|
292
|
+
implementations remain open objects; their implementation-specific fields
|
|
293
|
+
are not configuration typos.
|
|
294
|
+
- `call_tool` and `call_destructive_tool` no longer accept `fields`. Put
|
|
295
|
+
projection in one `execute_code` program. For a legitimate oversized direct
|
|
296
|
+
read, call without `fields` and follow the returned `get_result` action; that
|
|
297
|
+
paging path remains part of the seven-tool surface.
|
|
298
|
+
- `connecta.ui` accepts one HTML string and is display-only. Remove its second
|
|
299
|
+
read-binding argument and any page calls to `connecta.read`. Fetch and shape
|
|
300
|
+
data in the program before rendering, then return the same compact summary
|
|
301
|
+
the view initially displays. Views cannot call any Connecta tool.
|
|
302
|
+
|
|
303
|
+
The Node template layout remains generation B. Reconcile it as usual after the
|
|
304
|
+
version bump; no new deployment file or environment variable is required.
|
|
305
|
+
|
|
210
306
|
### 0.18.3 → 0.19.0
|
|
211
307
|
|
|
212
308
|
Nothing changes for a deployment. Bump the version and reconcile the template
|
|
@@ -451,9 +547,11 @@ built-in routes miss, so it can add a route and never shadow one
|
|
|
451
547
|
|
|
452
548
|
### Removed options that throw
|
|
453
549
|
|
|
454
|
-
These fail at construction
|
|
455
|
-
|
|
456
|
-
|
|
550
|
+
These fail at construction rather than falling back to a default, because
|
|
551
|
+
silently ignoring a removed option is how a deployment runs a policy its config
|
|
552
|
+
file says it has. Releases through 0.19 name the migration in the error. Version
|
|
553
|
+
0.20's strict configuration boundary names the unknown path; this table remains
|
|
554
|
+
the migration map:
|
|
457
555
|
|
|
458
556
|
| Option | Removed in | Do |
|
|
459
557
|
| --- | --- | --- |
|
|
@@ -461,7 +559,7 @@ ends up running a policy its config file says it has:
|
|
|
461
559
|
| `credentials.health`, `credentialHealth` | 0.8.1 (#179) | delete; credentials fail at use |
|
|
462
560
|
| `surface` | 0.11.0 (#273) | delete; there is one seven-tool surface |
|
|
463
561
|
| `calls.maxBatchResultBytes` | 0.11.0 (#273) | delete; program batching is bounded by `execute_code`'s own limits |
|
|
464
|
-
| flat v0.6 config paths | 0.7.0 | move into their groups
|
|
562
|
+
| flat v0.6 config paths | 0.7.0 | move into their groups ([operations](./operations.md#configuration)) |
|
|
465
563
|
|
|
466
564
|
## Verify
|
|
467
565
|
|