@zackbart/connecta 0.18.3 → 0.19.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 (69) hide show
  1. package/CHANGELOG.md +73 -4
  2. package/dist/catalog-service.d.ts +16 -13
  3. package/dist/catalog-service.js +106 -115
  4. package/dist/catalog.js +29 -46
  5. package/dist/connector-scope.js +2 -7
  6. package/dist/connectors/api.d.ts +4 -16
  7. package/dist/connectors/api.js +19 -46
  8. package/dist/connectors/guarded-fetch.d.ts +9 -23
  9. package/dist/connectors/guarded-fetch.js +38 -76
  10. package/dist/connectors/remote-mcp.js +36 -79
  11. package/dist/errors.d.ts +6 -27
  12. package/dist/errors.js +8 -5
  13. package/dist/execute.d.ts +24 -22
  14. package/dist/execute.js +98 -145
  15. package/dist/executor-result.d.ts +1 -0
  16. package/dist/executor-result.js +4 -11
  17. package/dist/executors/quickjs-child.js +1 -3
  18. package/dist/executors/quickjs-runtime.js +1 -3
  19. package/dist/executors/quickjs.js +1 -3
  20. package/dist/index.js +27 -57
  21. package/dist/invocation.js +113 -183
  22. package/dist/meta-tools.d.ts +15 -28
  23. package/dist/meta-tools.js +33 -89
  24. package/dist/providers/cloudflare.d.ts +2 -18
  25. package/dist/providers/cloudflare.js +1460 -2451
  26. package/dist/providers/linear.d.ts +4 -41
  27. package/dist/providers/linear.js +8 -39
  28. package/dist/providers/mixpanel.d.ts +3 -25
  29. package/dist/providers/mixpanel.js +7 -22
  30. package/dist/providers/notion.d.ts +1 -15
  31. package/dist/providers/notion.js +44 -173
  32. package/dist/providers/revenuecat.d.ts +4 -57
  33. package/dist/providers/revenuecat.js +10 -93
  34. package/dist/providers/stripe.d.ts +1 -12
  35. package/dist/providers/stripe.js +7 -45
  36. package/dist/registry.d.ts +9 -34
  37. package/dist/registry.js +9 -103
  38. package/dist/routes/mcp.js +1 -1
  39. package/dist/routes/oauth.js +3 -3
  40. package/dist/routes/shared.d.ts +15 -15
  41. package/dist/routes/shared.js +1 -3
  42. package/dist/timeout.d.ts +8 -7
  43. package/dist/timeout.js +47 -38
  44. package/dist/types.d.ts +3 -3
  45. package/dist/ui.d.ts +1 -25
  46. package/dist/ui.js +18 -45
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/documentation/call-admission.md +1 -1
  50. package/documentation/cloudflare.md +1 -1
  51. package/documentation/code-mode.md +7 -7
  52. package/documentation/connectors.md +24 -1
  53. package/documentation/linear.md +1 -1
  54. package/documentation/mixpanel.md +1 -1
  55. package/documentation/notion.md +1 -1
  56. package/documentation/operations.md +18 -14
  57. package/documentation/provider-conventions.md +1 -1
  58. package/documentation/revenuecat.md +1 -1
  59. package/documentation/stripe.md +1 -1
  60. package/documentation/upgrading.md +13 -4
  61. package/ethos.md +75 -121
  62. package/package.json +3 -4
  63. package/templates/node/package.json +1 -1
  64. package/documentation/code-first-exploration.md +0 -292
  65. package/documentation/mcp-2026-07-28.md +0 -46
  66. package/documentation/mcp-ui-design.md +0 -382
  67. package/documentation/program-ui-read-calls.md +0 -213
  68. package/documentation/provider-audit.md +0 -198
  69. package/documentation/rich-output-design.md +0 -211
@@ -1,7 +1,7 @@
1
1
  import { Client, isInputRequiredResult, specTypeSchemas, StreamableHTTPClientTransport, UnauthorizedError, } from "@modelcontextprotocol/client";
2
2
  import { KvOAuthProvider } from "../auth/downstream-oauth.js";
3
3
  import { MAX_CATALOG_TOOLS } from "../catalog-limits.js";
4
- import { ConnectorCallError } from "../errors.js";
4
+ import { ConnectorCallError, msg } from "../errors.js";
5
5
  import { CONNECTA_VERSION } from "../version.js";
6
6
  /**
7
7
  * Apply a maintained provider's slot copy and header framing to credential
@@ -33,28 +33,6 @@ export function withCredentialDefaults(auth, defaults) {
33
33
  * response, while callers continue to wait at most 100 ms.
34
34
  */
35
35
  const TERMINATE_SESSION_BUDGET_MS = 1_000;
36
- /**
37
- * Ceiling on the tools one catalog refresh will accumulate while walking
38
- * `tools/list`.
39
- *
40
- * This is the bound that matters, and pages are the wrong dimension to put it
41
- * in: the *server* picks the page size, so a page ceiling is a tool ceiling
42
- * multiplied by a number connecta can neither observe in advance nor control.
43
- * At ten tools a page, 100 pages is 1,000 tools; at a hundred, 10,000 — and
44
- * connecta's own large-catalog envelope is benchmarked to 100,000 (issue #82).
45
- * A page ceiling low enough to be a real defense therefore sits *inside* the
46
- * catalog sizes this product exists to serve. Worse, the common conformant
47
- * idiom is to advertise a `nextCursor` whenever a page came back full and then
48
- * serve one empty page to terminate, so a perfectly well-behaved 10,000-tool
49
- * server paging at 100 spends 101 requests: bound the pages and its entire
50
- * catalog fails, for doing nothing wrong.
51
- *
52
- * So the ceiling goes on accumulated tools — the thing actually held in memory
53
- * — and it sits at the top of the benchmarked envelope rather than below it.
54
- * Deliberately the same philosophy as issue #82's discovery-response bounds:
55
- * cap the bytes a caller can be made to hold, not the number of round trips it
56
- * took to get them.
57
- */
58
36
  /**
59
37
  * Absolute backstop on `tools/list` pages in one refresh — a runaway guard, not
60
38
  * the primary defense.
@@ -111,9 +89,6 @@ function isCursorShapeError(err) {
111
89
  // failing path in the message rather than exposing the validator's issues.
112
90
  return msg(err).startsWith("Invalid result for tools/list: nextCursor:");
113
91
  }
114
- function msg(err) {
115
- return err instanceof Error ? err.message : String(err);
116
- }
117
92
  /**
118
93
  * End the downstream's session before the connection is torn down.
119
94
  *
@@ -130,6 +105,8 @@ function msg(err) {
130
105
  * close with the session left to age out as it did before.
131
106
  */
132
107
  async function terminateSession(transport, logger, connectorId) {
108
+ // See documentation/connectors.md#mcp-version-skew for the legacy DELETE
109
+ // that Client.close() does not send.
133
110
  const terminate = transport.terminateSession;
134
111
  if (typeof terminate !== "function")
135
112
  return;
@@ -517,11 +494,14 @@ export function remoteMcp(id, opts) {
517
494
  }
518
495
  return state;
519
496
  };
520
- const getProvider = (ctx, state) => {
521
- state.provider ??= new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
522
- return state.provider;
497
+ const newProvider = (ctx, state) => {
498
+ if (state?.provider)
499
+ return state.provider;
500
+ const provider = new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
501
+ if (state)
502
+ state.provider = provider;
503
+ return provider;
523
504
  };
524
- const newProvider = (ctx) => new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
525
505
  const buildTransport = (ctx, provider,
526
506
  /**
527
507
  * This attempt's assembled header value, for credential auth only — framed
@@ -560,6 +540,20 @@ export function remoteMcp(id, opts) {
560
540
  state.credentialDigest = null;
561
541
  // `closed` is deliberately not cleared — see ConnectionState.
562
542
  };
543
+ const closeHalf = async (state) => {
544
+ const client = state.client;
545
+ const transport = state.transport;
546
+ reset(state);
547
+ try {
548
+ if (client)
549
+ await client.close();
550
+ else
551
+ await transport?.close();
552
+ }
553
+ catch {
554
+ // The discarded state remains authoritative if local close fails.
555
+ }
556
+ };
563
557
  const ensureConnected = async (ctx, state) => {
564
558
  // A 401 after connect is a verdict for the whole request scope, not merely
565
559
  // for the one call that observed it. Do not let the still-cached client make
@@ -573,23 +567,12 @@ export function remoteMcp(id, opts) {
573
567
  // turn it back into a pending consent flow.
574
568
  let oauthGeneration;
575
569
  if (isOauth && (state.client || state.connecting)) {
576
- const provider = getProvider(ctx, state);
570
+ const provider = newProvider(ctx, state);
577
571
  oauthGeneration = await provider.generation();
578
572
  if (provider.isOperatorDisconnectedGeneration(oauthGeneration)) {
579
573
  const connecting = state.connecting;
580
- const client = state.client;
581
- const transport = state.transport;
582
- reset(state);
583
574
  void connecting?.catch(() => { });
584
- try {
585
- if (client)
586
- await client.close();
587
- else
588
- await transport?.close();
589
- }
590
- catch {
591
- // The disconnected epoch is authoritative even if local close fails.
592
- }
575
+ await closeHalf(state);
593
576
  throw operatorDisconnectedError();
594
577
  }
595
578
  }
@@ -625,19 +608,8 @@ export function remoteMcp(id, opts) {
625
608
  if (state.closed)
626
609
  throw scopeEndedError();
627
610
  const connecting = state.connecting;
628
- const client = state.client;
629
- const transport = state.transport;
630
- reset(state);
631
611
  void connecting?.catch(() => { });
632
- try {
633
- if (client)
634
- await client.close();
635
- else
636
- await transport?.close();
637
- }
638
- catch {
639
- // The rotated-away client is discarded either way.
640
- }
612
+ await closeHalf(state);
641
613
  }
642
614
  }
643
615
  if (state.closed)
@@ -754,7 +726,7 @@ export function remoteMcp(id, opts) {
754
726
  return state.connecting;
755
727
  };
756
728
  const disconnectAuthorization = async (ctx, state, operatorDisconnected = false) => {
757
- const provider = getProvider(ctx, state);
729
+ const provider = newProvider(ctx, state);
758
730
  // Publish the replacement epoch before waiting on or closing any
759
731
  // request-local transport. A hung connect therefore cannot delay the
760
732
  // fence, and every late OAuth write stays in the older namespace.
@@ -767,18 +739,7 @@ export function remoteMcp(id, opts) {
767
739
  // client/transport exists. Reset is unconditional because KV may already
768
740
  // be fenced behind a newer epoch after a cleanup error.
769
741
  void connecting?.catch(() => { });
770
- try {
771
- if (state.client) {
772
- await state.client.close();
773
- }
774
- else {
775
- await state.transport?.close();
776
- }
777
- }
778
- catch {
779
- // best-effort; the state is discarded either way
780
- }
781
- reset(state);
742
+ await closeHalf(state);
782
743
  }
783
744
  };
784
745
  const connector = {
@@ -854,6 +815,8 @@ export function remoteMcp(id, opts) {
854
815
  // the accumulator is returned rather than stored: a cursor is opaque and
855
816
  // session-bound, so nothing here may outlive this call.
856
817
  async listTools(ctx) {
818
+ // The complete-catalog rule is documented at
819
+ // documentation/connectors.md#catalog-contract.
857
820
  const state = stateFor(ctx);
858
821
  await ensureConnected(ctx, state);
859
822
  // Bind the client once so the whole walk provably rides one session — a
@@ -1019,13 +982,7 @@ export function remoteMcp(id, opts) {
1019
982
  state.closed = true;
1020
983
  const client = state.client;
1021
984
  const transport = state.transport;
1022
- state.client = null;
1023
- state.transport = null;
1024
- state.toolDefinitions.clear();
1025
- state.connecting = null;
1026
- state.authRequired = false;
1027
- state.connectedGeneration = null;
1028
- state.credentialDigest = null;
985
+ reset(state);
1029
986
  // Ask the downstream to drop its session first — closing only aborts our
1030
987
  // side, and the DELETE that frees the server's rides on the very
1031
988
  // AbortSignal the close is about to trip.
@@ -1059,7 +1016,7 @@ export function remoteMcp(id, opts) {
1059
1016
  // credential connector's downstream 401 is repaired on /credentials,
1060
1017
  // so do not reach into OAuth storage to look for one.
1061
1018
  const url = isOauth
1062
- ? await getProvider(ctx, state).pendingAuthorizationUrl()
1019
+ ? await newProvider(ctx, state).pendingAuthorizationUrl()
1063
1020
  : undefined;
1064
1021
  return {
1065
1022
  state: "auth_required",
@@ -1077,7 +1034,7 @@ export function remoteMcp(id, opts) {
1077
1034
  },
1078
1035
  async finishAuth(code, ctx, callbackParams) {
1079
1036
  const state = stateFor(ctx);
1080
- const provider = getProvider(ctx, state);
1037
+ const provider = newProvider(ctx, state);
1081
1038
  // verifyState ran on this request-scoped provider first and captured the
1082
1039
  // pending flow's generation. If force reset races the exchange, any late
1083
1040
  // token write remains tagged with that older generation and is unreadable.
@@ -1097,14 +1054,14 @@ export function remoteMcp(id, opts) {
1097
1054
  if (opts.auth?.type === "oauth") {
1098
1055
  connector.verifyState = async (oauthState, ctx) => {
1099
1056
  const state = stateFor(ctx);
1100
- return getProvider(ctx, state).verifyState(oauthState);
1057
+ return newProvider(ctx, state).verifyState(oauthState);
1101
1058
  };
1102
1059
  connector.disconnectAuth = async (ctx) => {
1103
1060
  await disconnectAuthorization(ctx, stateFor(ctx), true);
1104
1061
  };
1105
1062
  connector.startAuth = async (ctx, startOpts) => {
1106
1063
  const state = stateFor(ctx);
1107
- const p = getProvider(ctx, state);
1064
+ const p = newProvider(ctx, state);
1108
1065
  if (startOpts?.force || (await p.operatorDisconnected())) {
1109
1066
  await disconnectAuthorization(ctx, state);
1110
1067
  }
package/dist/errors.d.ts CHANGED
@@ -5,26 +5,8 @@
5
5
  * naming a cause — the rule provider conventions call H11.
6
6
  */
7
7
  export type ConnectorCallErrorCode = "timeout" | "auth_required" | "rate_limited" | "unavailable" | "invalid_args"
8
- /**
9
- * The downstream answered, and the thing addressed is not there.
10
- *
11
- * Its own code because the next move is none of the others': not a retry,
12
- * not `authorize_connector`, not a reshaped argument object, but
13
- * re-addressing — look the identifier up again, or accept the absence and
14
- * carry on. Inside `execute_code` a program reads that difference from a
15
- * caught error's `code` or a `connecta.batch` entry's `errorDetails.code` —
16
- * continue past this one, abort on `connector_call_failed`. Message prose
17
- * cannot be classified.
18
- *
19
- * Use it only where the provider distinguishes absence from a permission
20
- * gap. A status that means both "it is not there" and "you cannot see it" —
21
- * Notion's `object_not_found` is the worked example — stays
22
- * `connector_call_failed` with a message that states the ambiguity, because
23
- * inventing certainty here is how an agent concludes a page was deleted when
24
- * it was simply never shared. Addresses connecta itself cannot resolve are
25
- * already framed as `unknown_address` or `unknown_tool` and never reach a
26
- * connector, so this code is always about a resource the downstream owns.
27
- */
8
+ /** Provider-owned absence; see provider-conventions.md H11 for the rule and
9
+ * the permission-ambiguity exception. */
28
10
  | "not_found" | "input_required_unsupported" | "connector_call_failed";
29
11
  /** One bounded, payload-free explanation of an input-schema mismatch. */
30
12
  export interface ArgumentValidationIssue {
@@ -48,7 +30,7 @@ export declare const MAX_ARGUMENT_VALIDATION_ISSUES = 3;
48
30
  */
49
31
  export declare function boundedEchoText(value: string, maxBytes?: number): string;
50
32
  /**
51
- * `{ args }` when the caller's arguments fit {@link MAX_ECHOED_ARGS_BYTES},
33
+ * `{ args }` when the caller's arguments fit the shared echo budget,
52
34
  * `{}` when they do not. All or nothing: a clipped echo would be a *different*
53
35
  * call than the one that was refused, and the routes this feeds end at a human
54
36
  * approving one. Unserializable arguments are treated the same way as oversized
@@ -97,11 +79,7 @@ export interface CallErrorDetails {
97
79
  code: string;
98
80
  message: string;
99
81
  retryable: boolean;
100
- /**
101
- * Connector-reported wait window in ms, when known. Reported verbatim — the
102
- * engine bounds how long it will itself wait, but the caller sees the real
103
- * window so it can schedule a re-issue.
104
- */
82
+ /** Connector-known wait window; see {@link ConnectorCallError.retryAfterMs}. */
105
83
  retryAfterMs?: number;
106
84
  /** Bounded input-schema findings; paths and expectations, never values. */
107
85
  validation?: ArgumentValidationDetails;
@@ -132,7 +110,7 @@ export interface CallErrorDetails {
132
110
  address: string;
133
111
  /**
134
112
  * The caller's own arguments, echoed only when they fit
135
- * {@link MAX_ECHOED_ARGS_BYTES} — and then whole, never clipped. Absent
113
+ * the shared echo budget — and then whole, never clipped. Absent
136
114
  * means "re-send exactly what you sent": a half-copied argument object
137
115
  * routed into a human approval prompt would describe a call nobody made.
138
116
  */
@@ -172,3 +150,4 @@ export declare function framingError(code: string, message: string): CallErrorDe
172
150
  * heuristic.
173
151
  */
174
152
  export declare function classifyCallError(err: unknown, fallbackCode?: string): CallErrorDetails;
153
+ export declare function msg(err: unknown): string;
package/dist/errors.js CHANGED
@@ -20,7 +20,8 @@ function boundedIssueText(value, maxChars) {
20
20
  * the payload lands in both the text content and `structuredContent`. The agent
21
21
  * already holds what it sent; the echo is a convenience, never the record.
22
22
  */
23
- const MAX_ECHOED_ARGS_BYTES = 512;
23
+ // Shared by argument and text echoes; see meta-tools.md lines 360-372.
24
+ const MAX_ECHOED_BYTES = 512;
24
25
  /**
25
26
  * The same budget spent on caller-authored *text* — the address it mistyped,
26
27
  * the discovery query derived from it — rather than on its arguments.
@@ -37,7 +38,6 @@ const MAX_ECHOED_ARGS_BYTES = 512;
37
38
  * `structuredContent`), so an unbounded address turned a 50 KB typo into a
38
39
  * 200 KB refusal against a deployment that capped results at 1 KB.
39
40
  */
40
- const MAX_ECHOED_TEXT_BYTES = 512;
41
41
  const echoEncoder = new TextEncoder();
42
42
  const echoDecoder = new TextDecoder();
43
43
  /**
@@ -45,7 +45,7 @@ const echoDecoder = new TextDecoder();
45
45
  * Short strings — the common case, and the one that has to stay exact — are
46
46
  * returned unchanged and untagged.
47
47
  */
48
- export function boundedEchoText(value, maxBytes = MAX_ECHOED_TEXT_BYTES) {
48
+ export function boundedEchoText(value, maxBytes = MAX_ECHOED_BYTES) {
49
49
  const bytes = echoEncoder.encode(value);
50
50
  if (bytes.length <= maxBytes)
51
51
  return value;
@@ -57,7 +57,7 @@ export function boundedEchoText(value, maxBytes = MAX_ECHOED_TEXT_BYTES) {
57
57
  return `${echoDecoder.decode(bytes.slice(0, end))}…`;
58
58
  }
59
59
  /**
60
- * `{ args }` when the caller's arguments fit {@link MAX_ECHOED_ARGS_BYTES},
60
+ * `{ args }` when the caller's arguments fit the shared echo budget,
61
61
  * `{}` when they do not. All or nothing: a clipped echo would be a *different*
62
62
  * call than the one that was refused, and the routes this feeds end at a human
63
63
  * approving one. Unserializable arguments are treated the same way as oversized
@@ -75,7 +75,7 @@ export function echoedCallArgs(args) {
75
75
  }
76
76
  if (text === undefined)
77
77
  return {};
78
- return echoEncoder.encode(text).length <= MAX_ECHOED_ARGS_BYTES
78
+ return echoEncoder.encode(text).length <= MAX_ECHOED_BYTES
79
79
  ? { args }
80
80
  : {};
81
81
  }
@@ -221,3 +221,6 @@ export function classifyCallError(err, fallbackCode = "connector_call_failed") {
221
221
  retryable: RETRYABLE_MESSAGE_RE.test(message),
222
222
  };
223
223
  }
224
+ export function msg(err) {
225
+ return err instanceof Error ? err.message : String(err);
226
+ }
package/dist/execute.d.ts CHANGED
@@ -136,7 +136,9 @@ export declare class EmitCollector {
136
136
  * complaint about its type would send the author to fix the wrong thing.
137
137
  */
138
138
  acceptUi(...values: unknown[]): void;
139
- acceptUiPayload(payload: UiPayload): void;
139
+ acceptValidatedUi(payload: UiPayload): void;
140
+ private assertUiVacant;
141
+ private acceptUiPayload;
140
142
  }
141
143
  /** Convert a connector/tool name into a valid JS identifier. */
142
144
  export declare function sanitizeIdentifier(name: string): string;
@@ -146,30 +148,30 @@ export declare function sanitizeIdentifier(name: string): string;
146
148
  * calls that namespace or explicitly asks search/describe.
147
149
  */
148
150
  export declare function buildSandboxProviders(registry: RegistryView, baseUrl: string, logger: Logger, activity?: ActivityRequestContext, limits?: {
149
- signal?: AbortSignal;
150
- maxHostCalls?: number;
151
- hostCallTimeoutMs?: number;
152
- discoveryConcurrency?: number;
151
+ signal?: AbortSignal | undefined;
152
+ maxHostCalls?: number | undefined;
153
+ hostCallTimeoutMs?: number | undefined;
154
+ discoveryConcurrency?: number | undefined;
153
155
  /** Per-connector deadline for in-program catalog probes. Default 30_000. */
154
- probeTimeoutMs?: number;
155
- onInvocationFailure?: (failure: InvocationFailure) => void;
156
- diagnostics?: ExecuteDiagnostics;
156
+ probeTimeoutMs?: number | undefined;
157
+ onInvocationFailure?: ((failure: InvocationFailure) => void) | undefined;
158
+ diagnostics?: ExecuteDiagnostics | undefined;
157
159
  /**
158
160
  * Where `connecta.emit` collects. The handler that will deliver the
159
161
  * blocks owns it; without one, emit fails loudly rather than accept
160
162
  * blocks nobody will ever return.
161
163
  */
162
- emitCollector?: EmitCollector;
164
+ emitCollector?: EmitCollector | undefined;
163
165
  /** Runtime-owned tail for stale catalog refreshes. */
164
- defer?: DeferredWork;
166
+ defer?: DeferredWork | undefined;
165
167
  }): Promise<ExecutorProvider[]>;
166
168
  /** The execute_code handler. Exported for direct testing. */
167
169
  export declare function createExecuteTool(registry: RegistryView, baseUrl: string, executor: Executor, logger: Logger, activity?: ActivityRequestContext, config?: {
168
- discoveryConcurrency?: number;
169
- probeTimeoutMs?: number;
170
- maxEmittedBytes?: number;
171
- maxEmittedBlocks?: number;
172
- defer?: DeferredWork;
170
+ discoveryConcurrency?: number | undefined;
171
+ probeTimeoutMs?: number | undefined;
172
+ maxEmittedBytes?: number | undefined;
173
+ maxEmittedBlocks?: number | undefined;
174
+ defer?: DeferredWork | undefined;
173
175
  }): ({ code, diagnostics: diagnosticsRequested }: {
174
176
  code: string;
175
177
  diagnostics?: boolean;
@@ -181,20 +183,20 @@ export declare function registerExecuteTool(server: McpServer, registry: Registr
181
183
  baseUrl: string;
182
184
  executor: Executor;
183
185
  logger: Logger;
184
- activity?: ActivityRequestContext;
185
- requestSignal?: AbortSignal;
186
- discoveryConcurrency?: number;
186
+ activity?: ActivityRequestContext | undefined;
187
+ requestSignal?: AbortSignal | undefined;
188
+ discoveryConcurrency?: number | undefined;
187
189
  /**
188
190
  * The deployment's configured per-connector probe deadline. Programs probe
189
191
  * the same downstream catalogs the top-level tools do, so an operator who
190
192
  * tightened `discovery.probeTimeoutMs` gets it honored inside the sandbox
191
193
  * too rather than silently falling back to the 30s default.
192
194
  */
193
- probeTimeoutMs?: number;
195
+ probeTimeoutMs?: number | undefined;
194
196
  /** Aggregate serialized-byte budget for connecta.emit. Default 4_000_000. */
195
- maxEmittedBytes?: number;
197
+ maxEmittedBytes?: number | undefined;
196
198
  /** Block-count budget for connecta.emit. Default 32. */
197
- maxEmittedBlocks?: number;
198
- defer?: DeferredWork;
199
+ maxEmittedBlocks?: number | undefined;
200
+ defer?: DeferredWork | undefined;
199
201
  }): void;
200
202
  export {};