@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
@@ -1,11 +1,20 @@
1
1
  # Connecta deployment
2
2
 
3
- This is the prescribed Node deployment — the only one. It runs locally from
4
- source and, unchanged, as a container. Install and run it:
3
+ Agent setup guide for the Node deployment and its Docker packaging.
4
+ For cross-platform setup and upgrades, use [Deploying Connecta](https://github.com/zackbart/connecta/blob/main/documentation/deploying.md).
5
+ For connector changes, use [Integrating services](https://github.com/zackbart/connecta/blob/main/documentation/integrating.md).
6
+ The [agent index](https://github.com/zackbart/connecta/blob/main/documentation/README.md) routes endpoint use and package
7
+ maintenance. This README and [local agent instructions](./AGENTS.md) own the
8
+ runnable steps for a copied Node deployment.
9
+
10
+ This is the prescribed Node deployment. It runs locally from source and as
11
+ a container. Install, provision a machine token, then start it:
5
12
 
6
13
  ```sh
7
14
  npm install
8
- CONNECTA_TOKEN=dev-token npm start
15
+ npm run --silent provision-token -- "local-machine"
16
+ # Save the returned cta_ token privately. It is shown only once.
17
+ npm start
9
18
  ```
10
19
 
11
20
  The manifest approves only `esbuild@0.28.2` to run its install script. `tsx`
@@ -15,8 +24,39 @@ warning, and npm 12 does not block the script. A later esbuild version needs a
15
24
  new explicit review and approval; do not replace the pinned entry with a broad
16
25
  package-name approval.
17
26
 
18
- Then point an MCP client at `http://localhost:8787/mcp` with
19
- `Authorization: Bearer dev-token`.
27
+ Point an MCP client at `http://localhost:8787/mcp` with
28
+ `Authorization: Bearer <returned-cta-token>`. `CONNECTA_TOKEN` is a client and
29
+ doctor variable only. Setting it never configures server authentication.
30
+
31
+ `accessTokens(storage)` is always installed. With no stored tokens and no
32
+ Clerk keys, the server can start and answer `/health`, but every MCP request
33
+ is refused. There is no open startup or configured static bearer fallback.
34
+
35
+ ## Provision machine tokens
36
+
37
+ Run `npm run --silent provision-token -- "machine-name"` from this project
38
+ on a trusted machine. `src/provision-token.ts` imports the installed package's
39
+ `AccessTokenManager`, then calls `manager.create(name, "local-provisioning")`
40
+ on `sqliteStorage(openSqlite(process.env.CONNECTA_DATABASE || "./.connecta.sqlite"))`.
41
+ The server uses that same database path. If you override it, use the same
42
+ `CONNECTA_DATABASE` for provisioning and startup:
43
+
44
+ ```sh
45
+ export CONNECTA_DATABASE=/absolute/path/connecta.sqlite
46
+ npm run --silent provision-token -- "build-agent"
47
+ npm start
48
+ ```
49
+
50
+ The local commands read the process environment; they do not load `.env`.
51
+ Compose reads `.env` for the container commands below. Keep the returned
52
+ secret in a client secret store and out of source control and logs. Each run
53
+ creates a new token; it cannot recover an old secret. Only the hash persists.
54
+ The token is unbound to a human principal and has no interactive management
55
+ authority. Its name is a label, and deployment identity and pool rules decide
56
+ its access on every request. To revoke it locally, use `manager.list()` to
57
+ find its id, then `manager.revoke(id, "local-provisioning")` against that same
58
+ storage. An explicitly permitted Clerk operator can also manage tokens.
59
+ Never expose this provisioning script as an HTTP route or run it at startup.
20
60
 
21
61
  ## Run it in Docker
22
62
 
@@ -24,20 +64,48 @@ Same source, same configuration, one long-lived service:
24
64
 
25
65
  ```sh
26
66
  cp .env.example .env
27
- # edit .env — set CONNECTA_TOKEN to a long random value
28
-
29
- docker compose up -d --build
67
+ # edit .env for the database path and any optional modules
68
+ docker compose build
69
+ docker compose run --rm --no-deps connecta npm run --silent provision-token -- "container-machine"
70
+ # Save the returned cta_ token privately for clients and doctor.
71
+ docker compose up -d
30
72
  ```
31
73
 
32
- `CONNECTA_TOKEN` ships empty on purpose: `up` fails on it until you set it,
33
- rather than starting a deployment whose bearer is a value published in this
34
- template. Everything else in `.env.example` has a working default.
74
+ The provisioning container writes through the installed package API into the
75
+ same named volume and `CONNECTA_DATABASE` as the service. An empty volume
76
+ admits no machine client. Compose never passes `CONNECTA_TOKEN` to the server;
77
+ no environment value can substitute for a stored token.
35
78
 
36
79
  Compose reads `.env`, publishes `PORT` (8787 by default), and keeps state on
37
80
  the named volume `connecta-state`, mounted at `/data`. `docker compose down`
38
81
  stops the service and keeps state; `down -v` wipes it. `/health` is always
39
82
  open, so the container's health probe never carries the bearer token.
40
83
 
84
+ ## Storage
85
+
86
+ Every piece of state lives in one SQLite file, `CONNECTA_DATABASE`
87
+ (`./.connecta.sqlite` locally, `/data/connecta.sqlite` in the container):
88
+ downstream OAuth grants, sealed vault credentials, catalogs, result paging,
89
+ access tokens and activity. `@zackbart/connecta/sqlite` uses
90
+ Node's built-in `node:sqlite` (Node 22.13 or later), creates its tables on
91
+ first use, and commits one row per write. Back it up as one file, together
92
+ with its `-wal` file while the server runs. Node 22 and 23 print an
93
+ experimental-feature warning for `node:sqlite` once at startup.
94
+
95
+ Upgrading from 0.28, which kept state in `.connecta-state.json`: stop the
96
+ server, then copy the old file into the database once, before the first start:
97
+
98
+ ```sh
99
+ npx connecta migrate-state .connecta-state.json .connecta.sqlite
100
+ ```
101
+
102
+ In the container, run it against the volume, e.g. `docker compose run --rm
103
+ connecta npx connecta migrate-state /data/connecta-state.json
104
+ /data/connecta.sqlite`. It copies every live entry with its expiry, keeps any
105
+ key the database already holds, and never changes the old file; delete that
106
+ once the deployment is verified. The 0.28 activity log
107
+ (`.connecta-activity.jsonl`) is not imported; history starts fresh.
108
+
41
109
  A build with no lockfile in the context resolves the pinned Connecta version
42
110
  itself, and a lockfile npm writes inside the image never reaches this project.
43
111
  So commit the `package-lock.json` that the `npm install` above wrote on this
@@ -46,20 +114,19 @@ reproducible `npm ci` path.
46
114
 
47
115
  ## Select optional modules
48
116
 
49
- For scheduled artifact pages, uncomment the `artifacts()` module and hourly
50
- `setInterval` block in `src/index.ts`. The module uses the same CAS-capable
51
- state file and exposes `runDue()` for the timer; core starts no job on its own.
52
- Each tick starts at most 10 due pages. Refresh programs can call only shared
53
- connectors' explicitly read-only tools within the program owner's current
54
- grants. Revoking refresh or pool access stops future runs. Failed runs leave the last good data
55
- and mark the viewer stale.
117
+ Every optional module is code in `src/connecta.config.ts`, switched by an
118
+ environment variable: set it and the module is on, leave it empty and it is
119
+ off. `.env.example` lists each one, and `npm run typecheck` checks every module
120
+ whether or not it is switched on.
56
121
 
57
122
  The template explicitly enables `ui: operatorUi()` from
58
- `@zackbart/connecta/ui`. Open `http://localhost:8787/` and supply the configured
59
- bearer to inspect Connections. Omit that option and import for an API-only
123
+ `@zackbart/connecta/ui`. Open `http://localhost:8787/` and supply a
124
+ stored machine token to inspect Connections. Sign in with Clerk for human
125
+ connection management. Omit that option and import for an API-only
60
126
  server. OAuth callbacks remain in core even with no UI.
61
127
 
62
- The page labels whether each tool runs in programs or needs approval. For
128
+ The page labels each tool as a read or write. Trusted programs may write;
129
+ read-only pools use `call_destructive_tool`, with approval controlled by the host. For
63
130
  classified connection failures it offers a fixed repair prompt, and its
64
131
  endpoint section has client setup commands for `/mcp` and any pool available
65
132
  to the signed-in identity. Those commands contain no bearer token.
@@ -69,21 +136,37 @@ their URLs, `description`, `pageTitle`, `favicon`, and `theme`. The theme is
69
136
  five tokens — `accent`, `radius`, `fontFamily`, `monoFamily`, and
70
137
  `colorScheme` — and every other color is mixed from them, so one accent themes
71
138
  the whole page. A value that fails its gate falls back to the default, and the
72
- startup warning names it. `src/index.ts` carries the full shape commented out
73
- above `ui: operatorUi()`.
74
-
75
- Connection management needs an interactive identity. A configured bearer is a
76
- client key and never authorizes browser credential mutations. To enable Clerk:
77
-
78
- ```sh
79
- npm install @clerk/backend
80
- ```
81
-
82
- Set `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`, enable the corresponding
83
- `clerkAuth` import and auth entry in `src/index.ts`, and set `PUBLIC_URL`.
84
- Enable Dynamic Client Registration on the Clerk instance if MCP clients should
85
- sign in with OAuth. Connecta no longer issues named client access tokens; keep
86
- the configured bearer only for clients that need it.
139
+ startup warning names it. Pass it to `operatorUi()` in `src/connecta.config.ts`.
140
+
141
+ Connection management needs an interactive identity. A machine access token
142
+ never authorizes browser credential mutations. `@clerk/backend`
143
+ ships as a dependency of this template. To enable Clerk, set both
144
+ `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` (one without the other refuses to
145
+ start) and set `PUBLIC_URL`.
146
+ Enable `aud_claim_enabled: true` in Clerk's instance OAuth application settings
147
+ (`PATCH /v1/instance/oauth_application_settings` in Clerk's Backend API), then
148
+ read the setting back. Both JWT and opaque OAuth tokens are supported.
149
+ Leave `allowedOAuthClientIds` omitted or `[]` to require bound tokens.
150
+
151
+ Connecta's protected-resource metadata advertises the exact public `/mcp` or
152
+ `/mcp/<pool>` URL as `resource` and Clerk as the authorization server. MCP
153
+ hosts use that URL in their standard OAuth `resource` parameter. Enable the
154
+ Clerk registration methods your hosts need, including DCR or CIMD. Reconnect
155
+ after enabling audience issuance and confirm the new token's `aud` matches
156
+ the metadata URL, MCP initialization succeeds, and refresh retains the same
157
+ audience. Clerk's raw verification response exposes `aud` for opaque tokens.
158
+
159
+ An explicit `allowedOAuthClientIds` list is only a fallback for unbound tokens
160
+ from clients dedicated to this deployment. It never overrides a mismatched
161
+ audience. New DCR registrations need new entries, so prefer audience binding
162
+ for standard host onboarding. Clerk session tokens work only on operator
163
+ routes. [Inbound auth](https://github.com/zackbart/connecta/blob/main/documentation/auth.md#clerk-oauth-tokens-and-operator-sessions)
164
+ explains configuration, verification, and fixed rejection reason codes.
165
+ Machine clients use connecta-issued `cta_` access tokens
166
+ through `accessTokens(storage)`, which `src/connecta.config.ts` configures on
167
+ the database. Grant explicit `identity.accessTokenManagement` permissions to
168
+ let a signed-in human mint them. Trusted local provisioning above works without
169
+ Clerk and never requires opening the server.
87
170
 
88
171
  Set the code-owned identity resolvers deliberately. `connectorAccess` governs
89
172
  use; `credentialAdministration` permits shared-auth changes, and
@@ -94,20 +177,19 @@ connector where each person should connect their own downstream account.
94
177
 
95
178
  ### Credential vault
96
179
 
97
- Import `encryptedCredentialVault` from `@zackbart/connecta/credentials`, then
98
- set `vault: encryptedCredentialVault(storage, credentialKey)` — `storage` is
99
- the `fileStorage` binding `src/index.ts` already passes to `createConnecta`. Set
100
- `CONNECTA_CREDENTIAL_KEY` to a base64 32-byte AES key:
180
+ Set `CONNECTA_CREDENTIAL_KEY` to a base64 32-byte AES key and
181
+ `src/connecta.config.ts` passes `encryptedCredentialVault(storage, key)` over the
182
+ same database:
101
183
 
102
184
  ```sh
103
185
  node -e "console.log(crypto.randomBytes(32).toString('base64'))"
104
186
  ```
105
187
 
106
- Keep this key outside the state file. Losing it makes saved values unreadable;
188
+ Keep this key outside the database. Losing it makes saved values unreadable;
107
189
  upgrades must reuse it. The shipped `time` connector declares no credential
108
190
  slot. Add `credential: { label: "API token" }` to an `api()` connector and read
109
- it through `await ctx.credential?.get()`, or use a provider such as `notion()`
110
- that declares its own slot. Authorized humans manage the slot inside that
191
+ it through `await ctx.credential?.get()`, or use Notion's explicit
192
+ `surface: "api"` integration interface, which declares its own slot. Authorized humans manage the slot inside that
111
193
  connection on `/`; there is no separate Credentials tab.
112
194
 
113
195
  In 0.25.0, this vault also seals downstream OAuth tokens on their first read.
@@ -122,26 +204,26 @@ static credential recovery reports unavailable instead of offering a dead link.
122
204
 
123
205
  ### Activity history and diagnostics
124
206
 
125
- Import `activityHistory` from `@zackbart/connecta/activity` and wire the template's
126
- `fileActivityStore` through `activity: activityHistory({ store })`. The Activity
127
- tab appears for authorized readers when the store supports listing. Omit this
128
- option and its store wiring to record no activity.
207
+ Set `CONNECTA_ACTIVITY=on` and `src/connecta.config.ts` records activity with
208
+ `sqliteActivityStore(database, { retentionDays: 90 })` from
209
+ `@zackbart/connecta/sqlite`. The Activity tab appears for authorized readers.
210
+ Leave it empty to record no activity.
129
211
 
130
- `src/file-activity.ts` belongs to the deployment. It appends payload-free events
131
- and periodically retains the newest 5,000, allowing a small slack window between
132
- rewrites. Docker stores the log on the state volume. It records no arguments,
133
- results, generated code, or raw errors. Adjust retention in that file if needed.
212
+ Activity shares the one database file. Each write prunes a bounded batch of
213
+ rows older than `retentionDays`, so nothing has to be scheduled; change the
214
+ number in `src/connecta.config.ts`. It records no arguments, results, generated code, or raw errors.
134
215
 
135
216
  Diagnostics are independent. Keep the default logger or provide your own;
136
217
  `logger: "silent"` suppresses diagnostic output explicitly.
137
218
 
138
219
  The UI displays connections and current permissions. Configuration still owns
139
- the connector set, tool definitions, and access rules. There is no token tab,
140
- team roster, or policy editor.
220
+ the connector set, tool definitions, and access rules. Access token management
221
+ requires explicit Clerk operator permission. There is no team roster or policy editor.
141
222
 
142
223
  ## Deployment contract
143
224
 
144
- - Edit `src/index.ts` for connectors, auth, storage, and the public URL.
225
+ - Edit `src/connecta.config.ts` for connectors, auth, storage, the public URL,
226
+ and optional modules. `src/index.ts` only starts it.
145
227
  - Keep the required `executor: quickJsExecutor()` configuration; a deployment
146
228
  without an executor refuses to boot.
147
229
  - Keep secrets in environment variables or an external secret store.
@@ -156,19 +238,19 @@ Verify a change with:
156
238
  ```sh
157
239
  npm run typecheck
158
240
  # In another terminal, while the server is running (npm start or compose):
159
- CONNECTA_TOKEN=dev-token npm run doctor
241
+ CONNECTA_TOKEN='cta_REPLACE_WITH_RETURNED_SECRET' npm run doctor
160
242
  ```
161
243
 
162
- Doctor checks health, the executor, and the exact prescribed seven-tool
244
+ Doctor checks health, the executor, and the exact prescribed six-tool
163
245
  model-facing surface by running a harmless sandbox program. It reads the bearer
164
246
  from `CONNECTA_TOKEN`; it never accepts the secret as a command-line argument.
165
247
  Remote URLs must use HTTPS.
166
248
 
167
249
  A fully-wired deployment reports exactly the same line as a bare one —
168
- connector count, QuickJS executed, seven tools, plus any catalog drift:
250
+ connector count, QuickJS executed, six tools, plus any catalog drift:
169
251
 
170
252
  ```text
171
- Connecta doctor passed: 1 connector(s), QuickJS executed, prescribed seven-tool surface.
253
+ Connecta doctor passed: 1 connector(s), QuickJS executed, prescribed six-tool surface.
172
254
  ```
173
255
 
174
256
  `QuickJS` is this deployment's sandbox, reported by the deployment itself —
@@ -1,6 +1,8 @@
1
- # One service, no database: state is the fileStorage JSON on a named volume.
1
+ # One service, no database server: state is one SQLite file on a named volume.
2
2
  #
3
- # cp .env.example .env # then set CONNECTA_TOKEN
3
+ # cp .env.example .env
4
+ # docker compose build
5
+ # docker compose run --rm --no-deps connecta npm run --silent provision-token -- "machine-name"
4
6
  # docker compose up -d --build
5
7
  #
6
8
  # Compose reads `.env` from this directory, so one file configures both the
@@ -14,23 +16,20 @@ services:
14
16
  ports:
15
17
  - "${PORT:-8787}:${PORT:-8787}"
16
18
  environment:
17
- # Refuse to start without inbound auth — the same rule src/index.ts
18
- # enforces, stated early enough that `up` fails before the build.
19
- CONNECTA_TOKEN: ${CONNECTA_TOKEN:?set CONNECTA_TOKEN in .env}
19
+ # accessTokens(storage) is always installed; an empty database is closed.
20
+ # CONNECTA_TOKEN belongs to clients and is never configured on this server.
20
21
  PORT: ${PORT:-8787}
21
22
  # Downstream OAuth calls back to this origin. Unset is fine until this
22
23
  # deployment is reachable from somewhere other than this machine.
23
24
  PUBLIC_URL: ${PUBLIC_URL:-}
24
- # Keep the state file under /data so it lands on the volume below.
25
- CONNECTA_STATE_FILE: ${CONNECTA_STATE_FILE:-/data/connecta-state.json}
26
- # Operator surface. Passed through so the matching blocks in
27
- # src/index.ts work in the container the moment they are uncommented;
28
- # until then these are unread. The activity log joins the state file on
29
- # the volume for the same reason it does.
25
+ # Keep the database under /data so it lands on the volume below.
26
+ CONNECTA_DATABASE: ${CONNECTA_DATABASE:-/data/connecta.sqlite}
27
+ # Optional modules. Each switches its module in src/connecta.config.ts
28
+ # on when set and off when empty.
30
29
  CLERK_PUBLISHABLE_KEY: ${CLERK_PUBLISHABLE_KEY:-}
31
30
  CLERK_SECRET_KEY: ${CLERK_SECRET_KEY:-}
32
31
  CONNECTA_CREDENTIAL_KEY: ${CONNECTA_CREDENTIAL_KEY:-}
33
- CONNECTA_ACTIVITY_FILE: ${CONNECTA_ACTIVITY_FILE:-/data/connecta-activity.jsonl}
32
+ CONNECTA_ACTIVITY: ${CONNECTA_ACTIVITY:-}
34
33
  volumes:
35
34
  - connecta-state:/data
36
35
  restart: unless-stopped
@@ -4,18 +4,20 @@
4
4
  "version": "0.0.0",
5
5
  "type": "module",
6
6
  "engines": {
7
- "node": ">=22.0.0"
7
+ "node": ">=22.13.0"
8
8
  },
9
9
  "allowScripts": {
10
10
  "esbuild@0.28.2": true
11
11
  },
12
12
  "scripts": {
13
13
  "doctor": "connecta doctor",
14
+ "provision-token": "tsx src/provision-token.ts",
14
15
  "start": "tsx src/index.ts",
15
16
  "typecheck": "tsc --noEmit"
16
17
  },
17
18
  "dependencies": {
18
- "@zackbart/connecta": "0.28.1",
19
+ "@clerk/backend": "^3.12.0",
20
+ "@zackbart/connecta": "0.30.0",
19
21
  "quickjs-emscripten": "0.32.0"
20
22
  },
21
23
  "devDependencies": {
@@ -0,0 +1,119 @@
1
+ /**
2
+ * This deployment's configuration: connectors, authentication, storage, public
3
+ * origin, and the optional operator modules. Add application logic only inside
4
+ * deliberate api() connector handlers.
5
+ *
6
+ * Every optional module is type-checked code switched by the environment
7
+ * (.env.example lists each variable): set it and the module is on, leave it
8
+ * empty and it is off. README.md § "Select optional modules" covers each one.
9
+ * Connecta validates the result when src/index.ts starts it; a mistake refuses
10
+ * to boot rather than running in a shape nobody chose.
11
+ */
12
+ import { api, defineConfig } from "@zackbart/connecta";
13
+ import { activityHistory } from "@zackbart/connecta/activity";
14
+ import { accessTokens } from "@zackbart/connecta/auth/access-tokens";
15
+ import { clerkAuth } from "@zackbart/connecta/auth/clerk";
16
+ import { encryptedCredentialVault } from "@zackbart/connecta/credentials";
17
+ import { quickJsExecutor } from "@zackbart/connecta/quickjs";
18
+ import { openSqlite, sqliteActivityStore, sqliteStorage } from "@zackbart/connecta/sqlite";
19
+ import { operatorUi } from "@zackbart/connecta/ui";
20
+
21
+ /** The variables this file reads (see .env.example). */
22
+ export interface Env {
23
+ PORT?: string;
24
+ PUBLIC_URL?: string;
25
+ CONNECTA_DATABASE?: string;
26
+ CLERK_PUBLISHABLE_KEY?: string;
27
+ CLERK_SECRET_KEY?: string;
28
+ CONNECTA_CREDENTIAL_KEY?: string;
29
+ CONNECTA_ACTIVITY?: string;
30
+ }
31
+
32
+ export default defineConfig((env: Env) => {
33
+ // Empty is unset: an untouched `.env` passes through Compose as "".
34
+ const set = (name: keyof Env) => env[name] || undefined;
35
+ const publicUrl = set("PUBLIC_URL") ?? `http://localhost:${set("PORT") ?? 8787}`;
36
+
37
+ // Operator sign-in. Only a Clerk-authenticated human may manage connector
38
+ // credentials. Machine access tokens never grant interactive authority.
39
+ // Both keys, or neither.
40
+ const clerkPublishableKey = set("CLERK_PUBLISHABLE_KEY");
41
+ const clerkSecretKey = set("CLERK_SECRET_KEY");
42
+ if (Boolean(clerkPublishableKey) !== Boolean(clerkSecretKey)) {
43
+ throw new Error("Operator sign-in needs both CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY.");
44
+ }
45
+ const clerk =
46
+ clerkPublishableKey && clerkSecretKey
47
+ ? clerkAuth({
48
+ publishableKey: clerkPublishableKey,
49
+ secretKey: clerkSecretKey,
50
+ // Enable Clerk aud_claim_enabled; hosts request the MCP URL as
51
+ // resource. Bound JWT and opaque tokens are the default.
52
+ publicUrl,
53
+ // Restrict who may sign in with `allowedDomains: ["acme.com"]`, or
54
+ // `gate` for anything a domain cannot express. Absent, every
55
+ // authenticated Clerk user is admitted.
56
+ })
57
+ : undefined;
58
+ // Every piece of state — OAuth grants, sealed credentials, catalogs,
59
+ // paging, access tokens, activity — lives in this one file.
60
+ const database = openSqlite(set("CONNECTA_DATABASE") ?? "./.connecta.sqlite");
61
+ const storage = sqliteStorage(database);
62
+
63
+ // The credential vault. A connector that declares a `credential` slot
64
+ // becomes editable inside its connection on /, encrypted in the database
65
+ // with this key — so keep the key out of that file and out of source.
66
+ const credentialKey = set("CONNECTA_CREDENTIAL_KEY");
67
+
68
+ return {
69
+ storage,
70
+ publicUrl,
71
+ // Required: model-written programs run in a bounded QuickJS child.
72
+ executor: quickJsExecutor(),
73
+ auth: clerk ? [clerk] : [],
74
+ // Always installed: an empty database refuses machine requests. Provision
75
+ // locally with `npm run provision-token -- "machine-name"`, or grant an
76
+ // interactive human `identity.accessTokenManagement` for later issuance.
77
+ // v0.23 client tokens survive `connecta migrate-state` on this storage.
78
+ accessTokens: accessTokens(storage),
79
+ // Connection management permissions default to none, so the template
80
+ // grants them. Split members from operators with `connectorAccess`,
81
+ // `activityAccess`, and `accessTokenManagement`, each derived from the
82
+ // authenticated identity and never from an MCP argument.
83
+ identity: {
84
+ credentialAdministration: () => "all",
85
+ personalConnection: () => "all",
86
+ },
87
+ vault: credentialKey ? encryptedCredentialVault(storage, credentialKey) : undefined,
88
+ // Payload-free activity history at /activity: who called what, when, how
89
+ // long it took, and whether it worked. Each write prunes rows older than
90
+ // `retentionDays`; the number is yours to choose.
91
+ activity:
92
+ set("CONNECTA_ACTIVITY") === "on"
93
+ ? activityHistory({
94
+ store: sqliteActivityStore(database, { retentionDays: 90 }),
95
+ deploymentId: "production",
96
+ })
97
+ : undefined,
98
+ // The operator UI at /. Branding is code too: operatorUi({ branding }).
99
+ ui: operatorUi(),
100
+ connectors: [
101
+ api("time", {
102
+ description: "Time — current timestamp",
103
+ // A connector that needs an operator-managed secret declares a slot —
104
+ // credential: { label: "API token" },
105
+ // — and reads it inside a handler with `await ctx.credential?.get()`.
106
+ // Telling the time needs no secret, so this one declares nothing.
107
+ tools: [
108
+ {
109
+ name: "get_now",
110
+ description: "Return the current time as an ISO 8601 timestamp.",
111
+ inputSchema: { type: "object", properties: {} },
112
+ annotations: { readOnlyHint: true },
113
+ handler: async () => ({ now: new Date().toISOString() }),
114
+ },
115
+ ],
116
+ }),
117
+ ],
118
+ };
119
+ });
@@ -1,159 +1,14 @@
1
- import { bearerToken } from "@zackbart/connecta/auth/bearer";
2
- import { operatorUi } from "@zackbart/connecta/ui";
3
- // import { encryptedCredentialVault } from "@zackbart/connecta/credentials";
4
- // import { activityHistory } from "@zackbart/connecta/activity";
5
1
  /**
6
- * Prescribed Connecta deployment.
7
- *
8
- * Keep this file as deployment configuration: connectors, authentication,
9
- * storage, and public origin. Add application logic only inside deliberate
10
- * api() connector handlers.
11
- *
12
- * The optional modules — operator sign-in, credential vault, activity — ship
13
- * here as commented configuration, because each needs a secret or a retention
14
- * decision this file cannot make for you. Uncomment the block you want;
15
- * README.md § "Select optional modules" walks through all three.
16
- *
17
- * Environment (see .env.example):
18
- * CONNECTA_TOKEN required inbound bearer token
19
- * PORT listen port (default 8787)
20
- * PUBLIC_URL public origin; downstream OAuth calls back to it
21
- * CONNECTA_STATE_FILE fileStorage path (the container points it at /data)
22
- * CLERK_PUBLISHABLE_KEY operator sign-in, once the Clerk block is on
23
- * CLERK_SECRET_KEY operator sign-in, once the Clerk block is on
24
- * CONNECTA_CREDENTIAL_KEY vault key, once the credentials block is on
25
- * CONNECTA_ACTIVITY_FILE activity log, once the activity block is on
2
+ * Prescribed Connecta deployment. Configuration lives in src/connecta.config.ts;
3
+ * this file only starts it. The environment it reads is in .env.example.
26
4
  */
27
- import { api, createConnecta } from "@zackbart/connecta";
28
- import { fileStorage, listen } from "@zackbart/connecta/node";
29
- import { quickJsExecutor } from "@zackbart/connecta/quickjs";
30
- // import { accessTokens } from "@zackbart/connecta/auth/access-tokens";
31
- // import { artifacts, kvArtifactStore } from "@zackbart/connecta/artifacts";
32
- // Operator sign-in. Needs `npm install @clerk/backend` — it is an optional
33
- // peer, so it does not install with Connecta.
34
- // import { clerkAuth } from "@zackbart/connecta/auth/clerk";
35
- // Payload-free activity history, kept beside the state file.
36
- // import { fileActivityStore } from "./file-activity.js";
5
+ import { createConnecta } from "@zackbart/connecta";
6
+ import { listen } from "@zackbart/connecta/node";
7
+ import connectaConfig from "./connecta.config.js";
37
8
 
38
- const token = process.env.CONNECTA_TOKEN;
39
- if (!token) {
40
- throw new Error(
41
- "CONNECTA_TOKEN is required. Refusing to start without inbound auth.",
42
- );
43
- }
44
- const port = Number(process.env.PORT ?? 8787);
45
- // Empty is unset: an untouched `.env` passes through Compose as "", and an
46
- // empty state path or public origin is worse than the local default.
47
- const stateFile = process.env.CONNECTA_STATE_FILE || "./.connecta-state.json";
48
- const publicUrl = process.env.PUBLIC_URL || `http://localhost:${port}`;
49
- const storage = fileStorage(stateFile);
50
- // Optional artifact pages and refresh jobs use the same CAS-capable state file:
51
- // const artifactModule = artifacts({ store: kvArtifactStore(storage) });
52
-
53
- // Operator sign-in. A bearer token is a client key: it may call tools and read
54
- // connector status, but only a Clerk-authenticated human may write a visible
55
- // connector's credential. Without this block the operator UI still renders —
56
- // an operator pastes the bearer to read it — and connections stay read-only.
57
- // const clerkPublishableKey = process.env.CLERK_PUBLISHABLE_KEY;
58
- // const clerkSecretKey = process.env.CLERK_SECRET_KEY;
59
- // if (!clerkPublishableKey || !clerkSecretKey) {
60
- // throw new Error(
61
- // "Operator sign-in needs CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY.",
62
- // );
63
- // }
64
-
65
- const connecta = createConnecta({
66
- storage,
67
- // Reuse this storage to keep v0.23 client tokens without rotating secrets.
68
- // accessTokens: accessTokens(storage),
69
- auth: [
70
- bearerToken(token, { subjectId: "operator" }),
71
- // clerkAuth({
72
- // publishableKey: clerkPublishableKey,
73
- // secretKey: clerkSecretKey,
74
- // publicUrl,
75
- // // Restrict who may sign in — or use `gate` for anything a domain
76
- // // cannot express. Absent, every authenticated Clerk user is admitted.
77
- // // allowedDomains: ["acme.com"],
78
- // }),
79
- ],
80
- // Code-owned identity resolvers. Connection management permissions default to
81
- // none, so the template grants them. The commented pair is the optional
82
- // member/operator split for Clerk-backed deployments: connector access is
83
- // derived from the authenticated identity and cannot be selected by an MCP
84
- // argument. Leave them commented for the all-visible,
85
- // all-interactive-users-read-activity behavior.
86
- identity: {
87
- credentialAdministration: () => "all",
88
- personalConnection: () => "all",
89
- // connectorAccess: ({ principal }) =>
90
- // principal?.id === "user_admin" ? "all" : ["time"],
91
- // activityAccess: ({ id }) => id === "user_admin",
92
- // accessTokenManagement: ({ principal }) => principal?.id === "user_admin",
93
- },
94
- publicUrl,
95
- // Required: model-written programs run in a bounded QuickJS child.
96
- executor: quickJsExecutor(),
97
- // Credential vault. A connector that declares a `credential` slot becomes
98
- // editable inside its connection on /, and its value is encrypted in the state file
99
- // with this key — so keep the key out of that file and out of source:
100
- // node -e "console.log(crypto.randomBytes(32).toString('base64'))"
101
- // Rotating a credential takes effect on the next call; no restart.
102
- // vault: encryptedCredentialVault(storage, process.env.CONNECTA_CREDENTIAL_KEY!),
103
- // Payload-free activity history at /activity: who called what, when, how
104
- // long it took, and whether it worked. Never arguments, results, generated
105
- // code, or raw error messages. Commented because retention is yours to
106
- // choose — see src/file-activity.ts.
107
- // activity: activityHistory({
108
- // store: fileActivityStore(
109
- // process.env.CONNECTA_ACTIVITY_FILE || "./.connecta-activity.jsonl",
110
- // ),
111
- // deploymentId: "production",
112
- // }),
113
- // The operator UI at /. Its branding is code, like everything else here:
114
- // name, owner, description, favicon, and five theme tokens that every
115
- // other color is mixed from. A value that fails its check falls back to the
116
- // default, and the startup warning names it.
117
- // ui: operatorUi({
118
- // branding: {
119
- // productName: "Acme Tools",
120
- // ownerName: "Acme",
121
- // theme: {
122
- // accent: "#2f5fe0", // hex only
123
- // radius: 10, // pixels, or a CSS length such as "0.5rem"
124
- // fontFamily: "Inter, system-ui, sans-serif",
125
- // monoFamily: "ui-monospace, monospace",
126
- // colorScheme: "system", // or "light" | "dark"
127
- // },
128
- // },
129
- // }),
130
- ui: operatorUi(),
131
- // artifacts: artifactModule,
132
- connectors: [
133
- api("time", {
134
- description: "Time — current timestamp",
135
- // A connector that needs an operator-managed secret declares a slot —
136
- // credential: { label: "API token" },
137
- // — and reads it inside a handler with `await ctx.credential?.get()`.
138
- // Telling the time needs no secret, so this one declares nothing.
139
- tools: [
140
- {
141
- name: "get_now",
142
- description: "Return the current time as an ISO 8601 timestamp.",
143
- inputSchema: { type: "object", properties: {} },
144
- annotations: { readOnlyHint: true },
145
- handler: async () => ({ now: new Date().toISOString() }),
146
- },
147
- ],
148
- }),
149
- ],
150
- });
9
+ const config = connectaConfig(process.env);
10
+ const connecta = createConnecta(config);
11
+ const port = Number(process.env.PORT || 8787);
151
12
 
152
13
  listen(connecta, port);
153
- console.log(`connecta listening on port ${port}; MCP at ${publicUrl}/mcp`);
154
- // The deployment owns this timer; core starts no background work. Uncomment
155
- // with artifactModule above. Each tick starts at most 10 due pages.
156
- // const refreshTimer = setInterval(() => {
157
- // void artifactModule.runDue().catch((error) => console.error("artifact refresh failed", error));
158
- // }, 60 * 60 * 1000);
159
- // refreshTimer.unref();
14
+ console.log(`connecta listening on port ${port}; MCP at ${config.publicUrl}/mcp`);