@zackbart/connecta 0.37.1 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +2 -2
  3. package/bin/connecta.mjs +1 -39
  4. package/bin/version.mjs +1 -1
  5. package/dist/access-tokens.js +2 -4
  6. package/dist/agent-identity.js +1 -1
  7. package/dist/auth/clerk-sdk/generated.js +2 -1
  8. package/dist/auth/downstream-oauth.js +19 -153
  9. package/dist/auth/downstream-revocation.js +1 -1
  10. package/dist/auth/oauth-grant.js +11 -0
  11. package/dist/auth/oauth-token-response.js +1 -1
  12. package/dist/auth/vercel-agent.js +2 -1
  13. package/dist/auth-elicitation.js +2 -2
  14. package/dist/branding.d.ts +1 -15
  15. package/dist/branding.js +2 -2
  16. package/dist/bytes.js +42 -0
  17. package/dist/call-admission-context.js +2 -5
  18. package/dist/call-recovery.js +0 -3
  19. package/dist/catalog-fingerprint.js +2 -18
  20. package/dist/catalog-service.js +1 -1
  21. package/dist/config-defaults.d.ts +1 -0
  22. package/dist/config-defaults.js +1 -0
  23. package/dist/config-schema.d.ts +1 -1
  24. package/dist/config-schema.js +6 -2
  25. package/dist/config.d.ts +41 -14
  26. package/dist/config.js +21 -71
  27. package/dist/connectors/api-connector.js +4 -3
  28. package/dist/connectors/guarded-fetch.d.ts +0 -6
  29. package/dist/connectors/guarded-fetch.js +1 -11
  30. package/dist/connectors/remote-mcp.js +10 -43
  31. package/dist/connectors/resource-uri.js +0 -4
  32. package/dist/d1.d.ts +0 -89
  33. package/dist/d1.js +0 -34
  34. package/dist/downstream-input.js +2 -2
  35. package/dist/execute.js +22 -13
  36. package/dist/executor-result.js +2 -1
  37. package/dist/executors/quickjs-runtime.js +2 -25
  38. package/dist/executors/quickjs.js +1 -1
  39. package/dist/guest-runtime.js +5 -3
  40. package/dist/guest-types.d.ts +5 -5
  41. package/dist/http/client.js +1 -1
  42. package/dist/http/errors.js +2 -2
  43. package/dist/http/json-schema.js +1 -1
  44. package/dist/http/node-transport.js +0 -1
  45. package/dist/http/oauth.js +1 -1
  46. package/dist/http/paging.js +6 -9
  47. package/dist/http/provider.js +1 -1
  48. package/dist/http/safety.js +1 -1
  49. package/dist/http/services.js +1 -8
  50. package/dist/http/tools.js +1 -7
  51. package/dist/http/vendor.js +7 -7
  52. package/dist/identity.js +2 -6
  53. package/dist/invocation-auth.js +2 -1
  54. package/dist/meta-tools.js +27 -27
  55. package/dist/native-tools.js +2 -1
  56. package/dist/oauth-handoff.js +2 -2
  57. package/dist/operation-vocabulary.js +1 -1
  58. package/dist/operator-record.js +1 -49
  59. package/dist/operator-ui/contract.d.ts +2 -2
  60. package/dist/operator-ui/generated.js +3 -3
  61. package/dist/program-writes.js +3 -8
  62. package/dist/provider-call.js +0 -7
  63. package/dist/provider.d.ts +1 -1
  64. package/dist/providers/_shared/google/kit.js +1 -6
  65. package/dist/providers/_shared/google/service-account.js +1 -3
  66. package/dist/providers/_shared/google/workspace.d.ts +1 -1
  67. package/dist/providers/_shared/guide.js +3 -0
  68. package/dist/providers/_shared/json.js +12 -0
  69. package/dist/providers/_shared/rest/compact-index.js +1 -1
  70. package/dist/providers/_shared/rest/kit.js +1 -3
  71. package/dist/providers/_shared/rest/operation-index.js +1 -3
  72. package/dist/providers/_shared/rest/value-safety.js +26 -28
  73. package/dist/providers/breeze/api.js +2 -7
  74. package/dist/providers/breeze/index.js +4 -2
  75. package/dist/providers/breeze/tools.js +3 -4
  76. package/dist/providers/ccb/api.js +1 -6
  77. package/dist/providers/ccb/index.js +2 -1
  78. package/dist/providers/ccb/tools.js +1 -6
  79. package/dist/providers/cloudflare/api.js +2 -2
  80. package/dist/providers/cloudflare/index.js +2 -1
  81. package/dist/providers/cloudflare/safety.js +3 -3
  82. package/dist/providers/docs/tools.js +2 -10
  83. package/dist/providers/drive/tools.js +12 -25
  84. package/dist/providers/forms/tools.js +1 -9
  85. package/dist/providers/gmail/tools.js +5 -21
  86. package/dist/providers/overflow/api.js +1 -3
  87. package/dist/providers/overflow/index.js +2 -1
  88. package/dist/providers/overflow/tools.js +3 -7
  89. package/dist/providers/planning-center/api.js +2 -1
  90. package/dist/providers/planning-center/lib/constants.d.ts +1 -1
  91. package/dist/providers/planning-center/lib/json-api.js +1 -9
  92. package/dist/providers/planning-center/tools.js +2 -1
  93. package/dist/providers/sheets/tools.js +1 -9
  94. package/dist/providers/slides/tools.js +4 -13
  95. package/dist/providers/stripe/index.js +2 -1
  96. package/dist/providers/stripe/safety.js +2 -2
  97. package/dist/providers/tithely/api.js +2 -7
  98. package/dist/providers/tithely/index.js +3 -2
  99. package/dist/providers/tithely/tools.js +7 -5
  100. package/dist/providers/vercel/api.js +1 -6
  101. package/dist/providers/vercel/lib/pin.js +1 -1
  102. package/dist/providers/vercel/safety.js +1 -1
  103. package/dist/providers/vercel/tools.js +2 -1
  104. package/dist/redaction-marker.js +2 -2
  105. package/dist/registry.d.ts +1 -1
  106. package/dist/registry.js +5 -7
  107. package/dist/request-principal.js +1 -1
  108. package/dist/request-state.js +2 -2
  109. package/dist/routes/access-tokens.js +1 -1
  110. package/dist/routes/activity-disclosure.js +1 -1
  111. package/dist/routes/connect.js +2 -2
  112. package/dist/routes/credentials.js +1 -1
  113. package/dist/routes/mcp.js +4 -3
  114. package/dist/routes/oauth-management.js +1 -1
  115. package/dist/routes/operator.js +4 -3
  116. package/dist/routes/shared.d.ts +8 -8
  117. package/dist/routes/shared.js +9 -9
  118. package/dist/routes/ui-config.js +1 -1
  119. package/dist/routes/ui.js +1 -1
  120. package/dist/runtime/call-admission.js +1 -1
  121. package/dist/runtime/call.js +1 -1
  122. package/dist/runtime/settlement.js +1 -1
  123. package/dist/runtime/shared-read.js +2 -15
  124. package/dist/sent-secrets.d.ts +1 -2
  125. package/dist/sent-secrets.js +3 -8
  126. package/dist/server.js +4 -4
  127. package/dist/skills.js +8 -35
  128. package/dist/sqlite.d.ts +0 -19
  129. package/dist/sqlite.js +2 -83
  130. package/dist/storage/keys.js +16 -125
  131. package/dist/storage/sql-native.js +0 -101
  132. package/dist/storage/sql.d.ts +1 -24
  133. package/dist/storage/sql.js +1 -12
  134. package/dist/tool-error.js +4 -0
  135. package/dist/url-safety.js +0 -4
  136. package/dist/usage-guide.js +2 -2
  137. package/dist/version.d.ts +1 -1
  138. package/dist/version.js +1 -1
  139. package/dist/worker.js +1 -1
  140. package/documentation/README.md +6 -42
  141. package/documentation/architecture.md +86 -496
  142. package/documentation/auth.md +12 -25
  143. package/documentation/code-mode.md +90 -66
  144. package/documentation/deploying.md +19 -40
  145. package/documentation/integrating.md +4 -19
  146. package/documentation/meta-tools.md +6 -6
  147. package/documentation/migration-0.33.md +5 -5
  148. package/documentation/migration-0.34.md +2 -4
  149. package/documentation/migration-retired-layouts.md +74 -0
  150. package/documentation/operator-tests.md +19 -119
  151. package/documentation/operator-ui.md +3 -4
  152. package/documentation/provider-auth-migration.md +4 -10
  153. package/documentation/provider-migration-0.29.md +4 -15
  154. package/examples/worker/AGENTS.md +4 -6
  155. package/examples/worker/README.md +20 -115
  156. package/guides/connecting-agents.md +7 -30
  157. package/guides/how-it-works.md +2 -2
  158. package/guides/safety-and-trust.md +4 -1
  159. package/package.json +19 -19
  160. package/templates/node/README.md +9 -26
  161. package/templates/node/package.json +1 -1
  162. package/dist/auth/oauth-v2-migration.js +0 -135
  163. package/dist/provider-call-facts.d.ts +0 -115
  164. package/dist/provider-call.d.ts +0 -112
  165. package/dist/storage/d1-copy.js +0 -255
  166. package/dist/storage/sql-schema.d.ts +0 -6
  167. package/examples/worker/kv-to-d1.wrangler.jsonc +0 -26
  168. package/examples/worker/scripts/copy-kv-to-d1.mjs +0 -162
@@ -466,7 +466,7 @@ export class CatalogService {
466
466
  // timeout, whichever asker starts it. Each asker waits under its own signal
467
467
  // and deadline, so a short-deadline call that starts the read and a search
468
468
  // that joins it each end on their own terms, and the read is cancelled only
469
- // once every asker has gone (#571).
469
+ // once every asker has gone.
470
470
  catalog(id, callOptions) {
471
471
  return Effect.suspend(() => {
472
472
  // Authored static definitions never depend on a downstream cache or
@@ -20,6 +20,7 @@ export declare const CONFIG_DEFAULTS: {
20
20
  readonly hostCallTimeoutMs: 15000;
21
21
  readonly watchdogMs: 120000;
22
22
  readonly maxWrites: 10;
23
+ readonly maxResultChars: 24000;
23
24
  };
24
25
  readonly admission: {
25
26
  readonly requests: {
@@ -27,6 +27,7 @@ export const CONFIG_DEFAULTS = {
27
27
  hostCallTimeoutMs: 15_000,
28
28
  watchdogMs: 120_000,
29
29
  maxWrites: 10,
30
+ maxResultChars: 24_000,
30
31
  },
31
32
  admission: {
32
33
  requests: {
@@ -62,7 +62,7 @@ export declare class ConfigError extends TypeError {
62
62
  }
63
63
  interface WholeOptions {
64
64
  /** Smallest accepted value. */
65
- min: 0 | 1;
65
+ min: number;
66
66
  /** Largest accepted value, when there is one. */
67
67
  max?: number;
68
68
  /** Unit named in the `max` refusal, e.g. "milliseconds". */
@@ -27,12 +27,16 @@ function ownValue(value, key) {
27
27
  return Object.prototype.hasOwnProperty.call(value, key) ? value[key] : undefined;
28
28
  }
29
29
  export function whole(options) {
30
- const kind = options.min === 1 ? "positive" : "non-negative";
30
+ const kind = options.min === 0
31
+ ? "a non-negative whole number"
32
+ : options.min === 1
33
+ ? "a positive whole number"
34
+ : `a whole number of at least ${options.min.toLocaleString("en-US")}`;
31
35
  return {
32
36
  optional: true,
33
37
  parse: (value, path) => {
34
38
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < options.min) {
35
- fail(`${path} must be a ${kind} whole number.`);
39
+ fail(`${path} must be ${kind}.`);
36
40
  }
37
41
  if (options.max !== undefined && value > options.max) {
38
42
  fail(`${path} must be at most ${options.max.toLocaleString("en-US")}` + (options.unit ? ` ${options.unit}.` : "."));
package/dist/config.d.ts CHANGED
@@ -28,11 +28,12 @@ declare const discovery: {
28
28
  declare const calls: {
29
29
  /**
30
30
  * Deadline (ms) for `call_tool`/`call_destructive_tool` calls that pass no
31
- * `timeoutMs`. An explicit per-call value wins. Opt-in: unset by default, so
32
- * existing long-running calls gain no surprise deadline.
31
+ * `timeoutMs`. An explicit per-call value wins. Unset by default, when those
32
+ * calls fall back to `execute.hostCallTimeoutMs`.
33
33
  *
34
- * Each call makes one attempt. `execute_code` host calls are
35
- * unaffected because they already carry their own bound.
34
+ * Each call makes one attempt. `connecta.call` inside `execute_code` uses
35
+ * it too, ahead of `execute.hostCallTimeoutMs`; `connecta.result`,
36
+ * `connecta.skill` and `connecta.read` do not.
36
37
  */
37
38
  defaultTimeoutMs: import("./config-schema.js").Field<number, number | undefined, true>;
38
39
  /**
@@ -60,9 +61,12 @@ declare const execute: {
60
61
  /** Host calls one program may make. Default 20. */
61
62
  maxHostCalls: import("./config-schema.js").Field<number, number, true>;
62
63
  /**
63
- * Deadline for each host call a program makes, in milliseconds. Default
64
- * 15_000. Raise it for providers whose legitimate calls run longer, such as
65
- * analytics queries; `call_tool`'s own `timeoutMs` is unaffected.
64
+ * Deadline for a program's `connecta.result`, `connecta.skill` and
65
+ * `connecta.read`, in milliseconds. Default 15_000. Discovery uses
66
+ * `discovery.probeTimeoutMs`. `connecta.call` and the direct call tools use it only when
67
+ * `calls.defaultTimeoutMs` is unset, and an explicit per-call `timeoutMs`
68
+ * always wins. Raise it for providers whose legitimate calls run longer,
69
+ * such as analytics queries.
66
70
  */
67
71
  hostCallTimeoutMs: import("./config-schema.js").Field<number, number, true>;
68
72
  /**
@@ -78,6 +82,14 @@ declare const execute: {
78
82
  * budget every call already spends. Default 10.
79
83
  */
80
84
  maxWrites: import("./config-schema.js").Field<number, number, true>;
85
+ /**
86
+ * Serialized characters a program may return, shared with emitted text,
87
+ * before Connecta stashes the return and answers with a paging notice.
88
+ * Default 24_000 (~6k tokens). Raise it when agents need large results whole
89
+ * and the model's context can afford them: each paging round trip costs a
90
+ * model step. From 4_000 to 1_000_000.
91
+ */
92
+ maxResultChars: import("./config-schema.js").Field<number, number, true>;
81
93
  };
82
94
  declare const codeAdmission: {
83
95
  /** Simultaneous work admitted to this pool. */
@@ -333,11 +345,12 @@ declare const connectaConfig: {
333
345
  readonly shape: {
334
346
  /**
335
347
  * Deadline (ms) for `call_tool`/`call_destructive_tool` calls that pass no
336
- * `timeoutMs`. An explicit per-call value wins. Opt-in: unset by default, so
337
- * existing long-running calls gain no surprise deadline.
348
+ * `timeoutMs`. An explicit per-call value wins. Unset by default, when those
349
+ * calls fall back to `execute.hostCallTimeoutMs`.
338
350
  *
339
- * Each call makes one attempt. `execute_code` host calls are
340
- * unaffected because they already carry their own bound.
351
+ * Each call makes one attempt. `connecta.call` inside `execute_code` uses
352
+ * it too, ahead of `execute.hostCallTimeoutMs`; `connecta.result`,
353
+ * `connecta.skill` and `connecta.read` do not.
341
354
  */
342
355
  defaultTimeoutMs: import("./config-schema.js").Field<number, number | undefined, true>;
343
356
  /**
@@ -371,6 +384,7 @@ declare const connectaConfig: {
371
384
  hostCallTimeoutMs?: number | undefined;
372
385
  watchdogMs?: number | undefined;
373
386
  maxWrites?: number | undefined;
387
+ maxResultChars?: number | undefined;
374
388
  }, {
375
389
  readonly maxEmittedBytes: number;
376
390
  readonly maxEmittedBlocks: number;
@@ -378,6 +392,7 @@ declare const connectaConfig: {
378
392
  readonly hostCallTimeoutMs: number;
379
393
  readonly watchdogMs: number;
380
394
  readonly maxWrites: number;
395
+ readonly maxResultChars: number;
381
396
  }, true> & {
382
397
  readonly shape: {
383
398
  /**
@@ -391,9 +406,12 @@ declare const connectaConfig: {
391
406
  /** Host calls one program may make. Default 20. */
392
407
  maxHostCalls: import("./config-schema.js").Field<number, number, true>;
393
408
  /**
394
- * Deadline for each host call a program makes, in milliseconds. Default
395
- * 15_000. Raise it for providers whose legitimate calls run longer, such as
396
- * analytics queries; `call_tool`'s own `timeoutMs` is unaffected.
409
+ * Deadline for a program's `connecta.result`, `connecta.skill` and
410
+ * `connecta.read`, in milliseconds. Default 15_000. Discovery uses
411
+ * `discovery.probeTimeoutMs`. `connecta.call` and the direct call tools use it only when
412
+ * `calls.defaultTimeoutMs` is unset, and an explicit per-call `timeoutMs`
413
+ * always wins. Raise it for providers whose legitimate calls run longer,
414
+ * such as analytics queries.
397
415
  */
398
416
  hostCallTimeoutMs: import("./config-schema.js").Field<number, number, true>;
399
417
  /**
@@ -409,6 +427,14 @@ declare const connectaConfig: {
409
427
  * budget every call already spends. Default 10.
410
428
  */
411
429
  maxWrites: import("./config-schema.js").Field<number, number, true>;
430
+ /**
431
+ * Serialized characters a program may return, shared with emitted text,
432
+ * before Connecta stashes the return and answers with a paging notice.
433
+ * Default 24_000 (~6k tokens). Raise it when agents need large results whole
434
+ * and the model's context can afford them: each paging round trip costs a
435
+ * model step. From 4_000 to 1_000_000.
436
+ */
437
+ maxResultChars: import("./config-schema.js").Field<number, number, true>;
412
438
  };
413
439
  };
414
440
  /**
@@ -654,5 +680,6 @@ export declare function executeLimits(config: ResolvedConfig): {
654
680
  hostCallTimeoutMs: number;
655
681
  watchdogMs: number;
656
682
  maxWrites: number;
683
+ maxResultChars: number;
657
684
  };
658
685
  export {};
package/dist/config.js CHANGED
@@ -79,11 +79,12 @@ const discovery = {
79
79
  const calls = {
80
80
  /**
81
81
  * Deadline (ms) for `call_tool`/`call_destructive_tool` calls that pass no
82
- * `timeoutMs`. An explicit per-call value wins. Opt-in: unset by default, so
83
- * existing long-running calls gain no surprise deadline.
82
+ * `timeoutMs`. An explicit per-call value wins. Unset by default, when those
83
+ * calls fall back to `execute.hostCallTimeoutMs`.
84
84
  *
85
- * Each call makes one attempt. `execute_code` host calls are
86
- * unaffected because they already carry their own bound.
85
+ * Each call makes one attempt. `connecta.call` inside `execute_code` uses
86
+ * it too, ahead of `execute.hostCallTimeoutMs`; `connecta.result`,
87
+ * `connecta.skill` and `connecta.read` do not.
87
88
  */
88
89
  defaultTimeoutMs: whole({ min: 1 }),
89
90
  /**
@@ -111,9 +112,12 @@ const execute = {
111
112
  /** Host calls one program may make. Default 20. */
112
113
  maxHostCalls: whole({ min: 1, default: D.execute.maxHostCalls }),
113
114
  /**
114
- * Deadline for each host call a program makes, in milliseconds. Default
115
- * 15_000. Raise it for providers whose legitimate calls run longer, such as
116
- * analytics queries; `call_tool`'s own `timeoutMs` is unaffected.
115
+ * Deadline for a program's `connecta.result`, `connecta.skill` and
116
+ * `connecta.read`, in milliseconds. Default 15_000. Discovery uses
117
+ * `discovery.probeTimeoutMs`. `connecta.call` and the direct call tools use it only when
118
+ * `calls.defaultTimeoutMs` is unset, and an explicit per-call `timeoutMs`
119
+ * always wins. Raise it for providers whose legitimate calls run longer,
120
+ * such as analytics queries.
117
121
  */
118
122
  hostCallTimeoutMs: whole({ min: 1, default: D.execute.hostCallTimeoutMs }),
119
123
  /**
@@ -129,6 +133,14 @@ const execute = {
129
133
  * budget every call already spends. Default 10.
130
134
  */
131
135
  maxWrites: whole({ min: 1, default: D.execute.maxWrites }),
136
+ /**
137
+ * Serialized characters a program may return, shared with emitted text,
138
+ * before Connecta stashes the return and answers with a paging notice.
139
+ * Default 24_000 (~6k tokens). Raise it when agents need large results whole
140
+ * and the model's context can afford them: each paging round trip costs a
141
+ * model step. From 4_000 to 1_000_000.
142
+ */
143
+ maxResultChars: whole({ min: 4_000, max: 1_000_000, default: D.execute.maxResultChars }),
132
144
  };
133
145
  function admissionPool(defaults) {
134
146
  return {
@@ -492,48 +504,6 @@ const connectaConfig = {
492
504
  readOnly: required(opaque({ check: assertFlag }), (path) => READ_ONLY_REQUIRED(path)),
493
505
  };
494
506
  const CONFIG = object(connectaConfig);
495
- /** Pause-only options #672 removed with `resume_execution`. */
496
- const RETIRED_PAUSE_OPTIONS = ["ConnectaConfig.execute.resumableWrites", "ConnectaConfig.execute.pausedRunTtlSeconds"];
497
- /** Access options pools replaced (#837, decisions/0006). */
498
- const isRetiredPoolGrant = (path) => /^ConnectaConfig\.pools\.[^.]+\.grant$/.test(path);
499
- /** Management resolvers maintainers and pool membership replaced (#837, decisions/0006). */
500
- const RETIRED_IDENTITY = [
501
- ["credentialAdministration", "maintainers administer shared credentials and OAuth grants. List them in maintainers."],
502
- [
503
- "personalConnection",
504
- "pool members connect and disconnect their own personal connectors in their pools, and maintainers their own. Add people to a pool's members.",
505
- ],
506
- [
507
- "accessTokenManagement",
508
- "maintainers issue, rotate, and revoke agent tokens from an interactive session. List them in maintainers.",
509
- ],
510
- ["activityAccess", "maintainers read activity; activity.readGate can still narrow it. List them in maintainers."],
511
- ];
512
- /** `trust`, on the deployment or a pool, was replaced by `readOnly` (#820). */
513
- const isRetiredTrust = (path) => path === "ConnectaConfig.trust" || (path.startsWith("ConnectaConfig.pools.") && path.endsWith(".trust"));
514
- /**
515
- * `identity` was removed whole (#837), so the walk reports only the section.
516
- * Name each key it still holds, read by descriptor without running a getter
517
- * or echoing a value, so a retired resolver's message names its replacement.
518
- */
519
- function expandRetiredIdentity(config, paths) {
520
- if (!paths.includes("ConnectaConfig.identity"))
521
- return paths;
522
- let keys = [];
523
- try {
524
- const descriptor = Reflect.getOwnPropertyDescriptor(config, "identity");
525
- const value = descriptor && "value" in descriptor ? descriptor.value : undefined;
526
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
527
- keys = Reflect.ownKeys(value).filter((key) => typeof key === "string");
528
- }
529
- }
530
- catch {
531
- keys = [];
532
- }
533
- if (keys.length === 0)
534
- return paths;
535
- return paths.flatMap((path) => path === "ConnectaConfig.identity" ? keys.map((key) => `ConnectaConfig.identity.${key}`) : [path]);
536
- }
537
507
  function rejectUnknownOptions(paths) {
538
508
  if (paths.length === 0)
539
509
  return;
@@ -547,27 +517,6 @@ function rejectUnknownOptions(paths) {
547
517
  : "") +
548
518
  (paths.includes("ConnectaConfig.execute.approval")
549
519
  ? "\nexecute.approval was removed. The MCP client owns approval; set readOnly: true on the deployment or a pool to refuse writes."
550
- : "") +
551
- (paths.some((path) => RETIRED_PAUSE_OPTIONS.includes(path))
552
- ? "\nPrograms no longer pause at writes, so there is nothing to configure: writable endpoints let programs and call_destructive_tool write; readOnly endpoints refuse every write (issue #672). Delete the option."
553
- : "") +
554
- (paths.includes("ConnectaConfig.identity.connectorAccess")
555
- ? "\nidentity.connectorAccess was removed (#837): pools are the access model. List who may use plain /mcp in maintainers, and give each pool its tools and members. A guarded { tool, requireReadOnly: true } grant becomes a pool with readOnly: true."
556
- : "") +
557
- RETIRED_IDENTITY.filter(([key]) => paths.includes(`ConnectaConfig.identity.${key}`))
558
- .map(([key, replacement]) => `\nidentity.${key} was removed (#837): ${replacement}`)
559
- .join("") +
560
- (paths.some((path) => path === "ConnectaConfig.identity" || path.startsWith("ConnectaConfig.identity."))
561
- ? "\nThe identity section was removed (#837): maintainers and pool members decide access and management. Delete it."
562
- : "") +
563
- (paths.includes("ConnectaConfig.grant")
564
- ? "\nThe top-level grant was removed (#837); list the people who may use plain /mcp in maintainers."
565
- : "") +
566
- (paths.some(isRetiredPoolGrant)
567
- ? "\nPool grant was removed (#837); list who may open the pool in its members."
568
- : "") +
569
- (paths.some(isRetiredTrust)
570
- ? '\ntrust was removed (#820); set readOnly, which every deployment now chooses explicitly. trust: "read-only" becomes readOnly: true, which now also refuses call_destructive_tool. trust: "trusted" becomes readOnly: false. A pool inherits the deployment readOnly unless it sets its own.'
571
520
  : ""));
572
521
  }
573
522
  /** Checks that span fields; each value is already individually valid. */
@@ -598,7 +547,7 @@ export function resolveConfig(config) {
598
547
  */
599
548
  export function readConfig(config) {
600
549
  const read = readPlain(config, "ConnectaConfig", CONFIG);
601
- rejectUnknownOptions(expandRetiredIdentity(config, read.unknown));
550
+ rejectUnknownOptions(read.unknown);
602
551
  const input = read.value;
603
552
  const parsed = CONFIG.parse(input, "ConnectaConfig");
604
553
  assertCoherent(parsed);
@@ -648,5 +597,6 @@ export function executeLimits(config) {
648
597
  hostCallTimeoutMs: config.execute.hostCallTimeoutMs,
649
598
  watchdogMs: config.execute.watchdogMs,
650
599
  maxWrites: config.execute.maxWrites,
600
+ maxResultChars: config.execute.maxResultChars,
651
601
  };
652
602
  }
@@ -1,3 +1,4 @@
1
+ import { wrapViewCredentials } from "../runtime/call.js";
1
2
  import { storedAuthObservation, withStoredAuth } from "../auth/stored-observation.js";
2
3
  import { Effect, Exit } from "effect";
3
4
  import { registerConnectorVocabulary } from "../operation-vocabulary.js";
@@ -13,7 +14,7 @@ import { describedEndpoint, describedOrigin, describedTools } from "../described
13
14
  import { READ_ONLY, CALL_ADMISSION, CREDENTIAL, USAGE_GUIDE } from "./option-shapes.js";
14
15
  import { assertStaticToolNames } from "../tool-name.js";
15
16
  import { registerInvocationAuth } from "../invocation-auth.js";
16
- import { redactCatalog, redactSentSecrets, sentSecretsFetch, trackCredentialReads } from "../sent-secrets.js";
17
+ import { redactCatalog, redactSentSecrets, sentSecretsFetch } from "../sent-secrets.js";
17
18
  import { callClassification } from "../call-classification.js";
18
19
  import { classifyTool } from "../tool-safety.js";
19
20
  import { closeProviderCall, enterProviderBoundary, inLogicalCall, knownProviderFailure, nestedProviderRequests, providerBoundary, providerCallContext, providerFetch, providerRequests, tracksRequests, } from "../provider-call.js";
@@ -24,7 +25,7 @@ export function defined(value) {
24
25
  }
25
26
  /**
26
27
  * Three things a hand-written surface is refused for at construction rather
27
- * than in production (#340): no description (discovery has nothing to route on
28
+ * than in production: no description (discovery has nothing to route on
28
29
  * and a guess costs a call), no explicit `readOnlyHint` (connecta never infers
29
30
  * the safety class, so an unclassified tool is a deployment bug), and an
30
31
  * `inputSchema` the validator cannot compile (declaring one is optional;
@@ -173,7 +174,7 @@ export function apiConnector(id, opts, oauth) {
173
174
  callTool: (name, args, ctx, options) => runEdge(core(name, args, ctx, options)),
174
175
  };
175
176
  const core = (name, args, ctx) => Effect.gen(function* () {
176
- trackCredentialReads(ctx);
177
+ wrapViewCredentials(ctx);
177
178
  enterProviderBoundary(ctx, connector);
178
179
  const tool = byName.get(name);
179
180
  // Refusals before the handler runs are known failures: nothing was sent.
@@ -1,5 +1,4 @@
1
1
  export { retryAfterMs } from "../http-policy.js";
2
- import { type ProviderRequest } from "../provider-call.js";
3
2
  import type { ConnectorContext } from "../types.js";
4
3
  /** The methods a hand-written provider surface actually uses. */
5
4
  type GuardedMethod = "GET" | "HEAD" | "POST" | "PUT" | "PATCH" | "DELETE";
@@ -182,11 +181,6 @@ type GuardedFetcher = (url: string, init: RequestInit, ctx: ConnectorContext) =>
182
181
  export declare function oauthBearer(provider: string): Pick<GuardedFetchOptions, "authenticate" | "fetch">;
183
182
  /** Send one guarded request and map its response with provider knowledge. */
184
183
  export type GuardedTransport = <T>(request: GuardedRequest, ctx: ConnectorContext, map: GuardedResponseMapper<T>) => Promise<T>;
185
- /**
186
- * Test-only legacy response lookup for renewal-provenance fixtures outside
187
- * the kit. Production renewal uses the kit ledger. Undefined for other objects.
188
- */
189
- export declare function answeredRequest(response: object): ProviderRequest | undefined;
190
184
  /**
191
185
  * Build the transport a connector sends every request through. `maxResponseBytes`
192
186
  * is required rather than defaulted: what counts as an absurd response is a fact
@@ -3,7 +3,7 @@ export { retryAfterMs } from "../http-policy.js";
3
3
  import { callerSignal, duringViewCall, settleOnClose, viewSignal } from "../runtime/call.js";
4
4
  /**
5
5
  * The safety machinery every hand-written HTTP surface needs, extracted once
6
- * (#341): path confinement, encoded query and framed bodies, per-request
6
+ *: path confinement, encoded query and framed bodies, per-request
7
7
  * credential headers applied last, a refused redirect, a bounded read, and
8
8
  * network-failure normalization. It owns no vendor-specific meaning and never
9
9
  * invents an auth scheme, because the same 403 means an ungranted
@@ -280,15 +280,6 @@ async function jsonResult(read) {
280
280
  return { parseError: cause };
281
281
  }
282
282
  }
283
- // Each response a mapper reads, and the ledger entry of the request it answered.
284
- const answeredRequests = new WeakMap();
285
- /**
286
- * Test-only legacy response lookup for renewal-provenance fixtures outside
287
- * the kit. Production renewal uses the kit ledger. Undefined for other objects.
288
- */
289
- export function answeredRequest(response) {
290
- return answeredRequests.get(response);
291
- }
292
283
  /**
293
284
  * Build the transport a connector sends every request through. `maxResponseBytes`
294
285
  * is required rather than defaulted: what counts as an absurd response is a fact
@@ -463,7 +454,6 @@ export function guardedFetch(options) {
463
454
  throw oversized(provider, limit, `a declared ${declared} bytes`);
464
455
  }
465
456
  const answer = boundedResponse(provider, response, limit, signal);
466
- answeredRequests.set(answer, dispatch);
467
457
  const abort = () => {
468
458
  void response?.body?.cancel().catch(() => { });
469
459
  };
@@ -1,3 +1,5 @@
1
+ import { wrapViewCredentials } from "../runtime/call.js";
2
+ import { sha256Hex, utf8Length } from "../bytes.js";
1
3
  import { withStoredAuth } from "../auth/stored-observation.js";
2
4
  import { authorizationParamsFor } from "../auth/oauth-authorization-params.js";
3
5
  import { authView } from "../auth/native-call.js";
@@ -11,7 +13,7 @@ import { Deferred, Duration, Effect, Exit, Scope } from "effect";
11
13
  import { assertOAuthScope, authorizingContext, codeExchangeResponse, KvOAuthProvider, OAuthRequestNotSentError, refreshCoordinatorsByPartition, } from "../auth/downstream-oauth.js";
12
14
  import { trackOAuthStartReset } from "../auth/oauth-start-reset.js";
13
15
  import { byteReadResponse } from "../byte-read-response.js";
14
- import { redactCatalog, redactSentSecrets, requestSentSecrets, sentSecretsFor, shortSecretWarning, trackCredentialReads, } from "../sent-secrets.js";
16
+ import { redactCatalog, redactSentSecrets, requestSentSecrets, sentSecretsFor, shortSecretWarning, } from "../sent-secrets.js";
15
17
  import { MAX_CATALOG_TOOLS, MAX_SERIALIZED_CATALOG_BYTES } from "../catalog-limits.js";
16
18
  import { catalogClientOptions, catalogItems, observeCompletedCatalogRefresh, closeCatalogCacheScope, observeCatalogChange, observeCatalogFetch, observeCatalogExpiry, } from "../catalog-cache.js";
17
19
  import { connectorScopeCleanupClaimed } from "../connector-scope.js";
@@ -115,32 +117,11 @@ const MAX_SKILL_BYTES = 16 * 1024 * 1024;
115
117
  // Leave room for the envelope while accepting every file up to the spec limit.
116
118
  const MAX_SKILL_READ_RPC_BYTES = 6 * MAX_SKILL_BYTES + 1024 * 1024;
117
119
  /** Count UTF-8 without allocating another full copy of a bounded response. */
118
- function skillTextBytes(value) {
119
- let bytes = 0;
120
- for (let i = 0; i < value.length; i++) {
121
- const code = value.charCodeAt(i);
122
- if (code < 0x80)
123
- bytes++;
124
- else if (code < 0x800)
125
- bytes += 2;
126
- else if (code >= 0xd800 &&
127
- code <= 0xdbff &&
128
- i + 1 < value.length &&
129
- value.charCodeAt(i + 1) >= 0xdc00 &&
130
- value.charCodeAt(i + 1) <= 0xdfff) {
131
- bytes += 4;
132
- i++;
133
- }
134
- else
135
- bytes += 3;
136
- }
137
- return bytes;
138
- }
139
120
  function skillObject(value) {
140
121
  return typeof value === "object" && value !== null && !Array.isArray(value);
141
122
  }
142
123
  function skillJsonBytes(value) {
143
- return skillTextBytes(JSON.stringify(value));
124
+ return utf8Length(JSON.stringify(value));
144
125
  }
145
126
  function validSkill(value) {
146
127
  if (!skillObject(value) ||
@@ -229,9 +210,7 @@ function skillReadSchema(uri) {
229
210
  return { issues: [{ message: "Unexpected skill resource contents." }] };
230
211
  }
231
212
  const mimeType = typeof content.mimeType === "string" ? { mimeType: content.mimeType } : {};
232
- if (typeof content.text === "string" &&
233
- !("blob" in content) &&
234
- skillTextBytes(content.text) <= MAX_SKILL_BYTES) {
213
+ if (typeof content.text === "string" && !("blob" in content) && utf8Length(content.text) <= MAX_SKILL_BYTES) {
235
214
  return { value: [{ uri, ...mimeType, text: content.text }] };
236
215
  }
237
216
  if (typeof content.blob === "string" &&
@@ -668,18 +647,6 @@ function base64Utf8(value) {
668
647
  }
669
648
  return btoa(binary);
670
649
  }
671
- /**
672
- * Hex SHA-256 of a credential, used only to notice that a cached client
673
- * connected with a value the vault no longer holds. WebCrypto rather than a
674
- * `node:` hash: the whole core has to keep running unchanged on Workers.
675
- */
676
- async function digestOf(value) {
677
- const bytes = new Uint8Array(await crypto.subtle.digest("SHA-256", encoder.encode(value)));
678
- let hex = "";
679
- for (const byte of bytes)
680
- hex += byte.toString(16).padStart(2, "0");
681
- return hex;
682
- }
683
650
  /**
684
651
  * Assemble the one header a credential-auth connector sends.
685
652
  *
@@ -1141,7 +1108,7 @@ export function remoteMcp(id, opts) {
1141
1108
  // handshake/discovery requests and OAuth rotations. Remove settled users.
1142
1109
  const activeContexts = new WeakMap();
1143
1110
  // Resource headers are non-secret context by contract. They never join the
1144
- // sent set, so arguments and results equal to them pass unchanged (#1108).
1111
+ // sent set, so arguments and results equal to them pass unchanged.
1145
1112
  // An argument mirrored as `Mcp-Param-*` carrying a resource value is the
1146
1113
  // same context under a name the tracker may read as credential-shaped.
1147
1114
  const resourceValues = new Set(Object.values(extraHeaders ?? {}));
@@ -2177,7 +2144,7 @@ export function remoteMcp(id, opts) {
2177
2144
  credentialFramed = credentialHeaderValue(credentialScheme, credentialValue);
2178
2145
  // The principal joins the client's identity: another principal never
2179
2146
  // reuses this client, even if its resolver returns the same token.
2180
- credentialDigest = (yield authCall(digestOf, [
2147
+ credentialDigest = (yield authCall(sha256Hex, [
2181
2148
  principal ? JSON.stringify([principal, credentialValue]) : credentialValue,
2182
2149
  ]));
2183
2150
  if ((state.client || state.connecting) &&
@@ -2302,7 +2269,7 @@ export function remoteMcp(id, opts) {
2302
2269
  clientName: ctx.oauthClientName,
2303
2270
  }
2304
2271
  : undefined;
2305
- const negotiationDigest = yield* promised(authMethod(() => authCall(digestOf, [
2272
+ const negotiationDigest = yield* promised(authMethod(() => authCall(sha256Hex, [
2306
2273
  JSON.stringify([
2307
2274
  opts.url,
2308
2275
  opts.versionNegotiation ?? "auto",
@@ -2349,7 +2316,7 @@ export function remoteMcp(id, opts) {
2349
2316
  provider
2350
2317
  ? authMethod(() => authFlow(function* () {
2351
2318
  const tokens = yield authInvoke(provider, "tokens", []);
2352
- return yield authCall(digestOf, [JSON.stringify(tokens)]);
2319
+ return yield authCall(sha256Hex, [JSON.stringify(tokens)]);
2353
2320
  }))
2354
2321
  : undefined,
2355
2322
  ])));
@@ -3186,7 +3153,7 @@ export function remoteMcp(id, opts) {
3186
3153
  }
3187
3154
  }));
3188
3155
  const withActiveSecrets = authMethod((ctx, run, redactResult = true, preserveInput = false) => authFlow(function* () {
3189
- trackCredentialReads(ctx);
3156
+ wrapViewCredentials(ctx);
3190
3157
  const secrets = sentSecretsFor(ctx);
3191
3158
  if (opts.auth?.type === "headers") {
3192
3159
  for (const value of Object.values(opts.auth.headers))
@@ -26,10 +26,6 @@ export function resourceUriMatchesTemplates(uri, templates, note = () => { }) {
26
26
  }
27
27
  return matched ? { matched } : { matched, ...(refusal ? { refusal } : {}) };
28
28
  }
29
- export function resourceUriMatchesTemplate(uri, template) {
30
- const parsed = parse(template);
31
- return typeof parsed === "object" && matches(uri, parsed);
32
- }
33
29
  function parse(template) {
34
30
  if (template.length > MAX_URI_LENGTH)
35
31
  return;
package/dist/d1.d.ts CHANGED
@@ -38,93 +38,4 @@ export declare function d1Storage(db: D1DatabaseBinding): KVStorage;
38
38
  * write prunes a bounded batch of rows older than `retentionDays`.
39
39
  */
40
40
  export declare function d1ActivityStore(db: D1DatabaseBinding, options?: D1ActivityOptions): ActivityStore;
41
- /**
42
- * The part of a Workers KV binding `copyKvToD1` reads. Structural, like
43
- * `D1DatabaseBinding`; a Worker's `KVNamespace` satisfies it.
44
- */
45
- export interface KVNamespaceBinding {
46
- list(options?: {
47
- limit?: number;
48
- cursor?: string | null;
49
- }): Promise<{
50
- keys: readonly {
51
- name: string;
52
- expiration?: number;
53
- }[];
54
- list_complete: boolean;
55
- cursor?: string;
56
- }>;
57
- get(key: string, type: "text"): Promise<string | null>;
58
- }
59
- export interface KvToD1CopyOptions {
60
- /** The source KV namespace id. Resume tokens are bound to this identity. */
61
- source: string;
62
- /** Resume against the same source and database within seven days. */
63
- cursor?: string;
64
- /** Explicit families whose conflicting D1 rows the operator judged stale. */
65
- overwriteFamilies?: readonly string[];
66
- /** Compare value hashes and absolute expiries without copying entries. */
67
- verify?: boolean;
68
- /** Override the cutover guard only after assessing stale KV state. */
69
- allowStale?: boolean;
70
- /** Keys read per call. Default 500; use a smaller budget for large rows. */
71
- maxKeys?: number;
72
- }
73
- /** What a copy did with one family's keys. */
74
- export interface KvToD1Counts {
75
- /** Written where D1 held no live entry. */
76
- copied: number;
77
- /** D1 already held the same value. */
78
- unchanged: number;
79
- /** D1 held a different value or expiry and kept it. */
80
- conflicts: number;
81
- /** D1 held a different value or expiry, replaced under `overwriteFamilies`. */
82
- overwritten: number;
83
- /** Expired or deleted in Workers KV before it could be read. */
84
- expired: number;
85
- /** A key/value/row D1 cannot hold, left in Workers KV. */
86
- invalid: number;
87
- /** Exact value hash and expiry match during a verification pass. */
88
- verified: number;
89
- /** Missing or different value/expiry during a verification pass. */
90
- mismatches: number;
91
- }
92
- export interface KvToD1CopyResult {
93
- /** True once the whole namespace has been read. */
94
- done: boolean;
95
- /**
96
- * Pass back as `options.cursor` to continue; absent when `done`. A random
97
- * token: the Workers KV cursor it stands for stays in D1, because that
98
- * cursor can spell the last key listed.
99
- */
100
- cursor?: string;
101
- /**
102
- * Counts by key family (`src/storage/keys.ts`), plus `connector-owned` and
103
- * `unclassified`. Never a key or a value.
104
- */
105
- families: Record<string, KvToD1Counts>;
106
- }
107
- /**
108
- * A copy that stopped. The message is fixed wording that names a family at
109
- * most, never a key or value, and the binding's own error is not attached:
110
- * KV and D1 errors can quote either. Entries before `cursor` are copied;
111
- * rerunning from it is safe while the maintenance window still holds.
112
- */
113
- export declare class KvToD1CopyError extends Error {
114
- /** Resume point; absent means start over, which is also safe. */
115
- readonly cursor: string | undefined;
116
- readonly name = "KvToD1CopyError";
117
- constructor(message: string,
118
- /** Resume point; absent means start over, which is also safe. */
119
- cursor: string | undefined);
120
- }
121
- /** Mark cutover before reopening traffic. The marker stays in D1 permanently. */
122
- export declare function markKvToD1Live(db: D1DatabaseBinding, source: string): Promise<void>;
123
- /**
124
- * Copy live KV entries verbatim while all writers and traffic are stopped.
125
- * A live D1 row is kept unless its family is explicitly allowed to overwrite.
126
- * `verify` reads hashes and absolute expiries without changing copied entries.
127
- * Results contain counts only. Resume tokens are source-bound atomic claims.
128
- */
129
- export declare function copyKvToD1(kv: KVNamespaceBinding, db: D1DatabaseBinding, options: KvToD1CopyOptions): Promise<KvToD1CopyResult>;
130
41
  export {};