@zackbart/connecta 0.15.1 → 0.16.1

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 (335) hide show
  1. package/AGENTS.md +40 -20
  2. package/CHANGELOG.md +653 -0
  3. package/README.md +25 -5
  4. package/bin/connecta.mjs +44 -3
  5. package/dist/access-tokens.d.ts +0 -1
  6. package/dist/access-tokens.js +0 -1
  7. package/dist/activity.d.ts +50 -2
  8. package/dist/activity.js +34 -1
  9. package/dist/apps-shell.d.ts +0 -1
  10. package/dist/apps-shell.js +0 -1
  11. package/dist/auth/bearer.d.ts +0 -1
  12. package/dist/auth/bearer.js +0 -1
  13. package/dist/auth/clerk.d.ts +0 -1
  14. package/dist/auth/clerk.js +45 -9
  15. package/dist/auth/downstream-oauth.d.ts +0 -1
  16. package/dist/auth/downstream-oauth.js +0 -1
  17. package/dist/call-admission.d.ts +0 -1
  18. package/dist/call-admission.js +0 -1
  19. package/dist/catalog-drift.d.ts +99 -0
  20. package/dist/catalog-drift.js +251 -0
  21. package/dist/catalog-fingerprint.d.ts +0 -1
  22. package/dist/catalog-fingerprint.js +0 -1
  23. package/dist/catalog-limits.d.ts +0 -1
  24. package/dist/catalog-limits.js +0 -1
  25. package/dist/catalog-service.d.ts +0 -1
  26. package/dist/catalog-service.js +41 -5
  27. package/dist/catalog.d.ts +11 -1
  28. package/dist/catalog.js +20 -1
  29. package/dist/concurrency.d.ts +0 -1
  30. package/dist/concurrency.js +0 -1
  31. package/dist/connector-scope.d.ts +0 -1
  32. package/dist/connector-scope.js +0 -1
  33. package/dist/connectors/api.d.ts +29 -21
  34. package/dist/connectors/api.js +45 -19
  35. package/dist/connectors/guarded-fetch.d.ts +106 -0
  36. package/dist/connectors/guarded-fetch.js +289 -0
  37. package/dist/connectors/remote-mcp.d.ts +0 -1
  38. package/dist/connectors/remote-mcp.js +0 -1
  39. package/dist/credentials.d.ts +0 -1
  40. package/dist/credentials.js +0 -1
  41. package/dist/errors.d.ts +30 -3
  42. package/dist/errors.js +1 -1
  43. package/dist/execute.d.ts +0 -1
  44. package/dist/execute.js +0 -1
  45. package/dist/executor-admission.d.ts +11 -1
  46. package/dist/executor-admission.js +28 -1
  47. package/dist/executor-result.d.ts +0 -1
  48. package/dist/executor-result.js +0 -1
  49. package/dist/executors/quickjs-child.d.ts +0 -1
  50. package/dist/executors/quickjs-child.js +0 -1
  51. package/dist/executors/quickjs-protocol.d.ts +0 -1
  52. package/dist/executors/quickjs-protocol.js +0 -1
  53. package/dist/executors/quickjs-runtime.d.ts +0 -1
  54. package/dist/executors/quickjs-runtime.js +0 -1
  55. package/dist/executors/quickjs.d.ts +0 -1
  56. package/dist/executors/quickjs.js +2 -1
  57. package/dist/favicon.d.ts +0 -1
  58. package/dist/favicon.js +0 -1
  59. package/dist/index.d.ts +2 -3
  60. package/dist/index.js +24 -7
  61. package/dist/invocation.d.ts +0 -1
  62. package/dist/invocation.js +0 -1
  63. package/dist/json-schema.d.ts +0 -1
  64. package/dist/json-schema.js +0 -1
  65. package/dist/mcp-result.d.ts +0 -1
  66. package/dist/mcp-result.js +0 -1
  67. package/dist/meta-tools.d.ts +0 -1
  68. package/dist/meta-tools.js +0 -1
  69. package/dist/node.d.ts +0 -1
  70. package/dist/node.js +0 -1
  71. package/dist/operator-ui/generated.d.ts +2 -3
  72. package/dist/operator-ui/generated.js +3 -4
  73. package/dist/operator-ui/model.d.ts +10 -1
  74. package/dist/operator-ui/model.js +0 -1
  75. package/dist/operator-ui/view.d.ts +167 -0
  76. package/dist/operator-ui/view.js +270 -0
  77. package/dist/providers/cloudflare.d.ts +0 -1
  78. package/dist/providers/cloudflare.js +261 -299
  79. package/dist/providers/linear.d.ts +26 -5
  80. package/dist/providers/linear.js +32 -61
  81. package/dist/providers/mixpanel.d.ts +35 -4
  82. package/dist/providers/mixpanel.js +53 -79
  83. package/dist/providers/notion.d.ts +0 -1
  84. package/dist/providers/notion.js +87 -42
  85. package/dist/providers/stripe.d.ts +13 -1
  86. package/dist/providers/stripe.js +31 -60
  87. package/dist/registry.d.ts +34 -2
  88. package/dist/registry.js +85 -5
  89. package/dist/retired-toolkits.d.ts +0 -1
  90. package/dist/retired-toolkits.js +0 -1
  91. package/dist/routes/access-tokens.d.ts +0 -1
  92. package/dist/routes/access-tokens.js +0 -1
  93. package/dist/routes/activity.d.ts +0 -1
  94. package/dist/routes/activity.js +0 -1
  95. package/dist/routes/credentials.d.ts +0 -1
  96. package/dist/routes/credentials.js +0 -1
  97. package/dist/routes/mcp.d.ts +0 -1
  98. package/dist/routes/mcp.js +0 -1
  99. package/dist/routes/oauth.d.ts +0 -1
  100. package/dist/routes/oauth.js +0 -1
  101. package/dist/routes/shared.d.ts +2 -1
  102. package/dist/routes/shared.js +0 -1
  103. package/dist/routes/ui.d.ts +0 -1
  104. package/dist/routes/ui.js +0 -1
  105. package/dist/server.d.ts +0 -1
  106. package/dist/server.js +11 -1
  107. package/dist/skills.d.ts +0 -1
  108. package/dist/skills.js +0 -1
  109. package/dist/storage/file.d.ts +0 -1
  110. package/dist/storage/file.js +0 -1
  111. package/dist/storage/memory.d.ts +0 -1
  112. package/dist/storage/memory.js +0 -1
  113. package/dist/timeout.d.ts +0 -1
  114. package/dist/timeout.js +0 -1
  115. package/dist/tool-safety.d.ts +0 -1
  116. package/dist/tool-safety.js +0 -1
  117. package/dist/types.d.ts +45 -1
  118. package/dist/types.js +0 -1
  119. package/dist/ui.d.ts +0 -1
  120. package/dist/ui.js +13 -137
  121. package/dist/validate.d.ts +13 -15
  122. package/dist/validate.js +24 -11
  123. package/dist/version.d.ts +1 -2
  124. package/dist/version.js +1 -2
  125. package/documentation/architecture.md +186 -5
  126. package/documentation/auth.md +11 -0
  127. package/documentation/call-admission.md +142 -6
  128. package/documentation/cloudflare.md +92 -10
  129. package/documentation/code-first-exploration.md +2 -2
  130. package/documentation/code-mode.md +14 -14
  131. package/documentation/connector-guides.md +172 -5
  132. package/documentation/connectors.md +89 -0
  133. package/documentation/linear.md +20 -2
  134. package/documentation/mcp-ui-design.md +2 -2
  135. package/documentation/meta-tools.md +7 -1
  136. package/documentation/mixpanel.md +42 -9
  137. package/documentation/notion.md +23 -2
  138. package/documentation/operations.md +325 -5
  139. package/documentation/operator-ui.md +120 -5
  140. package/documentation/provider-audit.md +160 -0
  141. package/documentation/provider-conventions.md +667 -0
  142. package/documentation/request-admission.md +167 -5
  143. package/documentation/rich-output-design.md +1 -2
  144. package/documentation/stripe.md +15 -0
  145. package/documentation/upgrading.md +454 -0
  146. package/ethos.md +14 -9
  147. package/examples/worker/README.md +102 -12
  148. package/examples/worker/src/index.ts +46 -1
  149. package/examples/worker/wrangler.jsonc +14 -1
  150. package/package.json +10 -6
  151. package/templates/node/.dockerignore +10 -0
  152. package/templates/node/.env.example +40 -3
  153. package/templates/node/AGENTS.md +16 -1
  154. package/templates/node/Dockerfile +49 -0
  155. package/templates/node/README.md +117 -2
  156. package/templates/node/docker-compose.yml +39 -0
  157. package/templates/node/package.json +1 -1
  158. package/templates/node/src/file-activity.ts +182 -0
  159. package/templates/node/src/index.ts +80 -4
  160. package/assets/connecta-clay-hero.png +0 -0
  161. package/dist/access-tokens.d.ts.map +0 -1
  162. package/dist/access-tokens.js.map +0 -1
  163. package/dist/activity.d.ts.map +0 -1
  164. package/dist/activity.js.map +0 -1
  165. package/dist/apps-shell.d.ts.map +0 -1
  166. package/dist/apps-shell.js.map +0 -1
  167. package/dist/auth/bearer.d.ts.map +0 -1
  168. package/dist/auth/bearer.js.map +0 -1
  169. package/dist/auth/clerk.d.ts.map +0 -1
  170. package/dist/auth/clerk.js.map +0 -1
  171. package/dist/auth/downstream-oauth.d.ts.map +0 -1
  172. package/dist/auth/downstream-oauth.js.map +0 -1
  173. package/dist/call-admission.d.ts.map +0 -1
  174. package/dist/call-admission.js.map +0 -1
  175. package/dist/catalog-fingerprint.d.ts.map +0 -1
  176. package/dist/catalog-fingerprint.js.map +0 -1
  177. package/dist/catalog-limits.d.ts.map +0 -1
  178. package/dist/catalog-limits.js.map +0 -1
  179. package/dist/catalog-service.d.ts.map +0 -1
  180. package/dist/catalog-service.js.map +0 -1
  181. package/dist/catalog.d.ts.map +0 -1
  182. package/dist/catalog.js.map +0 -1
  183. package/dist/concurrency.d.ts.map +0 -1
  184. package/dist/concurrency.js.map +0 -1
  185. package/dist/connector-scope.d.ts.map +0 -1
  186. package/dist/connector-scope.js.map +0 -1
  187. package/dist/connectors/api.d.ts.map +0 -1
  188. package/dist/connectors/api.js.map +0 -1
  189. package/dist/connectors/remote-mcp.d.ts.map +0 -1
  190. package/dist/connectors/remote-mcp.js.map +0 -1
  191. package/dist/credentials.d.ts.map +0 -1
  192. package/dist/credentials.js.map +0 -1
  193. package/dist/errors.d.ts.map +0 -1
  194. package/dist/errors.js.map +0 -1
  195. package/dist/execute.d.ts.map +0 -1
  196. package/dist/execute.js.map +0 -1
  197. package/dist/executor-admission.d.ts.map +0 -1
  198. package/dist/executor-admission.js.map +0 -1
  199. package/dist/executor-result.d.ts.map +0 -1
  200. package/dist/executor-result.js.map +0 -1
  201. package/dist/executors/quickjs-child.d.ts.map +0 -1
  202. package/dist/executors/quickjs-child.js.map +0 -1
  203. package/dist/executors/quickjs-protocol.d.ts.map +0 -1
  204. package/dist/executors/quickjs-protocol.js.map +0 -1
  205. package/dist/executors/quickjs-runtime.d.ts.map +0 -1
  206. package/dist/executors/quickjs-runtime.js.map +0 -1
  207. package/dist/executors/quickjs.d.ts.map +0 -1
  208. package/dist/executors/quickjs.js.map +0 -1
  209. package/dist/favicon.d.ts.map +0 -1
  210. package/dist/favicon.js.map +0 -1
  211. package/dist/index.d.ts.map +0 -1
  212. package/dist/index.js.map +0 -1
  213. package/dist/invocation.d.ts.map +0 -1
  214. package/dist/invocation.js.map +0 -1
  215. package/dist/json-schema.d.ts.map +0 -1
  216. package/dist/json-schema.js.map +0 -1
  217. package/dist/mcp-result.d.ts.map +0 -1
  218. package/dist/mcp-result.js.map +0 -1
  219. package/dist/meta-tools.d.ts.map +0 -1
  220. package/dist/meta-tools.js.map +0 -1
  221. package/dist/node.d.ts.map +0 -1
  222. package/dist/node.js.map +0 -1
  223. package/dist/operator-ui/generated.d.ts.map +0 -1
  224. package/dist/operator-ui/generated.js.map +0 -1
  225. package/dist/operator-ui/model.d.ts.map +0 -1
  226. package/dist/operator-ui/model.js.map +0 -1
  227. package/dist/providers/cloudflare.d.ts.map +0 -1
  228. package/dist/providers/cloudflare.js.map +0 -1
  229. package/dist/providers/linear.d.ts.map +0 -1
  230. package/dist/providers/linear.js.map +0 -1
  231. package/dist/providers/mixpanel.d.ts.map +0 -1
  232. package/dist/providers/mixpanel.js.map +0 -1
  233. package/dist/providers/notion.d.ts.map +0 -1
  234. package/dist/providers/notion.js.map +0 -1
  235. package/dist/providers/stripe.d.ts.map +0 -1
  236. package/dist/providers/stripe.js.map +0 -1
  237. package/dist/registry.d.ts.map +0 -1
  238. package/dist/registry.js.map +0 -1
  239. package/dist/retired-toolkits.d.ts.map +0 -1
  240. package/dist/retired-toolkits.js.map +0 -1
  241. package/dist/routes/access-tokens.d.ts.map +0 -1
  242. package/dist/routes/access-tokens.js.map +0 -1
  243. package/dist/routes/activity.d.ts.map +0 -1
  244. package/dist/routes/activity.js.map +0 -1
  245. package/dist/routes/credentials.d.ts.map +0 -1
  246. package/dist/routes/credentials.js.map +0 -1
  247. package/dist/routes/mcp.d.ts.map +0 -1
  248. package/dist/routes/mcp.js.map +0 -1
  249. package/dist/routes/oauth.d.ts.map +0 -1
  250. package/dist/routes/oauth.js.map +0 -1
  251. package/dist/routes/shared.d.ts.map +0 -1
  252. package/dist/routes/shared.js.map +0 -1
  253. package/dist/routes/ui.d.ts.map +0 -1
  254. package/dist/routes/ui.js.map +0 -1
  255. package/dist/server.d.ts.map +0 -1
  256. package/dist/server.js.map +0 -1
  257. package/dist/skills.d.ts.map +0 -1
  258. package/dist/skills.js.map +0 -1
  259. package/dist/storage/file.d.ts.map +0 -1
  260. package/dist/storage/file.js.map +0 -1
  261. package/dist/storage/memory.d.ts.map +0 -1
  262. package/dist/storage/memory.js.map +0 -1
  263. package/dist/timeout.d.ts.map +0 -1
  264. package/dist/timeout.js.map +0 -1
  265. package/dist/tool-safety.d.ts.map +0 -1
  266. package/dist/tool-safety.js.map +0 -1
  267. package/dist/types.d.ts.map +0 -1
  268. package/dist/types.js.map +0 -1
  269. package/dist/ui.d.ts.map +0 -1
  270. package/dist/ui.js.map +0 -1
  271. package/dist/validate.d.ts.map +0 -1
  272. package/dist/validate.js.map +0 -1
  273. package/dist/version.d.ts.map +0 -1
  274. package/dist/version.js.map +0 -1
  275. package/examples/node/README.md +0 -52
  276. package/examples/node/src/index.ts +0 -71
  277. package/src/access-tokens.ts +0 -289
  278. package/src/activity.ts +0 -234
  279. package/src/apps-shell.ts +0 -370
  280. package/src/auth/bearer.ts +0 -61
  281. package/src/auth/clerk.ts +0 -553
  282. package/src/auth/downstream-oauth.ts +0 -575
  283. package/src/call-admission.ts +0 -521
  284. package/src/catalog-fingerprint.ts +0 -52
  285. package/src/catalog-limits.ts +0 -11
  286. package/src/catalog-service.ts +0 -1153
  287. package/src/catalog.ts +0 -790
  288. package/src/concurrency.ts +0 -39
  289. package/src/connector-scope.ts +0 -66
  290. package/src/connectors/api.ts +0 -159
  291. package/src/connectors/remote-mcp.ts +0 -1090
  292. package/src/credentials.ts +0 -428
  293. package/src/errors.ts +0 -364
  294. package/src/execute.ts +0 -1406
  295. package/src/executor-admission.ts +0 -328
  296. package/src/executor-result.ts +0 -107
  297. package/src/executors/quickjs-child.ts +0 -172
  298. package/src/executors/quickjs-protocol.ts +0 -99
  299. package/src/executors/quickjs-runtime.ts +0 -470
  300. package/src/executors/quickjs.ts +0 -776
  301. package/src/favicon.ts +0 -53
  302. package/src/index.ts +0 -666
  303. package/src/invocation.ts +0 -655
  304. package/src/json-schema.ts +0 -11
  305. package/src/mcp-result.ts +0 -43
  306. package/src/meta-tools.ts +0 -1607
  307. package/src/node.ts +0 -206
  308. package/src/operator-ui/browser.css +0 -423
  309. package/src/operator-ui/browser.ts +0 -1281
  310. package/src/operator-ui/generated.ts +0 -4
  311. package/src/operator-ui/model.ts +0 -111
  312. package/src/providers/cloudflare.ts +0 -3999
  313. package/src/providers/linear.ts +0 -302
  314. package/src/providers/mixpanel.ts +0 -229
  315. package/src/providers/notion.ts +0 -1879
  316. package/src/providers/stripe.ts +0 -307
  317. package/src/registry.ts +0 -1085
  318. package/src/retired-toolkits.ts +0 -14
  319. package/src/routes/access-tokens.ts +0 -115
  320. package/src/routes/activity.ts +0 -215
  321. package/src/routes/credentials.ts +0 -254
  322. package/src/routes/mcp.ts +0 -429
  323. package/src/routes/oauth.ts +0 -322
  324. package/src/routes/shared.ts +0 -247
  325. package/src/routes/ui.ts +0 -152
  326. package/src/server.ts +0 -195
  327. package/src/skills.ts +0 -271
  328. package/src/storage/file.ts +0 -123
  329. package/src/storage/memory.ts +0 -44
  330. package/src/timeout.ts +0 -84
  331. package/src/tool-safety.ts +0 -15
  332. package/src/types.ts +0 -523
  333. package/src/ui.ts +0 -744
  334. package/src/validate.ts +0 -387
  335. package/src/version.ts +0 -7
package/src/index.ts DELETED
@@ -1,666 +0,0 @@
1
- import {
2
- CredentialVault,
3
- credentialTestRule,
4
- describeCredentialTestMismatch,
5
- } from "./credentials.js";
6
- import { AccessTokenManager } from "./access-tokens.js";
7
- import { Registry } from "./registry.js";
8
- import { createFetchHandler } from "./server.js";
9
- import { droppedBrandingUrls, droppedUiAuthUrls } from "./ui.js";
10
- import { memoryStorage } from "./storage/memory.js";
11
- import { CONNECTA_VERSION } from "./version.js";
12
- import {
13
- AdmissionController,
14
- isAdmittingExecutor,
15
- withExecutorAdmission,
16
- } from "./executor-admission.js";
17
- import type { ActivityReadGate, ActivityStore } from "./activity.js";
18
- import type {
19
- Connector,
20
- ConnectaBranding,
21
- Executor,
22
- InboundAuth,
23
- KVStorage,
24
- Logger,
25
- } from "./types.js";
26
-
27
- /** Payload-free activity storage and operator-read policy. */
28
- export interface ConnectaActivityConfig {
29
- /**
30
- * Privacy-minimal downstream tool activity storage. Writes are best-effort
31
- * and never change tool results. Implement `list` to enable the Activity UI.
32
- */
33
- store: ActivityStore;
34
- /**
35
- * Optional authorization gate for the Activity read API. MCP authentication
36
- * is still required first. Omit to admit every authenticated actor.
37
- */
38
- readGate?: ActivityReadGate;
39
- /** Stable deployment label included in activity events, e.g. "production". */
40
- deploymentId?: string;
41
- }
42
-
43
- /** Operator-vault encryption. */
44
- export interface ConnectaCredentialsConfig {
45
- /**
46
- * Base64-encoded 32-byte AES key for credentials managed on /credentials.
47
- * Keep this in the runtime's secret store, never in KV or source control.
48
- */
49
- encryptionKey?: string;
50
- }
51
-
52
- /** Operator-issued credentials for clients connecting to this deployment. */
53
- export interface ConnectaAccessTokensConfig {
54
- /** Maximum simultaneously active access tokens. Defaults to 100. */
55
- maxActive?: number;
56
- }
57
-
58
- /** Tool-catalog caching, persistence, stale fallback, and probe deadlines. */
59
- export interface ConnectaDiscoveryConfig {
60
- /**
61
- * Maximum connector catalogs/status probes fetched at once by discovery
62
- * operations. Default 4.
63
- */
64
- concurrency?: number;
65
- /** Tool-list cache TTL (seconds). Default 300. */
66
- catalogTtlSeconds?: number;
67
- /**
68
- * Persist serializable remote tool catalogs in storage so cold isolates can
69
- * discover tools without a downstream handshake. Default true.
70
- */
71
- persistCatalog?: boolean;
72
- /**
73
- * How long an expired persisted catalog remains available as a fallback
74
- * when a live refresh fails. Default 3600 seconds.
75
- */
76
- staleCatalogSeconds?: number;
77
- /**
78
- * Deadline (ms) for each downstream probe/catalog call fanned out by
79
- * `search_tools` and by `connecta.search`/`connecta.describe` inside
80
- * `execute_code`. Defaults to 30_000. A timed-out connector degrades
81
- * independently; this does not apply to tool calls. Catalog walks receive the
82
- * same cancellation signal, which aborts an in-flight page where supported and
83
- * prevents another from starting.
84
- */
85
- probeTimeoutMs?: number;
86
- }
87
-
88
- /** Deployment-wide call deadlines and inline-result paging thresholds. */
89
- export interface ConnectaCallsConfig {
90
- /**
91
- * Deadline (ms) for `call_tool`/`call_destructive_tool` calls that pass no
92
- * `timeoutMs`. An explicit per-call value wins. Opt-in: unset by default, so
93
- * existing long-running calls gain no surprise deadline.
94
- *
95
- * This bounds one attempt, not all retries. `execute_code` host calls are
96
- * unaffected because they already carry their own bound.
97
- */
98
- defaultTimeoutMs?: number;
99
- /**
100
- * Max inline result size (bytes) before truncation and `get_result` paging.
101
- * Must be a finite whole number >= 1; invalid values warn and fall back to
102
- * 50_000. Connectors may override it individually.
103
- */
104
- maxResultBytes?: number;
105
- }
106
-
107
- /** Budgets for rich output emitted by execute_code programs (`connecta.emit`). */
108
- export interface ConnectaExecuteConfig {
109
- /**
110
- * Aggregate serialized bytes `connecta.emit` accepts per run. Default
111
- * 4_000_000 — a transport bound, not a context bound: emitted image/audio
112
- * blocks reach the model as media, not base64 text. Invalid values fall
113
- * back to the default.
114
- */
115
- maxEmittedBytes?: number;
116
- /** Content blocks `connecta.emit` accepts per run. Default 32. */
117
- maxEmittedBlocks?: number;
118
- }
119
-
120
- export interface AdmissionPoolConfig {
121
- /** Simultaneous work admitted to this pool. */
122
- concurrency?: number;
123
- /** Callers allowed to wait behind active work. Set zero to fail fast. */
124
- maxQueueSize?: number;
125
- /** Maximum queue wait in milliseconds. */
126
- queueTimeoutMs?: number;
127
- /** Retry hint returned with overload failures, in milliseconds. */
128
- retryAfterMs?: number;
129
- }
130
-
131
- /**
132
- * Runtime-portable server-memory boundaries. `/health` and operator routes do
133
- * not consume these permits, so they remain responsive during MCP saturation.
134
- */
135
- export interface ConnectaAdmissionConfig {
136
- /**
137
- * The `/mcp` request boundary. Defaults to 16 active, 32 queued, and a
138
- * 5-second maximum wait.
139
- */
140
- requests?: AdmissionPoolConfig;
141
- /**
142
- * Fallback pool for an `executor` that does not implement its own `acquire`.
143
- * Defaults to 2 active, 8 queued, and a 5-second maximum wait. Bounded
144
- * executors (including `quickJsExecutor`) keep their own tighter pool.
145
- */
146
- code?: AdmissionPoolConfig;
147
- }
148
-
149
- export interface ConnectaConfig {
150
- connectors: Connector[];
151
- /** Inbound auth adapters. Includes bearerToken(...); omit for open (dev). */
152
- auth?: InboundAuth | InboundAuth[];
153
- /** KVStorage impl. Defaults to memoryStorage(). */
154
- storage?: KVStorage;
155
- /**
156
- * Public base URL. Defaults to the request origin per-request. Configuring an
157
- * HTTPS URL also redirects matching inbound HTTP requests to HTTPS.
158
- */
159
- publicUrl?: string;
160
- /** Payload-free tool activity storage and operator-read policy. */
161
- activity?: ConnectaActivityConfig;
162
- /** Operator credential vault settings. */
163
- credentials?: ConnectaCredentialsConfig;
164
- /**
165
- * Named, revocable Bearer tokens for MCP clients. Creation and mutation
166
- * require an eligible Clerk operator; token secrets are returned once.
167
- */
168
- accessTokens?: ConnectaAccessTokensConfig;
169
- /** Tool-catalog caching, persistence, stale fallback, and probe deadlines. */
170
- discovery?: ConnectaDiscoveryConfig;
171
- /** Deployment-wide call deadlines and result paging threshold. */
172
- calls?: ConnectaCallsConfig;
173
- /** Budgets for the `connecta.emit` rich-output channel in execute_code. */
174
- execute?: ConnectaExecuteConfig;
175
- /** Bounded MCP and fallback code-mode admission. */
176
- admission?: ConnectaAdmissionConfig;
177
- /** Optional browser UI and OAuth result-page labels. */
178
- branding?: ConnectaBranding;
179
- logger?: Logger;
180
- serverInfo?: {
181
- name?: string;
182
- version?: string;
183
- /** Human-readable name clients may show instead of `name`. */
184
- title?: string;
185
- /** Homepage clients may link from the server listing. */
186
- websiteUrl?: string;
187
- /** MCP icons-spec entries; clients render these instead of a scraped favicon. */
188
- icons?: Array<{ src: string; mimeType?: string; sizes?: string[] }>;
189
- };
190
- /** Deployment metadata exposed by /health (for example a Worker version). */
191
- deploymentInfo?: Record<string, unknown>;
192
- /**
193
- * Required sandbox for `execute_code`. Workers use
194
- * `new DynamicWorkerExecutor({ loader: env.LOADER })` from
195
- * `@cloudflare/codemode`; Node uses `quickJsExecutor()` from
196
- * `@zackbart/connecta/quickjs`.
197
- */
198
- executor: Executor;
199
- }
200
-
201
- export interface Connecta {
202
- /** Web-standard fetch handler. Usable as `export default { fetch: connecta.fetch }`. */
203
- fetch: (request: Request, env?: unknown, ctx?: unknown) => Promise<Response>;
204
- registry: Registry;
205
- /** Drain and release configured executor resources. Idempotent. */
206
- close: () => Promise<void>;
207
- }
208
-
209
- const REQUEST_ADMISSION_DEFAULTS = {
210
- concurrency: 16,
211
- maxQueueSize: 32,
212
- queueTimeoutMs: 5_000,
213
- retryAfterMs: 1_000,
214
- } as const;
215
-
216
- const CODE_ADMISSION_DEFAULTS = {
217
- concurrency: 2,
218
- maxQueueSize: 8,
219
- queueTimeoutMs: 5_000,
220
- retryAfterMs: 1_000,
221
- } as const;
222
-
223
- function admissionController(
224
- options: AdmissionPoolConfig | undefined,
225
- defaults: typeof REQUEST_ADMISSION_DEFAULTS | typeof CODE_ADMISSION_DEFAULTS,
226
- ): AdmissionController {
227
- return new AdmissionController({
228
- concurrency: options?.concurrency ?? defaults.concurrency,
229
- maxQueueSize: options?.maxQueueSize ?? defaults.maxQueueSize,
230
- queueTimeoutMs: options?.queueTimeoutMs ?? defaults.queueTimeoutMs,
231
- retryAfterMs: options?.retryAfterMs ?? defaults.retryAfterMs,
232
- });
233
- }
234
-
235
- function defaultLogger(): Logger {
236
- return {
237
- debug: (...a) => console.debug("[connecta]", ...a),
238
- info: (...a) => console.info("[connecta]", ...a),
239
- warn: (...a) => console.warn("[connecta]", ...a),
240
- error: (...a) => console.error("[connecta]", ...a),
241
- };
242
- }
243
-
244
- /** Bearer providers are checked before Clerk (per spec). */
245
- function normalizeAuth(auth: ConnectaConfig["auth"]): InboundAuth[] {
246
- const list = auth ? (Array.isArray(auth) ? auth : [auth]) : [];
247
- return [...list].sort((a, b) => {
248
- const rank = (x: InboundAuth) => (x.kind === "bearer" ? 0 : 1);
249
- return rank(a) - rank(b);
250
- });
251
- }
252
-
253
- const LEGACY_CONFIG_MIGRATIONS = [
254
- ["activityReadGate", "activity.readGate"],
255
- ["activityDeploymentId", "activity.deploymentId"],
256
- ["credentialEncryptionKey", "credentials.encryptionKey"],
257
- ["toolCacheTtlSeconds", "discovery.catalogTtlSeconds"],
258
- ["persistToolCatalog", "discovery.persistCatalog"],
259
- ["toolCatalogStaleSeconds", "discovery.staleCatalogSeconds"],
260
- ["probeTimeoutMs", "discovery.probeTimeoutMs"],
261
- ["defaultToolTimeoutMs", "calls.defaultTimeoutMs"],
262
- ["maxResultBytes", "calls.maxResultBytes"],
263
- ] as const;
264
-
265
- const hasOwn = (value: object, key: PropertyKey): boolean =>
266
- Object.prototype.hasOwnProperty.call(value, key);
267
-
268
- /**
269
- * Fail closed at the public boundary: a JavaScript caller on the v0.6 shape
270
- * must receive one complete migration error, never silently lose an option to
271
- * a default. This runs before createConnecta reads any other config field.
272
- */
273
- function assertNoLegacyConfig(config: ConnectaConfig): void {
274
- const candidate = config as unknown as Record<PropertyKey, unknown>;
275
- if (hasOwn(candidate, "toolkits")) {
276
- throw new Error(
277
- "ConnectaConfig.toolkits was removed in issue #178. Deploy one " +
278
- "connecta instance per audience instead; see ethos.md.",
279
- );
280
- }
281
- const credentials = candidate.credentials;
282
- const hasNestedHealth =
283
- typeof credentials === "object" &&
284
- credentials !== null &&
285
- hasOwn(credentials, "health");
286
- if (hasOwn(candidate, "credentialHealth") || hasNestedHealth) {
287
- throw new Error(
288
- "`credentials.health` and legacy `credentialHealth` were removed in " +
289
- "issue #179. Credentials now fail at use; see ethos.md.",
290
- );
291
- }
292
- const calls = candidate.calls;
293
- if (
294
- typeof calls === "object" &&
295
- calls !== null &&
296
- hasOwn(calls, "maxBatchResultBytes")
297
- ) {
298
- throw new Error(
299
- "`calls.maxBatchResultBytes` was removed in issue #273 along with " +
300
- "batch_call. Remove it; a program's batching is bounded by " +
301
- "execute_code's own limits — connecta.batch's per-run call ceiling " +
302
- "and the executor result cap — while each call inside it still honours " +
303
- "calls.maxResultBytes and any per-connector override.",
304
- );
305
- }
306
- const found: Array<readonly [string, string]> = [];
307
- if (hasOwn(candidate, "activity")) {
308
- const activity = candidate.activity;
309
- const isObject =
310
- typeof activity === "object" && activity !== null;
311
- // A valid v0.6 ActivityStore can itself own a backend field named `store`.
312
- // Its required `record` method (including a prototype method) therefore
313
- // takes precedence over the otherwise-new wrapper shape.
314
- const hasLegacyRecord =
315
- isObject &&
316
- typeof (activity as { record?: unknown }).record === "function";
317
- if (
318
- activity !== undefined &&
319
- (!isObject ||
320
- hasLegacyRecord ||
321
- !hasOwn(activity, "store"))
322
- ) {
323
- found.push(["activity", "activity.store"]);
324
- }
325
- }
326
- for (const migration of LEGACY_CONFIG_MIGRATIONS) {
327
- if (hasOwn(candidate, migration[0])) found.push(migration);
328
- }
329
- if (found.length === 0) return;
330
- throw new Error(
331
- "Unsupported v0.6.x ConnectaConfig options. Migrate each path for v0.7.0:\n" +
332
- found.map(([oldPath, newPath]) => `- ${oldPath} -> ${newPath}`).join("\n"),
333
- );
334
- }
335
-
336
- /**
337
- * One-time construction warnings for deployment shapes that run fine but are
338
- * usually unintended. Warning-only — never throws and never changes behavior;
339
- * each deployment-wide condition emits at most one `logger.warn`, and each
340
- * per-connector condition at most one per connector it names.
341
- */
342
- function warnInsecureConfig(
343
- config: ConnectaConfig,
344
- inboundAuth: InboundAuth[],
345
- logger: Logger,
346
- ): void {
347
- const oauthConnectors = config.connectors.filter((c) => c.finishAuth);
348
- const hasCredentialConnector = config.connectors.some((c) => c.credential);
349
-
350
- // Open mode (no inbound auth) with connectors that expose credentials or
351
- // downstream OAuth: any caller reaches everything, including the vault.
352
- if (
353
- inboundAuth.length === 0 &&
354
- (hasCredentialConnector || oauthConnectors.length > 0)
355
- ) {
356
- logger.warn(
357
- "[connecta] running with no inbound authentication: any caller can " +
358
- "invoke every connector and read or overwrite stored credentials. " +
359
- "Configure `auth` (for example bearerToken(...) or Clerk) to gate access.",
360
- );
361
- }
362
-
363
- // Unset publicUrl with OAuth connectors: the downstream redirect_uri is
364
- // derived per-request from the attacker-influenced inbound Host header.
365
- if (oauthConnectors.length > 0 && !config.publicUrl) {
366
- logger.warn(
367
- "[connecta] publicUrl is unset while OAuth connectors are configured: " +
368
- "the downstream OAuth redirect_uri is derived per-request from the " +
369
- "inbound Host header, so an attacker who controls that header can point " +
370
- "it at their own host and capture the authorization code. Set " +
371
- "`publicUrl` to a fixed https origin.",
372
- );
373
- }
374
-
375
- // Branding URLs that failed their scheme gate. Rendering silently falls back
376
- // (a bad URL must not take the page down), so this warning is the only way an
377
- // operator learns their value never reached the page.
378
- const dropped = droppedBrandingUrls(config.branding);
379
- if (dropped.length > 0) {
380
- logger.warn(
381
- `[connecta] branding ${dropped.join(", ")} dropped: a branding URL is ` +
382
- "used as an href, so it must be an absolute http(s) URL (favicon.href " +
383
- "may also be a root-relative path). The default is rendered instead.",
384
- );
385
- }
386
-
387
- // Operator shells render exactly one provider's browser sign-in config — the
388
- // first that offers one, matching the server route's `find` — and that
389
- // provider's URLs reach the browser: frontendApiUrl as the loader's
390
- // `<script src>`, signInUrl/signUpUrl as the addresses ClerkJS navigates to.
391
- // Gate-or-drop like a branding href: rendering drops a rejected value and the
392
- // operator page then reports that Clerk could not load or quietly signs in
393
- // through Clerk's defaults — both confusing symptoms without this line naming
394
- // the cause. Checking only the rendered provider keeps the claim true — a
395
- // later provider's uiAuth never reaches the page, so there is nothing there
396
- // to warn about.
397
- const uiAuthProvider = inboundAuth.find((provider) => provider.uiAuth);
398
- const droppedUiAuth = droppedUiAuthUrls(uiAuthProvider?.uiAuth);
399
- if (uiAuthProvider && droppedUiAuth.length > 0) {
400
- logger.warn(
401
- `[connecta] inbound auth provider "${uiAuthProvider.kind}" had ` +
402
- `${droppedUiAuth.join(", ")} dropped: every uiAuth URL reaches the ` +
403
- "browser — as the sign-in loader's source, or as a place Clerk sends " +
404
- "the operator — so each must be an absolute https URL. A dropped " +
405
- "value reaches no part of the page: without frontendApiUrl the operator shell renders " +
406
- "no loader and cannot start a sign-in, and without signInUrl/signUpUrl " +
407
- "it signs in through Clerk's defaults.",
408
- );
409
- }
410
-
411
- // A credential test hook that cannot test the declared credential shape.
412
- // The shape picks the hook (see `credentialTestRule`) and the other one is
413
- // never substituted, so the connector is simply not testable: /credentials offers no
414
- // Test action and the route answers 400. Without this line the only way to
415
- // discover the mistake is to click a button that isn't there.
416
- for (const connector of config.connectors) {
417
- const { mismatch } = credentialTestRule(connector);
418
- if (!mismatch) continue;
419
- logger.warn(
420
- `[connecta] connector "${connector.id}" cannot test its credential: ` +
421
- `${describeCredentialTestMismatch(mismatch)}. /credentials offers no Test ` +
422
- `action and POST /ui/credentials/${connector.id}/test answers 400 ` +
423
- "until the matching hook is implemented.",
424
- );
425
- }
426
-
427
- // OAuth connectors whose callback cannot perform a state/CSRF check. The
428
- // public route refuses every callback for these connectors rather than hand
429
- // an unverified code to finishAuth, so this warning explains why auth cannot
430
- // complete instead of describing a vulnerability the server permits.
431
- for (const connector of oauthConnectors) {
432
- if (!connector.verifyState) {
433
- logger.warn(
434
- `[connecta] connector "${connector.id}" has an OAuth callback with no ` +
435
- `state/CSRF check: /oauth/callback/${connector.id} refuses every ` +
436
- "callback rather than exchange an unverified code. Implement " +
437
- "`verifyState` to complete authorization (the shipped remoteMcp " +
438
- "connector already does).",
439
- );
440
- }
441
- }
442
- }
443
-
444
- export function createConnecta(config: ConnectaConfig): Connecta {
445
- assertNoLegacyConfig(config);
446
- if (Object.prototype.hasOwnProperty.call(config, "surface")) {
447
- throw new Error(
448
- "ConnectaConfig.surface was removed in issue #273. Remove it; connecta " +
449
- "now serves one seven-tool surface.",
450
- );
451
- }
452
- if (!config.executor) {
453
- throw new Error(
454
- "ConnectaConfig.executor is required. Configure quickJsExecutor() from " +
455
- '"@zackbart/connecta/quickjs" on Node, or ' +
456
- "new DynamicWorkerExecutor({ loader: env.LOADER }) from " +
457
- '"@cloudflare/codemode" on Workers.',
458
- );
459
- }
460
- const storage = config.storage ?? memoryStorage();
461
- const logger = config.logger ?? defaultLogger();
462
- const credentialConnectors = config.connectors.filter((c) => c.credential);
463
- const encryptionKey = config.credentials?.encryptionKey;
464
- if (credentialConnectors.length > 0 && !encryptionKey) {
465
- logger.warn(
466
- "Operator-managed credentials are unavailable because " +
467
- "credentials.encryptionKey is not configured for connectors: " +
468
- credentialConnectors.map((c) => c.id).join(", "),
469
- );
470
- }
471
- const credentialVault = encryptionKey
472
- ? new CredentialVault(storage, encryptionKey)
473
- : undefined;
474
- const configuredAuth = normalizeAuth(config.auth);
475
- const accessTokens = config.accessTokens
476
- ? new AccessTokenManager(storage, config.accessTokens)
477
- : undefined;
478
- if (
479
- accessTokens &&
480
- !configuredAuth.some((provider) => provider.uiAuth?.kind === "clerk")
481
- ) {
482
- throw new Error(
483
- "accessTokens requires a Clerk auth provider: only an eligible Clerk " +
484
- "operator may create, rename, or revoke deployment access tokens",
485
- );
486
- }
487
- const registry = new Registry(config.connectors, {
488
- storage,
489
- logger,
490
- ...(credentialVault !== undefined ? { credentialVault } : {}),
491
- ...(config.discovery?.catalogTtlSeconds !== undefined
492
- ? { toolCacheTtlSeconds: config.discovery.catalogTtlSeconds }
493
- : {}),
494
- ...(config.discovery?.persistCatalog !== undefined
495
- ? { persistToolCatalog: config.discovery.persistCatalog }
496
- : {}),
497
- ...(config.discovery?.staleCatalogSeconds !== undefined
498
- ? { toolCatalogStaleSeconds: config.discovery.staleCatalogSeconds }
499
- : {}),
500
- ...(config.calls?.maxResultBytes !== undefined
501
- ? { maxResultBytes: config.calls.maxResultBytes }
502
- : {}),
503
- });
504
- const inboundAuth = normalizeAuth(
505
- accessTokens ? [accessTokens.auth, ...configuredAuth] : configuredAuth,
506
- );
507
- warnInsecureConfig(config, inboundAuth, logger);
508
- const requestAdmission = admissionController(
509
- config.admission?.requests,
510
- REQUEST_ADMISSION_DEFAULTS,
511
- );
512
- const configuredCodeAdmission = admissionController(
513
- config.admission?.code,
514
- CODE_ADMISSION_DEFAULTS,
515
- );
516
- let codeAdmission: AdmissionController | undefined;
517
- let executor = config.executor;
518
- if (!isAdmittingExecutor(executor)) {
519
- codeAdmission = configuredCodeAdmission;
520
- executor = withExecutorAdmission(executor, codeAdmission);
521
- } else if (config.admission?.code) {
522
- logger.warn(
523
- "[connecta] admission.code is ignored because the configured executor " +
524
- "implements acquire() and owns its admission pool; configure that " +
525
- "executor's concurrency and queue options instead.",
526
- );
527
- }
528
- const handler = createFetchHandler({
529
- registry,
530
- auth: inboundAuth,
531
- ...(config.publicUrl !== undefined ? { publicUrl: config.publicUrl } : {}),
532
- serverInfo: {
533
- ...config.serverInfo,
534
- name: config.serverInfo?.name ?? "connecta",
535
- version: config.serverInfo?.version ?? CONNECTA_VERSION,
536
- },
537
- logger,
538
- ...(config.activity?.store !== undefined
539
- ? { activity: config.activity.store }
540
- : {}),
541
- ...(config.activity?.readGate !== undefined
542
- ? { activityReadGate: config.activity.readGate }
543
- : {}),
544
- ...(config.activity?.deploymentId !== undefined
545
- ? { activityDeploymentId: config.activity.deploymentId }
546
- : {}),
547
- executor,
548
- requestAdmission,
549
- ...(config.calls?.defaultTimeoutMs !== undefined
550
- ? { defaultToolTimeoutMs: config.calls.defaultTimeoutMs }
551
- : {}),
552
- ...(config.discovery?.probeTimeoutMs !== undefined
553
- ? { probeTimeoutMs: config.discovery.probeTimeoutMs }
554
- : {}),
555
- ...(config.discovery?.concurrency !== undefined
556
- ? { discoveryConcurrency: config.discovery.concurrency }
557
- : {}),
558
- ...(config.execute?.maxEmittedBytes !== undefined
559
- ? { maxEmittedBytes: config.execute.maxEmittedBytes }
560
- : {}),
561
- ...(config.execute?.maxEmittedBlocks !== undefined
562
- ? { maxEmittedBlocks: config.execute.maxEmittedBlocks }
563
- : {}),
564
- ...(credentialVault !== undefined ? { credentialVault } : {}),
565
- ...(accessTokens !== undefined ? { accessTokens } : {}),
566
- ...(config.deploymentInfo !== undefined
567
- ? { deploymentInfo: config.deploymentInfo }
568
- : {}),
569
- ...(config.branding !== undefined ? { branding: config.branding } : {}),
570
- });
571
- let closePromise: Promise<void> | undefined;
572
- return {
573
- fetch: (request, _env, ctx) =>
574
- handler(
575
- request,
576
- ctx && typeof (ctx as { waitUntil?: unknown }).waitUntil === "function"
577
- ? (ctx as { waitUntil(promise: Promise<unknown>): void })
578
- : undefined,
579
- ),
580
- registry,
581
- close: async () => {
582
- closePromise ??= Promise.resolve().then(async () => {
583
- requestAdmission.close();
584
- codeAdmission?.close();
585
- registry.closeCallAdmission();
586
- await config.executor?.close?.();
587
- });
588
- await closePromise;
589
- },
590
- };
591
- }
592
-
593
- export { remoteMcp } from "./connectors/remote-mcp.js";
594
- export { api } from "./connectors/api.js";
595
- export { ConnectorCallError } from "./errors.js";
596
- export type { ConnectorCallErrorCode, CallErrorDetails } from "./errors.js";
597
- // The same argument validation api() performs, usable by connectors that
598
- // implement the Connector interface directly. Returns the error rather than
599
- // throwing so the caller decides what to do with it.
600
- export { validateToolInput } from "./validate.js";
601
- export type { ValidateToolInputOptions } from "./validate.js";
602
- export { bearerToken } from "./auth/bearer.js";
603
- export type { BearerTokenOptions } from "./auth/bearer.js";
604
- export type {
605
- AccessTokenMetadata,
606
- CreatedAccessToken,
607
- } from "./access-tokens.js";
608
- export { memoryStorage } from "./storage/memory.js";
609
- export { CONNECTA_VERSION } from "./version.js";
610
- // Registry is reachable through `Connecta.registry`, so its type is public;
611
- // the class itself, the credential vault, and the meta-tool/sandbox factories
612
- // are internal factoring and are deliberately not part of the API surface.
613
- export type { Registry } from "./registry.js";
614
-
615
- export type {
616
- RemoteMcpOptions,
617
- RemoteMcpAuth,
618
- RemoteMcpRedirectPolicy,
619
- } from "./connectors/remote-mcp.js";
620
- export type { ApiOptions, ApiTool } from "./connectors/api.js";
621
- export type {
622
- Connector,
623
- ConnectorCallAdmissionInput,
624
- ConnectorCallAdmissionPolicy,
625
- ConnectorCallAdmissionRule,
626
- ConnectorRollingWindowBudget,
627
- ConnectaBranding,
628
- ConnectorCredentialAccess,
629
- ConnectorCredentialConfig,
630
- ConnectorCredentialFieldConfig,
631
- ConnectorCredentialValues,
632
- ConnectorContext,
633
- ConnectorUsageGuide,
634
- ConnectorStatus,
635
- CredentialTestResult,
636
- AdmittingExecutor,
637
- AdmissionSnapshot,
638
- ExecuteResult,
639
- Executor,
640
- ExecutorLease,
641
- ExecutorProvider,
642
- InboundAuth,
643
- UiAuthConfig,
644
- AuthResult,
645
- JsonSchema,
646
- KVStorage,
647
- Logger,
648
- ToolDef,
649
- ToolAnnotations,
650
- } from "./types.js";
651
- export type {
652
- ActivityActor,
653
- ActivityCallSource,
654
- ActivityOutcome,
655
- ActivityPage,
656
- ActivityReadActor,
657
- ActivityReadEvent,
658
- ActivityReader,
659
- ActivityReadGate,
660
- ActivityReadPage,
661
- ActivitySink,
662
- ActivityStore,
663
- AgentFriction,
664
- ToolCallActivityEvent,
665
- } from "./activity.js";
666
- export { InvalidActivityCursorError } from "./activity.js";