@zackbart/connecta 0.39.0 → 0.41.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 +115 -0
- package/bin/connecta.mjs +4 -8
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.js +6 -4
- package/dist/activity.d.ts +30 -4
- package/dist/activity.js +28 -2
- package/dist/agent-observation.js +24 -2
- package/dist/agent-routes.js +4 -41
- package/dist/auth/clerk.d.ts +6 -1
- package/dist/auth/clerk.js +16 -0
- package/dist/auth/cloudflare-access.js +49 -7
- package/dist/auth/downstream-oauth/consent.js +79 -29
- package/dist/auth/downstream-oauth/grant-store.js +58 -7
- package/dist/auth/downstream-oauth/refresh-records.js +6 -5
- package/dist/auth/downstream-oauth.js +12 -4
- package/dist/auth/native.js +10 -0
- package/dist/auth/oauth-request-not-sent.js +4 -0
- package/dist/auth/static-oauth.js +51 -21
- package/dist/catalog-cache.js +151 -37
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-service.js +39 -12
- package/dist/catalog.js +103 -38
- package/dist/config.d.ts +10 -4
- package/dist/config.js +30 -7
- package/dist/connectors/remote-mcp/call.js +1 -1
- package/dist/connectors/remote-mcp/connection.js +52 -7
- package/dist/connectors/remote-mcp/oauth.js +6 -2
- package/dist/connectors/remote-mcp/resources.js +5 -2
- package/dist/connectors/remote-mcp/transport.js +37 -8
- package/dist/connectors/remote-mcp.js +8 -5
- package/dist/credential-contract.d.ts +3 -1
- package/dist/describe-config.d.ts +1 -0
- package/dist/describe-config.js +1 -0
- package/dist/downstream-input.js +11 -2
- package/dist/errors.d.ts +8 -1
- package/dist/errors.js +2 -0
- package/dist/execute.js +20 -7
- package/dist/executor-result.js +1 -1
- package/dist/executors/quickjs-child.js +1 -1
- package/dist/executors/quickjs-runtime.js +1 -1
- package/dist/executors/quickjs.js +1 -1
- package/dist/guarded-transport.js +2 -0
- package/dist/http/client.js +7 -0
- package/dist/http/hatch.js +2 -0
- package/dist/http/node-transport.js +110 -4
- package/dist/http/oauth.js +17 -6
- package/dist/index.js +10 -21
- package/dist/invocation-failure.js +28 -0
- package/dist/invocation.js +77 -35
- package/dist/membership.d.ts +1 -1
- package/dist/meta-tools.js +58 -36
- package/dist/module-contracts.d.ts +3 -1
- package/dist/native-tools.js +12 -5
- package/dist/node.d.ts +7 -0
- package/dist/node.js +82 -3
- package/dist/operation-activity.js +103 -0
- package/dist/operator-record.d.ts +8 -0
- package/dist/operator-record.js +15 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/provider-call-facts.js +6 -2
- package/dist/provider.d.ts +1 -1
- package/dist/providers/_shared/google/workspace.d.ts +1 -1
- package/dist/providers/breeze/index.js +1 -1
- package/dist/providers/ccb/index.js +1 -1
- package/dist/providers/cloudflare/index.js +1 -1
- package/dist/providers/docs/index.js +1 -1
- package/dist/providers/drive/index.js +1 -1
- package/dist/providers/forms/index.js +1 -1
- package/dist/providers/github/index.js +1 -1
- package/dist/providers/gmail/index.js +1 -1
- package/dist/providers/granola/index.js +1 -1
- package/dist/providers/overflow/index.js +1 -1
- package/dist/providers/planning-center/index.js +1 -1
- package/dist/providers/planning-center/lib/constants.d.ts +1 -1
- package/dist/providers/quickbooks/api.js +28 -25
- package/dist/providers/quickbooks/index.js +1 -1
- package/dist/providers/quickbooks/lib/writes.js +55 -0
- package/dist/providers/quickbooks/safety.js +17 -5
- package/dist/providers/quickbooks/skill.generated.js +1 -1
- package/dist/providers/sheets/index.js +1 -1
- package/dist/providers/slides/index.js +1 -1
- package/dist/providers/stripe/index.js +2 -2
- package/dist/providers/tithely/index.js +1 -1
- package/dist/providers/vercel/api.js +1 -0
- package/dist/registry.js +16 -4
- package/dist/resource-read.js +21 -2
- package/dist/route-names.js +44 -0
- package/dist/routes/activity-context.js +1 -0
- package/dist/routes/activity-disclosure.js +26 -4
- package/dist/routes/activity.js +2 -1
- package/dist/routes/mcp.js +32 -13
- package/dist/routes/ui-config.js +1 -1
- package/dist/routes/ui-data.js +3 -2
- package/dist/runtime/native-storage.js +15 -0
- package/dist/runtime/request-reads.js +87 -10
- package/dist/runtime/request-scope.js +2 -1
- package/dist/skill-origin.js +16 -0
- package/dist/skills.js +132 -43
- package/dist/storage/d1-driver.js +33 -5
- package/dist/storage/keys.js +7 -1
- package/dist/storage/sql-native.js +85 -3
- package/dist/storage/sql.js +6 -0
- package/dist/timing-trace.js +84 -0
- package/dist/types.d.ts +5 -0
- package/dist/url-safety.js +38 -20
- package/dist/utility-recovery.js +33 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +33 -8
- package/documentation/architecture.md +83 -2
- package/documentation/auth.md +132 -37
- package/documentation/code-mode.md +61 -46
- package/documentation/deploying.md +25 -1
- package/documentation/integrating.md +2 -2
- package/documentation/meta-tools.md +134 -15
- package/documentation/operating.md +86 -1
- package/documentation/operator-ui.md +51 -2
- package/documentation/providers.md +16 -14
- package/package.json +10 -8
- package/templates/node/package.json +1 -1
package/documentation/auth.md
CHANGED
|
@@ -295,7 +295,7 @@ It has no queue and no configuration option. When full, a request receives HTTP
|
|
|
295
295
|
`error: { code: "authentication_busy", message: "Authentication capacity reached.", retryable: true }`.
|
|
296
296
|
The operator log records only the checked `authentication_busy` reason, never
|
|
297
297
|
credentials or identity-provider diagnostics. Retry after the indicated delay;
|
|
298
|
-
Connecta does not automatically retry
|
|
298
|
+
Connecta does not automatically retry authentication, except for one rejected Cloudflare Access identity lookup inside its existing deadline (see [Access on Workers](#cloudflare-access-on-workers)).
|
|
299
299
|
|
|
300
300
|
Underlying work stays charged until it settles, including cancellation cleanup.
|
|
301
301
|
A caller leaving alone never releases capacity. After an authorization's hard
|
|
@@ -399,7 +399,9 @@ This bound is independent of MCP request/program admission and downstream call
|
|
|
399
399
|
limits. `Mcp-Method: subscriptions/listen` still defers its MCP request permit:
|
|
400
400
|
after authentication and endpoint admission, a body-confirmed modern listen is
|
|
401
401
|
refused promptly even when execution capacity is full. It always passes the
|
|
402
|
-
authentication bound, and no request body
|
|
402
|
+
authentication bound, and the MCP route reads no request body before
|
|
403
|
+
authentication. On Node, `listen()` has already buffered the body up to its own
|
|
404
|
+
[pre-auth cap](./deploying.md#start-on-node) before core sees the request.
|
|
403
405
|
|
|
404
406
|
Routes that do not invoke an inbound verifier consume no authentication slot:
|
|
405
407
|
health, public OAuth discovery and client metadata, UI shells and static assets,
|
|
@@ -558,6 +560,7 @@ createConnecta({
|
|
|
558
560
|
storage,
|
|
559
561
|
agents: ["assistant", "ci"],
|
|
560
562
|
accessTokens: accessTokens(storage),
|
|
563
|
+
publicUrl: "https://connecta.example.com",
|
|
561
564
|
auth: clerkAuth({ publishableKey, secretKey }),
|
|
562
565
|
ui: operatorUi(),
|
|
563
566
|
maintainers: ["your-operator-id"],
|
|
@@ -651,6 +654,11 @@ agent's slot is `issued` naming exactly that record. Nothing else counts: a
|
|
|
651
654
|
lookup or record the slot does not name is inert garbage. Every mutation
|
|
652
655
|
commits by one `compareAndSet` on the slot and only moves forward; no security
|
|
653
656
|
outcome depends on cleanup or on undoing a write.
|
|
657
|
+
Admission reads this state afresh on every request; successful token verdicts
|
|
658
|
+
are never cached. D1 and SQLite read the lookup, record, and slot in one
|
|
659
|
+
statement, with the same validation and expiry checks. Custom storage adapters
|
|
660
|
+
retain the sequential reads. Rotation and revocation therefore retain their
|
|
661
|
+
next-request refusal bound.
|
|
654
662
|
|
|
655
663
|
- **Rotate** writes the new record and its lookup (inert), checks the
|
|
656
664
|
request's signal, then compare-and-sets the slot from what it read to
|
|
@@ -943,6 +951,7 @@ cache entries remain partitioned by the admitted pool.
|
|
|
943
951
|
createConnecta({
|
|
944
952
|
storage,
|
|
945
953
|
accessTokens: accessTokens(storage),
|
|
954
|
+
publicUrl: "https://connecta.example.com",
|
|
946
955
|
auth: clerkAuth({ publishableKey, secretKey }),
|
|
947
956
|
readOnly: false, // required; pools without their own readOnly inherit it
|
|
948
957
|
maintainers: ["user_owner"],
|
|
@@ -966,19 +975,19 @@ warning says, every pool path answers the 404 because nobody can be a member,
|
|
|
966
975
|
and every agent endpoint answers the machine-only 401 because no agent can be
|
|
967
976
|
admitted.
|
|
968
977
|
|
|
969
|
-
| Rule | Contract
|
|
970
|
-
| ------------ |
|
|
971
|
-
| Scope | `/mcp/<pool>` and `/agent/<pool>` serve exactly the pool's `tools` (connector ids or exact `connector.tool` addresses), with the pool's `readOnly`, to its member people and member agents respectively. Plain `/mcp` serves the whole catalog to maintainers and the unique member pool to other people. Neither intersects with or widens anything.
|
|
972
|
-
| Refusal | A person with zero or several memberships at `/mcp`, a non-member, and an undeclared pool get an identical 404 status, body, and headers, after auth. The operator log records `not_maintainer` (zero memberships), `ambiguous_pool` (several memberships), `not_pool_member`, or `pool_not_declared`. Names are not anonymously enumerable; valid credentials cannot distinguish these cases by content.
|
|
973
|
-
| Agents | An agent member reaches its pools only at `/agent/<pool>`, with its `cta_` token. Human endpoints refuse `cta_`; see [agent endpoints](#agent-endpoints).
|
|
974
|
-
| Surface | From 0.35.0, optional `surface`: `"meta"` (default) serves the six meta-tools; `"native"` lists each of the pool's downstream tools directly, for clients with their own tool search, with optional `executeCode: false` to replace `execute_code` with `read_result` (invalid on meta pools). Calls take the same paths either way. See the [native tool surface](./meta-tools.md#native-tool-surface).
|
|
975
|
-
| Description | Optional `description`: plain text telling the model what this endpoint is for. `/mcp/<pool>` and `/agent/<pool>`
|
|
976
|
-
| Construction | Malformed names, unknown options or connectors, empty pools, empty or missing `members`, mixed people and agent membership (a `ConfigError` naming the pool), unresolvable member references, a non-boolean `readOnly`, an `owner` that is not a Workspace email address, a `description` that is not 1 to 500
|
|
977
|
-
| Discovery | Clerk's pool 401 names `/.well-known/oauth-protected-resource/mcp/<pool>` with the pool URL as `resource`, matching RFC 9728. Cloudflare Managed OAuth is application-level and needs no pool setup.
|
|
978
|
-
| Drift | No wildcards; pool tools are exact names. Missing live tools are unreachable and warned once while in a bounded 1,024-entry FIFO.
|
|
978
|
+
| Rule | Contract |
|
|
979
|
+
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
980
|
+
| Scope | `/mcp/<pool>` and `/agent/<pool>` serve exactly the pool's `tools` (connector ids or exact `connector.tool` addresses), with the pool's `readOnly`, to its member people and member agents respectively. Plain `/mcp` serves the whole catalog to maintainers and the unique member pool to other people. Neither intersects with or widens anything. |
|
|
981
|
+
| Refusal | A person with zero or several memberships at `/mcp`, a non-member, and an undeclared pool get an identical 404 status, body, and headers, after auth. The operator log records `not_maintainer` (zero memberships), `ambiguous_pool` (several memberships), `not_pool_member`, or `pool_not_declared`. Names are not anonymously enumerable; valid credentials cannot distinguish these cases by content. |
|
|
982
|
+
| Agents | An agent member reaches its pools only at `/agent/<pool>`, with its `cta_` token. Human endpoints refuse `cta_`; see [agent endpoints](#agent-endpoints). |
|
|
983
|
+
| Surface | From 0.35.0, optional `surface`: `"meta"` (default) serves the six meta-tools; `"native"` lists each of the pool's downstream tools directly, for clients with their own tool search, with optional `executeCode: false` to replace `execute_code` with `read_result` (invalid on meta pools). Calls take the same paths either way. See the [native tool surface](./meta-tools.md#native-tool-surface). |
|
|
984
|
+
| Description | Optional `description`: plain text telling the model what this endpoint is for. `/mcp/<pool>` and `/agent/<pool>` prefix the MCP instructions with `Use skills. ` and the description before routing rules; a maintainer at plain `/mcp` and a pool without one serve the shared instructions unchanged. A routed person receives their pool description. It grants, hides, and refuses nothing, and changes no tool or tool description. |
|
|
985
|
+
| Construction | Malformed names, unknown options or connectors, empty pools, empty or missing `members`, mixed people and agent membership (a `ConfigError` naming the pool), unresolvable member references, a non-boolean `readOnly`, an `owner` that is not a Workspace email address, a `description` that is not 1 to 500 UTF-16 code units of one-line text after trimming, a retired `trust` or `grant`, and addresses absent from an `api()` static catalog throw. Remote catalogs are checked at lazy load. |
|
|
986
|
+
| Discovery | Clerk's pool 401 names `/.well-known/oauth-protected-resource/mcp/<pool>` with the pool URL as `resource`, matching RFC 9728. Cloudflare Managed OAuth is application-level and needs no pool setup. |
|
|
987
|
+
| Drift | No wildcards; pool tools are exact names. Missing live tools are unreachable and warned once while in a bounded 1,024-entry FIFO. |
|
|
979
988
|
|
|
980
989
|
Pool descriptions are trimmed before validation. The remaining text must be
|
|
981
|
-
1 to 500 characters and contain no C0 or C1 control characters (including tabs,
|
|
990
|
+
1 to 500 UTF-16 code units (non-BMP characters such as emoji count as two units) and contain no C0 or C1 control characters (including tabs,
|
|
982
991
|
newlines, and NEL U+0085), LINE SEPARATOR (U+2028), or PARAGRAPH SEPARATOR
|
|
983
992
|
(U+2029).
|
|
984
993
|
|
|
@@ -1097,6 +1106,7 @@ const team = [
|
|
|
1097
1106
|
{ handle: "bob", id: "user_bob", email: "bob@example.com" },
|
|
1098
1107
|
];
|
|
1099
1108
|
createConnecta({
|
|
1109
|
+
publicUrl: "https://connecta.example.com",
|
|
1100
1110
|
auth: clerkAuth({ publishableKey, secretKey }),
|
|
1101
1111
|
storage,
|
|
1102
1112
|
accessTokens: accessTokens(storage),
|
|
@@ -1245,6 +1255,7 @@ const workspace: GoogleWorkspaceOptions = {
|
|
|
1245
1255
|
};
|
|
1246
1256
|
|
|
1247
1257
|
createConnecta({
|
|
1258
|
+
publicUrl: "https://connecta.example.com",
|
|
1248
1259
|
auth: clerkAuth({ publishableKey, secretKey }),
|
|
1249
1260
|
storage,
|
|
1250
1261
|
accessTokens: accessTokens(storage),
|
|
@@ -1345,25 +1356,48 @@ code, so `remoteMcp()` refuses it as personal at construction.
|
|
|
1345
1356
|
|
|
1346
1357
|
## Downstream OAuth state at rest
|
|
1347
1358
|
|
|
1359
|
+
An OAuth remote MCP connector requires an access token on passive MCP requests,
|
|
1360
|
+
including handshakes, catalog requests, and tool dispatches, even if the server
|
|
1361
|
+
accepts anonymous requests. This requirement survives provider replacement.
|
|
1362
|
+
If the SDK cannot obtain a token at send time, Connecta returns OAuth recovery
|
|
1363
|
+
before sending. A locally refused write counts as failed, without reconciliation;
|
|
1364
|
+
a write that may already have left remains unknown and is never replayed.
|
|
1365
|
+
Only an explicit authorization start may probe the MCP endpoint without a token
|
|
1366
|
+
for the SDK's challenge, never to call a tool. Authorization-server discovery,
|
|
1367
|
+
client registration, token exchange, and refresh retain their OAuth flows.
|
|
1368
|
+
|
|
1348
1369
|
Each owner of an OAuth connector (the deployment when shared, each principal
|
|
1349
1370
|
when personal) has one **grant record**, `oauth:grant` in the connector's
|
|
1350
1371
|
namespace: the live **epoch**, the latest consent's state digest, and one
|
|
1351
1372
|
authorization server's client registration, tokens, and discovery. Each
|
|
1352
|
-
consent has a **flow record**, `oauth:flow:<sha256(state)>`, holding its
|
|
1353
|
-
|
|
1354
|
-
stored nowhere
|
|
1373
|
+
consent has a **flow record**, `oauth:flow:<sha256(state)>`, holding its epoch
|
|
1374
|
+
and timestamp, its binding to the selected server and client, its consent URL,
|
|
1375
|
+
and its PKCE verifier for fifteen minutes; the state itself is stored nowhere
|
|
1376
|
+
outside that URL.
|
|
1355
1377
|
|
|
1356
|
-
With a vault, the grant's body and each
|
|
1357
|
-
key, the additional authenticated data naming the connector, owner partition,
|
|
1378
|
+
With a vault, the grant's body and each flow record's binding, consent URL and
|
|
1379
|
+
verifier are sealed with its AES-GCM key, the additional authenticated data naming the connector, owner partition,
|
|
1358
1380
|
record, and epoch, so ciphertext moved to another connector, principal,
|
|
1359
1381
|
record, or epoch does not open. Anything that fails to open (tampered, or
|
|
1360
1382
|
under a rotated key) reads as absent: `auth_required` and a logged warning.
|
|
1361
|
-
The epoch,
|
|
1362
|
-
nothing. A plaintext body written before the vault could seal is sealed where
|
|
1383
|
+
The epoch, timestamp, and state digest stay plaintext and authenticate nothing. A plaintext body written before the vault could seal is sealed where
|
|
1363
1384
|
it lies on first read, by compare-and-set. An [`api()` OAuth
|
|
1364
|
-
connector](#downstream-oauth-on-api) stores no client.
|
|
1365
|
-
|
|
1366
|
-
|
|
1385
|
+
connector](#downstream-oauth-on-api) stores no client.
|
|
1386
|
+
|
|
1387
|
+
`createConnecta` throws when a configured vault lacks `seal` or `open` and any
|
|
1388
|
+
connector has `startAuth`. A vault without them still works for deployments with
|
|
1389
|
+
no OAuth connector. To migrate, use `encryptedCredentialVault(storage, key)` or
|
|
1390
|
+
add both methods; grants stored plaintext are then sealed on first read as above.
|
|
1391
|
+
|
|
1392
|
+
**With no vault, the guarantee is narrower.** Nothing is encrypted at rest: the
|
|
1393
|
+
grant's body and the PKCE verifier are plaintext, and a configured URL's path can
|
|
1394
|
+
appear in them. The flow record is minimized instead. It stores no consent URL,
|
|
1395
|
+
and its binding keeps no URL userinfo, query or fragment, in plaintext or in its
|
|
1396
|
+
unkeyed discovery digest. Connect, callback and restart still work, and two things
|
|
1397
|
+
differ. A repeated non-forced start mints a fresh consent rather than handing the
|
|
1398
|
+
pending URL back; earlier links stay valid until their epoch ends. A change confined
|
|
1399
|
+
to a URL's query or fragment does not fence a pending consent.
|
|
1400
|
+
Use a vault wherever stored OAuth state must be protected.
|
|
1367
1401
|
|
|
1368
1402
|
The body also holds `expiresAt`, the epoch milliseconds the stored access token
|
|
1369
1403
|
expires: its `expires_in`, counted from just before the request that issued it
|
|
@@ -1432,7 +1466,7 @@ with the gate a call passes:
|
|
|
1432
1466
|
| Stored grant | Status | Start (Connect, Continue, Restart, `authorize_connector`) |
|
|
1433
1467
|
| ------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1434
1468
|
| Disconnected | `auth_required`; the downstream is not asked | Replaces the epoch, then proceeds as for no tokens |
|
|
1435
|
-
| No tokens |
|
|
1469
|
+
| No tokens | `auth_required`; tokenless MCP requests are refused locally | Connects first, so a 401's `resource_metadata` starts consent as before. A downstream that answers without credentials still gets consent, discovered from RFC 9728 metadata at the configured URL's well-known locations. The start answers `auth_required` with the consent URL. |
|
|
1436
1470
|
| Tokens (any expiry) | Connects; `ok`, or `auth_required` when a 401 needs consent | Connects; `ok` without starting a flow when healthy |
|
|
1437
1471
|
|
|
1438
1472
|
A start without a challenge runs the same SDK flow as a 401 without
|
|
@@ -2068,11 +2102,17 @@ targeting the host's private network:
|
|
|
2068
2102
|
- A URL on the connector's configured origin is trusted; the operator wrote it.
|
|
2069
2103
|
- Any other URL must be `https` and must not name a private host: `localhost`
|
|
2070
2104
|
and `*.localhost`, `127/8`, `10/8`, `172.16/12`, `192.168/16`, `169.254/16`,
|
|
2071
|
-
`100.64/10`, `0/8`,
|
|
2072
|
-
|
|
2105
|
+
`100.64/10`, `0/8`, `192.0.0/24`, `192.0.2/24`, `192.88.99/24`, `198.18/15`,
|
|
2106
|
+
`198.51.100/24`, `203.0.113/24`, `224/4`, `240/4`, `::`, `::1`, any IPv6
|
|
2107
|
+
address outside global unicast `2000::/3` (which covers `fc00::/7`,
|
|
2108
|
+
`fe80::/10`, `fec0::/10`, `ff00::/8` and `64:ff9b:1::/48`), `2001::/23`,
|
|
2109
|
+
`2001:db8::/32`, or `3fff::/20`. An IPv6 address carrying an IPv4 address in
|
|
2110
|
+
mapped, compatible, translated, NAT64 (`64:ff9b::/96`) or 6to4 (`2002::/16`)
|
|
2111
|
+
form is judged by the address it carries.
|
|
2073
2112
|
- A connector configured on a loopback host may also learn loopback URLs, over
|
|
2074
2113
|
`http` too, so a local MCP server with a local authorization server keeps
|
|
2075
|
-
working.
|
|
2114
|
+
working. Of the IPv4-carrying forms, only IPv4-mapped loopback counts as
|
|
2115
|
+
loopback. LAN and link-local addresses stay refused.
|
|
2076
2116
|
|
|
2077
2117
|
A refused URL is never requested. Discovery, registration, and code exchange
|
|
2078
2118
|
fail with a non-retryable `connector_call_failed`. Resource-metadata origin
|
|
@@ -2083,10 +2123,22 @@ and the grant requires re-consent. Redirects cannot route around the
|
|
|
2083
2123
|
rule; token requests never follow them, and resource redirects follow only
|
|
2084
2124
|
same-origin hops.
|
|
2085
2125
|
|
|
2086
|
-
The check
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2126
|
+
The shared check reads canonical URL syntax (including legacy IPv4 spellings).
|
|
2127
|
+
On Node, the owned transport also resolves learned hosts immediately before
|
|
2128
|
+
connecting, refuses the whole answer set if any IPv4 or IPv6 address violates
|
|
2129
|
+
the same rules, and pins the connection to a checked address. TLS SNI and
|
|
2130
|
+
certificate validation retain the original hostname, including through a proxy.
|
|
2131
|
+
Proxy TLS authenticates the proxy hostname separately from destination TLS.
|
|
2132
|
+
Resolution uses request-owned A/AAAA queries, cancelled when the request ends
|
|
2133
|
+
and bounded to ten seconds even without a caller deadline. Only absent address
|
|
2134
|
+
families may be omitted; resolver failures refuse the request. These DNS queries
|
|
2135
|
+
do not consult OS hosts-file aliases.
|
|
2136
|
+
Each redirect hop is checked. Configured origins remain exempt. Resolution
|
|
2137
|
+
refusals are typed, non-retryable, and send no destination request.
|
|
2138
|
+
|
|
2139
|
+
Workers exposes no connection-time DNS hook and has no route to private networks;
|
|
2140
|
+
its behavior remains the shared syntactic check. The shared core never imports
|
|
2141
|
+
Node networking or the optional undici peer.
|
|
2090
2142
|
|
|
2091
2143
|
Downstream advertisements choose consent destinations, never destinations for
|
|
2092
2144
|
existing grants. Tokens and registered clients bind to their issuing server;
|
|
@@ -2213,7 +2265,9 @@ the first request on a fresh instance. It grants no identity and never falls
|
|
|
2213
2265
|
back to another provider. Missing context without an assertion still returns 401. An unusable trusted AUD returns retryable 503 with
|
|
2214
2266
|
`problem: "access_audience_invalid"`; it never proceeds to identity lookup.
|
|
2215
2267
|
A rejected human identity, including a service identity or an unusable user
|
|
2216
|
-
id, returns 403. A thrown identity lookup
|
|
2268
|
+
id, returns 403. A thrown identity lookup gets one retry after 100–250 ms of
|
|
2269
|
+
jitter, within the original five-second deadline. A hanging lookup is never
|
|
2270
|
+
retried concurrently. The second rejection or the deadline returns retryable
|
|
2217
2271
|
503 with `problem: "identity_unavailable"` and `Retry-After: 1`. Every refusal
|
|
2218
2272
|
carries `Cache-Control: no-store`; every unavailable-verification 503 carries
|
|
2219
2273
|
`Retry-After: 1` and no `WWW-Authenticate` challenge. None of these failures admits an identity,
|
|
@@ -2231,9 +2285,24 @@ identifies the generic route fallthrough, `authorization_header_invalid` a
|
|
|
2231
2285
|
malformed header, and `authentication_failed` an unclassified provider refusal.
|
|
2232
2286
|
Access verification 503s emit `[connecta] Cloudflare Access verification unavailable`
|
|
2233
2287
|
with the same facts and `access_context_unavailable`, `access_audience_invalid`,
|
|
2234
|
-
or `access_identity_unavailable`.
|
|
2288
|
+
or `access_identity_unavailable`. Identity lookup failures additionally carry
|
|
2289
|
+
checked `identityLookup` facts: `outcome` (`timeout` or `rejected`), `durationMs`,
|
|
2290
|
+
`cold` (whether this was the isolate's first identity lookup), and `inFlight`
|
|
2291
|
+
(the isolate's lookup attempts still pending when the failure was recorded; this
|
|
2292
|
+
request's own attempt counts only while it is pending, so a hung lookup counts
|
|
2293
|
+
itself, and a rejected lookup or a deadline during retry backoff does not).
|
|
2294
|
+
These records contain no header values,
|
|
2235
2295
|
assertions, cookies, identities, URLs, response bodies, or exception text.
|
|
2236
2296
|
|
|
2297
|
+
Identity lookups stay request-owned: Connecta neither coalesces them across
|
|
2298
|
+
requests nor caches identity results. A caller-supplied assertion header is
|
|
2299
|
+
not an identity cache key. Failed identity lookups always refuse admission.
|
|
2300
|
+
|
|
2301
|
+
After an authorized release, validate this mitigation with about 20 concurrent
|
|
2302
|
+
sessions. Count runs containing `identity_unavailable`, targeting fewer than
|
|
2303
|
+
1% of runs; distinguish `timeout` from `rejected` in the checked lookup facts.
|
|
2304
|
+
A passing local concurrency fixture does not establish production acceptance.
|
|
2305
|
+
|
|
2237
2306
|
Protect the Worker with a Worker-level Access application whose destination is
|
|
2238
2307
|
`{ "type": "worker", "worker_id": "<the Worker script tag>" }`. A traditional
|
|
2239
2308
|
hostname-level application blocks the URL but does not attach `ctx.access` to
|
|
@@ -2278,7 +2347,15 @@ tokens by default, both JWT and opaque. Verified `aud` or `resource` must
|
|
|
2278
2347
|
contain the endpoint's exact canonical URL from protected-resource metadata.
|
|
2279
2348
|
If both claims are present, both must match. Trailing slashes, case, queries,
|
|
2280
2349
|
and fragments are not normalized. `/mcp` and `/mcp/support` are distinct
|
|
2281
|
-
resources.
|
|
2350
|
+
resources.
|
|
2351
|
+
|
|
2352
|
+
Clerk needs a fixed deployment URL. Set `ConnectaConfig.publicUrl`, or
|
|
2353
|
+
`clerkAuth({ publicUrl })` when only Clerk should use it; `createConnecta` throws
|
|
2354
|
+
when neither is set, on Node and on Workers. Both token `resource` checks and the
|
|
2355
|
+
session `azp` pin read this value, so a request's `Host` and `X-Forwarded-Proto`
|
|
2356
|
+
never decide them. There is no implicit loopback default: a local deployment names
|
|
2357
|
+
its origin, such as `http://localhost:8787`. The Node template does this when
|
|
2358
|
+
`PUBLIC_URL` is unset.
|
|
2282
2359
|
|
|
2283
2360
|
```ts
|
|
2284
2361
|
clerkAuth({ publishableKey, secretKey,
|
|
@@ -2908,9 +2985,27 @@ grant with different consent settings.
|
|
|
2908
2985
|
|
|
2909
2986
|
The grant record and consents, epoch fencing, vault sealing, shared/personal ownership,
|
|
2910
2987
|
callback state/principal checks, `authorize_connector`, Connect, Restart, and
|
|
2911
|
-
Disconnect match `remoteMcp()`. Status
|
|
2912
|
-
|
|
2913
|
-
|
|
2988
|
+
Disconnect match `remoteMcp()`. Status reads do not probe tokens, start OAuth,
|
|
2989
|
+
or write grant state. A grant for the configured token endpoint starts as `ok`;
|
|
2990
|
+
a real API 401 records `refused` and status becomes `auth_required`. A real API
|
|
2991
|
+
2xx records `accepted`. Other HTTP statuses do not establish an auth outcome.
|
|
2992
|
+
A persisted refusal does not block a later invocation: the API may have recovered,
|
|
2993
|
+
and an accepted response restores `ok`. Within the failing request, a second 401
|
|
2994
|
+
still latches authorization failure. Connect on a refused grant begins fresh consent
|
|
2995
|
+
rather than reporting existing tokens as healthy. Maintained OAuth providers record
|
|
2996
|
+
these same outcomes for initial and replayed requests. Repeated identical outcomes
|
|
2997
|
+
for the current revision do not rewrite the grant.
|
|
2998
|
+
Each consent and refresh advances a monotonic token revision within its grant
|
|
2999
|
+
epoch and clears the prior observation in the same compare-and-set write.
|
|
3000
|
+
Call observations carry the epoch and revision read with their token and are
|
|
3001
|
+
accepted only while both still match the live grant. No wall clock orders
|
|
3002
|
+
observations. Reconsent with an identical token still advances the revision.
|
|
3003
|
+
The observation stores only its revision and the `accepted`/`refused` enum;
|
|
3004
|
+
arguments, response bodies, code and error text are excluded. A declared oversized
|
|
3005
|
+
401 records refusal without reading its body, including on a replay. Normal Connect
|
|
3006
|
+
resets only while the refused epoch, revision and outcome it read still match;
|
|
3007
|
+
a concurrently recovered grant is preserved. An observation
|
|
3008
|
+
storage failure does not replace the already received API response. `oauth` and
|
|
2914
3009
|
`credential` are exclusive per connector, giving `auth_required` one recovery.
|
|
2915
3010
|
For providers offering both, deployment config chooses; handlers check `ctx.oauth`.
|
|
2916
3011
|
|
|
@@ -1113,9 +1113,18 @@ fields that are otherwise operator- and connector-authored, so `connectorId`
|
|
|
1113
1113
|
and `toolName` clamp at 128 UTF-8 bytes (`address` at 257) with a `…` marker:
|
|
1114
1114
|
payload-free _by construction_ means the event has nowhere to put a payload.
|
|
1115
1115
|
|
|
1116
|
-
**V4.**
|
|
1117
|
-
|
|
1118
|
-
|
|
1116
|
+
**V4.** By default the execution and its utility operations emit no events.
|
|
1117
|
+
With `activityHistory({ operations: true })`, each executed search, describe,
|
|
1118
|
+
result page and skill read adds a `kind: "operation"` row, and the whole program
|
|
1119
|
+
adds a `program` row with host-call counts. Utility attempts refused above the
|
|
1120
|
+
execution boundary remain represented by the program's host-call accounting.
|
|
1121
|
+
Rows use fixed operation names rather than argument-supplied addresses or IDs;
|
|
1122
|
+
they carry timings, typed outcomes/codes and serialized return byte counts,
|
|
1123
|
+
never program source or payloads. The existing detached sink handles storage,
|
|
1124
|
+
and these rows do not count as calls or friction. The
|
|
1125
|
+
[operation-history contract](./operator-ui.md#opt-in-to-operation-history)
|
|
1126
|
+
owns opt-in cost, scope and owner disclosure rules. Recording history changes
|
|
1127
|
+
no authorization or capability state.
|
|
1119
1128
|
|
|
1120
1129
|
**V5.** A write a program issues after it has already returned is not
|
|
1121
1130
|
sent and records nothing: it was never an attempt (`W9`).
|
|
@@ -1337,6 +1346,12 @@ receive a fixed description.
|
|
|
1337
1346
|
|
|
1338
1347
|
### Verification
|
|
1339
1348
|
|
|
1349
|
+
The QuickJS child imports only the guest runtime, IPC helpers and dependency-light
|
|
1350
|
+
error/route constants. `test/purity.node.test.ts` walks its emitted import graph
|
|
1351
|
+
to exclude server orchestration, Effect and the MCP SDK. The shared
|
|
1352
|
+
`InvocationFailure` constructor preserves host error identity across existing
|
|
1353
|
+
exports and typed IPC reconstruction.
|
|
1354
|
+
|
|
1340
1355
|
The earlier alternatives are in [decision history](https://github.com/zackbart/connecta/blob/main/decisions/0001-ethos-verdict-table.md)
|
|
1341
1356
|
([#267](https://github.com/zackbart/connecta/issues/267),
|
|
1342
1357
|
[#270](https://github.com/zackbart/connecta/issues/270)).
|
|
@@ -1350,49 +1365,49 @@ rejection, and branded adapter acceptance across module copies.
|
|
|
1350
1365
|
declaration against `GuestApi`, checks arguments in both directions, and rejects
|
|
1351
1366
|
invented, mistyped, and missing members and authored blocks the host refuses.
|
|
1352
1367
|
|
|
1353
|
-
| Clauses | Test
|
|
1354
|
-
| ---------------------- |
|
|
1355
|
-
| `P1`, `P5` | both guest-contract executors (TypeScript syntax, trailing terminators, wrapper recovery), `test/program-source.test.ts` (which semicolons and wrappers are recovered), `test/quickjs-executor.node.test.ts` (`normalizeCode`)
|
|
1356
|
-
| `P2`, `X5` | `test/guest-api-contract.test.ts` (Dynamic globals plus loader-only filesystem, HTTP, environment, egress, DNS, and local `data:` boundaries), `test/guest-api-contract-quickjs.node.test.ts` (exact absent globals and blocked imports), `test/deployment-shapes.node.test.ts` (loader-only Worker construction)
|
|
1357
|
-
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts`
|
|
1358
|
-
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution)
|
|
1359
|
-
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (canonical addressing), `test/server.test.ts` (bounded live connector inventory)
|
|
1360
|
-
| `S1`, `S1a`, `S2` | `test/guest-api-contract.test.ts` (flat page, connector guides, schema keys, unfiltered browse), `test/execute.test.ts` (guide pagination/partial/no-match behavior and `$ref`/`allOf`), `test/meta-tools-search.test.ts` (mixed complete/partial ranking, stable pagination, the two safety classes), `test/typescript-signatures.test.ts` (the TypeScript format over provider and pathological schemas, search/describe parity, observed labeling)
|
|
1361
|
-
| `S3` | `test/guest-api-contract.test.ts` (typed uncaught bound), `test/execute.test.ts` (count limits, fan-out bound)
|
|
1362
|
-
| `S4` | both guest-contract executors (ordered mixed describe results with unknown-address, unknown-tool suggestion, and catalog-failure details), `test/meta-tools-search.test.ts` (top-level routing, no-suggestion, catalog-failure, and hostile-input bounds)
|
|
1363
|
-
| `S5`, `S6` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`unwrapMcpResult`, fail-closed annotations, activity parity)
|
|
1364
|
-
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (parallel calls and shared admission)
|
|
1365
|
-
| `S8`, `E1`, `X11` | both guest-contract executors (caught call, discovery, utility, removed-function, and forgery cases; typed promise rejections), `test/quickjs-executor.node.test.ts` (oversized messages, private transport, forged outcomes)
|
|
1366
|
-
| `S9` | `test/result-shapes.test.ts` (value exclusion, bounds, merging, LRU and time expiry, runtime isolation, read-only admission, declared precedence, definition invalidation, unwrapped MCP results, discovery provenance, copy isolation, failure isolation)
|
|
1367
|
-
| `S10` | `test/resource-read.test.ts` (qualified routing, whole-connector grants, personal credentials, redaction, admission, timeout, cancellation and downstream MCP reads), both guest-contract executors (successful resource reads and caught/uncaught typed failures)
|
|
1368
|
-
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught, parallel, and uncaught validation recovery, a conflict's bounded `current`), `test/meta-tools-call.test.ts` (direct, destructive, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts`
|
|
1369
|
-
| `E3`, `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`, destructive reroute), `test/identity-write-journey.node.test.ts` (read-only refusals before validation or dispatch, actual QuickJS)
|
|
1370
|
-
| `E5` | `test/guest-api-contract.test.ts` (execution-failure channel, in-flight `cancelled`), `test/execute.test.ts` (admission), `test/executor-admission.test.ts`, `test/quickjs-executor.node.test.ts` (mid-run shutdown)
|
|
1371
|
-
| `E6`, `X8` | `test/guest-api-contract.test.ts` (unknown and inherited members, retained error identities), `test/quickjs-executor.node.test.ts`
|
|
1372
|
-
| `E7` | `test/guest-api-contract.test.ts` (refusals about a `503`-named connector), `test/errors.test.ts`
|
|
1373
|
-
| `R1`, `R2`, `R3`, `R4` | `test/guest-api-contract.test.ts` and `test/guest-api-contract-quickjs.node.test.ts` (small pass-through, shared return paging and unavailable fallback, no repeated writes, live authority), `test/program-result-cases.ts` (reconstruction, redaction, notice survives a 2,000-character spill)
|
|
1374
|
-
| `M6`, `M9` | verdicts; `R2`'s guard, `M1`'s strict typing, and `M2`'s collect-then-deliver are their enforcement
|
|
1375
|
-
| `R5` | `test/guest-api-contract.test.ts`
|
|
1376
|
-
| `R6`–`R8` | `test/guest-api-contract.test.ts` (normal result keys), `test/execute.test.ts` (opt-in operation aggregates, failure paths, payload exclusion)
|
|
1377
|
-
| `Y1`, `Y2`, `Y3` | `test/guest-api-contract.test.ts` (one attempt per call, retryable flags by code)
|
|
1378
|
-
| `Y4` | `test/meta-tools-call.test.ts`, `test/call-admission.test.ts` (one attempt, retry hints, caller reissue)
|
|
1379
|
-
| `L1`, `L2` | `test/guest-api-contract.test.ts` (in-flight call fails `cancelled`), `test/execute.test.ts` (cancels outstanding host calls, discovery included, and refuses discovery after the run; a cancelled wedged executor, or one whose `acquire()` ignores the signal, returns promptly and releases its lease)
|
|
1380
|
-
| `L3`, `X1` | `test/guest-api-contract.test.ts` (short-deadline executors), `test/execute.test.ts` (the watchdog ends a never-settling executor, frees the default pool, spares a slow run, and falls back from an unusable value)
|
|
1381
|
-
| `L4`, `L8` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (shared discovery/call budgets and terminal catch-and-continue loops and queued-write cancellation on both executors)
|
|
1382
|
-
| `L5`, `L7`, `X2` | `test/quickjs-executor.node.test.ts` (CPU, heap), `test/execute.test.ts` and `test/executor-admission.test.ts` (bounded admission and queue), `test/executor-requests.test.ts` (queued handoffs and refusal shape across separate workerd requests), `test/request-context.node.test.ts` (queued and QuickJS host-call request context)
|
|
1383
|
-
| `L6`, `X10` | `test/guest-api-contract-quickjs.node.test.ts` and `test/guest-api-contract.test.ts` (whole oversized reads and one-write pageable handles), `test/sqlite-storage.node.test.ts` and `test/storage-sql-d1.test.ts` (SQL stash and native D1 fault probes), `test/quickjs-executor.node.test.ts` (bridge and IPC bounds for arguments and result; the address in the over-bound message)
|
|
1384
|
-
| `V1`–`V4` | `test/guest-api-contract.test.ts` (dispatched calls, every refusal class including an address no connector owns, the friction each derives, no event
|
|
1385
|
-
| `V5`, `W9` | `test/program-writes.test.ts` (unawaited program drain, failed-program accounting), `test/identity-write-journey.node.test.ts` (committed ambiguity, reconciliation and physical writes), `test/invocation-pipeline.test.ts` (the gate after validation, an unrecorded refusal)
|
|
1386
|
-
| `W10`, `W12` | `test/identity-write-journey.node.test.ts` (real HTTP/MCP and QuickJS: write budget, read-only discovery and refusal, named guide, pool inheritance/reopening and connector policy), `test/program-writes.test.ts` (construction refusals and classification drift), `test/browser/operator-ui.spec.ts` (the badge)
|
|
1387
|
-
| `M1` | `test/guest-api-contract.test.ts` (invalid emits throw catchably, accept nothing), `test/execute-emit.test.ts` (rejected shapes, bounded native snapshots, paging before metadata traversal, and cyclic presentation refusal)
|
|
1388
|
-
| `M2`, `M3` | `test/guest-api-contract.test.ts` (delivery order, truncated return plus delivered blocks), `test/execute-emit.test.ts` (envelope, `structuredContent`, byte-for-byte no-emit path)
|
|
1389
|
-
| `M4` | `test/guest-api-contract.test.ts` (discard is visible), `test/execute-emit.test.ts` (structured and plain paths), `test/quickjs-executor.node.test.ts` (mid-run shutdown)
|
|
1390
|
-
| `M5`, `M7` | `test/execute-emit.test.ts` (both budgets fail the crossing block; host-call budget untouched)
|
|
1391
|
-
| `M8` | two arms passing one case table, `test/codemode-compat.test.ts`
|
|
1392
|
-
| `M10` | `test/execute-emit.test.ts` (aggregate present, numbers only, absent when nothing emitted)
|
|
1393
|
-
| `X4` | `test/guest-api-contract.test.ts` (string logs only), `test/quickjs-executor.node.test.ts` (logs before cancellation)
|
|
1394
|
-
| `X3`, `X6` | `test/quickjs-executor.node.test.ts` (cancels a running child, never-settling await), `test/execute.test.ts` (a wedged executor stops being awaited)
|
|
1395
|
-
| `X7` | `P3`'s tests; the Workers superset is deliberately unused
|
|
1368
|
+
| Clauses | Test |
|
|
1369
|
+
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1370
|
+
| `P1`, `P5` | both guest-contract executors (TypeScript syntax, trailing terminators, wrapper recovery), `test/program-source.test.ts` (which semicolons and wrappers are recovered), `test/quickjs-executor.node.test.ts` (`normalizeCode`) |
|
|
1371
|
+
| `P2`, `X5` | `test/guest-api-contract.test.ts` (Dynamic globals plus loader-only filesystem, HTTP, environment, egress, DNS, and local `data:` boundaries), `test/guest-api-contract-quickjs.node.test.ts` (exact absent globals and blocked imports), `test/deployment-shapes.node.test.ts` (loader-only Worker construction) |
|
|
1372
|
+
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` |
|
|
1373
|
+
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution) |
|
|
1374
|
+
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (canonical addressing), `test/server.test.ts` (bounded live connector inventory) |
|
|
1375
|
+
| `S1`, `S1a`, `S2` | `test/guest-api-contract.test.ts` (flat page, connector guides, schema keys, unfiltered browse), `test/execute.test.ts` (guide pagination/partial/no-match behavior and `$ref`/`allOf`), `test/meta-tools-search.test.ts` (mixed complete/partial ranking, stable pagination, the two safety classes), `test/typescript-signatures.test.ts` (the TypeScript format over provider and pathological schemas, search/describe parity, observed labeling) |
|
|
1376
|
+
| `S3` | `test/guest-api-contract.test.ts` (typed uncaught bound), `test/execute.test.ts` (count limits, fan-out bound) |
|
|
1377
|
+
| `S4` | both guest-contract executors (ordered mixed describe results with unknown-address, unknown-tool suggestion, and catalog-failure details), `test/meta-tools-search.test.ts` (top-level routing, no-suggestion, catalog-failure, and hostile-input bounds) |
|
|
1378
|
+
| `S5`, `S6` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`unwrapMcpResult`, fail-closed annotations, activity parity) |
|
|
1379
|
+
| `S7` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (parallel calls and shared admission) |
|
|
1380
|
+
| `S8`, `E1`, `X11` | both guest-contract executors (caught call, discovery, utility, removed-function, and forgery cases; typed promise rejections), `test/quickjs-executor.node.test.ts` (oversized messages, private transport, forged outcomes) |
|
|
1381
|
+
| `S9` | `test/result-shapes.test.ts` (value exclusion, bounds, merging, LRU and time expiry, runtime isolation, read-only admission, declared precedence, definition invalidation, unwrapped MCP results, discovery provenance, copy isolation, failure isolation) |
|
|
1382
|
+
| `S10` | `test/resource-read.test.ts` (qualified routing, whole-connector grants, personal credentials, redaction, admission, timeout, cancellation and downstream MCP reads), both guest-contract executors (successful resource reads and caught/uncaught typed failures) |
|
|
1383
|
+
| `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, caught, parallel, and uncaught validation recovery, a conflict's bounded `current`), `test/meta-tools-call.test.ts` (direct, destructive, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
|
|
1384
|
+
| `E3`, `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`, destructive reroute), `test/identity-write-journey.node.test.ts` (read-only refusals before validation or dispatch, actual QuickJS) |
|
|
1385
|
+
| `E5` | `test/guest-api-contract.test.ts` (execution-failure channel, in-flight `cancelled`), `test/execute.test.ts` (admission), `test/executor-admission.test.ts`, `test/quickjs-executor.node.test.ts` (mid-run shutdown) |
|
|
1386
|
+
| `E6`, `X8` | `test/guest-api-contract.test.ts` (unknown and inherited members, retained error identities), `test/quickjs-executor.node.test.ts` |
|
|
1387
|
+
| `E7` | `test/guest-api-contract.test.ts` (refusals about a `503`-named connector), `test/errors.test.ts` |
|
|
1388
|
+
| `R1`, `R2`, `R3`, `R4` | `test/guest-api-contract.test.ts` and `test/guest-api-contract-quickjs.node.test.ts` (small pass-through, shared return paging and unavailable fallback, no repeated writes, live authority), `test/program-result-cases.ts` (reconstruction, redaction, notice survives a 2,000-character spill) |
|
|
1389
|
+
| `M6`, `M9` | verdicts; `R2`'s guard, `M1`'s strict typing, and `M2`'s collect-then-deliver are their enforcement |
|
|
1390
|
+
| `R5` | `test/guest-api-contract.test.ts` |
|
|
1391
|
+
| `R6`–`R8` | `test/guest-api-contract.test.ts` (normal result keys), `test/execute.test.ts` (opt-in operation aggregates, failure paths, payload exclusion) |
|
|
1392
|
+
| `Y1`, `Y2`, `Y3` | `test/guest-api-contract.test.ts` (one attempt per call, retryable flags by code) |
|
|
1393
|
+
| `Y4` | `test/meta-tools-call.test.ts`, `test/call-admission.test.ts` (one attempt, retry hints, caller reissue) |
|
|
1394
|
+
| `L1`, `L2` | `test/guest-api-contract.test.ts` (in-flight call fails `cancelled`), `test/execute.test.ts` (cancels outstanding host calls, discovery included, and refuses discovery after the run; a cancelled wedged executor, or one whose `acquire()` ignores the signal, returns promptly and releases its lease) |
|
|
1395
|
+
| `L3`, `X1` | `test/guest-api-contract.test.ts` (short-deadline executors), `test/execute.test.ts` (the watchdog ends a never-settling executor, frees the default pool, spares a slow run, and falls back from an unusable value) |
|
|
1396
|
+
| `L4`, `L8` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (shared discovery/call budgets and terminal catch-and-continue loops and queued-write cancellation on both executors) |
|
|
1397
|
+
| `L5`, `L7`, `X2` | `test/quickjs-executor.node.test.ts` (CPU, heap), `test/execute.test.ts` and `test/executor-admission.test.ts` (bounded admission and queue), `test/executor-requests.test.ts` (queued handoffs and refusal shape across separate workerd requests), `test/request-context.node.test.ts` (queued and QuickJS host-call request context) |
|
|
1398
|
+
| `L6`, `X10` | `test/guest-api-contract-quickjs.node.test.ts` and `test/guest-api-contract.test.ts` (whole oversized reads and one-write pageable handles), `test/sqlite-storage.node.test.ts` and `test/storage-sql-d1.test.ts` (SQL stash and native D1 fault probes), `test/quickjs-executor.node.test.ts` (bridge and IPC bounds for arguments and result; the address in the over-bound message) |
|
|
1399
|
+
| `V1`–`V4` | `test/guest-api-contract.test.ts` (dispatched calls, every refusal class including an address no connector owns, the friction each derives, no execution event by default), `test/identity-write-journey.node.test.ts` (opt-in real-program utility/program rows, payload exclusion and detached writes), `test/activity.test.ts` (the shared code → friction table, the identity clamp, the one-attempt floor), `test/browser/operator-ui.spec.ts` (identity changes), `test/sql-storage-contract.ts`, run by `test/sqlite-storage.node.test.ts` (historical activity rows still round-trip) |
|
|
1400
|
+
| `V5`, `W9` | `test/program-writes.test.ts` (unawaited program drain, failed-program accounting), `test/identity-write-journey.node.test.ts` (committed ambiguity, reconciliation and physical writes), `test/invocation-pipeline.test.ts` (the gate after validation, an unrecorded refusal) |
|
|
1401
|
+
| `W10`, `W12` | `test/identity-write-journey.node.test.ts` (real HTTP/MCP and QuickJS: write budget, read-only discovery and refusal, named guide, pool inheritance/reopening and connector policy), `test/program-writes.test.ts` (construction refusals and classification drift), `test/browser/operator-ui.spec.ts` (the badge) |
|
|
1402
|
+
| `M1` | `test/guest-api-contract.test.ts` (invalid emits throw catchably, accept nothing), `test/execute-emit.test.ts` (rejected shapes, bounded native snapshots, paging before metadata traversal, and cyclic presentation refusal) |
|
|
1403
|
+
| `M2`, `M3` | `test/guest-api-contract.test.ts` (delivery order, truncated return plus delivered blocks), `test/execute-emit.test.ts` (envelope, `structuredContent`, byte-for-byte no-emit path) |
|
|
1404
|
+
| `M4` | `test/guest-api-contract.test.ts` (discard is visible), `test/execute-emit.test.ts` (structured and plain paths), `test/quickjs-executor.node.test.ts` (mid-run shutdown) |
|
|
1405
|
+
| `M5`, `M7` | `test/execute-emit.test.ts` (both budgets fail the crossing block; host-call budget untouched) |
|
|
1406
|
+
| `M8` | two arms passing one case table, `test/codemode-compat.test.ts` |
|
|
1407
|
+
| `M10` | `test/execute-emit.test.ts` (aggregate present, numbers only, absent when nothing emitted) |
|
|
1408
|
+
| `X4` | `test/guest-api-contract.test.ts` (string logs only), `test/quickjs-executor.node.test.ts` (logs before cancellation) |
|
|
1409
|
+
| `X3`, `X6` | `test/quickjs-executor.node.test.ts` (cancels a running child, never-settling await), `test/execute.test.ts` (a wedged executor stops being awaited) |
|
|
1410
|
+
| `X7` | `P3`'s tests; the Workers superset is deliberately unused |
|
|
1396
1411
|
|
|
1397
1412
|
The surface itself is checked by `test/server.test.ts` (the exact six-tool list)
|
|
1398
1413
|
and `test/program-writes.test.ts` (deployment policy and classification construction refusals).
|
|
@@ -61,6 +61,17 @@ authenticated `admission.requests.maxBodyBytes` default. To accept larger MCP
|
|
|
61
61
|
bodies, configure both core and `listen(..., { maxBodyBytes })`; a smaller
|
|
62
62
|
platform, proxy or adapter cap still wins. See
|
|
63
63
|
[request body limits](./architecture.md#admission-in-two-places).
|
|
64
|
+
`listen(..., { maxInFlightBodyBytes })` caps the body bytes all in-flight
|
|
65
|
+
requests hold together, counted from the first chunk until the response finishes
|
|
66
|
+
or the client leaves. It defaults to 64 MiB, or `maxBodyBytes` when that is
|
|
67
|
+
larger, and may not be set below `maxBodyBytes`. Past it a request gets `503` with
|
|
68
|
+
`Retry-After: 1` and `Connection: close`. Raise it when legitimate concurrent
|
|
69
|
+
large bodies are refused, keeping it within the process's memory budget.
|
|
70
|
+
`listen()` answers `400` with `Connection: close`, before reading any body, when
|
|
71
|
+
`Host` is anything but a host with an optional port, when `X-Forwarded-Proto` is
|
|
72
|
+
anything but `http` or `https`, or when the request target does not start with
|
|
73
|
+
`/`. A reverse proxy must overwrite `X-Forwarded-Proto` with one value; a
|
|
74
|
+
comma-separated chain such as `https,http` is refused.
|
|
64
75
|
A Node host serving `connecta.fetch` without `listen()` has no owned sender:
|
|
65
76
|
every maintained-provider write, every reviewed POST read and every remote MCP
|
|
66
77
|
write is refused before sending. Downstream OAuth credential POSTs also require
|
|
@@ -199,7 +210,9 @@ and `describeConfig()`, and [optional modules](./architecture.md#optional-deploy
|
|
|
199
210
|
owns their composition contracts.
|
|
200
211
|
|
|
201
212
|
Enable `encryptedCredentialVault(storage, key)` before persisting downstream
|
|
202
|
-
OAuth credentials.
|
|
213
|
+
OAuth credentials. With no vault, OAuth grants are stored as plaintext. A
|
|
214
|
+
configured vault without `seal` and `open` refuses construction when any connector
|
|
215
|
+
uses OAuth.
|
|
203
216
|
The platform templates describe the base64 32-byte encryption key. Keep it
|
|
204
217
|
outside the database and source control, and preserve it across upgrades.
|
|
205
218
|
[OAuth state at rest](./auth.md#downstream-oauth-state-at-rest) owns sealing and
|
|
@@ -302,6 +315,17 @@ Bump the exact package pin, read the [changelog](../CHANGELOG.md) for every
|
|
|
302
315
|
intervening release, and apply the relevant migration before startup. `init`
|
|
303
316
|
does not merge changes into an existing deployment.
|
|
304
317
|
|
|
318
|
+
A custom vault without `seal` and `open` now refuses construction when any
|
|
319
|
+
connector has OAuth. Before upgrading, add both methods or switch to
|
|
320
|
+
`encryptedCredentialVault(storage, key)`. Existing plaintext grants are sealed on
|
|
321
|
+
first read; see [OAuth state at rest](./auth.md#downstream-oauth-state-at-rest).
|
|
322
|
+
|
|
323
|
+
A deployment using `clerkAuth` must set a fixed URL before upgrading:
|
|
324
|
+
`ConnectaConfig.publicUrl`, or `clerkAuth({ publicUrl })`. Startup otherwise fails
|
|
325
|
+
with a configuration error. Use the origin clients reach, because tokens' `resource`
|
|
326
|
+
must match it exactly; see
|
|
327
|
+
[Clerk OAuth tokens](./auth.md#clerk-oauth-tokens-and-operator-sessions).
|
|
328
|
+
|
|
305
329
|
Before upgrading past 0.37.1 with pre-0.29 state, follow
|
|
306
330
|
[Retired layout migrations](./migration-retired-layouts.md). Version 0.37.1 is
|
|
307
331
|
the last bridge for KV → D1, JSON → SQLite, and OAuth layout-2 conversions.
|
|
@@ -345,8 +345,8 @@ check shared behavior. Provider-specific tests remain beside each provider.
|
|
|
345
345
|
|
|
346
346
|
Use [`@zackbart/connecta-eve`](https://github.com/zackbart/connecta/blob/main/packages/connecta-eve/README.md)
|
|
347
347
|
in the Eve app for an app-owned connection and endpoint instructions refreshed
|
|
348
|
-
once per turn. It
|
|
349
|
-
|
|
348
|
+
once per turn. It installs separately from Connecta. Follow its README for the
|
|
349
|
+
supported Node and Eve versions, the two agent files, token environment variables,
|
|
350
350
|
optional write approval and Vercel OIDC token source. Configure the server's
|
|
351
351
|
[agent and pool membership](./auth.md#issue-rotate-or-revoke-an-agent-token)
|
|
352
352
|
before connecting.
|