@zackbart/connecta 0.18.2 → 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 (75) hide show
  1. package/CHANGELOG.md +100 -4
  2. package/README.md +4 -0
  3. package/dist/catalog-service.d.ts +20 -13
  4. package/dist/catalog-service.js +123 -116
  5. package/dist/catalog.js +29 -46
  6. package/dist/connector-scope.js +2 -7
  7. package/dist/connectors/api.d.ts +4 -16
  8. package/dist/connectors/api.js +19 -46
  9. package/dist/connectors/guarded-fetch.d.ts +9 -23
  10. package/dist/connectors/guarded-fetch.js +38 -76
  11. package/dist/connectors/remote-mcp.js +36 -79
  12. package/dist/errors.d.ts +6 -27
  13. package/dist/errors.js +8 -5
  14. package/dist/execute.d.ts +24 -22
  15. package/dist/execute.js +98 -145
  16. package/dist/executor-result.d.ts +1 -0
  17. package/dist/executor-result.js +4 -11
  18. package/dist/executors/quickjs-child.js +1 -3
  19. package/dist/executors/quickjs-runtime.js +1 -3
  20. package/dist/executors/quickjs.js +1 -3
  21. package/dist/index.js +27 -57
  22. package/dist/invocation.js +114 -178
  23. package/dist/meta-tools.d.ts +15 -28
  24. package/dist/meta-tools.js +33 -89
  25. package/dist/providers/cloudflare.d.ts +2 -18
  26. package/dist/providers/cloudflare.js +1460 -2451
  27. package/dist/providers/linear.d.ts +4 -41
  28. package/dist/providers/linear.js +8 -39
  29. package/dist/providers/mixpanel.d.ts +3 -25
  30. package/dist/providers/mixpanel.js +7 -22
  31. package/dist/providers/notion.d.ts +1 -15
  32. package/dist/providers/notion.js +44 -173
  33. package/dist/providers/revenuecat.d.ts +4 -57
  34. package/dist/providers/revenuecat.js +10 -93
  35. package/dist/providers/stripe.d.ts +1 -12
  36. package/dist/providers/stripe.js +7 -45
  37. package/dist/registry.d.ts +16 -34
  38. package/dist/registry.js +18 -103
  39. package/dist/result-shapes.d.ts +13 -0
  40. package/dist/result-shapes.js +331 -0
  41. package/dist/routes/mcp.js +1 -1
  42. package/dist/routes/oauth.js +3 -3
  43. package/dist/routes/shared.d.ts +15 -15
  44. package/dist/routes/shared.js +1 -3
  45. package/dist/skills.js +3 -3
  46. package/dist/timeout.d.ts +8 -7
  47. package/dist/timeout.js +47 -38
  48. package/dist/types.d.ts +3 -3
  49. package/dist/ui.d.ts +1 -25
  50. package/dist/ui.js +18 -45
  51. package/dist/version.d.ts +1 -1
  52. package/dist/version.js +1 -1
  53. package/documentation/architecture.md +5 -2
  54. package/documentation/call-admission.md +1 -1
  55. package/documentation/cloudflare.md +1 -1
  56. package/documentation/code-mode.md +13 -13
  57. package/documentation/connectors.md +34 -1
  58. package/documentation/linear.md +1 -1
  59. package/documentation/meta-tools.md +17 -3
  60. package/documentation/mixpanel.md +1 -1
  61. package/documentation/notion.md +1 -1
  62. package/documentation/operations.md +20 -15
  63. package/documentation/provider-conventions.md +1 -1
  64. package/documentation/revenuecat.md +1 -1
  65. package/documentation/stripe.md +1 -1
  66. package/documentation/upgrading.md +24 -4
  67. package/ethos.md +74 -120
  68. package/package.json +3 -4
  69. package/templates/node/package.json +1 -1
  70. package/documentation/code-first-exploration.md +0 -292
  71. package/documentation/mcp-2026-07-28.md +0 -46
  72. package/documentation/mcp-ui-design.md +0 -382
  73. package/documentation/program-ui-read-calls.md +0 -213
  74. package/documentation/provider-audit.md +0 -198
  75. package/documentation/rich-output-design.md +0 -211
package/dist/execute.js CHANGED
@@ -4,7 +4,7 @@ import { boundedDiscoveryText, CatalogService, DiscoveryPolicyError, flatSearchR
4
4
  import { errorResult, jsonResult } from "./meta-tools.js";
5
5
  import { guardExecuteResultValue, MAX_EXECUTE_LOG_CHARS, truncateExecuteText, } from "./executor-result.js";
6
6
  import { ExecutorAdmissionError, ExecutorExecutionError, isAdmittingExecutor, } from "./executor-admission.js";
7
- import { boundedEchoText, classifyCallError } from "./errors.js";
7
+ import { boundedEchoText, classifyCallError, msg } from "./errors.js";
8
8
  import { InvocationFailure, InvocationService, } from "./invocation.js";
9
9
  import { hasConnectorGuides } from "./skills.js";
10
10
  import { isExplicitlyReadOnly } from "./tool-safety.js";
@@ -306,15 +306,19 @@ export class EmitCollector {
306
306
  * complaint about its type would send the author to fix the wrong thing.
307
307
  */
308
308
  acceptUi(...values) {
309
- if (this.ui) {
310
- throw guestFailure("invalid_args", "connecta.ui accepts at most one payload per run: a view was already accepted and stands");
311
- }
309
+ this.assertUiVacant();
312
310
  this.acceptUiPayload(requireUiPayload(values));
313
311
  }
314
- acceptUiPayload(payload) {
312
+ acceptValidatedUi(payload) {
313
+ this.assertUiVacant();
314
+ this.acceptUiPayload(payload);
315
+ }
316
+ assertUiVacant() {
315
317
  if (this.ui) {
316
318
  throw guestFailure("invalid_args", "connecta.ui accepts at most one payload per run: a view was already accepted and stands");
317
319
  }
320
+ }
321
+ acceptUiPayload(payload) {
318
322
  let serialized;
319
323
  try {
320
324
  serialized = JSON.stringify(payload);
@@ -429,9 +433,6 @@ const SANDBOX_RESERVED_NAMES = new Set([
429
433
  "__stringifyForCodemode",
430
434
  "__parseForCodemode",
431
435
  ]);
432
- function msg(err) {
433
- return err instanceof Error ? err.message : String(err);
434
- }
435
436
  function guestFailure(code, message, retryable = false) {
436
437
  return new InvocationFailure({ code, message, retryable });
437
438
  }
@@ -515,13 +516,9 @@ export async function buildSandboxProviders(registry, baseUrl, logger, activity,
515
516
  requestScope,
516
517
  // A program that just missed an address cannot call search_tools.
517
518
  searchRoute: "connecta.search",
518
- ...(limits.discoveryConcurrency !== undefined
519
- ? { concurrency: limits.discoveryConcurrency }
520
- : {}),
521
- ...(limits.probeTimeoutMs !== undefined
522
- ? { probeTimeoutMs: limits.probeTimeoutMs }
523
- : {}),
524
- ...(limits.defer !== undefined ? { defer: limits.defer } : {}),
519
+ concurrency: limits.discoveryConcurrency,
520
+ probeTimeoutMs: limits.probeTimeoutMs,
521
+ defer: limits.defer,
525
522
  });
526
523
  const invocation = new InvocationService(registry, catalog, activity);
527
524
  const maxHostCalls = Math.max(1, Math.trunc(limits.maxHostCalls ?? EXECUTE_MAX_HOST_CALLS));
@@ -573,23 +570,30 @@ export async function buildSandboxProviders(registry, baseUrl, logger, activity,
573
570
  throw err;
574
571
  }
575
572
  };
576
- const callAddress = async (address, args, diagnosticOperation = "call") => {
577
- const outcome = await invocation.invoke(String(address), args ?? {}, invocationContext());
578
- limits.diagnostics?.recordCall(diagnosticOperation, outcome);
579
- if (!outcome.ok) {
580
- const failure = new InvocationFailure(outcome.error);
581
- throw failure;
573
+ const timedCatalog = async (operation, fn) => {
574
+ const started = Date.now();
575
+ try {
576
+ const result = await fn();
577
+ limits.diagnostics?.recordCatalog(operation, Date.now() - started, true, result);
578
+ return result;
582
579
  }
580
+ catch (err) {
581
+ limits.diagnostics?.recordCatalog(operation, Date.now() - started, false);
582
+ throw err;
583
+ }
584
+ };
585
+ const called = async (operation, invoke) => {
586
+ const outcome = await invoke();
587
+ limits.diagnostics?.recordCall(operation, outcome);
588
+ if (!outcome.ok)
589
+ throw new InvocationFailure(outcome.error);
583
590
  return outcome.value;
584
591
  };
592
+ const callAddress = async (address, args, diagnosticOperation = "call") => {
593
+ return called(diagnosticOperation, () => invocation.invoke(String(address), args ?? {}, invocationContext()));
594
+ };
585
595
  const callNamespace = async (connectorId, toolAlias, args) => {
586
- const outcome = await invocation.invokeToolAlias(String(connectorId), String(toolAlias), sanitizeIdentifier, args ?? {}, invocationContext());
587
- limits.diagnostics?.recordCall("call", outcome);
588
- if (!outcome.ok) {
589
- const failure = new InvocationFailure(outcome.error);
590
- throw failure;
591
- }
592
- return outcome.value;
596
+ return called("call", () => invocation.invokeToolAlias(String(connectorId), String(toolAlias), sanitizeIdentifier, args ?? {}, invocationContext()));
593
597
  };
594
598
  /**
595
599
  * A read binding is admitted while the program still owns the request. The
@@ -643,7 +647,7 @@ export async function buildSandboxProviders(registry, baseUrl, logger, activity,
643
647
  throw guestFailure("unavailable", "connecta.ui is unavailable: no emission collector was configured for this execution", true);
644
648
  }
645
649
  const payload = await validateUiReads(requireUiPayload(values));
646
- limits.emitCollector.acceptUiPayload(payload);
650
+ limits.emitCollector.acceptValidatedUi(payload);
647
651
  },
648
652
  batch: async (calls) => {
649
653
  const started = Date.now();
@@ -684,43 +688,21 @@ export async function buildSandboxProviders(registry, baseUrl, logger, activity,
684
688
  throw err;
685
689
  }
686
690
  },
687
- search: async (raw) => {
688
- const started = Date.now();
689
- try {
690
- const result = await typedDiscovery(async () => {
691
- const args = (raw ?? {});
692
- const result = flatSearchResult(await catalog.search({
693
- ...args,
694
- includeSchemaKeys: args.includeSchemaKeys !== false,
695
- }));
696
- boundedDiscoveryText(result, "Request a smaller limit, omit fullDescriptions, use compact schemas, or pass includeSchemaKeys: false.");
697
- return result;
698
- });
699
- limits.diagnostics?.recordCatalog("search", Date.now() - started, true, result);
700
- return result;
701
- }
702
- catch (err) {
703
- limits.diagnostics?.recordCatalog("search", Date.now() - started, false);
704
- throw err;
705
- }
706
- },
707
- describe: async (raw) => {
708
- const started = Date.now();
709
- try {
710
- const result = await typedDiscovery(async () => {
711
- const args = (raw ?? {});
712
- const result = { tools: await catalog.describe(args) };
713
- boundedDiscoveryText(result, 'Split the address list or use format: "compact".');
714
- return result;
715
- });
716
- limits.diagnostics?.recordCatalog("describe", Date.now() - started, true, result);
717
- return result;
718
- }
719
- catch (err) {
720
- limits.diagnostics?.recordCatalog("describe", Date.now() - started, false);
721
- throw err;
722
- }
723
- },
691
+ search: async (raw) => timedCatalog("search", () => typedDiscovery(async () => {
692
+ const args = (raw ?? {});
693
+ const result = flatSearchResult(await catalog.search({
694
+ ...args,
695
+ includeSchemaKeys: args.includeSchemaKeys !== false,
696
+ }));
697
+ boundedDiscoveryText(result, "Request a smaller limit, omit fullDescriptions, use compact schemas, or pass includeSchemaKeys: false.");
698
+ return result;
699
+ })),
700
+ describe: async (raw) => timedCatalog("describe", () => typedDiscovery(async () => {
701
+ const args = (raw ?? {});
702
+ const result = { tools: await catalog.describe(args) };
703
+ boundedDiscoveryText(result, 'Split the address list or use format: "compact".');
704
+ return result;
705
+ })),
724
706
  };
725
707
  const transportedFns = Object.fromEntries(Object.entries(fns).map(([name, fn]) => [
726
708
  name,
@@ -790,13 +772,9 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
790
772
  },
791
773
  emitCollector: emitted,
792
774
  ...(diagnostics ? { diagnostics } : {}),
793
- ...(config.discoveryConcurrency !== undefined
794
- ? { discoveryConcurrency: config.discoveryConcurrency }
795
- : {}),
796
- ...(config.probeTimeoutMs !== undefined
797
- ? { probeTimeoutMs: config.probeTimeoutMs }
798
- : {}),
799
- ...(config.defer !== undefined ? { defer: config.defer } : {}),
775
+ discoveryConcurrency: config.discoveryConcurrency,
776
+ probeTimeoutMs: config.probeTimeoutMs,
777
+ defer: config.defer,
800
778
  });
801
779
  }
802
780
  finally {
@@ -826,8 +804,10 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
826
804
  retryAfterMs: err.retryAfterMs,
827
805
  });
828
806
  }
829
- const result = jsonResult({
830
- error: {
807
+ return failureResponse(err.message, {
808
+ emitted: err instanceof ExecutorExecutionError ? emitted : undefined,
809
+ diagnostics,
810
+ code: {
831
811
  code: err.code,
832
812
  message: err.message,
833
813
  retryable: err.retryable,
@@ -835,28 +815,13 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
835
815
  ? { retryAfterMs: err.retryAfterMs }
836
816
  : {}),
837
817
  },
838
- ...(err instanceof ExecutorExecutionError
839
- ? discardedEmits(emitted)
840
- : {}),
841
- ...(diagnostics ? { diagnostics: diagnostics.finish() } : {}),
842
818
  });
843
- result.isError = true;
844
- return result;
845
819
  }
846
- if (diagnostics) {
847
- const result = jsonResult({
848
- error: {
849
- code: "executor_failed",
850
- message: `Executor failed: ${msg(err)}`,
851
- retryable: false,
852
- },
853
- ...discardedEmits(emitted),
854
- diagnostics: diagnostics.finish(),
855
- });
856
- result.isError = true;
857
- return result;
858
- }
859
- return errorResult(`Executor failed: ${msg(err)}${discardedEmitsText(emitted)}`);
820
+ return failureResponse(`Executor failed: ${msg(err)}`, {
821
+ emitted,
822
+ diagnostics,
823
+ code: "executor_failed",
824
+ });
860
825
  }
861
826
  finally {
862
827
  // A sandbox timeout or early return must also release any outstanding
@@ -900,31 +865,20 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
900
865
  // framed with bounded caller text (`boundedEchoText`) precisely so
901
866
  // this path never needs one. Adding a cap here instead would leave the
902
867
  // top-level surfaces, which have the same amplification, uncovered.
903
- const result = jsonResult({
904
- error: invocationFailure.details,
905
- ...(logs ? { logs } : {}),
906
- ...discardedEmits(emitted),
907
- ...(diagnostics ? { diagnostics: diagnostics.finish() } : {}),
868
+ return failureResponse(invocationFailure.details.message, {
869
+ logs,
870
+ emitted,
871
+ diagnostics,
872
+ code: invocationFailure.details,
908
873
  });
909
- result.isError = true;
910
- return result;
911
874
  }
912
875
  const message = `Error: ${outcome.error}`;
913
- if (diagnostics) {
914
- const result = jsonResult({
915
- error: {
916
- code: "executor_failed",
917
- message,
918
- retryable: false,
919
- },
920
- ...(logs ? { logs } : {}),
921
- ...discardedEmits(emitted),
922
- diagnostics: diagnostics.finish(),
923
- });
924
- result.isError = true;
925
- return result;
926
- }
927
- return errorResult(`${message}${logs ? `\n\nLogs:\n${logs}` : ""}${discardedEmitsText(emitted)}`);
876
+ return failureResponse(message, {
877
+ logs,
878
+ emitted,
879
+ diagnostics,
880
+ code: "executor_failed",
881
+ });
928
882
  }
929
883
  // A result crossing back as a host BigInt (or otherwise unserializable
930
884
  // value) makes JSON.stringify throw — keep that inside the structured
@@ -935,21 +889,12 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
935
889
  }
936
890
  catch (err) {
937
891
  const message = `Error: result is not JSON-serializable: ${msg(err)}`;
938
- if (diagnostics) {
939
- const response = jsonResult({
940
- error: {
941
- code: "executor_failed",
942
- message,
943
- retryable: false,
944
- },
945
- ...(logs ? { logs } : {}),
946
- ...discardedEmits(emitted),
947
- diagnostics: diagnostics.finish(),
948
- });
949
- response.isError = true;
950
- return response;
951
- }
952
- return errorResult(`${message}${logs ? `\n\nLogs:\n${logs}` : ""}${discardedEmitsText(emitted)}`);
892
+ return failureResponse(message, {
893
+ logs,
894
+ emitted,
895
+ diagnostics,
896
+ code: "executor_failed",
897
+ });
953
898
  }
954
899
  const response = jsonResult({
955
900
  result,
@@ -976,6 +921,22 @@ export function createExecuteTool(registry, baseUrl, executor, logger, activity,
976
921
  return response;
977
922
  };
978
923
  }
924
+ function failureResponse(message, options) {
925
+ const { logs, emitted, diagnostics, code } = options;
926
+ if (diagnostics || typeof code !== "string") {
927
+ const result = jsonResult({
928
+ error: typeof code === "string"
929
+ ? { code, message, retryable: false }
930
+ : code,
931
+ ...(logs ? { logs } : {}),
932
+ ...(emitted ? discardedEmits(emitted) : {}),
933
+ ...(diagnostics ? { diagnostics: diagnostics.finish() } : {}),
934
+ });
935
+ result.isError = true;
936
+ return result;
937
+ }
938
+ return errorResult(`${message}${logs ? `\n\nLogs:\n${logs}` : ""}${emitted ? discardedEmitsText(emitted) : ""}`);
939
+ }
979
940
  /**
980
941
  * M4 and U3: a failed program delivers no blocks and no view, but each
981
942
  * discard is visible — and one failure can discard both.
@@ -1049,15 +1010,11 @@ export function registerExecuteTool(server, registry, ctx) {
1049
1010
  };
1050
1011
  const connectors = registry.listConnectors();
1051
1012
  const handler = createExecuteTool(registry, ctx.baseUrl, ctx.executor, ctx.logger, ctx.activity, {
1052
- ...(ctx.discoveryConcurrency !== undefined
1053
- ? { discoveryConcurrency: ctx.discoveryConcurrency }
1054
- : {}),
1055
- ...(ctx.probeTimeoutMs !== undefined
1056
- ? { probeTimeoutMs: ctx.probeTimeoutMs }
1057
- : {}),
1013
+ discoveryConcurrency: ctx.discoveryConcurrency,
1014
+ probeTimeoutMs: ctx.probeTimeoutMs,
1058
1015
  maxEmittedBytes: emitBudgets.maxBytes,
1059
1016
  maxEmittedBlocks: emitBudgets.maxBlocks,
1060
- ...(ctx.defer !== undefined ? { defer: ctx.defer } : {}),
1017
+ defer: ctx.defer,
1061
1018
  });
1062
1019
  server.registerTool("execute_code", {
1063
1020
  description: executeDescription(emitBudgets, hasConnectorGuides(connectors), connectors),
@@ -1078,12 +1035,8 @@ export function registerExecuteTool(server, registry, ctx) {
1078
1035
  destructiveHint: false,
1079
1036
  openWorldHint: true,
1080
1037
  },
1081
- // U5 and U10: declared unconditionally. A host without the Apps
1082
- // extension ignores unknown _meta and sees the ordinary envelope, which
1083
- // is the text fallback the spec mandates — and a stateless aggregator
1084
- // has nowhere dependable to hold a negotiation check anyway. The
1085
- // explicit visibility keeps hosts from being told the view may call
1086
- // execute_code; the default ["model","app"] would say exactly that.
1038
+ // U5 and U10 are specified in documentation/code-mode.md; explicit model
1039
+ // visibility prevents hosts from offering execute_code to the view.
1087
1040
  _meta: {
1088
1041
  ui: {
1089
1042
  resourceUri: PROGRAM_UI_RESOURCE_URI,
@@ -1,5 +1,6 @@
1
1
  import type { ExecuteResult } from "./types.js";
2
2
  export declare const MAX_EXECUTE_LOG_CHARS = 4000;
3
+ export declare function serializeResultText(value: unknown): string;
3
4
  export declare function guardExecuteResultValue(value: unknown): unknown;
4
5
  export declare function truncateExecuteText(text: string, max: number): string;
5
6
  /**
@@ -1,10 +1,8 @@
1
+ import { msg } from "./errors.js";
1
2
  /** ~6k tokens. Sandbox code should filter data down before returning. */
2
3
  const MAX_EXECUTE_RESULT_CHARS = 24_000;
3
4
  export const MAX_EXECUTE_LOG_CHARS = 4_000;
4
- function msg(err) {
5
- return err instanceof Error ? err.message : String(err);
6
- }
7
- function serializeExecuteValue(value) {
5
+ export function serializeResultText(value) {
8
6
  const serialized = JSON.stringify(value);
9
7
  return serialized === undefined ? String(value) : serialized;
10
8
  }
@@ -37,15 +35,10 @@ function truncationEnvelope(text) {
37
35
  // the overshoot ratio (minus a step) strictly shrinks the budget.
38
36
  budget = Math.max(0, Math.floor(budget * (MAX_EXECUTE_RESULT_CHARS / size)) - 8);
39
37
  }
40
- // The loop shrinks monotonically, so this is unreachable in practice — but an
41
- // unchecked slice is exactly how a "bounded" envelope stops being bounded.
42
- const clamped = { ...base, preview: text.slice(0, Math.max(0, budget)) };
43
- return JSON.stringify(clamped).length <= MAX_EXECUTE_RESULT_CHARS
44
- ? clamped
45
- : { ...base, preview: "" };
38
+ return { ...base, preview: text.slice(0, budget) };
46
39
  }
47
40
  export function guardExecuteResultValue(value) {
48
- const text = serializeExecuteValue(value);
41
+ const text = serializeResultText(value);
49
42
  if (text.length <= MAX_EXECUTE_RESULT_CHARS)
50
43
  return value;
51
44
  return truncationEnvelope(text);
@@ -1,12 +1,10 @@
1
1
  import { prepareExecuteResultForTransport } from "../executor-result.js";
2
+ import { msg } from "../errors.js";
2
3
  import { MAX_QUICKJS_IPC_BYTES, MAX_QUICKJS_HOST_RPC_BYTES, serializedBytes, stringifyBounded, } from "./quickjs-protocol.js";
3
4
  import { executeQuickJs, prepareQuickJs } from "./quickjs-runtime.js";
4
5
  let activeJobId;
5
6
  let nextCallId = 1;
6
7
  const pending = new Map();
7
- function msg(err) {
8
- return err instanceof Error ? err.message : String(err);
9
- }
10
8
  function send(message) {
11
9
  if (!process.send)
12
10
  throw new Error("QuickJS child IPC channel is unavailable.");
@@ -8,6 +8,7 @@
8
8
  // continuations from a host-side loop. Values cross the boundary as JSON, so
9
9
  // provider args/results must be JSON-serializable.
10
10
  import { getQuickJS, } from "quickjs-emscripten";
11
+ import { msg } from "../errors.js";
11
12
  import { hostCallLabel, MAX_QUICKJS_LOG_TRANSPORT_BYTES, serializedBytes, } from "./quickjs-protocol.js";
12
13
  /** Load and compile the shared QuickJS WASM module before a run budget starts. */
13
14
  export async function prepareQuickJs() {
@@ -29,9 +30,6 @@ const MAX_LOG_MARKER_TRANSPORT_BYTES = Math.max(logTransportBytes(LOG_ENTRY_LIMI
29
30
  // This still lets guest code reduce data more than ten times larger than
30
31
  // connecta's final response budget.
31
32
  const MAX_HOST_RESULT_BYTES = 256 * 1024;
32
- function msg(err) {
33
- return err instanceof Error ? err.message : String(err);
34
- }
35
33
  function logTransportBytes(entry) {
36
34
  // The log is encoded into ExecutionPayload, then that payloadJson string is
37
35
  // encoded into ChildToParentMessage. Measure the units the IPC cap sees.
@@ -6,6 +6,7 @@ import { fork } from "node:child_process";
6
6
  import { existsSync } from "node:fs";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { AdmissionController, ExecutorAdmissionError, ExecutorExecutionError, } from "../executor-admission.js";
9
+ import { msg } from "../errors.js";
9
10
  import { hostCallLabel, MAX_QUICKJS_IPC_BYTES, MAX_QUICKJS_HOST_RPC_BYTES, serializedBytes, stringifyBounded, } from "./quickjs-protocol.js";
10
11
  export { normalizeCode } from "./quickjs-runtime.js";
11
12
  const DEFAULT_TIMEOUT_MS = 30_000;
@@ -19,9 +20,6 @@ const CHILD_EXIT_GRACE_MS = 250;
19
20
  const CHILD_STARTUP_TIMEOUT_MS = 10_000;
20
21
  const MAX_CHILD_STDERR_BYTES = 8 * 1024;
21
22
  const MAX_ERROR_CHARS = 4_000;
22
- function msg(err) {
23
- return err instanceof Error ? err.message : String(err);
24
- }
25
23
  function retainStderrTail(current, chunk) {
26
24
  const incoming = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
27
25
  if (incoming.length >= MAX_CHILD_STDERR_BYTES) {
package/dist/index.js CHANGED
@@ -194,7 +194,7 @@ function warnInsecureConfig(config, inboundAuth, logger) {
194
194
  }
195
195
  export function createConnecta(config) {
196
196
  assertNoLegacyConfig(config);
197
- if (Object.prototype.hasOwnProperty.call(config, "surface")) {
197
+ if (hasOwn(config, "surface")) {
198
198
  throw new Error("ConnectaConfig.surface was removed in issue #273. Remove it; connecta " +
199
199
  "now serves one seven-tool surface.");
200
200
  }
@@ -233,30 +233,20 @@ export function createConnecta(config) {
233
233
  const registry = new Registry(config.connectors, {
234
234
  storage,
235
235
  logger,
236
- ...(credentialVault !== undefined ? { credentialVault } : {}),
237
- ...(config.activity?.store !== undefined
236
+ credentialVault,
237
+ catalogDriftActivity: config.activity?.store
238
238
  ? {
239
- catalogDriftActivity: {
240
- sink: config.activity.store,
241
- serverInfo,
242
- ...(config.activity.deploymentId !== undefined
243
- ? { deploymentId: config.activity.deploymentId }
244
- : {}),
245
- },
239
+ sink: config.activity.store,
240
+ serverInfo,
241
+ ...(config.activity.deploymentId !== undefined
242
+ ? { deploymentId: config.activity.deploymentId }
243
+ : {}),
246
244
  }
247
- : {}),
248
- ...(config.discovery?.catalogTtlSeconds !== undefined
249
- ? { toolCacheTtlSeconds: config.discovery.catalogTtlSeconds }
250
- : {}),
251
- ...(config.discovery?.persistCatalog !== undefined
252
- ? { persistToolCatalog: config.discovery.persistCatalog }
253
- : {}),
254
- ...(config.discovery?.staleCatalogSeconds !== undefined
255
- ? { toolCatalogStaleSeconds: config.discovery.staleCatalogSeconds }
256
- : {}),
257
- ...(config.calls?.maxResultBytes !== undefined
258
- ? { maxResultBytes: config.calls.maxResultBytes }
259
- : {}),
245
+ : undefined,
246
+ toolCacheTtlSeconds: config.discovery?.catalogTtlSeconds,
247
+ persistToolCatalog: config.discovery?.persistCatalog,
248
+ toolCatalogStaleSeconds: config.discovery?.staleCatalogSeconds,
249
+ maxResultBytes: config.calls?.maxResultBytes,
260
250
  });
261
251
  const inboundAuth = normalizeAuth(accessTokens ? [accessTokens.auth, ...configuredAuth] : configuredAuth);
262
252
  warnInsecureConfig(config, inboundAuth, logger);
@@ -279,44 +269,24 @@ export function createConnecta(config) {
279
269
  const handler = createFetchHandler({
280
270
  registry,
281
271
  auth: inboundAuth,
282
- ...(config.publicUrl !== undefined ? { publicUrl: config.publicUrl } : {}),
272
+ publicUrl: config.publicUrl,
283
273
  serverInfo,
284
274
  logger,
285
- ...(config.activity?.store !== undefined
286
- ? { activity: config.activity.store }
287
- : {}),
288
- ...(config.activity?.readGate !== undefined
289
- ? { activityReadGate: config.activity.readGate }
290
- : {}),
291
- ...(config.activity?.deploymentId !== undefined
292
- ? { activityDeploymentId: config.activity.deploymentId }
293
- : {}),
275
+ activity: config.activity?.store,
276
+ activityReadGate: config.activity?.readGate,
277
+ activityDeploymentId: config.activity?.deploymentId,
294
278
  executor,
295
- ...(configuredExecutorName !== undefined
296
- ? { executorName: configuredExecutorName }
297
- : {}),
279
+ executorName: configuredExecutorName,
298
280
  requestAdmission,
299
- ...(config.calls?.defaultTimeoutMs !== undefined
300
- ? { defaultToolTimeoutMs: config.calls.defaultTimeoutMs }
301
- : {}),
302
- ...(config.discovery?.probeTimeoutMs !== undefined
303
- ? { probeTimeoutMs: config.discovery.probeTimeoutMs }
304
- : {}),
305
- ...(config.discovery?.concurrency !== undefined
306
- ? { discoveryConcurrency: config.discovery.concurrency }
307
- : {}),
308
- ...(config.execute?.maxEmittedBytes !== undefined
309
- ? { maxEmittedBytes: config.execute.maxEmittedBytes }
310
- : {}),
311
- ...(config.execute?.maxEmittedBlocks !== undefined
312
- ? { maxEmittedBlocks: config.execute.maxEmittedBlocks }
313
- : {}),
314
- ...(credentialVault !== undefined ? { credentialVault } : {}),
315
- ...(accessTokens !== undefined ? { accessTokens } : {}),
316
- ...(config.deploymentInfo !== undefined
317
- ? { deploymentInfo: config.deploymentInfo }
318
- : {}),
319
- ...(config.branding !== undefined ? { branding: config.branding } : {}),
281
+ defaultToolTimeoutMs: config.calls?.defaultTimeoutMs,
282
+ probeTimeoutMs: config.discovery?.probeTimeoutMs,
283
+ discoveryConcurrency: config.discovery?.concurrency,
284
+ maxEmittedBytes: config.execute?.maxEmittedBytes,
285
+ maxEmittedBlocks: config.execute?.maxEmittedBlocks,
286
+ credentialVault,
287
+ accessTokens,
288
+ deploymentInfo: config.deploymentInfo,
289
+ branding: config.branding,
320
290
  });
321
291
  let closePromise;
322
292
  return {