@zackbart/connecta 0.15.0 → 0.16.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/AGENTS.md +28 -15
  2. package/CHANGELOG.md +493 -0
  3. package/README.md +19 -4
  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 +0 -1
  27. package/dist/catalog.d.ts +0 -1
  28. package/dist/catalog.js +0 -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 +0 -1
  42. package/dist/errors.js +0 -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 +5 -2
  78. package/dist/providers/cloudflare.js +435 -328
  79. package/dist/providers/linear.d.ts +26 -5
  80. package/dist/providers/linear.js +32 -60
  81. package/dist/providers/mixpanel.d.ts +35 -4
  82. package/dist/providers/mixpanel.js +53 -78
  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 -59
  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 +95 -27
  129. package/documentation/code-mode.md +12 -12
  130. package/documentation/connector-guides.md +172 -5
  131. package/documentation/connectors.md +98 -7
  132. package/documentation/linear.md +26 -9
  133. package/documentation/mcp-ui-design.md +2 -2
  134. package/documentation/mixpanel.md +48 -16
  135. package/documentation/notion.md +16 -0
  136. package/documentation/operations.md +283 -5
  137. package/documentation/operator-ui.md +120 -5
  138. package/documentation/provider-audit.md +160 -0
  139. package/documentation/provider-conventions.md +631 -0
  140. package/documentation/request-admission.md +167 -5
  141. package/documentation/rich-output-design.md +1 -2
  142. package/documentation/stripe.md +27 -12
  143. package/ethos.md +14 -9
  144. package/examples/worker/README.md +96 -12
  145. package/examples/worker/src/index.ts +46 -1
  146. package/examples/worker/wrangler.jsonc +14 -1
  147. package/package.json +4 -5
  148. package/templates/node/.dockerignore +10 -0
  149. package/templates/node/.env.example +40 -3
  150. package/templates/node/AGENTS.md +11 -1
  151. package/templates/node/Dockerfile +49 -0
  152. package/templates/node/README.md +117 -2
  153. package/templates/node/docker-compose.yml +39 -0
  154. package/templates/node/package.json +1 -1
  155. package/templates/node/src/file-activity.ts +182 -0
  156. package/templates/node/src/index.ts +80 -4
  157. package/assets/connecta-clay-hero.png +0 -0
  158. package/dist/access-tokens.d.ts.map +0 -1
  159. package/dist/access-tokens.js.map +0 -1
  160. package/dist/activity.d.ts.map +0 -1
  161. package/dist/activity.js.map +0 -1
  162. package/dist/apps-shell.d.ts.map +0 -1
  163. package/dist/apps-shell.js.map +0 -1
  164. package/dist/auth/bearer.d.ts.map +0 -1
  165. package/dist/auth/bearer.js.map +0 -1
  166. package/dist/auth/clerk.d.ts.map +0 -1
  167. package/dist/auth/clerk.js.map +0 -1
  168. package/dist/auth/downstream-oauth.d.ts.map +0 -1
  169. package/dist/auth/downstream-oauth.js.map +0 -1
  170. package/dist/call-admission.d.ts.map +0 -1
  171. package/dist/call-admission.js.map +0 -1
  172. package/dist/catalog-fingerprint.d.ts.map +0 -1
  173. package/dist/catalog-fingerprint.js.map +0 -1
  174. package/dist/catalog-limits.d.ts.map +0 -1
  175. package/dist/catalog-limits.js.map +0 -1
  176. package/dist/catalog-service.d.ts.map +0 -1
  177. package/dist/catalog-service.js.map +0 -1
  178. package/dist/catalog.d.ts.map +0 -1
  179. package/dist/catalog.js.map +0 -1
  180. package/dist/concurrency.d.ts.map +0 -1
  181. package/dist/concurrency.js.map +0 -1
  182. package/dist/connector-scope.d.ts.map +0 -1
  183. package/dist/connector-scope.js.map +0 -1
  184. package/dist/connectors/api.d.ts.map +0 -1
  185. package/dist/connectors/api.js.map +0 -1
  186. package/dist/connectors/remote-mcp.d.ts.map +0 -1
  187. package/dist/connectors/remote-mcp.js.map +0 -1
  188. package/dist/credentials.d.ts.map +0 -1
  189. package/dist/credentials.js.map +0 -1
  190. package/dist/errors.d.ts.map +0 -1
  191. package/dist/errors.js.map +0 -1
  192. package/dist/execute.d.ts.map +0 -1
  193. package/dist/execute.js.map +0 -1
  194. package/dist/executor-admission.d.ts.map +0 -1
  195. package/dist/executor-admission.js.map +0 -1
  196. package/dist/executor-result.d.ts.map +0 -1
  197. package/dist/executor-result.js.map +0 -1
  198. package/dist/executors/quickjs-child.d.ts.map +0 -1
  199. package/dist/executors/quickjs-child.js.map +0 -1
  200. package/dist/executors/quickjs-protocol.d.ts.map +0 -1
  201. package/dist/executors/quickjs-protocol.js.map +0 -1
  202. package/dist/executors/quickjs-runtime.d.ts.map +0 -1
  203. package/dist/executors/quickjs-runtime.js.map +0 -1
  204. package/dist/executors/quickjs.d.ts.map +0 -1
  205. package/dist/executors/quickjs.js.map +0 -1
  206. package/dist/favicon.d.ts.map +0 -1
  207. package/dist/favicon.js.map +0 -1
  208. package/dist/index.d.ts.map +0 -1
  209. package/dist/index.js.map +0 -1
  210. package/dist/invocation.d.ts.map +0 -1
  211. package/dist/invocation.js.map +0 -1
  212. package/dist/json-schema.d.ts.map +0 -1
  213. package/dist/json-schema.js.map +0 -1
  214. package/dist/mcp-result.d.ts.map +0 -1
  215. package/dist/mcp-result.js.map +0 -1
  216. package/dist/meta-tools.d.ts.map +0 -1
  217. package/dist/meta-tools.js.map +0 -1
  218. package/dist/node.d.ts.map +0 -1
  219. package/dist/node.js.map +0 -1
  220. package/dist/operator-ui/generated.d.ts.map +0 -1
  221. package/dist/operator-ui/generated.js.map +0 -1
  222. package/dist/operator-ui/model.d.ts.map +0 -1
  223. package/dist/operator-ui/model.js.map +0 -1
  224. package/dist/providers/cloudflare.d.ts.map +0 -1
  225. package/dist/providers/cloudflare.js.map +0 -1
  226. package/dist/providers/linear.d.ts.map +0 -1
  227. package/dist/providers/linear.js.map +0 -1
  228. package/dist/providers/mixpanel.d.ts.map +0 -1
  229. package/dist/providers/mixpanel.js.map +0 -1
  230. package/dist/providers/notion.d.ts.map +0 -1
  231. package/dist/providers/notion.js.map +0 -1
  232. package/dist/providers/stripe.d.ts.map +0 -1
  233. package/dist/providers/stripe.js.map +0 -1
  234. package/dist/registry.d.ts.map +0 -1
  235. package/dist/registry.js.map +0 -1
  236. package/dist/retired-toolkits.d.ts.map +0 -1
  237. package/dist/retired-toolkits.js.map +0 -1
  238. package/dist/routes/access-tokens.d.ts.map +0 -1
  239. package/dist/routes/access-tokens.js.map +0 -1
  240. package/dist/routes/activity.d.ts.map +0 -1
  241. package/dist/routes/activity.js.map +0 -1
  242. package/dist/routes/credentials.d.ts.map +0 -1
  243. package/dist/routes/credentials.js.map +0 -1
  244. package/dist/routes/mcp.d.ts.map +0 -1
  245. package/dist/routes/mcp.js.map +0 -1
  246. package/dist/routes/oauth.d.ts.map +0 -1
  247. package/dist/routes/oauth.js.map +0 -1
  248. package/dist/routes/shared.d.ts.map +0 -1
  249. package/dist/routes/shared.js.map +0 -1
  250. package/dist/routes/ui.d.ts.map +0 -1
  251. package/dist/routes/ui.js.map +0 -1
  252. package/dist/server.d.ts.map +0 -1
  253. package/dist/server.js.map +0 -1
  254. package/dist/skills.d.ts.map +0 -1
  255. package/dist/skills.js.map +0 -1
  256. package/dist/storage/file.d.ts.map +0 -1
  257. package/dist/storage/file.js.map +0 -1
  258. package/dist/storage/memory.d.ts.map +0 -1
  259. package/dist/storage/memory.js.map +0 -1
  260. package/dist/timeout.d.ts.map +0 -1
  261. package/dist/timeout.js.map +0 -1
  262. package/dist/tool-safety.d.ts.map +0 -1
  263. package/dist/tool-safety.js.map +0 -1
  264. package/dist/types.d.ts.map +0 -1
  265. package/dist/types.js.map +0 -1
  266. package/dist/ui.d.ts.map +0 -1
  267. package/dist/ui.js.map +0 -1
  268. package/dist/validate.d.ts.map +0 -1
  269. package/dist/validate.js.map +0 -1
  270. package/dist/version.d.ts.map +0 -1
  271. package/dist/version.js.map +0 -1
  272. package/examples/node/README.md +0 -52
  273. package/examples/node/src/index.ts +0 -71
  274. package/src/access-tokens.ts +0 -289
  275. package/src/activity.ts +0 -234
  276. package/src/apps-shell.ts +0 -370
  277. package/src/auth/bearer.ts +0 -61
  278. package/src/auth/clerk.ts +0 -553
  279. package/src/auth/downstream-oauth.ts +0 -575
  280. package/src/call-admission.ts +0 -521
  281. package/src/catalog-fingerprint.ts +0 -52
  282. package/src/catalog-limits.ts +0 -11
  283. package/src/catalog-service.ts +0 -1153
  284. package/src/catalog.ts +0 -790
  285. package/src/concurrency.ts +0 -39
  286. package/src/connector-scope.ts +0 -66
  287. package/src/connectors/api.ts +0 -159
  288. package/src/connectors/remote-mcp.ts +0 -1090
  289. package/src/credentials.ts +0 -428
  290. package/src/errors.ts +0 -364
  291. package/src/execute.ts +0 -1406
  292. package/src/executor-admission.ts +0 -328
  293. package/src/executor-result.ts +0 -107
  294. package/src/executors/quickjs-child.ts +0 -172
  295. package/src/executors/quickjs-protocol.ts +0 -99
  296. package/src/executors/quickjs-runtime.ts +0 -470
  297. package/src/executors/quickjs.ts +0 -776
  298. package/src/favicon.ts +0 -53
  299. package/src/index.ts +0 -666
  300. package/src/invocation.ts +0 -655
  301. package/src/json-schema.ts +0 -11
  302. package/src/mcp-result.ts +0 -43
  303. package/src/meta-tools.ts +0 -1607
  304. package/src/node.ts +0 -206
  305. package/src/operator-ui/browser.css +0 -423
  306. package/src/operator-ui/browser.ts +0 -1281
  307. package/src/operator-ui/generated.ts +0 -4
  308. package/src/operator-ui/model.ts +0 -111
  309. package/src/providers/cloudflare.ts +0 -3803
  310. package/src/providers/linear.ts +0 -301
  311. package/src/providers/mixpanel.ts +0 -228
  312. package/src/providers/notion.ts +0 -1879
  313. package/src/providers/stripe.ts +0 -306
  314. package/src/registry.ts +0 -1085
  315. package/src/retired-toolkits.ts +0 -14
  316. package/src/routes/access-tokens.ts +0 -115
  317. package/src/routes/activity.ts +0 -215
  318. package/src/routes/credentials.ts +0 -254
  319. package/src/routes/mcp.ts +0 -429
  320. package/src/routes/oauth.ts +0 -322
  321. package/src/routes/shared.ts +0 -247
  322. package/src/routes/ui.ts +0 -152
  323. package/src/server.ts +0 -195
  324. package/src/skills.ts +0 -271
  325. package/src/storage/file.ts +0 -123
  326. package/src/storage/memory.ts +0 -44
  327. package/src/timeout.ts +0 -84
  328. package/src/tool-safety.ts +0 -15
  329. package/src/types.ts +0 -523
  330. package/src/ui.ts +0 -744
  331. package/src/validate.ts +0 -387
  332. package/src/version.ts +0 -7
package/src/activity.ts DELETED
@@ -1,234 +0,0 @@
1
- import { boundedEchoText } from "./errors.js";
2
- import type { Logger } from "./types.js";
3
-
4
- /**
5
- * How long an identity field may be before the store stops believing it.
6
- *
7
- * `connectorId` and `toolName` are ordinarily operator- and connector-authored,
8
- * and 128 bytes is far past any real one. But an address that resolved to
9
- * nothing is recorded *as written*, which puts a caller-authored string in both
10
- * fields — and "payload-free by construction" has to mean the event type has
11
- * nowhere to put a payload, not merely that connecta declines to. A 40 KB
12
- * invented connector id is a payload wearing an id's clothing.
13
- *
14
- * Clamped rather than dropped: the invented id is precisely what an operator
15
- * needs to see, and its first 128 bytes identify the mistake as well as all
16
- * 40,000 would. The `…` marker keeps a clamped value from reading as a real one.
17
- */
18
- const MAX_ACTIVITY_NAME_BYTES = 128;
19
-
20
- /** Two names and the dot between them. */
21
- const MAX_ACTIVITY_ADDRESS_BYTES = MAX_ACTIVITY_NAME_BYTES * 2 + 1;
22
-
23
- export type ActivityCallSource =
24
- | "call_tool"
25
- | "call_destructive_tool"
26
- // Read-only history. Nothing emits `batch_call` since issue #273 removed the
27
- // tool, but activity storage is append-only: rows written by older
28
- // deployments are still read back — the D1 example maps a stored row straight
29
- // into this type — and an operator's timeline should not have to lie about
30
- // where a call came from. Never widen this member back into a live source.
31
- | "batch_call"
32
- | "execute_code";
33
-
34
- export type ActivityOutcome =
35
- | "success"
36
- | "error"
37
- | "timeout"
38
- | "cancelled";
39
-
40
- export type AgentFriction =
41
- | "tool_not_found"
42
- | "schema_retry"
43
- | "destructive_reroute"
44
- | "auth_required"
45
- | "result_too_large";
46
-
47
- /** Coarse recovery class derived without inspecting payloads or error prose. */
48
- export function agentFrictionForCode(
49
- code: string | undefined,
50
- ): AgentFriction | undefined {
51
- switch (code) {
52
- case "unknown_address":
53
- case "unknown_tool":
54
- case "ambiguous_tool_alias":
55
- return "tool_not_found";
56
- case "invalid_args":
57
- return "schema_retry";
58
- case "destructive_tool_requires_approval":
59
- return "destructive_reroute";
60
- case "auth_required":
61
- return "auth_required";
62
- case "result_too_large":
63
- return "result_too_large";
64
- default:
65
- return undefined;
66
- }
67
- }
68
-
69
- /**
70
- * Authenticated identity attached to an activity event. `id` is intentionally
71
- * optional: open deployments and shared bearer tokens cannot honestly identify
72
- * a person.
73
- */
74
- export interface ActivityActor {
75
- kind: string;
76
- id?: string;
77
- /**
78
- * Stable, non-secret identity-directory namespace supplied by the admitting
79
- * auth provider. It lets authorized reads resolve ids through the same
80
- * provider rather than another provider that happens to share `kind`.
81
- */
82
- namespace?: string;
83
- }
84
-
85
- /**
86
- * Privacy-minimal history of one resolved downstream connector call.
87
- *
88
- * Arguments, results, generated code, search text, and raw errors are excluded
89
- * by construction. Deployments that need a safe human summary can add a
90
- * separate, explicit connector-level feature later.
91
- */
92
- export interface ToolCallActivityEvent {
93
- schemaVersion: 1;
94
- id: string;
95
- occurredAt: string;
96
- requestId: string;
97
- actor: ActivityActor;
98
- connectorId: string;
99
- toolName: string;
100
- address: string;
101
- source: ActivityCallSource;
102
- outcome: ActivityOutcome;
103
- durationMs: number;
104
- attempts: number;
105
- /** Set only when the call actually failed; a truncated success has none. */
106
- errorCode?: string;
107
- /**
108
- * Payload-free recovery class. Usually derived from `errorCode`, but it can
109
- * also stand alone: a result too large to return inline is friction for the
110
- * agent while remaining an `outcome: "success"` call with no error code.
111
- */
112
- friction?: AgentFriction;
113
- serverName: string;
114
- serverVersion: string;
115
- deploymentId?: string;
116
- }
117
-
118
- export interface ActivityPage {
119
- events: ToolCallActivityEvent[];
120
- nextCursor?: string;
121
- }
122
-
123
- /** Display-only actor returned by the authenticated activity read API. */
124
- export interface ActivityReadActor extends ActivityActor {
125
- label?: string;
126
- }
127
-
128
- export type ActivityReadEvent = Omit<ToolCallActivityEvent, "actor"> & {
129
- actor: ActivityReadActor;
130
- };
131
-
132
- export interface ActivityReadPage {
133
- events: ActivityReadEvent[];
134
- nextCursor?: string;
135
- }
136
-
137
- /** Write-only deployments can implement only this small, vendor-neutral seam. */
138
- export interface ActivitySink {
139
- record(event: ToolCallActivityEvent): void | Promise<void>;
140
- }
141
-
142
- /** Optional read side used by Connecta's authenticated Activity UI. */
143
- export interface ActivityReader {
144
- list(options: { cursor?: string; limit: number }): Promise<ActivityPage>;
145
- }
146
-
147
- export interface ActivityStore extends ActivitySink {
148
- list?: ActivityReader["list"];
149
- }
150
-
151
- /** Reader implementations throw this for an opaque cursor they cannot decode. */
152
- export class InvalidActivityCursorError extends Error {
153
- override name = "InvalidActivityCursorError";
154
-
155
- constructor() {
156
- super("invalid activity cursor");
157
- }
158
- }
159
-
160
- export type ActivityReadGate = (
161
- actor: ActivityActor,
162
- ) => boolean | Promise<boolean>;
163
-
164
- /** Request-scoped context shared by direct, batch, and code-mode call paths. */
165
- export interface ActivityRequestContext {
166
- sink: ActivitySink;
167
- actor: ActivityActor;
168
- requestId: string;
169
- serverInfo: { name: string; version: string };
170
- deploymentId?: string;
171
- defer?: (promise: Promise<unknown>) => void;
172
- logger: Logger;
173
- }
174
-
175
- export type ActivityEventInput = Pick<
176
- ToolCallActivityEvent,
177
- | "connectorId"
178
- | "toolName"
179
- | "address"
180
- | "source"
181
- | "outcome"
182
- | "durationMs"
183
- | "attempts"
184
- | "errorCode"
185
- | "friction"
186
- >;
187
-
188
- /**
189
- * Best-effort by design: activity storage can never change a tool result.
190
- * Workers attach async sinks to waitUntil; synchronous sinks such as Analytics
191
- * Engine complete inline; Node promises remain detached from the response.
192
- */
193
- export function recordToolActivity(
194
- context: ActivityRequestContext | undefined,
195
- input: ActivityEventInput,
196
- ): void {
197
- if (!context) return;
198
- // A caller-supplied class wins because it knows something the code table
199
- // cannot: friction that belongs to a call which did not fail.
200
- const friction = input.friction ?? agentFrictionForCode(input.errorCode);
201
- const event: ToolCallActivityEvent = {
202
- schemaVersion: 1,
203
- id: crypto.randomUUID(),
204
- occurredAt: new Date().toISOString(),
205
- requestId: context.requestId,
206
- actor: context.actor,
207
- connectorId: boundedEchoText(input.connectorId, MAX_ACTIVITY_NAME_BYTES),
208
- toolName: boundedEchoText(input.toolName, MAX_ACTIVITY_NAME_BYTES),
209
- address: boundedEchoText(input.address, MAX_ACTIVITY_ADDRESS_BYTES),
210
- source: input.source,
211
- outcome: input.outcome,
212
- durationMs: Math.max(0, Math.trunc(input.durationMs)),
213
- attempts: Math.max(1, Math.trunc(input.attempts)),
214
- ...(input.errorCode ? { errorCode: input.errorCode } : {}),
215
- ...(friction ? { friction } : {}),
216
- serverName: context.serverInfo.name,
217
- serverVersion: context.serverInfo.version,
218
- ...(context.deploymentId
219
- ? { deploymentId: context.deploymentId }
220
- : {}),
221
- };
222
- try {
223
- const result = context.sink.record(event);
224
- if (!result || typeof (result as Promise<unknown>).then !== "function") {
225
- return;
226
- }
227
- const pending = Promise.resolve(result).catch((error) => {
228
- context.logger.warn("[connecta] activity record failed", error);
229
- });
230
- if (context.defer) context.defer(pending);
231
- } catch (error) {
232
- context.logger.warn("[connecta] activity record failed", error);
233
- }
234
- }
package/src/apps-shell.ts DELETED
@@ -1,370 +0,0 @@
1
- /**
2
- * The one MCP Apps template connecta serves (`U5`, `U6`).
3
- *
4
- * A build-time string constant, not a file read at startup: the core is
5
- * Web-API-only so it runs unchanged on Workers, and the same bytes have to
6
- * serve everywhere. It renders whatever HTML a program handed `connecta.ui`
7
- * inside a nested `srcdoc` frame. The one-argument form forwards no channel;
8
- * an explicitly bound view gets only named read calls through the trusted
9
- * shell, never a raw host channel.
10
- *
11
- * The address carries a version segment because hosts are permitted to
12
- * prefetch and cache templates by URI: change these bytes, bump the version.
13
- */
14
-
15
- /** The only `ui://` URI in the system. No program input reaches it. */
16
- export const PROGRAM_UI_RESOURCE_URI = "ui://connecta/program-ui/v2";
17
-
18
- /** The mimeType the Apps spec requires of an HTML template. */
19
- export const PROGRAM_UI_MIME_TYPE = "text/html;profile=mcp-app";
20
-
21
- /**
22
- * The result `_meta` key carrying the payload (`U3`). A plain single-label
23
- * prefix rather than the reverse-DNS form MCP's SHOULD prefers: connecta has
24
- * no domain to reverse, and fabricating one to satisfy a SHOULD is a worse
25
- * answer than the shape the key format's MUST already permits.
26
- */
27
- export const PROGRAM_UI_META_KEY = "connecta/ui";
28
-
29
- /** The one extension identifier connecta advertises (`U11`). */
30
- export const MCP_APPS_EXTENSION = "io.modelcontextprotocol/ui";
31
-
32
- /**
33
- * The shell document. Dependency-free and deliberately small: it speaks the
34
- * Apps postMessage dialect (`ui/initialize`, `ui/notifications/initialized`,
35
- * `ui/notifications/tool-result`, `ui/notifications/size-changed`,
36
- * `ui/resource-teardown`), lifts `_meta["connecta/ui"].html` out of the
37
- * delivered tool result, and puts it in a frame. An optional read manifest
38
- * installs one narrow `connecta.read(name, args)` bridge in that inner frame;
39
- * the outer shell maps declared names to the existing `call_tool` meta-tool.
40
- * It declares no CSP domains, so the host applies its restrictive default and
41
- * the `srcdoc` frame inherits `default-src 'none'` — program markup still gets
42
- * no direct network.
43
- */
44
- export const PROGRAM_UI_SHELL_HTML = `<!doctype html>
45
- <html lang="en">
46
- <head>
47
- <meta charset="utf-8" />
48
- <meta name="viewport" content="width=device-width, initial-scale=1" />
49
- <title>connecta program view</title>
50
- <style>
51
- html,
52
- body {
53
- margin: 0;
54
- padding: 0;
55
- background: transparent;
56
- }
57
- #program-view {
58
- display: block;
59
- width: 100%;
60
- min-height: 480px;
61
- border: 0;
62
- }
63
- </style>
64
- </head>
65
- <body>
66
- <iframe
67
- id="program-view"
68
- title="Program-rendered view"
69
- sandbox="allow-scripts"
70
- srcdoc=""
71
- ></iframe>
72
- <script>
73
- (function () {
74
- "use strict";
75
- // The outer shell is the only host peer. The payload frame is
76
- // sandboxed to scripts alone, with no same-origin escape. Its one
77
- // optional message dialect is handled below and translated into
78
- // bounded call_tool requests; raw JSON-RPC is never forwarded.
79
- var host = window.parent;
80
- var view = document.getElementById("program-view");
81
- var initializeId = "connecta-ui-initialize";
82
- var lastWidth = 0;
83
- var lastHeight = 0;
84
- var reads = null;
85
- var hostCanCallTools = false;
86
- var nextHostRequestId = 0;
87
- var pendingHostReads = Object.create(null);
88
- var activeHostReads = 0;
89
- var maxActiveHostReads = 8;
90
-
91
- function send(message) {
92
- if (!host || host === window) return;
93
- host.postMessage(message, "*");
94
- }
95
-
96
- function notify(method, params) {
97
- send({ jsonrpc: "2.0", method: method, params: params });
98
- }
99
-
100
- // Program views are fixed-height by construction. The shell has no
101
- // content-height bridge to the payload frame, so it can never learn
102
- // the payload's content height, and
103
- // what it reports here is its own box: the min-height above, unless
104
- // the host has given it more. Taller content scrolls inside the inner
105
- // frame rather than growing the view. Raising the min-height is the
106
- // only lever; a content-height signal would cost the isolation.
107
- function reportSize() {
108
- var width = Math.ceil(document.documentElement.clientWidth);
109
- var height = Math.ceil(document.documentElement.scrollHeight);
110
- if (width === lastWidth && height === lastHeight) return;
111
- lastWidth = width;
112
- lastHeight = height;
113
- notify("ui/notifications/size-changed", {
114
- width: width,
115
- height: height
116
- });
117
- }
118
-
119
- function payload(result) {
120
- if (!result || typeof result !== "object") return null;
121
- var meta = result._meta;
122
- if (!meta || typeof meta !== "object") return null;
123
- var value = meta["connecta/ui"];
124
- if (!value || typeof value !== "object") return null;
125
- return typeof value.html === "string" && value.html.length > 0
126
- ? value
127
- : null;
128
- }
129
-
130
- // This function is serialized into the opaque-origin payload frame.
131
- // It knows no addresses and has no host channel of its own: one named
132
- // read request goes to the trusted outer shell and one correlated
133
- // result comes back.
134
- function payloadReadBridge() {
135
- "use strict";
136
- var pending = Object.create(null);
137
- var nextId = 0;
138
-
139
- function read(name, args) {
140
- return new Promise(function (resolve, reject) {
141
- var id = String(++nextId);
142
- pending[id] = { resolve: resolve, reject: reject };
143
- try {
144
- window.parent.postMessage({
145
- type: "connecta/read",
146
- id: id,
147
- name: name,
148
- args: args === undefined ? {} : args
149
- }, "*");
150
- } catch (error) {
151
- delete pending[id];
152
- reject(error);
153
- }
154
- });
155
- }
156
-
157
- Object.defineProperty(globalThis, "connecta", {
158
- value: Object.freeze({ read: read }),
159
- configurable: false,
160
- enumerable: true,
161
- writable: false
162
- });
163
-
164
- window.addEventListener("message", function (event) {
165
- if (event.source !== window.parent) return;
166
- var message = event.data;
167
- if (!message || message.type !== "connecta/read-result") return;
168
- var waiter = pending[message.id];
169
- if (!waiter) return;
170
- delete pending[message.id];
171
- if (message.ok) waiter.resolve(message.value);
172
- else waiter.reject(new Error(message.error || "Read failed"));
173
- });
174
- }
175
-
176
- function htmlWithReadBridge(html) {
177
- var script =
178
- "<scr" + "ipt>(" + payloadReadBridge.toString() + ")();</scr" + "ipt>";
179
- var head = /<head(?:\\s[^>]*)?>/i.exec(html);
180
- if (head) {
181
- var at = (head.index || 0) + head[0].length;
182
- return html.slice(0, at) + script + html.slice(at);
183
- }
184
- var document = /<html(?:\\s[^>]*)?>/i.exec(html);
185
- if (document) {
186
- var afterHtml = (document.index || 0) + document[0].length;
187
- return html.slice(0, afterHtml) + "<head>" + script + "</head>" + html.slice(afterHtml);
188
- }
189
- return script + html;
190
- }
191
-
192
- function render(params) {
193
- var value =
194
- payload(params) ||
195
- payload(params && params.result) ||
196
- payload(params && params.toolResult);
197
- if (value === null) return;
198
- reads = value.reads && typeof value.reads === "object"
199
- ? value.reads
200
- : null;
201
- view.srcdoc = reads
202
- ? htmlWithReadBridge(value.html)
203
- : value.html;
204
- reportSize();
205
- }
206
-
207
- function readError(message, fallback) {
208
- if (message && typeof message.message === "string") return message.message;
209
- if (message && message.data && typeof message.data.message === "string") {
210
- return message.data.message;
211
- }
212
- return fallback;
213
- }
214
-
215
- function finishInnerRead(innerId, ok, value) {
216
- if (!view.contentWindow) return;
217
- view.contentWindow.postMessage(ok
218
- ? { type: "connecta/read-result", id: innerId, ok: true, value: value }
219
- : { type: "connecta/read-result", id: innerId, ok: false, error: value }, "*");
220
- }
221
-
222
- function beginInnerRead(message) {
223
- if (!hostCanCallTools) {
224
- finishInnerRead(message && message.id, false, "This host does not support app-initiated server tool calls");
225
- return;
226
- }
227
- if (!message || typeof message.id !== "string" || typeof message.name !== "string") return;
228
- if (!reads || !Object.prototype.hasOwnProperty.call(reads, message.name)) {
229
- finishInnerRead(message.id, false, "Unknown read binding");
230
- return;
231
- }
232
- if (activeHostReads >= maxActiveHostReads) {
233
- finishInnerRead(message.id, false, "Too many concurrent reads");
234
- return;
235
- }
236
- var binding = reads[message.name];
237
- if (!binding || typeof binding !== "object" || typeof binding.address !== "string") {
238
- finishInnerRead(message.id, false, "Invalid read binding");
239
- return;
240
- }
241
- var supplied = message.args;
242
- if (!supplied || typeof supplied !== "object" || Array.isArray(supplied)) {
243
- finishInnerRead(message.id, false, "Read arguments must be an object");
244
- return;
245
- }
246
- var allowed = Array.isArray(binding.viewArgs) ? binding.viewArgs : [];
247
- var suppliedKeys = Object.keys(supplied);
248
- for (var i = 0; i < suppliedKeys.length; i++) {
249
- var key = suppliedKeys[i];
250
- if (allowed.indexOf(key) === -1) {
251
- finishInnerRead(message.id, false, "Undeclared read argument " + JSON.stringify(key));
252
- return;
253
- }
254
- }
255
- var args = Object.create(null);
256
- var fixed = binding.fixedArgs && typeof binding.fixedArgs === "object"
257
- ? binding.fixedArgs
258
- : {};
259
- Object.keys(fixed).forEach(function (key) { args[key] = fixed[key]; });
260
- suppliedKeys.forEach(function (key) { args[key] = supplied[key]; });
261
-
262
- var hostId = "connecta-ui-read-" + String(++nextHostRequestId);
263
- pendingHostReads[hostId] = { innerId: message.id };
264
- activeHostReads++;
265
- send({
266
- jsonrpc: "2.0",
267
- id: hostId,
268
- method: "tools/call",
269
- params: {
270
- name: "call_tool",
271
- arguments: {
272
- address: binding.address,
273
- args: args,
274
- resultMode: "value"
275
- }
276
- }
277
- });
278
- }
279
-
280
- function finishHostRead(message) {
281
- var pending = pendingHostReads[message.id];
282
- if (!pending) return false;
283
- delete pendingHostReads[message.id];
284
- activeHostReads--;
285
- if (message.error) {
286
- finishInnerRead(pending.innerId, false, readError(message.error, "Host rejected read"));
287
- return true;
288
- }
289
- var toolResult = message.result;
290
- if (!toolResult || typeof toolResult !== "object") {
291
- finishInnerRead(pending.innerId, false, "Host returned an invalid tool result");
292
- return true;
293
- }
294
- var structured = toolResult.structuredContent;
295
- if (toolResult.isError || (structured && structured.ok === false)) {
296
- var detail = structured && structured.error;
297
- var content = Array.isArray(toolResult.content)
298
- ? toolResult.content.find(function (block) { return block && block.type === "text"; })
299
- : null;
300
- finishInnerRead(
301
- pending.innerId,
302
- false,
303
- readError(detail, content && content.text ? content.text : "Read failed")
304
- );
305
- return true;
306
- }
307
- var value = structured && structured.ok === true &&
308
- Object.prototype.hasOwnProperty.call(structured, "data")
309
- ? structured.data
310
- : structured !== undefined
311
- ? structured
312
- : toolResult;
313
- finishInnerRead(pending.innerId, true, value);
314
- return true;
315
- }
316
-
317
- window.addEventListener("message", function (event) {
318
- var message = event.data;
319
- if (event.source === view.contentWindow) {
320
- if (message && message.type === "connecta/read") beginInnerRead(message);
321
- return;
322
- }
323
- if (event.source !== host) return;
324
- if (!message || message.jsonrpc !== "2.0") return;
325
- if (message.id !== undefined && finishHostRead(message)) return;
326
- if (message.method === "ui/notifications/tool-result") {
327
- render(message.params);
328
- return;
329
- }
330
- if (message.method === "ui/resource-teardown") {
331
- // A host->view request, not a notification: the host waits for
332
- // this reply before it tears the view down. There is nothing to
333
- // release, so answer immediately rather than make it time out.
334
- if (message.id !== undefined && message.id !== null) {
335
- send({ jsonrpc: "2.0", id: message.id, result: {} });
336
- }
337
- return;
338
- }
339
- // Only a completed handshake earns "initialized". A JSON-RPC error
340
- // response carries the same id, and announcing initialization on one
341
- // would assert a handshake that never happened.
342
- if (message.id === initializeId && message.result !== undefined) {
343
- var capabilities = message.result.hostCapabilities;
344
- hostCanCallTools = Boolean(capabilities && capabilities.serverTools);
345
- notify("ui/notifications/initialized", {});
346
- }
347
- });
348
-
349
- window.addEventListener("resize", reportSize);
350
- view.addEventListener("load", reportSize);
351
-
352
- // Every field here is required by the Apps initialize schema, and a
353
- // conforming host rejects the request outright when one is missing —
354
- // which would strand the shell before any tool result arrives.
355
- send({
356
- jsonrpc: "2.0",
357
- id: initializeId,
358
- method: "ui/initialize",
359
- params: {
360
- appInfo: { name: "connecta program view", version: "1" },
361
- appCapabilities: {},
362
- protocolVersion: "2026-01-26"
363
- }
364
- });
365
- reportSize();
366
- })();
367
- </script>
368
- </body>
369
- </html>
370
- `;
@@ -1,61 +0,0 @@
1
- import { assertNoRetiredToolkitOptions } from "../retired-toolkits.js";
2
- import type { AuthResult, InboundAuth } from "../types.js";
3
-
4
- const encoder = new TextEncoder();
5
-
6
- /** Constant-time byte comparison. Differing lengths still iterate to reduce leak. */
7
- function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {
8
- if (a.length !== b.length) {
9
- let r = 1;
10
- const n = Math.max(a.length, b.length);
11
- for (let i = 0; i < n; i++) r |= (a[i] ?? 0) ^ (b[i] ?? 0);
12
- return false;
13
- }
14
- let r = 0;
15
- for (let i = 0; i < a.length; i++) r |= (a[i] ?? 0) ^ (b[i] ?? 0);
16
- return r === 0;
17
- }
18
-
19
- export interface BearerTokenOptions {
20
- /** Stable identity for this credential, used on activity events. */
21
- subjectId?: string;
22
- }
23
-
24
- /**
25
- * Static bearer-token inbound auth. Constant-time compares the Bearer token
26
- * against `secret`. Checked BEFORE the Clerk gate in the server; a mismatch
27
- * falls through so a co-configured Clerk provider can still admit the request.
28
- */
29
- export function bearerToken(
30
- secret: string,
31
- options: BearerTokenOptions = {},
32
- ): InboundAuth {
33
- assertNoRetiredToolkitOptions("bearerToken", options);
34
- const secretBytes = encoder.encode(secret);
35
- return {
36
- kind: "bearer",
37
- authorize(request): AuthResult {
38
- const header = request.headers.get("authorization") ?? "";
39
- const match = /^Bearer\s+(.+)$/i.exec(header);
40
- if (match && timingSafeEqual(encoder.encode(match[1]), secretBytes)) {
41
- return {
42
- ok: true,
43
- ...(options.subjectId ? { subjectId: options.subjectId } : {}),
44
- };
45
- }
46
- return {
47
- ok: false,
48
- response: new Response(
49
- JSON.stringify({ error: "unauthorized" }),
50
- {
51
- status: 401,
52
- headers: {
53
- "Content-Type": "application/json",
54
- "WWW-Authenticate": "Bearer",
55
- },
56
- },
57
- ),
58
- };
59
- },
60
- };
61
- }