@zackbart/connecta 0.28.1 → 0.30.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 (332) hide show
  1. package/CHANGELOG.md +855 -5
  2. package/README.md +125 -116
  3. package/bin/connecta.mjs +121 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/argument-redaction.js +230 -0
  12. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  13. package/dist/auth/clerk-sdk/client.js +5 -0
  14. package/dist/auth/clerk-sdk/generated.js +1845 -0
  15. package/dist/auth/clerk-transport.js +19 -0
  16. package/dist/auth/clerk.d.ts +17 -7
  17. package/dist/auth/clerk.js +189 -107
  18. package/dist/auth/cloudflare-access.js +25 -26
  19. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  20. package/dist/auth/downstream-client-metadata.js +133 -0
  21. package/dist/auth/downstream-oauth.js +1584 -1580
  22. package/dist/auth/downstream-revocation.js +106 -0
  23. package/dist/auth/oauth-token-response.js +231 -0
  24. package/dist/auth/oauth-v2-migration.js +116 -0
  25. package/dist/auth/static-oauth.js +93 -71
  26. package/dist/auth-elicitation.js +288 -0
  27. package/dist/authorization-handoff.js +111 -0
  28. package/dist/branding.d.ts +8 -16
  29. package/dist/branding.js +26 -59
  30. package/dist/byte-read-response.js +39 -0
  31. package/dist/call-admission.js +12 -16
  32. package/dist/catalog-cache.js +739 -0
  33. package/dist/catalog-drift.d.ts +50 -15
  34. package/dist/catalog-drift.js +365 -128
  35. package/dist/catalog-fingerprint.js +2 -4
  36. package/dist/catalog-freshness.js +13 -0
  37. package/dist/catalog-limits.js +2 -2
  38. package/dist/catalog-service.js +409 -225
  39. package/dist/catalog.js +43 -84
  40. package/dist/concurrency.js +3 -4
  41. package/dist/config-defaults.d.ts +39 -0
  42. package/dist/config-defaults.js +46 -0
  43. package/dist/config-schema.d.ts +181 -0
  44. package/dist/config-schema.js +435 -0
  45. package/dist/config-value-sources.js +102 -0
  46. package/dist/config.d.ts +633 -0
  47. package/dist/config.js +508 -0
  48. package/dist/connector-access.d.ts +1 -0
  49. package/dist/connector-access.js +13 -15
  50. package/dist/connector-caller.d.ts +8 -0
  51. package/dist/connector-caller.js +15 -6
  52. package/dist/connector-scope.js +1 -1
  53. package/dist/connectors/api-connector.d.ts +59 -7
  54. package/dist/connectors/api-connector.js +106 -19
  55. package/dist/connectors/api.js +4 -1
  56. package/dist/connectors/guarded-fetch.d.ts +144 -0
  57. package/dist/connectors/guarded-fetch.js +87 -38
  58. package/dist/connectors/negotiation-cache.js +46 -0
  59. package/dist/connectors/option-shapes.js +27 -0
  60. package/dist/connectors/remote-mcp.d.ts +30 -4
  61. package/dist/connectors/remote-mcp.js +1774 -320
  62. package/dist/connectors/resource-uri.js +335 -0
  63. package/dist/credential-contract.d.ts +10 -0
  64. package/dist/credential-rules.js +1 -3
  65. package/dist/credential-url.js +108 -0
  66. package/dist/credentials.d.ts +6 -1
  67. package/dist/credentials.js +27 -18
  68. package/dist/d1.d.ts +130 -0
  69. package/dist/d1.js +290 -0
  70. package/dist/describe-config.d.ts +165 -0
  71. package/dist/describe-config.js +315 -0
  72. package/dist/described.js +106 -0
  73. package/dist/downstream-input-context.js +128 -0
  74. package/dist/downstream-input.js +325 -0
  75. package/dist/errors.d.ts +132 -31
  76. package/dist/errors.js +175 -87
  77. package/dist/execute.js +798 -318
  78. package/dist/executor-admission.d.ts +1 -0
  79. package/dist/executor-admission.js +11 -15
  80. package/dist/executor-contract.d.ts +20 -0
  81. package/dist/executor-contract.js +48 -0
  82. package/dist/executor-result.js +30 -13
  83. package/dist/executors/quickjs-child.js +15 -9
  84. package/dist/executors/quickjs-protocol.js +5 -6
  85. package/dist/executors/quickjs-runtime.js +152 -59
  86. package/dist/executors/quickjs.js +49 -39
  87. package/dist/favicon.js +1 -2
  88. package/dist/fix-prompt.js +1 -3
  89. package/dist/guest-runtime.js +238 -0
  90. package/dist/guest-types.d.ts +218 -0
  91. package/dist/guest-types.js +1 -0
  92. package/dist/html-security.js +24 -0
  93. package/dist/identity.js +1 -3
  94. package/dist/inbound-credential.js +52 -0
  95. package/dist/index.d.ts +24 -256
  96. package/dist/index.js +65 -478
  97. package/dist/invocation-auth.js +69 -0
  98. package/dist/invocation.js +262 -79
  99. package/dist/json-schema.d.ts +1 -1
  100. package/dist/mcp-client-context.js +35 -0
  101. package/dist/mcp-result.js +11 -7
  102. package/dist/meta-output.js +61 -0
  103. package/dist/meta-tool-names.d.ts +2 -0
  104. package/dist/meta-tool-names.js +3 -0
  105. package/dist/meta-tools.js +419 -272
  106. package/dist/module-contracts.d.ts +8 -23
  107. package/dist/node.d.ts +0 -2
  108. package/dist/node.js +2 -2
  109. package/dist/oauth-callback-outcome.js +1 -3
  110. package/dist/oauth-handoff.js +194 -0
  111. package/dist/oauth-sealing.js +20 -0
  112. package/dist/operator-record.d.ts +137 -0
  113. package/dist/operator-record.js +420 -0
  114. package/dist/operator-ui/assets.js +31 -0
  115. package/dist/operator-ui/contract.d.ts +72 -0
  116. package/dist/operator-ui/contract.js +1 -0
  117. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  118. package/dist/operator-ui/generated.js +5 -4
  119. package/dist/operator-ui/model.d.ts +12 -87
  120. package/dist/operator-ui/model.js +2 -9
  121. package/dist/operator-ui/setup-commands.js +1 -3
  122. package/dist/operator-ui/view.d.ts +323 -0
  123. package/dist/operator-ui/view.js +62 -189
  124. package/dist/page-styles.js +2 -3
  125. package/dist/program-result.js +5 -0
  126. package/dist/program-source.js +14 -2
  127. package/dist/{exempt-writes.js → program-writes.js} +60 -19
  128. package/dist/provider.d.ts +142 -0
  129. package/dist/provider.js +187 -0
  130. package/dist/providers/_shared/google/result-size.js +57 -0
  131. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  132. package/dist/providers/_shared/google/service-account.js +500 -0
  133. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  134. package/dist/providers/_shared/google/workspace.js +518 -0
  135. package/dist/providers/_shared/request-token.js +83 -0
  136. package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
  137. package/dist/providers/basecamp/index.js +997 -0
  138. package/dist/providers/basecamp/skill.generated.js +9 -0
  139. package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
  140. package/dist/providers/{breeze.js → breeze/index.js} +184 -140
  141. package/dist/providers/breeze/skill.generated.js +9 -0
  142. package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
  143. package/dist/providers/{ccb.js → ccb/index.js} +271 -116
  144. package/dist/providers/ccb/skill.generated.js +9 -0
  145. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  146. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  147. package/dist/providers/cloudflare/skill.generated.js +10 -0
  148. package/dist/providers/docs/index.d.ts +54 -0
  149. package/dist/providers/docs/index.js +1237 -0
  150. package/dist/providers/docs/skill.generated.js +9 -0
  151. package/dist/providers/drive/index.d.ts +53 -0
  152. package/dist/providers/drive/index.js +1523 -0
  153. package/dist/providers/drive/skill.generated.js +9 -0
  154. package/dist/providers/forms/index.d.ts +54 -0
  155. package/dist/providers/forms/index.js +1217 -0
  156. package/dist/providers/forms/skill.generated.js +11 -0
  157. package/dist/providers/github/auth.d.ts +32 -0
  158. package/dist/providers/github/auth.js +361 -0
  159. package/dist/providers/github/hosted.js +218 -0
  160. package/dist/providers/github/index.d.ts +13 -0
  161. package/dist/providers/github/index.js +140 -0
  162. package/dist/providers/github/key.js +100 -0
  163. package/dist/providers/github/rest.js +321 -0
  164. package/dist/providers/github/scope.d.ts +29 -0
  165. package/dist/providers/github/scope.js +124 -0
  166. package/dist/providers/github/skill.generated.js +8 -0
  167. package/dist/providers/gmail/index.d.ts +51 -0
  168. package/dist/providers/gmail/index.js +1436 -0
  169. package/dist/providers/gmail/skill.generated.js +9 -0
  170. package/dist/providers/infisical/index.d.ts +7 -0
  171. package/dist/providers/infisical/index.js +713 -0
  172. package/dist/providers/infisical/skill.generated.js +8 -0
  173. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  174. package/dist/providers/linear/index.js +352 -0
  175. package/dist/providers/linear/skill.generated.js +8 -0
  176. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  177. package/dist/providers/mixpanel/index.js +416 -0
  178. package/dist/providers/mixpanel/skill.generated.js +9 -0
  179. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  180. package/dist/providers/{notion.js → notion/index.js} +226 -239
  181. package/dist/providers/notion/skill.generated.js +10 -0
  182. package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
  183. package/dist/providers/{overflow.js → overflow/index.js} +74 -111
  184. package/dist/providers/overflow/skill.generated.js +8 -0
  185. package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
  186. package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
  187. package/dist/providers/planning-center/skill.generated.js +10 -0
  188. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  189. package/dist/providers/revenuecat/index.js +557 -0
  190. package/dist/providers/revenuecat/skill.generated.js +11 -0
  191. package/dist/providers/sheets/index.d.ts +54 -0
  192. package/dist/providers/sheets/index.js +1237 -0
  193. package/dist/providers/sheets/skill.generated.js +10 -0
  194. package/dist/providers/slides/index.d.ts +53 -0
  195. package/dist/providers/slides/index.js +2645 -0
  196. package/dist/providers/slides/skill.generated.js +9 -0
  197. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  198. package/dist/providers/stripe/index.js +266 -0
  199. package/dist/providers/stripe/skill.generated.js +11 -0
  200. package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
  201. package/dist/providers/{tithely.js → tithely/index.js} +60 -91
  202. package/dist/providers/tithely/skill.generated.js +8 -0
  203. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  204. package/dist/providers/vercel/index.js +1038 -0
  205. package/dist/providers/vercel/mcp-ownership.js +212 -0
  206. package/dist/providers/vercel/skill.generated.js +11 -0
  207. package/dist/registry.d.ts +110 -171
  208. package/dist/registry.js +588 -927
  209. package/dist/request-state.js +21 -0
  210. package/dist/resource-read.js +103 -0
  211. package/dist/result-shapes.js +17 -49
  212. package/dist/retired-toolkits.js +1 -1
  213. package/dist/routes/access-tokens.js +3 -6
  214. package/dist/routes/activity-context.js +21 -0
  215. package/dist/routes/activity-disclosure.js +40 -0
  216. package/dist/routes/activity.js +59 -21
  217. package/dist/routes/actor-labels.js +3 -50
  218. package/dist/routes/connect.js +221 -0
  219. package/dist/routes/credentials.js +15 -27
  220. package/dist/routes/mcp.js +365 -130
  221. package/dist/routes/oauth-client-metadata.js +15 -0
  222. package/dist/routes/oauth-management.js +45 -107
  223. package/dist/routes/oauth.js +110 -57
  224. package/dist/routes/operator.js +3 -3
  225. package/dist/routes/shared.d.ts +25 -64
  226. package/dist/routes/shared.js +160 -80
  227. package/dist/routes/skills.js +30 -0
  228. package/dist/routes/ui-config.js +225 -0
  229. package/dist/routes/ui-data.js +40 -35
  230. package/dist/routes/ui.js +66 -56
  231. package/dist/runtime/admission.js +4 -2
  232. package/dist/runtime/call-admission.js +3 -1
  233. package/dist/runtime/connector-scope.js +1 -4
  234. package/dist/runtime/run.js +10 -39
  235. package/dist/runtime/services.js +12 -117
  236. package/dist/runtime/shared-read.js +1 -3
  237. package/dist/runtime/storage.js +8 -1
  238. package/dist/sent-secrets.d.ts +93 -0
  239. package/dist/sent-secrets.js +1013 -0
  240. package/dist/server.js +28 -71
  241. package/dist/skills.js +416 -174
  242. package/dist/sqlite.d.ts +48 -0
  243. package/dist/sqlite.js +181 -0
  244. package/dist/storage/keys.js +443 -0
  245. package/dist/storage/memory.js +16 -4
  246. package/dist/storage/sql.d.ts +66 -0
  247. package/dist/storage/sql.js +543 -0
  248. package/dist/timeout.js +4 -2
  249. package/dist/tool-name.js +17 -0
  250. package/dist/tool-safety.d.ts +9 -35
  251. package/dist/tool-safety.js +20 -40
  252. package/dist/types.d.ts +336 -56
  253. package/dist/types.js +0 -1
  254. package/dist/ui.d.ts +7 -19
  255. package/dist/ui.js +76 -90
  256. package/dist/url-safety.js +3 -6
  257. package/dist/usage-guide.js +146 -0
  258. package/dist/validate.d.ts +7 -0
  259. package/dist/validate.js +309 -47
  260. package/dist/version.d.ts +1 -7
  261. package/dist/version.js +3 -7
  262. package/dist/worker.d.ts +11 -0
  263. package/dist/worker.js +435 -0
  264. package/documentation/README.md +63 -0
  265. package/documentation/architecture.md +696 -231
  266. package/documentation/auth.md +1069 -546
  267. package/documentation/code-mode.md +662 -356
  268. package/documentation/deploying.md +146 -0
  269. package/documentation/integrating.md +159 -0
  270. package/documentation/meta-tools.md +570 -216
  271. package/documentation/operating.md +135 -0
  272. package/documentation/operator-tests.md +97 -0
  273. package/documentation/operator-ui.md +132 -0
  274. package/documentation/provider-migration-0.29.md +65 -0
  275. package/examples/worker/AGENTS.md +34 -12
  276. package/examples/worker/README.md +293 -255
  277. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  278. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  279. package/examples/worker/src/connecta.config.ts +151 -0
  280. package/examples/worker/src/index.ts +14 -197
  281. package/examples/worker/wrangler.jsonc +15 -35
  282. package/package.json +126 -54
  283. package/templates/node/.dockerignore +1 -2
  284. package/templates/node/.env.example +20 -21
  285. package/templates/node/AGENTS.md +21 -17
  286. package/templates/node/Dockerfile +3 -5
  287. package/templates/node/README.md +140 -58
  288. package/templates/node/docker-compose.yml +11 -12
  289. package/templates/node/package.json +4 -2
  290. package/templates/node/src/connecta.config.ts +119 -0
  291. package/templates/node/src/index.ts +9 -154
  292. package/templates/node/src/provision-token.ts +17 -0
  293. package/AGENTS.md +0 -170
  294. package/dist/artifacts/connector.d.ts +0 -58
  295. package/dist/artifacts/connector.js +0 -730
  296. package/dist/artifacts/document.js +0 -86
  297. package/dist/artifacts/guide.js +0 -140
  298. package/dist/artifacts/html-scan.js +0 -329
  299. package/dist/artifacts/json.js +0 -78
  300. package/dist/artifacts/kv-store.d.ts +0 -20
  301. package/dist/artifacts/kv-store.js +0 -140
  302. package/dist/artifacts/markdown.js +0 -478
  303. package/dist/artifacts/module.d.ts +0 -37
  304. package/dist/artifacts/module.js +0 -66
  305. package/dist/artifacts/operations.d.ts +0 -197
  306. package/dist/artifacts/operations.js +0 -1002
  307. package/dist/artifacts/refresh.d.ts +0 -55
  308. package/dist/artifacts/refresh.js +0 -236
  309. package/dist/artifacts/routes.js +0 -206
  310. package/dist/artifacts/types.d.ts +0 -214
  311. package/dist/artifacts/types.js +0 -22
  312. package/dist/artifacts/validate.d.ts +0 -62
  313. package/dist/artifacts/validate.js +0 -651
  314. package/dist/artifacts.d.ts +0 -6
  315. package/dist/artifacts.js +0 -9
  316. package/dist/auth/bearer.d.ts +0 -11
  317. package/dist/auth/bearer.js +0 -50
  318. package/dist/providers/basecamp.js +0 -445
  319. package/dist/providers/linear.js +0 -217
  320. package/dist/providers/mixpanel.js +0 -247
  321. package/dist/providers/revenuecat.js +0 -317
  322. package/dist/providers/stripe.js +0 -253
  323. package/dist/providers/vercel.js +0 -1253
  324. package/dist/storage/file.d.ts +0 -15
  325. package/dist/storage/file.js +0 -455
  326. package/ethos.md +0 -93
  327. package/examples/worker/src/cloudflare-kv.ts +0 -43
  328. package/examples/worker/src/d1-activity-row.ts +0 -155
  329. package/examples/worker/src/d1-activity.ts +0 -147
  330. package/examples/worker/src/d1-storage.ts +0 -138
  331. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  332. package/templates/node/src/file-activity.ts +0 -182
package/dist/worker.js ADDED
@@ -0,0 +1,435 @@
1
+ // The upstream sandbox, with request-owned loader/RPC handles. A guest's
2
+ // deadline cannot clean up after the parent response has already ended.
3
+ import { DynamicWorkerExecutor, normalizeCode } from "@cloudflare/codemode";
4
+ import { AdmissionController, ExecutorExecutionError } from "./executor-admission.js";
5
+ import { brandExecutor } from "./executor-contract.js";
6
+ import { InvocationFailure } from "./invocation.js";
7
+ import { parse } from "acorn";
8
+ import { guestInitializer, guestPrelude, guestPromiseInitializer, isolateGuestProgram } from "./guest-runtime.js";
9
+ /** Parse guest syntax before rewriting imports; strings and regexes are data. */
10
+ function routeGuestImports(source) {
11
+ const offsets = [];
12
+ const visit = (node) => {
13
+ if (node.type === "ImportExpression")
14
+ offsets.push(node.start - "export default (".length);
15
+ for (const value of Object.values(node)) {
16
+ if (Array.isArray(value)) {
17
+ for (const child of value)
18
+ if (child && typeof child === "object" && "type" in child)
19
+ visit(child);
20
+ }
21
+ else if (value && typeof value === "object" && "type" in value)
22
+ visit(value);
23
+ }
24
+ };
25
+ const module = parse(`export default (${source}\n);`, {
26
+ ecmaVersion: "latest",
27
+ sourceType: "module",
28
+ locations: true,
29
+ });
30
+ // Closing the parentheses and adding statements must never create module
31
+ // code outside this one expression. Check the assembled splice, including
32
+ // comments and all grouping parentheses, before the loader sees any source.
33
+ if (module.body.length !== 1 || module.body[0]?.type !== "ExportDefaultDeclaration") {
34
+ throw new SyntaxError("A Worker program must contain exactly one expression.");
35
+ }
36
+ visit(module);
37
+ for (const offset of offsets.sort((a, b) => b - a)) {
38
+ source = source.slice(0, offset) + "__connecta_import" + source.slice(offset + 6);
39
+ }
40
+ return source;
41
+ }
42
+ /** Loader-only upstream sandbox whose lease disposes handles at run end. */
43
+ export function workerExecutor(options) {
44
+ const admission = new AdmissionController(options.admission ?? {
45
+ concurrency: 2,
46
+ maxQueueSize: 8,
47
+ queueTimeoutMs: 5_000,
48
+ retryAfterMs: 1_000,
49
+ });
50
+ const active = new Set();
51
+ return brandExecutor({
52
+ name: "DynamicWorkerExecutor",
53
+ async acquire(request = {}) {
54
+ const permit = await admission.acquire(request);
55
+ const disposers = [];
56
+ let released = false;
57
+ let executed = false;
58
+ let runEnded = false;
59
+ let cancel;
60
+ let hostProviders;
61
+ const hostFailures = new Map();
62
+ // An upstream evaluation can remain pending after disposal. Its
63
+ // dispatchers retain only these forwarders, detached on lease release.
64
+ const forward = (index, name) => async (...args) => {
65
+ const fn = hostProviders?.[index]?.fns[name];
66
+ try {
67
+ if (!fn)
68
+ throw new Error("The Worker run ended.");
69
+ return { ok: true, value: await fn(...args) };
70
+ }
71
+ catch (error) {
72
+ const message = error instanceof Error ? error.message : "Host call failed.";
73
+ if (error instanceof InvocationFailure && !released && !runEnded) {
74
+ const failureId = crypto.randomUUID();
75
+ hostFailures.set(failureId, error.details);
76
+ // The codec may expose the copy to guest hooks. The authoritative
77
+ // record never leaves this host-side map.
78
+ return {
79
+ ok: false,
80
+ error: {
81
+ message,
82
+ code: error.details.code,
83
+ retryable: error.details.retryable,
84
+ details: structuredClone(error.details),
85
+ },
86
+ failureId,
87
+ };
88
+ }
89
+ return { ok: false, error: { message } };
90
+ }
91
+ };
92
+ let rpcOutcome;
93
+ // Keep each native method's receiver and make upstream's later finally
94
+ // harmless. Release RPC stubs before the Worker Loader handle.
95
+ const track = (resource, entrypoint = false) => {
96
+ let disposed = false;
97
+ const dispose = () => {
98
+ if (disposed)
99
+ return;
100
+ disposed = true;
101
+ const method = Reflect.get(resource, Symbol.dispose);
102
+ if (typeof method === "function")
103
+ method.call(resource);
104
+ };
105
+ disposers.push(dispose);
106
+ return new Proxy(resource, {
107
+ get(target, key) {
108
+ if (key === Symbol.dispose)
109
+ return dispose;
110
+ if (key === "getEntrypoint" && !entrypoint) {
111
+ return (...args) => track(Reflect.apply(Reflect.get(target, key), target, args), true);
112
+ }
113
+ if (key === "evaluate" && entrypoint)
114
+ return async (...args) => {
115
+ const result = (await Reflect.apply(Reflect.get(target, key), target, args));
116
+ // Only the native RPC return channel supplies executor facts.
117
+ rpcOutcome = result;
118
+ return result;
119
+ };
120
+ const value = Reflect.get(target, key);
121
+ return typeof value === "function" ? (...args) => Reflect.apply(value, target, args) : value;
122
+ },
123
+ });
124
+ };
125
+ let executableCode;
126
+ let guestProgram;
127
+ let normalizationLines = 0;
128
+ const loader = new Proxy(options.loader, {
129
+ get(target, key) {
130
+ if (key === "load")
131
+ return (...args) => {
132
+ if (released)
133
+ throw new Error("Executor lease was already released.");
134
+ const definition = args[0];
135
+ const source = definition?.modules?.["executor.js"];
136
+ // Keep guest source in its own module, outside the lexical scope of
137
+ // RPC dispatchers and retained host-failure identities.
138
+ if (typeof source !== "string" || !executableCode || !hostProviders)
139
+ throw new Error("Worker executable module was unavailable.");
140
+ const index = source.indexOf(executableCode);
141
+ if (index < 0)
142
+ throw new Error("Worker executable module did not contain the program.");
143
+ const guest = guestProgram;
144
+ if (guest)
145
+ normalizationLines = 0;
146
+ const names = hostProviders.map((provider) => provider.name).join(", ");
147
+ const globals = hostProviders
148
+ .map((provider) => `globalThis[${JSON.stringify(provider.name)}] = ${provider.name};`)
149
+ .join("\n");
150
+ let isolated = source.slice(0, index) + "__connecta_program" + source.slice(index + executableCode.length);
151
+ const bridge = `if (data.error) throw new Error(data.error);\n return data.result;`;
152
+ if (hostProviders.length > 0 && !isolated.includes(bridge))
153
+ throw new Error("Worker bridge contract changed.");
154
+ isolated = isolated.replaceAll(bridge, `if (data.error) throw new NativeError(data.error);
155
+ const reply = data.result;
156
+ if (!reply.ok) {
157
+ const error = new NativeError(reply.error.message);
158
+ if (typeof reply.failureId === "string") {
159
+ retain(failures, error, reply.failureId);
160
+ defineProperties(error, {
161
+ code: { value: reply.error.code, enumerable: true },
162
+ retryable: { value: reply.error.retryable, enumerable: true },
163
+ details: { value: freeze(clone(reply.error.details)), enumerable: true },
164
+ data: { value: freeze(clone(reply.error.details)), enumerable: true }
165
+ });
166
+ }
167
+ throw error;
168
+ }
169
+ return reply.value;`);
170
+ isolated = isolated.replace(" const __logs = [];", ` if (initialized) throw new NativeError("Worker initialization is single-use.");
171
+ initialized = true;
172
+ const failures = new NativeWeakMap();
173
+ const timeoutError = new NativeError("Execution timed out");
174
+ const __logs = [];`);
175
+ isolated = isolated.replace('new Error("Execution timed out")', "timeoutError");
176
+ isolated = isolated.replace("setTimeout(() => reject(timeoutError)", "nativeSetTimeout(() => reject(timeoutError)");
177
+ isolated = isolated.replace("return { result: undefined, error: err.message, logs: __logs };", `
178
+ const failureId = lookup(failures, err);
179
+ let name = "Error", message = "Program threw a value.", stack = "";
180
+ try {
181
+ if (typeof err === "string") message = slice(err, 0, 1000);
182
+ else if (err) {
183
+ if (typeof err.name === "string") name = slice(err.name, 0, 64);
184
+ if (typeof err.message === "string") message = slice(err.message, 0, 1000);
185
+ if (typeof err.stack === "string") stack = slice(err.stack, 0, 1000);
186
+ }
187
+ } catch {}
188
+ const location = exec(/connecta-guest\\.js:(\\d+):\\d+/, stack);
189
+ return { result: undefined, error: message, logs: __logs, failure: {
190
+ name, ...(failureId ? { failureId } : {}), ...(location ? { line: toNumber(location[1]) - 1 } : {}),
191
+ ...(err === timeoutError ? { timeout: { elapsedMs: ${options.timeout ?? 60_000}, deadlineMs: ${options.timeout ?? 60_000} } } : {})
192
+ } };`);
193
+ const preludes = [];
194
+ let firstInitializer;
195
+ for (const provider of hostProviders) {
196
+ if (!provider.prelude)
197
+ continue;
198
+ if (!isolated.includes(provider.prelude))
199
+ throw new Error("Worker provider setup was unavailable.");
200
+ preludes.push(provider.prelude);
201
+ const call = firstInitializer ? "" : `__connecta_initialize(${names});`;
202
+ isolated = isolated.replace(provider.prelude, call);
203
+ firstInitializer ||= call;
204
+ }
205
+ // Successive preludes share lexical bindings in both executors.
206
+ const captureGuest = preludes.includes(guestPrelude());
207
+ const initializer = preludes.length
208
+ ? `const __connecta_initialize = (${names}) => {\n${preludes.map((prelude) => (prelude === guestPrelude() ? "__connecta_guest_initialize(connecta);" : prelude)).join("\n")}\n};\n`
209
+ : "";
210
+ // Runner modules are inaccessible to guest imports. The callback has
211
+ // no lexical access to initialization or RPC dispatchers.
212
+ const programName = guest ? "__connecta_user_program" : "__connecta_program";
213
+ const imports = 'import Runner from "./connecta-runner.js";\n' + `import program from "./connecta-guest.js";\n`;
214
+ const wrapper = guest ? ` const __connecta_program = (${guest.wrapper});\n` : "";
215
+ const hardening = `
216
+ const builtinAllowed = name => typeof name === "string" && name !== "module" && name !== "node:module" && name !== "process" && name !== "node:process";
217
+ if (typeof process !== "undefined" && typeof process.getBuiltinModule === "function") {
218
+ const getBuiltin = process.getBuiltinModule.bind(process);
219
+ Object.defineProperty(process, "getBuiltinModule", { configurable: false, writable: false,
220
+ value: name => builtinAllowed(name) ? getBuiltin(name) : undefined });
221
+ }
222
+ `;
223
+ // ESM evaluates the first dependency completely before the next.
224
+ // This module has no guest dependency; its references and retained
225
+ // failures stay private, and guest imports cannot reach its export.
226
+ const captures = `
227
+ const {
228
+ NativeError, NativeWeakMap, NativeProxy, NativePromise, NativeUint8Array, NativeArrayBuffer,
229
+ defineProperties, freeze, clone, retain, lookup, slice, nativeSetTimeout, toNumber, exec,
230
+ hasOwn, push, map, join, toString, fromCharCode, min, subarray, charCodeAt, bufferSlice,
231
+ isView, nativeBtoa, nativeAtob, race, jsonParse, jsonStringify, nativeConsole
232
+ } = Object.freeze({
233
+ NativeError: Error, NativeWeakMap: WeakMap, NativeProxy: Proxy, NativePromise: Promise,
234
+ NativeUint8Array: Uint8Array, NativeArrayBuffer: ArrayBuffer,
235
+ defineProperties: Object.defineProperties, freeze: Object.freeze, clone: structuredClone,
236
+ retain: Function.prototype.call.bind(WeakMap.prototype.set),
237
+ lookup: Function.prototype.call.bind(WeakMap.prototype.get),
238
+ slice: Function.prototype.call.bind(String.prototype.slice),
239
+ nativeSetTimeout: setTimeout, toNumber: Number,
240
+ exec: Function.prototype.call.bind(RegExp.prototype.exec),
241
+ hasOwn: Function.prototype.call.bind(Object.prototype.hasOwnProperty),
242
+ push: Function.prototype.call.bind(Array.prototype.push),
243
+ map: Function.prototype.call.bind(Array.prototype.map),
244
+ join: Function.prototype.call.bind(Array.prototype.join), toString: String,
245
+ fromCharCode: String.fromCharCode, min: Math.min,
246
+ subarray: Function.prototype.call.bind(Uint8Array.prototype.subarray),
247
+ charCodeAt: Function.prototype.call.bind(String.prototype.charCodeAt),
248
+ bufferSlice: Function.prototype.call.bind(ArrayBuffer.prototype.slice),
249
+ isView: ArrayBuffer.isView, nativeBtoa: btoa, nativeAtob: atob,
250
+ race: Promise.race.bind(Promise), jsonParse: JSON.parse, jsonStringify: JSON.stringify,
251
+ nativeConsole: console
252
+ });
253
+ `;
254
+ const binaryTagCheck = "(__CODEMODE_BINARY_TAG in value)";
255
+ const binaryDataCheck = 'typeof value.data !== "string"';
256
+ if (!isolated.includes(binaryTagCheck) || !isolated.includes(binaryDataCheck)) {
257
+ throw new Error("Worker binary codec contract changed.");
258
+ }
259
+ isolated = isolated
260
+ .replace("async evaluate(__dispatchers = {}, __connectors = {}) {", `async evaluate(__dispatchers = {}, __connectors = {}, ${programName}) {\n${wrapper}`)
261
+ .replaceAll("JSON.parse(", "jsonParse(")
262
+ .replaceAll("JSON.stringify(", "jsonStringify(")
263
+ .replaceAll(binaryTagCheck, "hasOwn(value, __CODEMODE_BINARY_TAG)")
264
+ .replaceAll(binaryDataCheck, '!hasOwn(value, "data") || typeof value.data !== "string"')
265
+ .replaceAll("console.", "nativeConsole.")
266
+ .replaceAll("new Proxy(", "new NativeProxy(")
267
+ .replaceAll("Object.prototype.hasOwnProperty.call(target, toolName)", "hasOwn(target, toolName)")
268
+ .replaceAll("String(toolName)", "toString(toolName)")
269
+ .replaceAll('a.map(String).join(" ")', 'join(map(a, toString), " ")')
270
+ .replaceAll("__logs.push(", "push(__logs, ")
271
+ .replaceAll("String.fromCharCode(", "fromCharCode(")
272
+ .replaceAll("bytes.subarray(i, Math.min(i + chunkSize, bytes.byteLength))", "subarray(bytes, i, min(i + chunkSize, bytes.byteLength))")
273
+ .replaceAll("btoa(binary)", "nativeBtoa(binary)")
274
+ .replaceAll("atob(b64)", "nativeAtob(b64)")
275
+ .replaceAll("new Uint8Array(", "new NativeUint8Array(")
276
+ .replaceAll("instanceof Uint8Array", "instanceof NativeUint8Array")
277
+ .replaceAll("instanceof ArrayBuffer", "instanceof NativeArrayBuffer")
278
+ .replaceAll("ArrayBuffer.isView(", "isView(")
279
+ .replaceAll("binary.charCodeAt(i)", "charCodeAt(binary, i)")
280
+ .replaceAll("bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)", "bufferSlice(bytes.buffer, bytes.byteOffset, bytes.byteOffset + bytes.byteLength)")
281
+ .replaceAll("Promise.race(", "race(")
282
+ .replaceAll("new Promise(", "new NativePromise(");
283
+ // Recompute the insertion point after changing the generated runner.
284
+ const setup = firstInitializer
285
+ ? isolated.indexOf(firstInitializer)
286
+ : isolated.indexOf(" try {\n const result = await race");
287
+ if (setup < 0)
288
+ throw new Error("Worker provider setup was unavailable.");
289
+ const runner = hardening +
290
+ (captureGuest
291
+ ? `const __connecta_guest_initialize = ${guestInitializer()};\n`
292
+ : `${guestPromiseInitializer()};\n`) +
293
+ captures +
294
+ "let initialized = false;\n" +
295
+ initializer +
296
+ isolated.slice(0, setup) +
297
+ globals +
298
+ "\n" +
299
+ isolated.slice(setup);
300
+ const main = imports +
301
+ `export default class CodeExecutor extends Runner {
302
+ evaluate(dispatchers, connectors) { return super.evaluate(dispatchers, connectors, program); }
303
+ }`;
304
+ const routed = routeGuestImports(guest?.program ?? executableCode);
305
+ return track(Reflect.apply(Reflect.get(target, key), target, [
306
+ {
307
+ ...definition,
308
+ modules: {
309
+ ...definition.modules,
310
+ "executor.js": main,
311
+ "connecta-runner.js": runner,
312
+ "connecta-guest.js": `const startsWith = Function.prototype.call.bind(String.prototype.startsWith); const reject = Promise.reject.bind(Promise); const NativeError = Error; const __connecta_import = specifier => typeof specifier === "string" && ((startsWith(specifier, "node:") && specifier !== "node:module" && specifier !== "node:process") || specifier === "cloudflare:workers") ? import(specifier) : reject(new NativeError("Imports of runner modules are outside the guest API."));\nexport default (${routed}\n);`,
313
+ },
314
+ },
315
+ ...args.slice(1),
316
+ ]));
317
+ };
318
+ const value = Reflect.get(target, key);
319
+ return typeof value === "function" ? (...args) => Reflect.apply(value, target, args) : value;
320
+ },
321
+ });
322
+ const lease = {
323
+ waitMs: permit.waitMs,
324
+ async execute(code, providers) {
325
+ if (released)
326
+ throw new Error("Executor lease was already released.");
327
+ if (executed)
328
+ throw new Error("Executor lease may execute only once.");
329
+ executed = true;
330
+ hostProviders = providers;
331
+ // Extract the fixed wrapper from the original source. Upstream may
332
+ // wrap invalid syntax as a bare body; that must not turn an attempted
333
+ // module escape into runnable statements or shift guest locations.
334
+ guestProgram = isolateGuestProgram(code.trim());
335
+ executableCode = normalizeCode(code);
336
+ const original = executableCode.indexOf(code.trim());
337
+ if (original >= 0)
338
+ normalizationLines = executableCode.slice(0, original).split("\n").length - 1;
339
+ const detached = providers.map((provider, index) => ({
340
+ name: provider.name,
341
+ ...(provider.prelude ? { prelude: provider.prelude } : {}),
342
+ fns: Object.fromEntries(Object.keys(provider.fns).map((name) => [name, forward(index, name)])),
343
+ }));
344
+ const stopped = new Promise((_resolve, reject) => {
345
+ cancel = () => reject(new ExecutorExecutionError("executor_cancelled", "Worker executor lease was released during execution."));
346
+ });
347
+ const started = Date.now();
348
+ try {
349
+ const result = await Promise.race([
350
+ new DynamicWorkerExecutor({
351
+ loader,
352
+ ...(options.timeout !== undefined ? { timeout: options.timeout } : {}),
353
+ }).execute(code, detached),
354
+ stopped,
355
+ ]);
356
+ const outcome = rpcOutcome ?? result;
357
+ if (outcome.failure) {
358
+ const failure = { ...outcome.failure };
359
+ const call = typeof failure.failureId === "string" ? hostFailures.get(failure.failureId) : undefined;
360
+ // Neither an unknown id nor a guest/RPC-supplied call record
361
+ // supplies typed host details. Strip the private id at the edge.
362
+ delete failure.call;
363
+ delete failure.failureId;
364
+ outcome.failure = { ...failure, ...(call ? { call } : {}) };
365
+ }
366
+ if (outcome.failure?.timeout)
367
+ outcome.failure.timeout.elapsedMs = Date.now() - started;
368
+ return outcome;
369
+ }
370
+ catch (error) {
371
+ const message = error instanceof Error ? error.message : "";
372
+ // Worker Loader erases the native SyntaxError type at its RPC edge.
373
+ // Match its startup diagnostic only; guest/downstream failures return normally.
374
+ const syntax = /^Failed to start Worker:\nUncaught SyntaxError: ([^\n]*)\n\s+at connecta-guest\.js:(\d+):\d+$/.exec(message);
375
+ if (error instanceof SyntaxError || syntax) {
376
+ const location = error instanceof SyntaxError && "loc" in error ? error.loc : undefined;
377
+ const line = syntax
378
+ ? Math.max(1, Number(syntax[2]) - normalizationLines - 1)
379
+ : location?.line !== undefined
380
+ ? Math.max(1, location.line)
381
+ : undefined;
382
+ return {
383
+ result: undefined,
384
+ error: (syntax?.[1] ?? message) || "Invalid JavaScript program.",
385
+ failure: { name: "SyntaxError", ...(line !== undefined ? { line } : {}) },
386
+ };
387
+ }
388
+ throw error;
389
+ }
390
+ finally {
391
+ runEnded = true;
392
+ cancel = undefined;
393
+ hostFailures.clear();
394
+ }
395
+ },
396
+ release() {
397
+ if (released)
398
+ return;
399
+ released = true;
400
+ hostProviders = undefined;
401
+ hostFailures.clear();
402
+ cancel?.();
403
+ for (const dispose of disposers.reverse()) {
404
+ try {
405
+ dispose();
406
+ }
407
+ catch {
408
+ /* Release every handle and the permit. */
409
+ }
410
+ }
411
+ disposers.length = 0;
412
+ active.delete(lease);
413
+ permit.release();
414
+ },
415
+ };
416
+ active.add(lease);
417
+ return lease;
418
+ },
419
+ async execute(code, providers) {
420
+ const lease = await this.acquire();
421
+ try {
422
+ return await lease.execute(code, providers);
423
+ }
424
+ finally {
425
+ lease.release();
426
+ }
427
+ },
428
+ admissionSnapshot: () => admission.snapshot(),
429
+ close() {
430
+ admission.close();
431
+ for (const lease of active)
432
+ lease.release();
433
+ },
434
+ }, "leased");
435
+ }
@@ -0,0 +1,63 @@
1
+ # Agent documentation
2
+
3
+ Choose a route by the work you are doing. Each route identifies the task guide
4
+ and contracts needed to operate an endpoint, set up a deployment, connect a
5
+ service, or change Connecta itself.
6
+
7
+ | Your task | Start here | Read next when needed |
8
+ | --------------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
9
+ | Use an existing endpoint to answer a question or perform a task | [Operating an endpoint](./operating.md) | [Meta-tools](./meta-tools.md), [guest API](./code-mode.md) |
10
+ | Set up, configure, upgrade, or diagnose a deployment | [Deploying Connecta](./deploying.md) | [Auth](./auth.md), [operator UI](./operator-ui.md) |
11
+ | Add a maintained integration, remote MCP, or HTTP API to a deployment | [Integrating services](./integrating.md) | Provider skill, [classification](./architecture.md#providers-and-reviewed-classification), [downstream auth](./auth.md#shared-and-personal-auth) |
12
+ | Change Connecta's source, tests, or published contracts | [AGENTS.md](https://github.com/zackbart/connecta/blob/main/AGENTS.md) | [Principles](https://github.com/zackbart/connecta/blob/main/PRINCIPLES.md), [architecture](./architecture.md), then the affected contract |
13
+
14
+ ## Contract reference
15
+
16
+ | Guide | Owns |
17
+ | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
18
+ | [Meta-tools](./meta-tools.md) | Six top-level tools, discovery, direct-call results, paging, skills, and recovery |
19
+ | [Code mode](./code-mode.md) | JavaScript guest API, executor requirements, output, retries, cancellation, limits, and writes |
20
+ | [Auth](./auth.md) | Inbound identity, grants, pools, machine tokens, credential ownership, and downstream OAuth |
21
+ | [Architecture](./architecture.md) | Request lifetimes, routes, storage, configuration, import boundaries, and Effect implementation |
22
+ | [Operator UI](./operator-ui.md) | Optional UI setup, scoped configuration and live-data contract, activity disclosure, and UI implementation |
23
+ | [Operator UI tests](./operator-tests.md) | Browser state matrix, real-server flows, and snapshot maintenance |
24
+ | [Provider migration for 0.29](./provider-migration-0.29.md) | Upgrade actions for Notion, Vercel, and Cloudflare; provider reconciliation tables supply exact name mappings |
25
+
26
+ Each long contract starts with task routes. Follow those section links before
27
+ reading the whole guide. Source and test pointers identify where to check a
28
+ claim or implement a change.
29
+
30
+ ## Documentation ownership
31
+
32
+ The root [README](../README.md) explains the product for people. It owns what
33
+ Connecta offers, how the pieces connect, deployment choices, and the setup
34
+ handoff. Keep JavaScript, imports, configuration, migrations, and internal
35
+ module maps here in agent documentation.
36
+
37
+ [AGENTS.md](https://github.com/zackbart/connecta/blob/main/AGENTS.md) is the
38
+ canonical repository policy, with `CLAUDE.md` as its symlink. Do not copy its
39
+ verification, review, or release rules into another policy document.
40
+
41
+ Deployment-local READMEs and agent instructions own runnable platform setup:
42
+ [Node and Docker](../templates/node/README.md), [Workers](../examples/worker/README.md).
43
+ Keep those aligned with their configuration and with this task router.
44
+ Repository [skills](https://github.com/zackbart/connecta/tree/main/.claude/skills)
45
+ own scoped change procedures. Each [provider folder](https://github.com/zackbart/connecta/tree/main/src/providers)
46
+ owns its maintained `SKILL.md`, options, tests, fixtures, and review data.
47
+ Use those details instead of copying provider catalogs into general guides.
48
+ The provider list in the human README is generated; preserve its marker pair
49
+ and run `npm run check:providers-generated` after edits.
50
+
51
+ When changing behavior, update its owning contract and task guide in the same
52
+ change. Check examples against current source and point to the tests that
53
+ defend the contract. Published Markdown links to repo-only files must use
54
+ canonical `https://github.com/zackbart/connecta/blob/main/…` or `tree/main/…`
55
+ links. Keep `documentation/` flat, with Markdown files only.
56
+
57
+ The [changelog](../CHANGELOG.md) records shipped releases.
58
+ [Decisions](https://github.com/zackbart/connecta/tree/main/decisions) explain
59
+ history and may be superseded. [Spec coverage](https://github.com/zackbart/connecta/blob/main/spec/coverage.json)
60
+ records implemented support, gaps, and test evidence. The
61
+ [0.29 plan of record](https://github.com/zackbart/connecta/issues/703) and other
62
+ issues describe planned work; do not turn their goals into claims of shipped
63
+ behavior.