@zackbart/connecta 0.28.0 → 0.29.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 (320) hide show
  1. package/CHANGELOG.md +961 -5
  2. package/README.md +62 -39
  3. package/bin/connecta.mjs +110 -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/auth/clerk-sdk/client.d.ts +65 -0
  12. package/dist/auth/clerk-sdk/client.js +5 -0
  13. package/dist/auth/clerk-sdk/generated.js +1845 -0
  14. package/dist/auth/clerk-transport.js +19 -0
  15. package/dist/auth/clerk.d.ts +17 -7
  16. package/dist/auth/clerk.js +189 -107
  17. package/dist/auth/cloudflare-access.js +25 -26
  18. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  19. package/dist/auth/downstream-client-metadata.js +133 -0
  20. package/dist/auth/downstream-oauth.js +1632 -1509
  21. package/dist/auth/downstream-revocation.js +106 -0
  22. package/dist/auth/oauth-token-response.js +231 -0
  23. package/dist/auth/oauth-v2-migration.js +116 -0
  24. package/dist/auth/static-oauth.js +526 -0
  25. package/dist/auth-elicitation.js +283 -0
  26. package/dist/branding.d.ts +8 -16
  27. package/dist/branding.js +26 -59
  28. package/dist/byte-read-response.js +39 -0
  29. package/dist/call-admission.js +12 -16
  30. package/dist/catalog-cache.js +739 -0
  31. package/dist/catalog-drift.d.ts +50 -15
  32. package/dist/catalog-drift.js +365 -128
  33. package/dist/catalog-fingerprint.js +2 -4
  34. package/dist/catalog-freshness.js +13 -0
  35. package/dist/catalog-limits.js +2 -2
  36. package/dist/catalog-service.js +368 -224
  37. package/dist/catalog.js +43 -84
  38. package/dist/concurrency.js +3 -4
  39. package/dist/config-defaults.d.ts +39 -0
  40. package/dist/config-defaults.js +46 -0
  41. package/dist/config-schema.d.ts +181 -0
  42. package/dist/config-schema.js +435 -0
  43. package/dist/config-value-sources.js +102 -0
  44. package/dist/config.d.ts +631 -0
  45. package/dist/config.js +503 -0
  46. package/dist/connector-access.d.ts +1 -0
  47. package/dist/connector-access.js +13 -15
  48. package/dist/connector-caller.d.ts +8 -0
  49. package/dist/connector-caller.js +15 -6
  50. package/dist/connector-scope.js +1 -1
  51. package/dist/connectors/api-connector.d.ts +220 -0
  52. package/dist/connectors/api-connector.js +214 -0
  53. package/dist/connectors/api.d.ts +8 -71
  54. package/dist/connectors/api.js +13 -99
  55. package/dist/connectors/guarded-fetch.d.ts +144 -0
  56. package/dist/connectors/guarded-fetch.js +108 -25
  57. package/dist/connectors/negotiation-cache.js +46 -0
  58. package/dist/connectors/option-shapes.js +27 -0
  59. package/dist/connectors/remote-mcp.d.ts +30 -4
  60. package/dist/connectors/remote-mcp.js +1780 -351
  61. package/dist/connectors/resource-uri.js +335 -0
  62. package/dist/credential-contract.d.ts +10 -0
  63. package/dist/credential-rules.js +1 -3
  64. package/dist/credential-url.js +108 -0
  65. package/dist/credentials.d.ts +6 -1
  66. package/dist/credentials.js +27 -18
  67. package/dist/d1.d.ts +130 -0
  68. package/dist/d1.js +290 -0
  69. package/dist/describe-config.d.ts +165 -0
  70. package/dist/describe-config.js +315 -0
  71. package/dist/described.js +106 -0
  72. package/dist/downstream-input-context.js +119 -0
  73. package/dist/downstream-input.js +323 -0
  74. package/dist/errors.d.ts +97 -20
  75. package/dist/errors.js +158 -80
  76. package/dist/execute.js +453 -305
  77. package/dist/executor-admission.d.ts +1 -0
  78. package/dist/executor-admission.js +11 -15
  79. package/dist/executor-contract.d.ts +20 -0
  80. package/dist/executor-contract.js +48 -0
  81. package/dist/executor-result.js +24 -9
  82. package/dist/executors/quickjs-child.js +3 -4
  83. package/dist/executors/quickjs-runtime.js +147 -59
  84. package/dist/executors/quickjs.js +29 -35
  85. package/dist/favicon.js +1 -2
  86. package/dist/fix-prompt.js +1 -3
  87. package/dist/guest-runtime.js +188 -0
  88. package/dist/guest-types.d.ts +176 -0
  89. package/dist/guest-types.js +1 -0
  90. package/dist/html-security.js +24 -0
  91. package/dist/identity.js +1 -3
  92. package/dist/inbound-credential.js +52 -0
  93. package/dist/index.d.ts +25 -257
  94. package/dist/index.js +65 -478
  95. package/dist/invocation-auth.js +69 -0
  96. package/dist/invocation.js +230 -73
  97. package/dist/json-schema.d.ts +1 -1
  98. package/dist/mcp-client-context.js +35 -0
  99. package/dist/mcp-result.js +11 -7
  100. package/dist/meta-output.js +76 -0
  101. package/dist/meta-tool-names.d.ts +2 -0
  102. package/dist/meta-tool-names.js +3 -0
  103. package/dist/meta-tools.js +285 -209
  104. package/dist/module-contracts.d.ts +8 -23
  105. package/dist/node.d.ts +0 -2
  106. package/dist/node.js +2 -2
  107. package/dist/oauth-callback-outcome.js +1 -3
  108. package/dist/oauth-handoff.js +117 -0
  109. package/dist/oauth-partition.js +17 -0
  110. package/dist/oauth-sealing.js +20 -0
  111. package/dist/operator-record.d.ts +137 -0
  112. package/dist/operator-record.js +420 -0
  113. package/dist/operator-ui/assets.js +31 -0
  114. package/dist/operator-ui/contract.d.ts +72 -0
  115. package/dist/operator-ui/contract.js +1 -0
  116. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  117. package/dist/operator-ui/generated.js +5 -4
  118. package/dist/operator-ui/model.d.ts +12 -87
  119. package/dist/operator-ui/model.js +2 -9
  120. package/dist/operator-ui/setup-commands.js +1 -3
  121. package/dist/operator-ui/view.d.ts +323 -0
  122. package/dist/operator-ui/view.js +62 -189
  123. package/dist/page-styles.js +2 -3
  124. package/dist/program-source.js +14 -2
  125. package/dist/{exempt-writes.js → program-writes.js} +55 -18
  126. package/dist/provider.d.ts +142 -0
  127. package/dist/provider.js +187 -0
  128. package/dist/providers/_shared/google/result-size.js +57 -0
  129. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  130. package/dist/providers/_shared/google/service-account.js +500 -0
  131. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  132. package/dist/providers/_shared/google/workspace.js +518 -0
  133. package/dist/providers/basecamp/index.d.ts +43 -0
  134. package/dist/providers/basecamp/index.js +997 -0
  135. package/dist/providers/basecamp/skill.generated.js +9 -0
  136. package/dist/providers/breeze/index.d.ts +34 -0
  137. package/dist/providers/breeze/index.js +1446 -0
  138. package/dist/providers/breeze/skill.generated.js +9 -0
  139. package/dist/providers/ccb/index.d.ts +103 -0
  140. package/dist/providers/ccb/index.js +1725 -0
  141. package/dist/providers/ccb/skill.generated.js +9 -0
  142. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  143. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  144. package/dist/providers/cloudflare/skill.generated.js +10 -0
  145. package/dist/providers/docs/index.d.ts +54 -0
  146. package/dist/providers/docs/index.js +1237 -0
  147. package/dist/providers/docs/skill.generated.js +9 -0
  148. package/dist/providers/drive/index.d.ts +53 -0
  149. package/dist/providers/drive/index.js +1523 -0
  150. package/dist/providers/drive/skill.generated.js +9 -0
  151. package/dist/providers/forms/index.d.ts +54 -0
  152. package/dist/providers/forms/index.js +1217 -0
  153. package/dist/providers/forms/skill.generated.js +11 -0
  154. package/dist/providers/github/auth.d.ts +32 -0
  155. package/dist/providers/github/auth.js +361 -0
  156. package/dist/providers/github/hosted.js +218 -0
  157. package/dist/providers/github/index.d.ts +13 -0
  158. package/dist/providers/github/index.js +140 -0
  159. package/dist/providers/github/key.js +100 -0
  160. package/dist/providers/github/rest.js +321 -0
  161. package/dist/providers/github/scope.d.ts +29 -0
  162. package/dist/providers/github/scope.js +124 -0
  163. package/dist/providers/github/skill.generated.js +8 -0
  164. package/dist/providers/gmail/index.d.ts +51 -0
  165. package/dist/providers/gmail/index.js +1436 -0
  166. package/dist/providers/gmail/skill.generated.js +9 -0
  167. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  168. package/dist/providers/linear/index.js +352 -0
  169. package/dist/providers/linear/skill.generated.js +8 -0
  170. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  171. package/dist/providers/mixpanel/index.js +416 -0
  172. package/dist/providers/mixpanel/skill.generated.js +9 -0
  173. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  174. package/dist/providers/{notion.js → notion/index.js} +226 -239
  175. package/dist/providers/notion/skill.generated.js +10 -0
  176. package/dist/providers/overflow/index.d.ts +60 -0
  177. package/dist/providers/overflow/index.js +1535 -0
  178. package/dist/providers/overflow/skill.generated.js +8 -0
  179. package/dist/providers/planning-center/index.d.ts +59 -0
  180. package/dist/providers/planning-center/index.js +2199 -0
  181. package/dist/providers/planning-center/skill.generated.js +10 -0
  182. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  183. package/dist/providers/revenuecat/index.js +557 -0
  184. package/dist/providers/revenuecat/skill.generated.js +11 -0
  185. package/dist/providers/sheets/index.d.ts +54 -0
  186. package/dist/providers/sheets/index.js +1237 -0
  187. package/dist/providers/sheets/skill.generated.js +10 -0
  188. package/dist/providers/slides/index.d.ts +53 -0
  189. package/dist/providers/slides/index.js +2645 -0
  190. package/dist/providers/slides/skill.generated.js +9 -0
  191. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  192. package/dist/providers/stripe/index.js +266 -0
  193. package/dist/providers/stripe/skill.generated.js +11 -0
  194. package/dist/providers/tithely/index.d.ts +49 -0
  195. package/dist/providers/tithely/index.js +1003 -0
  196. package/dist/providers/tithely/skill.generated.js +8 -0
  197. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  198. package/dist/providers/vercel/index.js +1038 -0
  199. package/dist/providers/vercel/mcp-ownership.js +212 -0
  200. package/dist/providers/vercel/skill.generated.js +11 -0
  201. package/dist/registry.d.ts +108 -171
  202. package/dist/registry.js +513 -925
  203. package/dist/request-state.js +21 -0
  204. package/dist/resource-read.js +100 -0
  205. package/dist/result-shapes.js +17 -49
  206. package/dist/retired-toolkits.js +1 -1
  207. package/dist/routes/access-tokens.js +3 -6
  208. package/dist/routes/activity-context.js +21 -0
  209. package/dist/routes/activity-disclosure.js +40 -0
  210. package/dist/routes/activity.js +59 -21
  211. package/dist/routes/actor-labels.js +3 -50
  212. package/dist/routes/connect.js +221 -0
  213. package/dist/routes/credentials.js +15 -27
  214. package/dist/routes/mcp.js +356 -130
  215. package/dist/routes/oauth-client-metadata.js +15 -0
  216. package/dist/routes/oauth-management.js +45 -107
  217. package/dist/routes/oauth.js +136 -57
  218. package/dist/routes/operator.js +3 -3
  219. package/dist/routes/shared.d.ts +25 -64
  220. package/dist/routes/shared.js +160 -80
  221. package/dist/routes/skills.js +30 -0
  222. package/dist/routes/ui-config.js +225 -0
  223. package/dist/routes/ui-data.js +40 -35
  224. package/dist/routes/ui.js +66 -56
  225. package/dist/runtime/admission.js +4 -2
  226. package/dist/runtime/call-admission.js +3 -1
  227. package/dist/runtime/connector-scope.js +1 -4
  228. package/dist/runtime/run.js +10 -39
  229. package/dist/runtime/services.js +12 -117
  230. package/dist/runtime/shared-read.js +1 -3
  231. package/dist/runtime/storage.js +8 -1
  232. package/dist/sent-secrets.d.ts +52 -0
  233. package/dist/sent-secrets.js +474 -0
  234. package/dist/server.js +28 -71
  235. package/dist/skills.js +406 -174
  236. package/dist/sqlite.d.ts +48 -0
  237. package/dist/sqlite.js +166 -0
  238. package/dist/storage/keys.js +428 -0
  239. package/dist/storage/memory.js +7 -0
  240. package/dist/storage/sql.d.ts +66 -0
  241. package/dist/storage/sql.js +534 -0
  242. package/dist/timeout.js +4 -2
  243. package/dist/tool-name.js +17 -0
  244. package/dist/tool-safety.d.ts +9 -35
  245. package/dist/tool-safety.js +20 -40
  246. package/dist/types.d.ts +320 -54
  247. package/dist/types.js +0 -1
  248. package/dist/ui.d.ts +7 -19
  249. package/dist/ui.js +76 -90
  250. package/dist/url-safety.js +3 -6
  251. package/dist/usage-guide.js +137 -0
  252. package/dist/validate.d.ts +7 -0
  253. package/dist/validate.js +309 -47
  254. package/dist/version.d.ts +1 -7
  255. package/dist/version.js +3 -7
  256. package/dist/worker.d.ts +11 -0
  257. package/dist/worker.js +434 -0
  258. package/documentation/architecture.md +665 -230
  259. package/documentation/auth.md +962 -458
  260. package/documentation/code-mode.md +501 -312
  261. package/documentation/meta-tools.md +449 -200
  262. package/documentation/operator-tests.md +93 -0
  263. package/documentation/provider-migration-0.29.md +60 -0
  264. package/examples/worker/AGENTS.md +34 -12
  265. package/examples/worker/README.md +286 -255
  266. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  267. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  268. package/examples/worker/src/connecta.config.ts +151 -0
  269. package/examples/worker/src/index.ts +14 -197
  270. package/examples/worker/wrangler.jsonc +15 -35
  271. package/package.json +125 -35
  272. package/templates/node/.dockerignore +1 -2
  273. package/templates/node/.env.example +20 -21
  274. package/templates/node/AGENTS.md +21 -17
  275. package/templates/node/Dockerfile +3 -5
  276. package/templates/node/README.md +133 -58
  277. package/templates/node/docker-compose.yml +11 -12
  278. package/templates/node/package.json +4 -2
  279. package/templates/node/src/connecta.config.ts +119 -0
  280. package/templates/node/src/index.ts +9 -154
  281. package/templates/node/src/provision-token.ts +17 -0
  282. package/AGENTS.md +0 -170
  283. package/dist/artifacts/connector.d.ts +0 -58
  284. package/dist/artifacts/connector.js +0 -730
  285. package/dist/artifacts/document.js +0 -86
  286. package/dist/artifacts/guide.js +0 -140
  287. package/dist/artifacts/html-scan.js +0 -329
  288. package/dist/artifacts/json.js +0 -78
  289. package/dist/artifacts/kv-store.d.ts +0 -20
  290. package/dist/artifacts/kv-store.js +0 -140
  291. package/dist/artifacts/markdown.js +0 -478
  292. package/dist/artifacts/module.d.ts +0 -37
  293. package/dist/artifacts/module.js +0 -66
  294. package/dist/artifacts/operations.d.ts +0 -197
  295. package/dist/artifacts/operations.js +0 -1002
  296. package/dist/artifacts/refresh.d.ts +0 -55
  297. package/dist/artifacts/refresh.js +0 -236
  298. package/dist/artifacts/routes.js +0 -206
  299. package/dist/artifacts/types.d.ts +0 -214
  300. package/dist/artifacts/types.js +0 -22
  301. package/dist/artifacts/validate.d.ts +0 -62
  302. package/dist/artifacts/validate.js +0 -651
  303. package/dist/artifacts.d.ts +0 -6
  304. package/dist/artifacts.js +0 -9
  305. package/dist/auth/bearer.d.ts +0 -11
  306. package/dist/auth/bearer.js +0 -50
  307. package/dist/providers/linear.js +0 -217
  308. package/dist/providers/mixpanel.js +0 -247
  309. package/dist/providers/revenuecat.js +0 -317
  310. package/dist/providers/stripe.js +0 -253
  311. package/dist/providers/vercel.js +0 -1253
  312. package/dist/storage/file.d.ts +0 -15
  313. package/dist/storage/file.js +0 -455
  314. package/ethos.md +0 -93
  315. package/examples/worker/src/cloudflare-kv.ts +0 -43
  316. package/examples/worker/src/d1-activity-row.ts +0 -155
  317. package/examples/worker/src/d1-activity.ts +0 -147
  318. package/examples/worker/src/d1-storage.ts +0 -138
  319. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  320. package/templates/node/src/file-activity.ts +0 -182
package/dist/worker.js ADDED
@@ -0,0 +1,434 @@
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
+ });
165
+ }
166
+ throw error;
167
+ }
168
+ return reply.value;`);
169
+ isolated = isolated.replace(" const __logs = [];", ` if (initialized) throw new NativeError("Worker initialization is single-use.");
170
+ initialized = true;
171
+ const failures = new NativeWeakMap();
172
+ const timeoutError = new NativeError("Execution timed out");
173
+ const __logs = [];`);
174
+ isolated = isolated.replace('new Error("Execution timed out")', "timeoutError");
175
+ isolated = isolated.replace("setTimeout(() => reject(timeoutError)", "nativeSetTimeout(() => reject(timeoutError)");
176
+ isolated = isolated.replace("return { result: undefined, error: err.message, logs: __logs };", `
177
+ const failureId = lookup(failures, err);
178
+ let name = "Error", message = "Program threw a value.", stack = "";
179
+ try {
180
+ if (typeof err === "string") message = slice(err, 0, 1000);
181
+ else if (err) {
182
+ if (typeof err.name === "string") name = slice(err.name, 0, 64);
183
+ if (typeof err.message === "string") message = slice(err.message, 0, 1000);
184
+ if (typeof err.stack === "string") stack = slice(err.stack, 0, 1000);
185
+ }
186
+ } catch {}
187
+ const location = exec(/connecta-guest\\.js:(\\d+):\\d+/, stack);
188
+ return { result: undefined, error: message, logs: __logs, failure: {
189
+ name, ...(failureId ? { failureId } : {}), ...(location ? { line: toNumber(location[1]) - 1 } : {}),
190
+ ...(err === timeoutError ? { timeout: { elapsedMs: ${options.timeout ?? 60_000}, deadlineMs: ${options.timeout ?? 60_000} } } : {})
191
+ } };`);
192
+ const preludes = [];
193
+ let firstInitializer;
194
+ for (const provider of hostProviders) {
195
+ if (!provider.prelude)
196
+ continue;
197
+ if (!isolated.includes(provider.prelude))
198
+ throw new Error("Worker provider setup was unavailable.");
199
+ preludes.push(provider.prelude);
200
+ const call = firstInitializer ? "" : `__connecta_initialize(${names});`;
201
+ isolated = isolated.replace(provider.prelude, call);
202
+ firstInitializer ||= call;
203
+ }
204
+ // Successive preludes share lexical bindings in both executors.
205
+ const captureGuest = preludes.includes(guestPrelude());
206
+ const initializer = preludes.length
207
+ ? `const __connecta_initialize = (${names}) => {\n${preludes.map((prelude) => (prelude === guestPrelude() ? "__connecta_guest_initialize(connecta);" : prelude)).join("\n")}\n};\n`
208
+ : "";
209
+ // Runner modules are inaccessible to guest imports. The callback has
210
+ // no lexical access to initialization or RPC dispatchers.
211
+ const programName = guest ? "__connecta_user_program" : "__connecta_program";
212
+ const imports = 'import Runner from "./connecta-runner.js";\n' + `import program from "./connecta-guest.js";\n`;
213
+ const wrapper = guest ? ` const __connecta_program = (${guest.wrapper});\n` : "";
214
+ const hardening = `
215
+ const builtinAllowed = name => typeof name === "string" && name !== "module" && name !== "node:module" && name !== "process" && name !== "node:process";
216
+ if (typeof process !== "undefined" && typeof process.getBuiltinModule === "function") {
217
+ const getBuiltin = process.getBuiltinModule.bind(process);
218
+ Object.defineProperty(process, "getBuiltinModule", { configurable: false, writable: false,
219
+ value: name => builtinAllowed(name) ? getBuiltin(name) : undefined });
220
+ }
221
+ `;
222
+ // ESM evaluates the first dependency completely before the next.
223
+ // This module has no guest dependency; its references and retained
224
+ // failures stay private, and guest imports cannot reach its export.
225
+ const captures = `
226
+ const {
227
+ NativeError, NativeWeakMap, NativeProxy, NativePromise, NativeUint8Array, NativeArrayBuffer,
228
+ defineProperties, freeze, clone, retain, lookup, slice, nativeSetTimeout, toNumber, exec,
229
+ hasOwn, push, map, join, toString, fromCharCode, min, subarray, charCodeAt, bufferSlice,
230
+ isView, nativeBtoa, nativeAtob, race, jsonParse, jsonStringify, nativeConsole
231
+ } = Object.freeze({
232
+ NativeError: Error, NativeWeakMap: WeakMap, NativeProxy: Proxy, NativePromise: Promise,
233
+ NativeUint8Array: Uint8Array, NativeArrayBuffer: ArrayBuffer,
234
+ defineProperties: Object.defineProperties, freeze: Object.freeze, clone: structuredClone,
235
+ retain: Function.prototype.call.bind(WeakMap.prototype.set),
236
+ lookup: Function.prototype.call.bind(WeakMap.prototype.get),
237
+ slice: Function.prototype.call.bind(String.prototype.slice),
238
+ nativeSetTimeout: setTimeout, toNumber: Number,
239
+ exec: Function.prototype.call.bind(RegExp.prototype.exec),
240
+ hasOwn: Function.prototype.call.bind(Object.prototype.hasOwnProperty),
241
+ push: Function.prototype.call.bind(Array.prototype.push),
242
+ map: Function.prototype.call.bind(Array.prototype.map),
243
+ join: Function.prototype.call.bind(Array.prototype.join), toString: String,
244
+ fromCharCode: String.fromCharCode, min: Math.min,
245
+ subarray: Function.prototype.call.bind(Uint8Array.prototype.subarray),
246
+ charCodeAt: Function.prototype.call.bind(String.prototype.charCodeAt),
247
+ bufferSlice: Function.prototype.call.bind(ArrayBuffer.prototype.slice),
248
+ isView: ArrayBuffer.isView, nativeBtoa: btoa, nativeAtob: atob,
249
+ race: Promise.race.bind(Promise), jsonParse: JSON.parse, jsonStringify: JSON.stringify,
250
+ nativeConsole: console
251
+ });
252
+ `;
253
+ const binaryTagCheck = "(__CODEMODE_BINARY_TAG in value)";
254
+ const binaryDataCheck = 'typeof value.data !== "string"';
255
+ if (!isolated.includes(binaryTagCheck) || !isolated.includes(binaryDataCheck)) {
256
+ throw new Error("Worker binary codec contract changed.");
257
+ }
258
+ isolated = isolated
259
+ .replace("async evaluate(__dispatchers = {}, __connectors = {}) {", `async evaluate(__dispatchers = {}, __connectors = {}, ${programName}) {\n${wrapper}`)
260
+ .replaceAll("JSON.parse(", "jsonParse(")
261
+ .replaceAll("JSON.stringify(", "jsonStringify(")
262
+ .replaceAll(binaryTagCheck, "hasOwn(value, __CODEMODE_BINARY_TAG)")
263
+ .replaceAll(binaryDataCheck, '!hasOwn(value, "data") || typeof value.data !== "string"')
264
+ .replaceAll("console.", "nativeConsole.")
265
+ .replaceAll("new Proxy(", "new NativeProxy(")
266
+ .replaceAll("Object.prototype.hasOwnProperty.call(target, toolName)", "hasOwn(target, toolName)")
267
+ .replaceAll("String(toolName)", "toString(toolName)")
268
+ .replaceAll('a.map(String).join(" ")', 'join(map(a, toString), " ")')
269
+ .replaceAll("__logs.push(", "push(__logs, ")
270
+ .replaceAll("String.fromCharCode(", "fromCharCode(")
271
+ .replaceAll("bytes.subarray(i, Math.min(i + chunkSize, bytes.byteLength))", "subarray(bytes, i, min(i + chunkSize, bytes.byteLength))")
272
+ .replaceAll("btoa(binary)", "nativeBtoa(binary)")
273
+ .replaceAll("atob(b64)", "nativeAtob(b64)")
274
+ .replaceAll("new Uint8Array(", "new NativeUint8Array(")
275
+ .replaceAll("instanceof Uint8Array", "instanceof NativeUint8Array")
276
+ .replaceAll("instanceof ArrayBuffer", "instanceof NativeArrayBuffer")
277
+ .replaceAll("ArrayBuffer.isView(", "isView(")
278
+ .replaceAll("binary.charCodeAt(i)", "charCodeAt(binary, i)")
279
+ .replaceAll("bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)", "bufferSlice(bytes.buffer, bytes.byteOffset, bytes.byteOffset + bytes.byteLength)")
280
+ .replaceAll("Promise.race(", "race(")
281
+ .replaceAll("new Promise(", "new NativePromise(");
282
+ // Recompute the insertion point after changing the generated runner.
283
+ const setup = firstInitializer
284
+ ? isolated.indexOf(firstInitializer)
285
+ : isolated.indexOf(" try {\n const result = await race");
286
+ if (setup < 0)
287
+ throw new Error("Worker provider setup was unavailable.");
288
+ const runner = hardening +
289
+ (captureGuest
290
+ ? `const __connecta_guest_initialize = ${guestInitializer()};\n`
291
+ : `${guestPromiseInitializer()};\n`) +
292
+ captures +
293
+ "let initialized = false;\n" +
294
+ initializer +
295
+ isolated.slice(0, setup) +
296
+ globals +
297
+ "\n" +
298
+ isolated.slice(setup);
299
+ const main = imports +
300
+ `export default class CodeExecutor extends Runner {
301
+ evaluate(dispatchers, connectors) { return super.evaluate(dispatchers, connectors, program); }
302
+ }`;
303
+ const routed = routeGuestImports(guest?.program ?? executableCode);
304
+ return track(Reflect.apply(Reflect.get(target, key), target, [
305
+ {
306
+ ...definition,
307
+ modules: {
308
+ ...definition.modules,
309
+ "executor.js": main,
310
+ "connecta-runner.js": runner,
311
+ "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);`,
312
+ },
313
+ },
314
+ ...args.slice(1),
315
+ ]));
316
+ };
317
+ const value = Reflect.get(target, key);
318
+ return typeof value === "function" ? (...args) => Reflect.apply(value, target, args) : value;
319
+ },
320
+ });
321
+ const lease = {
322
+ waitMs: permit.waitMs,
323
+ async execute(code, providers) {
324
+ if (released)
325
+ throw new Error("Executor lease was already released.");
326
+ if (executed)
327
+ throw new Error("Executor lease may execute only once.");
328
+ executed = true;
329
+ hostProviders = providers;
330
+ // Extract the fixed wrapper from the original source. Upstream may
331
+ // wrap invalid syntax as a bare body; that must not turn an attempted
332
+ // module escape into runnable statements or shift guest locations.
333
+ guestProgram = isolateGuestProgram(code.trim());
334
+ executableCode = normalizeCode(code);
335
+ const original = executableCode.indexOf(code.trim());
336
+ if (original >= 0)
337
+ normalizationLines = executableCode.slice(0, original).split("\n").length - 1;
338
+ const detached = providers.map((provider, index) => ({
339
+ name: provider.name,
340
+ ...(provider.prelude ? { prelude: provider.prelude } : {}),
341
+ fns: Object.fromEntries(Object.keys(provider.fns).map((name) => [name, forward(index, name)])),
342
+ }));
343
+ const stopped = new Promise((_resolve, reject) => {
344
+ cancel = () => reject(new ExecutorExecutionError("executor_cancelled", "Worker executor lease was released during execution."));
345
+ });
346
+ const started = Date.now();
347
+ try {
348
+ const result = await Promise.race([
349
+ new DynamicWorkerExecutor({
350
+ loader,
351
+ ...(options.timeout !== undefined ? { timeout: options.timeout } : {}),
352
+ }).execute(code, detached),
353
+ stopped,
354
+ ]);
355
+ const outcome = rpcOutcome ?? result;
356
+ if (outcome.failure) {
357
+ const failure = { ...outcome.failure };
358
+ const call = typeof failure.failureId === "string" ? hostFailures.get(failure.failureId) : undefined;
359
+ // Neither an unknown id nor a guest/RPC-supplied call record
360
+ // supplies typed host details. Strip the private id at the edge.
361
+ delete failure.call;
362
+ delete failure.failureId;
363
+ outcome.failure = { ...failure, ...(call ? { call } : {}) };
364
+ }
365
+ if (outcome.failure?.timeout)
366
+ outcome.failure.timeout.elapsedMs = Date.now() - started;
367
+ return outcome;
368
+ }
369
+ catch (error) {
370
+ const message = error instanceof Error ? error.message : "";
371
+ // Worker Loader erases the native SyntaxError type at its RPC edge.
372
+ // Match its startup diagnostic only; guest/downstream failures return normally.
373
+ const syntax = /^Failed to start Worker:\nUncaught SyntaxError: ([^\n]*)\n\s+at connecta-guest\.js:(\d+):\d+$/.exec(message);
374
+ if (error instanceof SyntaxError || syntax) {
375
+ const location = error instanceof SyntaxError && "loc" in error ? error.loc : undefined;
376
+ const line = syntax
377
+ ? Math.max(1, Number(syntax[2]) - normalizationLines - 1)
378
+ : location?.line !== undefined
379
+ ? Math.max(1, location.line)
380
+ : undefined;
381
+ return {
382
+ result: undefined,
383
+ error: (syntax?.[1] ?? message) || "Invalid JavaScript program.",
384
+ failure: { name: "SyntaxError", ...(line !== undefined ? { line } : {}) },
385
+ };
386
+ }
387
+ throw error;
388
+ }
389
+ finally {
390
+ runEnded = true;
391
+ cancel = undefined;
392
+ hostFailures.clear();
393
+ }
394
+ },
395
+ release() {
396
+ if (released)
397
+ return;
398
+ released = true;
399
+ hostProviders = undefined;
400
+ hostFailures.clear();
401
+ cancel?.();
402
+ for (const dispose of disposers.reverse()) {
403
+ try {
404
+ dispose();
405
+ }
406
+ catch {
407
+ /* Release every handle and the permit. */
408
+ }
409
+ }
410
+ disposers.length = 0;
411
+ active.delete(lease);
412
+ permit.release();
413
+ },
414
+ };
415
+ active.add(lease);
416
+ return lease;
417
+ },
418
+ async execute(code, providers) {
419
+ const lease = await this.acquire();
420
+ try {
421
+ return await lease.execute(code, providers);
422
+ }
423
+ finally {
424
+ lease.release();
425
+ }
426
+ },
427
+ admissionSnapshot: () => admission.snapshot(),
428
+ close() {
429
+ admission.close();
430
+ for (const lease of active)
431
+ lease.release();
432
+ },
433
+ }, "leased");
434
+ }