@segmentstream/ontology 0.0.0-stage → 0.92.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 (483) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +2 -0
  3. package/README.md +1655 -2
  4. package/dist/action.d.ts +193 -0
  5. package/dist/action.js +41 -0
  6. package/dist/agent-chat.d.ts +44 -0
  7. package/dist/agent-chat.js +91 -0
  8. package/dist/agent-task-contract.d.ts +64 -0
  9. package/dist/agent-task-contract.js +15 -0
  10. package/dist/agent-task.d.ts +39 -0
  11. package/dist/agent-task.js +112 -0
  12. package/dist/analyze.d.ts +215 -0
  13. package/dist/analyze.js +2438 -0
  14. package/dist/app-feedback.d.ts +167 -0
  15. package/dist/app-feedback.js +176 -0
  16. package/dist/authoring-input.d.ts +3 -0
  17. package/dist/authoring-input.js +107 -0
  18. package/dist/authoring-names.d.ts +4 -0
  19. package/dist/authoring-names.js +13 -0
  20. package/dist/authoring-records.d.ts +35 -0
  21. package/dist/authoring-records.js +264 -0
  22. package/dist/authoring.d.ts +15 -0
  23. package/dist/authoring.js +331 -0
  24. package/dist/bin/check.d.ts +30 -0
  25. package/dist/bin/check.js +99 -0
  26. package/dist/bin/load.d.ts +48 -0
  27. package/dist/bin/load.js +139 -0
  28. package/dist/bin/main.d.ts +31 -0
  29. package/dist/bin/main.js +121 -0
  30. package/dist/bin/migrate.d.ts +57 -0
  31. package/dist/bin/migrate.js +170 -0
  32. package/dist/bin/output.d.ts +31 -0
  33. package/dist/bin/output.js +84 -0
  34. package/dist/bin.d.ts +2 -0
  35. package/dist/bin.js +31 -0
  36. package/dist/blob.d.ts +52 -0
  37. package/dist/blob.js +87 -0
  38. package/dist/channel-session.d.ts +16 -0
  39. package/dist/channel-session.js +16 -0
  40. package/dist/chat.d.ts +43 -0
  41. package/dist/chat.js +34 -0
  42. package/dist/confirmation.d.ts +46 -0
  43. package/dist/confirmation.js +41 -0
  44. package/dist/connection.d.ts +213 -0
  45. package/dist/connection.js +289 -0
  46. package/dist/deployment.d.ts +35 -0
  47. package/dist/deployment.js +76 -0
  48. package/dist/diagnostics.d.ts +27 -0
  49. package/dist/diagnostics.js +106 -0
  50. package/dist/emails.d.ts +70 -0
  51. package/dist/emails.js +221 -0
  52. package/dist/entity.d.ts +331 -0
  53. package/dist/entity.js +153 -0
  54. package/dist/errors.d.ts +154 -0
  55. package/dist/errors.js +109 -0
  56. package/dist/feedback-config.d.ts +24 -0
  57. package/dist/feedback-config.js +126 -0
  58. package/dist/files.d.ts +39 -0
  59. package/dist/files.js +4 -0
  60. package/dist/groups.d.ts +95 -0
  61. package/dist/groups.js +280 -0
  62. package/dist/index.d.ts +109 -0
  63. package/dist/index.js +70 -0
  64. package/dist/internal/diagnostics.js +594 -0
  65. package/dist/legacy.d.ts +160 -0
  66. package/dist/legacy.js +270 -0
  67. package/dist/manifest-compatibility.d.ts +8 -0
  68. package/dist/manifest-compatibility.js +87 -0
  69. package/dist/manifest.d.ts +3329 -0
  70. package/dist/manifest.js +757 -0
  71. package/dist/me.d.ts +46 -0
  72. package/dist/me.js +109 -0
  73. package/dist/metric-filters.d.ts +48 -0
  74. package/dist/metric-filters.js +252 -0
  75. package/dist/metric-routes.d.ts +132 -0
  76. package/dist/metric-routes.js +498 -0
  77. package/dist/metric.d.ts +172 -0
  78. package/dist/metric.js +132 -0
  79. package/dist/migrate/apply.d.ts +94 -0
  80. package/dist/migrate/apply.js +526 -0
  81. package/dist/migrate/errors.d.ts +46 -0
  82. package/dist/migrate/errors.js +38 -0
  83. package/dist/migrate/index.d.ts +10 -0
  84. package/dist/migrate/index.js +7 -0
  85. package/dist/migrate/model.d.ts +2311 -0
  86. package/dist/migrate/model.js +148 -0
  87. package/dist/migrate/plan.d.ts +51 -0
  88. package/dist/migrate/plan.js +1856 -0
  89. package/dist/migrate/preview.d.ts +13 -0
  90. package/dist/migrate/preview.js +65 -0
  91. package/dist/migrate/storage.d.ts +226 -0
  92. package/dist/migrate/storage.js +774 -0
  93. package/dist/model-metrics.d.ts +22 -0
  94. package/dist/model-metrics.js +545 -0
  95. package/dist/names.d.ts +49 -0
  96. package/dist/names.js +110 -0
  97. package/dist/navigation-artifact.d.ts +13 -0
  98. package/dist/navigation-artifact.js +11 -0
  99. package/dist/navigation-catalog.d.ts +55 -0
  100. package/dist/navigation-catalog.js +297 -0
  101. package/dist/nitro-navigation.d.ts +3 -0
  102. package/dist/nitro-navigation.js +64 -0
  103. package/dist/nitro-workflows.d.ts +108 -0
  104. package/dist/nitro-workflows.js +286 -0
  105. package/dist/nitro.d.ts +40 -0
  106. package/dist/nitro.js +50 -0
  107. package/dist/ontology.d.ts +41 -0
  108. package/dist/ontology.js +46 -0
  109. package/dist/permissions.d.ts +198 -0
  110. package/dist/permissions.js +272 -0
  111. package/dist/property.d.ts +188 -0
  112. package/dist/property.js +301 -0
  113. package/dist/query.d.ts +245 -0
  114. package/dist/query.js +615 -0
  115. package/dist/relationship.d.ts +99 -0
  116. package/dist/relationship.js +33 -0
  117. package/dist/render.d.ts +81 -0
  118. package/dist/render.js +512 -0
  119. package/dist/replication/baseline.d.ts +51 -0
  120. package/dist/replication/baseline.js +215 -0
  121. package/dist/replication/bigquery.d.ts +37 -0
  122. package/dist/replication/bigquery.js +211 -0
  123. package/dist/replication/coverage.d.ts +14 -0
  124. package/dist/replication/coverage.js +53 -0
  125. package/dist/replication/evolution.d.ts +25 -0
  126. package/dist/replication/evolution.js +184 -0
  127. package/dist/replication/identities.d.ts +6 -0
  128. package/dist/replication/identities.js +47 -0
  129. package/dist/replication/legacy-baseline.d.ts +27 -0
  130. package/dist/replication/legacy-baseline.js +109 -0
  131. package/dist/replication/legacy-store.d.ts +19 -0
  132. package/dist/replication/legacy-store.js +63 -0
  133. package/dist/replication/lineage.d.ts +36 -0
  134. package/dist/replication/lineage.js +72 -0
  135. package/dist/replication/migrate.d.ts +21 -0
  136. package/dist/replication/migrate.js +84 -0
  137. package/dist/replication/model.d.ts +52 -0
  138. package/dist/replication/model.js +99 -0
  139. package/dist/replication/scans.d.ts +34 -0
  140. package/dist/replication/scans.js +158 -0
  141. package/dist/replication/schema.d.ts +11 -0
  142. package/dist/replication/schema.js +226 -0
  143. package/dist/replication/shadow-schema.d.ts +4 -0
  144. package/dist/replication/shadow-schema.js +61 -0
  145. package/dist/replication/shadow.d.ts +127 -0
  146. package/dist/replication/shadow.js +614 -0
  147. package/dist/replication/source-replacement.d.ts +33 -0
  148. package/dist/replication/source-replacement.js +76 -0
  149. package/dist/replication/store.d.ts +36 -0
  150. package/dist/replication/store.js +382 -0
  151. package/dist/replication/transaction.d.ts +23 -0
  152. package/dist/replication/transaction.js +88 -0
  153. package/dist/role.d.ts +61 -0
  154. package/dist/role.js +76 -0
  155. package/dist/runtime/action-deadlocks.d.ts +21 -0
  156. package/dist/runtime/action-deadlocks.js +130 -0
  157. package/dist/runtime/action-transactions.d.ts +35 -0
  158. package/dist/runtime/action-transactions.js +54 -0
  159. package/dist/runtime/agent-counters.d.ts +26 -0
  160. package/dist/runtime/agent-counters.js +98 -0
  161. package/dist/runtime/agent-tasks.d.ts +63 -0
  162. package/dist/runtime/agent-tasks.js +120 -0
  163. package/dist/runtime/agents.d.ts +15 -0
  164. package/dist/runtime/agents.js +457 -0
  165. package/dist/runtime/batch-diagnostics.d.ts +22 -0
  166. package/dist/runtime/batch-diagnostics.js +89 -0
  167. package/dist/runtime/batch.d.ts +52 -0
  168. package/dist/runtime/batch.js +534 -0
  169. package/dist/runtime/channel-session-revocation.d.ts +3 -0
  170. package/dist/runtime/channel-session-revocation.js +5 -0
  171. package/dist/runtime/channel-sessions.d.ts +4 -0
  172. package/dist/runtime/channel-sessions.js +61 -0
  173. package/dist/runtime/confirmations.d.ts +29 -0
  174. package/dist/runtime/confirmations.js +57 -0
  175. package/dist/runtime/cursor.d.ts +23 -0
  176. package/dist/runtime/cursor.js +100 -0
  177. package/dist/runtime/deployment.d.ts +7 -0
  178. package/dist/runtime/deployment.js +4 -0
  179. package/dist/runtime/errors.d.ts +118 -0
  180. package/dist/runtime/errors.js +109 -0
  181. package/dist/runtime/federation-tables.d.ts +2 -0
  182. package/dist/runtime/federation-tables.js +20 -0
  183. package/dist/runtime/federation.d.ts +42 -0
  184. package/dist/runtime/federation.js +222 -0
  185. package/dist/runtime/files.d.ts +39 -0
  186. package/dist/runtime/files.js +44 -0
  187. package/dist/runtime/generated-actions.d.ts +37 -0
  188. package/dist/runtime/generated-actions.js +307 -0
  189. package/dist/runtime/history.d.ts +91 -0
  190. package/dist/runtime/history.js +77 -0
  191. package/dist/runtime/ids.d.ts +6 -0
  192. package/dist/runtime/ids.js +39 -0
  193. package/dist/runtime/member-tables.d.ts +8 -0
  194. package/dist/runtime/member-tables.js +33 -0
  195. package/dist/runtime/member-writes.d.ts +78 -0
  196. package/dist/runtime/member-writes.js +202 -0
  197. package/dist/runtime/metric-query.d.ts +19 -0
  198. package/dist/runtime/metric-query.js +411 -0
  199. package/dist/runtime/model.d.ts +67 -0
  200. package/dist/runtime/model.js +150 -0
  201. package/dist/runtime/new-user-hook.d.ts +6 -0
  202. package/dist/runtime/new-user-hook.js +37 -0
  203. package/dist/runtime/oauth.d.ts +9 -0
  204. package/dist/runtime/oauth.js +299 -0
  205. package/dist/runtime/pipeline.d.ts +155 -0
  206. package/dist/runtime/pipeline.js +597 -0
  207. package/dist/runtime/postgres-tls.d.ts +10 -0
  208. package/dist/runtime/postgres-tls.js +14 -0
  209. package/dist/runtime/principals.d.ts +302 -0
  210. package/dist/runtime/principals.js +1307 -0
  211. package/dist/runtime/reads.d.ts +55 -0
  212. package/dist/runtime/reads.js +313 -0
  213. package/dist/runtime/records.d.ts +42 -0
  214. package/dist/runtime/records.js +245 -0
  215. package/dist/runtime/resolve-agent-identity.d.ts +6 -0
  216. package/dist/runtime/resolve-agent-identity.js +181 -0
  217. package/dist/runtime/service-binding.d.ts +18 -0
  218. package/dist/runtime/service-binding.js +266 -0
  219. package/dist/runtime/sign-in-links.d.ts +68 -0
  220. package/dist/runtime/sign-in-links.js +147 -0
  221. package/dist/runtime/sql-runtime.d.ts +131 -0
  222. package/dist/runtime/sql-runtime.js +362 -0
  223. package/dist/runtime/statement.d.ts +18 -0
  224. package/dist/runtime/statement.js +31 -0
  225. package/dist/runtime/user-identities.d.ts +66 -0
  226. package/dist/runtime/user-identities.js +106 -0
  227. package/dist/runtime/user-identity-sql.d.ts +86 -0
  228. package/dist/runtime/user-identity-sql.js +297 -0
  229. package/dist/runtime/user-roles.d.ts +16 -0
  230. package/dist/runtime/user-roles.js +32 -0
  231. package/dist/runtime/validation.d.ts +16 -0
  232. package/dist/runtime/validation.js +26 -0
  233. package/dist/runtime/where.d.ts +57 -0
  234. package/dist/runtime/where.js +404 -0
  235. package/dist/runtime/workflow-admission.d.ts +49 -0
  236. package/dist/runtime/workflow-admission.js +92 -0
  237. package/dist/runtime/workflow-argument-codec.d.ts +10 -0
  238. package/dist/runtime/workflow-argument-codec.js +120 -0
  239. package/dist/runtime/workflow-arguments.d.ts +17 -0
  240. package/dist/runtime/workflow-arguments.js +99 -0
  241. package/dist/runtime/workflow-starts.d.ts +203 -0
  242. package/dist/runtime/workflow-starts.js +493 -0
  243. package/dist/runtime/workflow-users.d.ts +9 -0
  244. package/dist/runtime/workflow-users.js +17 -0
  245. package/dist/runtime/workload.d.ts +25 -0
  246. package/dist/runtime/workload.js +24 -0
  247. package/dist/runtime/writes.d.ts +108 -0
  248. package/dist/runtime/writes.js +491 -0
  249. package/dist/runtime-source.d.ts +22 -0
  250. package/dist/runtime-source.js +28 -0
  251. package/dist/runtime.d.ts +310 -0
  252. package/dist/runtime.js +31 -0
  253. package/dist/server.d.ts +23 -0
  254. package/dist/server.js +107 -0
  255. package/dist/service/agent/attachments.d.ts +33 -0
  256. package/dist/service/agent/attachments.js +228 -0
  257. package/dist/service/agent/authentication.d.ts +22 -0
  258. package/dist/service/agent/authentication.js +58 -0
  259. package/dist/service/agent/confirmations.d.ts +5 -0
  260. package/dist/service/agent/confirmations.js +73 -0
  261. package/dist/service/agent/conversation-routes.d.ts +14 -0
  262. package/dist/service/agent/conversation-routes.js +45 -0
  263. package/dist/service/agent/conversations.d.ts +40 -0
  264. package/dist/service/agent/conversations.js +69 -0
  265. package/dist/service/agent/files.d.ts +12 -0
  266. package/dist/service/agent/files.js +69 -0
  267. package/dist/service/agent/protocol.d.ts +90 -0
  268. package/dist/service/agent/protocol.js +114 -0
  269. package/dist/service/agent/server.d.ts +28 -0
  270. package/dist/service/agent/server.js +374 -0
  271. package/dist/service/agent/task-caller.d.ts +21 -0
  272. package/dist/service/agent/task-caller.js +35 -0
  273. package/dist/service/agent/task-start.d.ts +53 -0
  274. package/dist/service/agent/task-start.js +161 -0
  275. package/dist/service/agent/tasks.d.ts +40 -0
  276. package/dist/service/agent/tasks.js +155 -0
  277. package/dist/service/api.d.ts +50 -0
  278. package/dist/service/api.js +288 -0
  279. package/dist/service/authentication.d.ts +227 -0
  280. package/dist/service/authentication.js +767 -0
  281. package/dist/service/caller-context.d.ts +24 -0
  282. package/dist/service/caller-context.js +6 -0
  283. package/dist/service/catalog.d.ts +42 -0
  284. package/dist/service/catalog.js +66 -0
  285. package/dist/service/channel/provider.d.ts +10 -0
  286. package/dist/service/channel/provider.js +1 -0
  287. package/dist/service/channel/providers/telegram.d.ts +18 -0
  288. package/dist/service/channel/providers/telegram.js +108 -0
  289. package/dist/service/channel/sessions.d.ts +5 -0
  290. package/dist/service/channel/sessions.js +53 -0
  291. package/dist/service/channel/sign-in.d.ts +7 -0
  292. package/dist/service/channel/sign-in.js +78 -0
  293. package/dist/service/chat/archive.d.ts +64 -0
  294. package/dist/service/chat/archive.js +62 -0
  295. package/dist/service/chat/attribution.d.ts +26 -0
  296. package/dist/service/chat/attribution.js +28 -0
  297. package/dist/service/chat/delivery.d.ts +18 -0
  298. package/dist/service/chat/delivery.js +251 -0
  299. package/dist/service/chat/diagnostics.d.ts +2 -0
  300. package/dist/service/chat/diagnostics.js +35 -0
  301. package/dist/service/chat/envelope.d.ts +96 -0
  302. package/dist/service/chat/envelope.js +39 -0
  303. package/dist/service/chat/idempotency.d.ts +19 -0
  304. package/dist/service/chat/idempotency.js +37 -0
  305. package/dist/service/chat/providers/telegram.d.ts +36 -0
  306. package/dist/service/chat/providers/telegram.js +133 -0
  307. package/dist/service/chat/reads.d.ts +25 -0
  308. package/dist/service/chat/reads.js +75 -0
  309. package/dist/service/chat/resolve.d.ts +34 -0
  310. package/dist/service/chat/resolve.js +150 -0
  311. package/dist/service/chat/routes.d.ts +23 -0
  312. package/dist/service/chat/routes.js +75 -0
  313. package/dist/service/chat/schemas.d.ts +43 -0
  314. package/dist/service/chat/schemas.js +31 -0
  315. package/dist/service/config.d.ts +218 -0
  316. package/dist/service/config.js +265 -0
  317. package/dist/service/connection-stream.d.ts +10 -0
  318. package/dist/service/connection-stream.js +191 -0
  319. package/dist/service/connections.d.ts +60 -0
  320. package/dist/service/connections.js +271 -0
  321. package/dist/service/decisions.d.ts +35 -0
  322. package/dist/service/decisions.js +63 -0
  323. package/dist/service/descriptions.d.ts +8 -0
  324. package/dist/service/descriptions.js +20 -0
  325. package/dist/service/discovery-schemas.d.ts +92 -0
  326. package/dist/service/discovery-schemas.js +59 -0
  327. package/dist/service/discovery-search.d.ts +30 -0
  328. package/dist/service/discovery-search.js +95 -0
  329. package/dist/service/discovery.d.ts +37 -0
  330. package/dist/service/discovery.js +436 -0
  331. package/dist/service/docs.d.ts +9 -0
  332. package/dist/service/docs.js +197 -0
  333. package/dist/service/errors.d.ts +145 -0
  334. package/dist/service/errors.js +704 -0
  335. package/dist/service/federation-provider.d.ts +36 -0
  336. package/dist/service/federation-provider.js +110 -0
  337. package/dist/service/federation-server.d.ts +20 -0
  338. package/dist/service/federation-server.js +249 -0
  339. package/dist/service/federation-status.d.ts +40 -0
  340. package/dist/service/federation-status.js +151 -0
  341. package/dist/service/handlers.d.ts +18 -0
  342. package/dist/service/handlers.js +287 -0
  343. package/dist/service/mcp/confirmation.d.ts +68 -0
  344. package/dist/service/mcp/confirmation.js +178 -0
  345. package/dist/service/mcp/find-input.d.ts +12 -0
  346. package/dist/service/mcp/find-input.js +122 -0
  347. package/dist/service/mcp/input-schema.d.ts +6 -0
  348. package/dist/service/mcp/input-schema.js +126 -0
  349. package/dist/service/mcp/listing.d.ts +26 -0
  350. package/dist/service/mcp/listing.js +92 -0
  351. package/dist/service/mcp/metric-tools.d.ts +85 -0
  352. package/dist/service/mcp/metric-tools.js +258 -0
  353. package/dist/service/mcp/request-log.d.ts +5 -0
  354. package/dist/service/mcp/request-log.js +53 -0
  355. package/dist/service/mcp/runtime-policy.d.ts +27 -0
  356. package/dist/service/mcp/runtime-policy.js +62 -0
  357. package/dist/service/mcp/server.d.ts +52 -0
  358. package/dist/service/mcp/server.js +861 -0
  359. package/dist/service/mcp/tools.d.ts +99 -0
  360. package/dist/service/mcp/tools.js +938 -0
  361. package/dist/service/member-file-routes.d.ts +22 -0
  362. package/dist/service/member-file-routes.js +52 -0
  363. package/dist/service/member-files.d.ts +245 -0
  364. package/dist/service/member-files.js +258 -0
  365. package/dist/service/metric-query-platform.d.ts +77 -0
  366. package/dist/service/metric-query-platform.js +198 -0
  367. package/dist/service/metric-query-scopes.d.ts +43 -0
  368. package/dist/service/metric-query-scopes.js +147 -0
  369. package/dist/service/metric-query.d.ts +48 -0
  370. package/dist/service/metric-query.js +200 -0
  371. package/dist/service/name-suggestions.d.ts +3 -0
  372. package/dist/service/name-suggestions.js +38 -0
  373. package/dist/service/navigation-schemas.d.ts +80 -0
  374. package/dist/service/navigation-schemas.js +49 -0
  375. package/dist/service/navigation.d.ts +20 -0
  376. package/dist/service/navigation.js +165 -0
  377. package/dist/service/oauth/protocol.d.ts +70 -0
  378. package/dist/service/oauth/protocol.js +157 -0
  379. package/dist/service/oauth/refresh-replay.d.ts +2 -0
  380. package/dist/service/oauth/refresh-replay.js +20 -0
  381. package/dist/service/oauth/server.d.ts +28 -0
  382. package/dist/service/oauth/server.js +769 -0
  383. package/dist/service/operations.d.ts +170 -0
  384. package/dist/service/operations.js +392 -0
  385. package/dist/service/plan.d.ts +57 -0
  386. package/dist/service/plan.js +96 -0
  387. package/dist/service/rate-limit.d.ts +22 -0
  388. package/dist/service/rate-limit.js +52 -0
  389. package/dist/service/record-reads.d.ts +21 -0
  390. package/dist/service/record-reads.js +155 -0
  391. package/dist/service/replication.d.ts +5 -0
  392. package/dist/service/replication.js +39 -0
  393. package/dist/service/runtime-contract.d.ts +508 -0
  394. package/dist/service/runtime-contract.js +18 -0
  395. package/dist/service/runtime-identity.d.ts +71 -0
  396. package/dist/service/runtime-identity.js +122 -0
  397. package/dist/service/schemas.d.ts +961 -0
  398. package/dist/service/schemas.js +639 -0
  399. package/dist/service/service.d.ts +21 -0
  400. package/dist/service/service.js +526 -0
  401. package/dist/service/warehouse-platform.d.ts +17 -0
  402. package/dist/service/warehouse-platform.js +122 -0
  403. package/dist/service/warehouse-query.d.ts +24 -0
  404. package/dist/service/warehouse-query.js +280 -0
  405. package/dist/service/webhooks.d.ts +106 -0
  406. package/dist/service/webhooks.js +233 -0
  407. package/dist/service/workflow-admission-provider.d.ts +31 -0
  408. package/dist/service/workflow-admission-provider.js +205 -0
  409. package/dist/service/workflow-argument-serialization.d.ts +2 -0
  410. package/dist/service/workflow-argument-serialization.js +14 -0
  411. package/dist/service/workflow-callback.d.ts +22 -0
  412. package/dist/service/workflow-callback.js +75 -0
  413. package/dist/service/workflow-deployment.d.ts +8 -0
  414. package/dist/service/workflow-deployment.js +131 -0
  415. package/dist/service/workflow-diagnostics.d.ts +23 -0
  416. package/dist/service/workflow-diagnostics.js +263 -0
  417. package/dist/service/workflow-errors.d.ts +26 -0
  418. package/dist/service/workflow-errors.js +181 -0
  419. package/dist/service/workflow-logging.d.ts +2 -0
  420. package/dist/service/workflow-logging.js +50 -0
  421. package/dist/service/workflow-queue-fence.d.ts +6 -0
  422. package/dist/service/workflow-queue-fence.js +66 -0
  423. package/dist/service/workflows.d.ts +200 -0
  424. package/dist/service/workflows.js +1549 -0
  425. package/dist/sign-in.d.ts +58 -0
  426. package/dist/sign-in.js +57 -0
  427. package/dist/source.d.ts +30 -0
  428. package/dist/source.js +107 -0
  429. package/dist/start-recovery-contract.d.ts +49 -0
  430. package/dist/start-recovery-contract.js +26 -0
  431. package/dist/start-recovery.d.ts +27 -0
  432. package/dist/start-recovery.js +81 -0
  433. package/dist/storage/api.d.ts +4 -0
  434. package/dist/storage/api.js +40 -0
  435. package/dist/storage/attachments.d.ts +146 -0
  436. package/dist/storage/attachments.js +733 -0
  437. package/dist/storage/authorization.d.ts +38 -0
  438. package/dist/storage/authorization.js +83 -0
  439. package/dist/storage/file-access.d.ts +17 -0
  440. package/dist/storage/file-access.js +8 -0
  441. package/dist/storage/limits.d.ts +12 -0
  442. package/dist/storage/limits.js +17 -0
  443. package/dist/storage/maintenance-auth.d.ts +20 -0
  444. package/dist/storage/maintenance-auth.js +24 -0
  445. package/dist/storage/maintenance.d.ts +11 -0
  446. package/dist/storage/maintenance.js +67 -0
  447. package/dist/storage/neon.d.ts +4 -0
  448. package/dist/storage/neon.js +318 -0
  449. package/dist/storage/operator.d.ts +11 -0
  450. package/dist/storage/operator.js +30 -0
  451. package/dist/storage/provider.d.ts +93 -0
  452. package/dist/storage/provider.js +36 -0
  453. package/dist/storage/sessions.d.ts +184 -0
  454. package/dist/storage/sessions.js +688 -0
  455. package/dist/storage/tables.d.ts +54 -0
  456. package/dist/storage/tables.js +205 -0
  457. package/dist/storage/transfers.d.ts +16 -0
  458. package/dist/storage/transfers.js +153 -0
  459. package/dist/storage/writes.d.ts +7 -0
  460. package/dist/storage/writes.js +88 -0
  461. package/dist/telegram.d.ts +35 -0
  462. package/dist/telegram.js +173 -0
  463. package/dist/user-identity.d.ts +28 -0
  464. package/dist/user-identity.js +106 -0
  465. package/dist/user.d.ts +75 -0
  466. package/dist/user.js +111 -0
  467. package/dist/warehouse-backed.d.ts +6 -0
  468. package/dist/warehouse-backed.js +495 -0
  469. package/dist/webhook-token.d.ts +11 -0
  470. package/dist/webhook-token.js +18 -0
  471. package/dist/webhooks.d.ts +40 -0
  472. package/dist/webhooks.js +55 -0
  473. package/dist/wire.d.ts +10 -0
  474. package/dist/wire.js +35 -0
  475. package/dist/workflow-runtime.d.ts +116 -0
  476. package/dist/workflow-runtime.js +109 -0
  477. package/dist/workflow-topics.d.ts +28 -0
  478. package/dist/workflow-topics.js +28 -0
  479. package/dist/workflow.d.ts +284 -0
  480. package/dist/workflow.js +259 -0
  481. package/dist/workflows.d.ts +24 -0
  482. package/dist/workflows.js +18 -0
  483. package/package.json +127 -4
@@ -0,0 +1,769 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Effect, Layer } from "effect";
3
+ import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
4
+ import { HttpApiBuilder, HttpApiSecurity } from "effect/unstable/httpapi";
5
+ import { BASE_PATH } from "../api.js";
6
+ import { CurrentPrincipal, withPrincipal } from "../authentication.js";
7
+ import { RequestId, errorBodyForWire } from "../errors.js";
8
+ import { fixedWindowLimiter, clientAddress } from "../rate-limit.js";
9
+ import { OntologyBackend, } from "../runtime-contract.js";
10
+ import { ACCESS_TOKEN_PREFIX, appSessionResource, ACCESS_TOKEN_TTL_MS, AUTHORIZATION_SERVER_PATH, CLIENT_ID_PREFIX, CLIENT_SECRET_PREFIX, CODE_PREFIX, CODE_TTL_MS, DEVICE_GRANT, DEVICE_TTL_MS, DEVICE_INTERVAL, humanCode, normalizedUserCode, CONSENT_PATH, FULL_SCOPE, PROTECTED_RESOURCE_PATH, READ_SCOPE, REFRESH_TOKEN_PREFIX, REFRESH_TOKEN_TTL_MS, REQUEST_TTL_MS, SCOPES, grantedScope, isLoopback, newSecret, publicOrigin, sameSecret, sameResource, secretHash, verifierMatches, } from "./protocol.js";
11
+ import { decryptReplay, encryptReplay } from "./refresh-replay.js";
12
+ /** The authorization server's endpoints, under the ontology service's path. */
13
+ export const OAUTH_PATH = `${BASE_PATH}/oauth`;
14
+ const REGISTER_PATH = `${OAUTH_PATH}/register`;
15
+ const AUTHORIZE_PATH = `${OAUTH_PATH}/authorize`;
16
+ const DEVICE_PATH = `${OAUTH_PATH}/device_authorization`;
17
+ const DEVICE_REQUEST_PATH = `${OAUTH_PATH}/device`;
18
+ const TOKEN_PATH = `${OAUTH_PATH}/token`;
19
+ const REVOKE_PATH = `${OAUTH_PATH}/revoke`;
20
+ const REQUESTS_PATH = `${OAUTH_PATH}/requests`;
21
+ /** Registrations one client address may make per minute; each one is a row in the database. */
22
+ export const REGISTRATION_LIMIT = { limit: 20, windowMs: 60_000, maxKeys: 10_000 };
23
+ const MAX_REDIRECT_URIS = 10;
24
+ const MAX_URI_LENGTH = 2000;
25
+ const MAX_NAME_LENGTH = 100;
26
+ const MAX_STATE_LENGTH = 1000;
27
+ /** The metadata, registration, token and revocation endpoints are read by clients on any origin. */
28
+ const CORS = {
29
+ "access-control-allow-origin": "*",
30
+ "access-control-allow-methods": "GET, POST, OPTIONS",
31
+ "access-control-allow-headers": "authorization, content-type, mcp-protocol-version",
32
+ };
33
+ const NO_STORE = { "cache-control": "no-store", pragma: "no-cache" };
34
+ function json(body, status = 200, headers = {}) {
35
+ return HttpServerResponse.jsonUnsafe(body, { status, headers: { ...CORS, ...headers } });
36
+ }
37
+ /** An OAuth error (RFC 6749 §5.2), as the token, registration and revocation endpoints answer. */
38
+ function oauthError(error, description, status = 400) {
39
+ return json({ error, error_description: description }, status, error === "invalid_client"
40
+ ? { "www-authenticate": 'Basic realm="ontology"', ...NO_STORE }
41
+ : NO_STORE);
42
+ }
43
+ /** Where the MCP server is, on the origin the client reached. */
44
+ export function mcpResource(origin) {
45
+ return `${origin}/mcp`;
46
+ }
47
+ /**
48
+ * The `WWW-Authenticate` challenge of the MCP server: it names the protected resource metadata,
49
+ * which is how a client learns where members authorize it (RFC 9728).
50
+ */
51
+ export function mcpChallenge(origin, missing) {
52
+ const metadata = `resource_metadata="${origin}${PROTECTED_RESOURCE_PATH}/mcp"`;
53
+ return missing
54
+ ? `Bearer ${metadata}, scope="${FULL_SCOPE}"`
55
+ : `Bearer error="invalid_token", ${metadata}`;
56
+ }
57
+ function protectedResourceMetadata(origin) {
58
+ return {
59
+ resource: mcpResource(origin),
60
+ authorization_servers: [origin],
61
+ scopes_supported: SCOPES,
62
+ bearer_methods_supported: ["header"],
63
+ resource_name: "Ontology",
64
+ };
65
+ }
66
+ function authorizationServerMetadata(origin) {
67
+ const authMethods = [
68
+ "none",
69
+ "client_secret_post",
70
+ "client_secret_basic",
71
+ ];
72
+ return {
73
+ issuer: origin,
74
+ authorization_endpoint: `${origin}${AUTHORIZE_PATH}`,
75
+ token_endpoint: `${origin}${TOKEN_PATH}`,
76
+ registration_endpoint: `${origin}${REGISTER_PATH}`,
77
+ revocation_endpoint: `${origin}${REVOKE_PATH}`,
78
+ scopes_supported: SCOPES,
79
+ response_types_supported: ["code"],
80
+ response_modes_supported: ["query"],
81
+ device_authorization_endpoint: `${origin}${DEVICE_PATH}`,
82
+ grant_types_supported: ["authorization_code", "refresh_token", DEVICE_GRANT],
83
+ token_endpoint_auth_methods_supported: authMethods,
84
+ revocation_endpoint_auth_methods_supported: authMethods,
85
+ code_challenge_methods_supported: ["S256"],
86
+ authorization_response_iss_parameter_supported: true,
87
+ };
88
+ }
89
+ function searchParams(request) {
90
+ return Object.fromEntries(new URL(request.url, "http://ontology.invalid").searchParams);
91
+ }
92
+ /** A form body (RFC 6749 §4.1.3), or a JSON object from clients that send one. */
93
+ function bodyParams(request) {
94
+ return Effect.map(Effect.orDie(request.text), (text) => {
95
+ const contentType = request.headers["content-type"]?.toLowerCase() ?? "";
96
+ if (contentType.includes("application/json")) {
97
+ try {
98
+ const parsed = JSON.parse(text);
99
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
100
+ ? Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === "string"))
101
+ : {};
102
+ }
103
+ catch {
104
+ return {};
105
+ }
106
+ }
107
+ return Object.fromEntries(new URLSearchParams(text));
108
+ });
109
+ }
110
+ function jsonBody(request) {
111
+ return Effect.map(Effect.orDie(request.text), (text) => {
112
+ try {
113
+ return JSON.parse(text);
114
+ }
115
+ catch {
116
+ return undefined;
117
+ }
118
+ });
119
+ }
120
+ /** Why a redirect URI cannot be registered, or `undefined` when it can (RFC 8252 for native apps). */
121
+ function redirectUriProblem(value) {
122
+ if (typeof value !== "string" || value.length > MAX_URI_LENGTH || !URL.canParse(value)) {
123
+ return "is not an absolute URL";
124
+ }
125
+ const url = new URL(value);
126
+ if (url.hash !== "") {
127
+ return "has a fragment";
128
+ }
129
+ if (url.protocol === "https:") {
130
+ return undefined;
131
+ }
132
+ if (url.protocol === "http:") {
133
+ return isLoopback(url.host) ? undefined : "uses http on a host other than this computer";
134
+ }
135
+ if (["javascript:", "data:", "file:", "vbscript:", "blob:", "about:"].includes(url.protocol)) {
136
+ return "uses a scheme that cannot receive a redirect";
137
+ }
138
+ // A native app's private-use scheme, such as cursor://.
139
+ return undefined;
140
+ }
141
+ /**
142
+ * Whether a redirect URI is one the client registered. A loopback URI matches on any port, as
143
+ * native apps listen on whichever port is free (RFC 8252 §7.3).
144
+ */
145
+ function registeredRedirect(client, value) {
146
+ return client.redirectUris.some((registered) => {
147
+ if (registered === value) {
148
+ return true;
149
+ }
150
+ if (!URL.canParse(registered) || !URL.canParse(value)) {
151
+ return false;
152
+ }
153
+ const expected = new URL(registered);
154
+ const actual = new URL(value);
155
+ return (expected.protocol === "http:" &&
156
+ isLoopback(expected.host) &&
157
+ actual.protocol === "http:" &&
158
+ expected.hostname === actual.hostname &&
159
+ expected.pathname === actual.pathname &&
160
+ expected.search === actual.search);
161
+ });
162
+ }
163
+ /** The redirect URI with the response's parameters, and `iss` to name this server (RFC 9207). */
164
+ function redirectWith(redirectUri, params) {
165
+ const url = new URL(redirectUri);
166
+ for (const [key, value] of Object.entries(params)) {
167
+ if (value !== null) {
168
+ url.searchParams.set(key, value);
169
+ }
170
+ }
171
+ return url.toString();
172
+ }
173
+ /** A page for problems the client cannot be told about, because its redirect URI is not trusted. */
174
+ function authorizeFailure(detail) {
175
+ return HttpServerResponse.text(`This authorization link cannot be used: ${detail}`, {
176
+ status: 400,
177
+ headers: NO_STORE,
178
+ });
179
+ }
180
+ function register(store, limiter) {
181
+ return (request) => Effect.gen(function* () {
182
+ if (limiter.take(clientAddress(request)) !== undefined) {
183
+ return oauthError("too_many_requests", "Too many registrations; try again in a minute.", 429);
184
+ }
185
+ const body = yield* jsonBody(request);
186
+ if (typeof body !== "object" || body === null || Array.isArray(body)) {
187
+ return oauthError("invalid_client_metadata", "Send the client metadata as a JSON object.");
188
+ }
189
+ const metadata = body;
190
+ const deviceOnly = Array.isArray(metadata.grant_types) &&
191
+ metadata.grant_types.includes(DEVICE_GRANT) &&
192
+ !metadata.grant_types.includes("authorization_code");
193
+ const redirectUris = metadata.redirect_uris ?? (deviceOnly ? [] : undefined);
194
+ if (!Array.isArray(redirectUris) ||
195
+ (!deviceOnly && redirectUris.length === 0) ||
196
+ redirectUris.length > MAX_REDIRECT_URIS) {
197
+ return oauthError("invalid_redirect_uri", `redirect_uris lists between 1 and ${MAX_REDIRECT_URIS} URIs.`);
198
+ }
199
+ for (const uri of redirectUris) {
200
+ const problem = redirectUriProblem(uri);
201
+ if (problem !== undefined) {
202
+ return oauthError("invalid_redirect_uri", `${String(uri)} ${problem}.`);
203
+ }
204
+ }
205
+ // RFC 7591 §2: without a method, the client authenticates with client_secret_basic.
206
+ const authMethod = metadata.token_endpoint_auth_method ?? "client_secret_basic";
207
+ if (authMethod !== "none" &&
208
+ authMethod !== "client_secret_post" &&
209
+ authMethod !== "client_secret_basic") {
210
+ return oauthError("invalid_client_metadata", "token_endpoint_auth_method is none, client_secret_post or client_secret_basic.");
211
+ }
212
+ const grantTypes = metadata.grant_types ?? ["authorization_code"];
213
+ const responseTypes = metadata.response_types ?? (deviceOnly ? [] : ["code"]);
214
+ if (!Array.isArray(grantTypes) ||
215
+ !grantTypes.every((type) => type === "authorization_code" || type === "refresh_token" || type === DEVICE_GRANT) ||
216
+ !Array.isArray(responseTypes) ||
217
+ !responseTypes.every((type) => type === "code")) {
218
+ return oauthError("invalid_client_metadata", "This server grants authorization_code and refresh_token, with the code response type.");
219
+ }
220
+ const name = typeof metadata.client_name === "string" && metadata.client_name.trim() !== ""
221
+ ? metadata.client_name.trim().slice(0, MAX_NAME_LENGTH)
222
+ : "An MCP client";
223
+ const clientUri = typeof metadata.client_uri === "string" &&
224
+ metadata.client_uri.length <= MAX_URI_LENGTH &&
225
+ URL.canParse(metadata.client_uri) &&
226
+ new URL(metadata.client_uri).protocol === "https:"
227
+ ? metadata.client_uri
228
+ : null;
229
+ const secret = authMethod === "none" ? undefined : newSecret(CLIENT_SECRET_PREFIX);
230
+ const client = {
231
+ id: newSecret(CLIENT_ID_PREFIX),
232
+ name,
233
+ redirectUris: redirectUris,
234
+ authMethod,
235
+ secretHash: secret === undefined ? null : secretHash(secret),
236
+ clientUri,
237
+ };
238
+ yield* store.saveClient(client);
239
+ return json({
240
+ client_id: client.id,
241
+ client_id_issued_at: Math.floor(Date.now() / 1000),
242
+ ...(secret === undefined ? {} : { client_secret: secret, client_secret_expires_at: 0 }),
243
+ client_name: client.name,
244
+ redirect_uris: client.redirectUris,
245
+ token_endpoint_auth_method: client.authMethod,
246
+ grant_types: grantTypes,
247
+ response_types: responseTypes,
248
+ ...(clientUri === null ? {} : { client_uri: clientUri }),
249
+ }, 201, NO_STORE);
250
+ });
251
+ }
252
+ /**
253
+ * `GET /api/ontology/oauth/authorize`: checks the client's request, keeps it for the member to
254
+ * decide, and sends the browser to the app's consent page, which signs the member in first.
255
+ */
256
+ function authorize(store) {
257
+ return (request) => Effect.gen(function* () {
258
+ const params = searchParams(request);
259
+ const origin = publicOrigin(request);
260
+ const client = params.client_id === undefined ? undefined : yield* store.findClient(params.client_id);
261
+ if (client === undefined) {
262
+ return authorizeFailure("the client is not registered with this app.");
263
+ }
264
+ const redirectUri = params.redirect_uri ??
265
+ (client.redirectUris.length === 1 ? client.redirectUris[0] : undefined);
266
+ if (redirectUri === undefined || !registeredRedirect(client, redirectUri)) {
267
+ return authorizeFailure("the redirect URI is not one the client registered.");
268
+ }
269
+ const state = params.state ?? null;
270
+ const fail = (error, description) => HttpServerResponse.redirect(redirectWith(redirectUri, {
271
+ error,
272
+ error_description: description,
273
+ state,
274
+ iss: origin,
275
+ }), { status: 302, headers: NO_STORE });
276
+ if (params.response_type !== "code") {
277
+ return fail("unsupported_response_type", "Only the code response type is supported.");
278
+ }
279
+ if (params.code_challenge === undefined || params.code_challenge_method !== "S256") {
280
+ return fail("invalid_request", "PKCE with the S256 method is required.");
281
+ }
282
+ if (!/^[A-Za-z0-9_-]{43}$/.test(params.code_challenge)) {
283
+ return fail("invalid_request", "code_challenge is not an S256 challenge.");
284
+ }
285
+ if (state !== null && state.length > MAX_STATE_LENGTH) {
286
+ return fail("invalid_request", "state is too long.");
287
+ }
288
+ const resource = params.resource ?? mcpResource(origin);
289
+ if (!sameResource(resource, mcpResource(origin))) {
290
+ return fail("invalid_target", `This server issues tokens for ${mcpResource(origin)} only.`);
291
+ }
292
+ const id = newSecret();
293
+ yield* store.saveRequest({
294
+ id,
295
+ clientId: client.id,
296
+ redirectUri,
297
+ state,
298
+ codeChallenge: params.code_challenge,
299
+ scope: grantedScope(params.scope),
300
+ resource,
301
+ expiresAt: new Date(Date.now() + REQUEST_TTL_MS),
302
+ });
303
+ return HttpServerResponse.redirect(`${origin}${CONSENT_PATH}?request=${id}`, {
304
+ status: 302,
305
+ headers: NO_STORE,
306
+ });
307
+ });
308
+ }
309
+ /** The member deciding a request: the requests endpoints answer members only. */
310
+ function requireMember() {
311
+ return Effect.gen(function* () {
312
+ const principal = yield* CurrentPrincipal;
313
+ return principal.kind === "member" ? principal : undefined;
314
+ });
315
+ }
316
+ function notMember(requestId) {
317
+ return HttpServerResponse.jsonUnsafe(errorBodyForWire({
318
+ error: "forbidden",
319
+ detail: "Only a signed-in member can authorize an agent.",
320
+ requestId,
321
+ }), { status: 403 });
322
+ }
323
+ function requestNotFound(requestId, reason) {
324
+ return HttpServerResponse.jsonUnsafe(errorBodyForWire({
325
+ error: "not_found",
326
+ detail: "The authorization request expired or was already decided. Connect the agent again.",
327
+ ...(reason === undefined ? {} : { reason }),
328
+ requestId,
329
+ }), { status: 404 });
330
+ }
331
+ function unavailableDevice(device) {
332
+ if (device === undefined) {
333
+ return "unknown";
334
+ }
335
+ if (device.status !== "pending") {
336
+ return "decided";
337
+ }
338
+ return device.expiresAt.getTime() <= Date.now() ? "expired" : undefined;
339
+ }
340
+ function routeId() {
341
+ return Effect.map(HttpRouter.params, (params) => params.id ?? "");
342
+ }
343
+ /** `GET /api/ontology/oauth/requests/:id`: what the consent page shows the member. */
344
+ function describeRequest(store) {
345
+ return Effect.gen(function* () {
346
+ const requestId = yield* RequestId;
347
+ const member = yield* requireMember();
348
+ if (member === undefined) {
349
+ return notMember(requestId);
350
+ }
351
+ const pending = yield* store.findRequest(yield* routeId());
352
+ const client = pending === undefined ? undefined : yield* store.findClient(pending.clientId);
353
+ if (pending === undefined || client === undefined) {
354
+ return requestNotFound(requestId);
355
+ }
356
+ return HttpServerResponse.jsonUnsafe({
357
+ id: pending.id,
358
+ client: {
359
+ name: client.name,
360
+ uri: client.clientUri,
361
+ redirect_uri: pending.redirectUri,
362
+ redirect_host: new URL(pending.redirectUri).host || pending.redirectUri,
363
+ },
364
+ scope: pending.scope,
365
+ permissions: member.permissions,
366
+ expires_at: pending.expiresAt.toISOString(),
367
+ }, { headers: NO_STORE });
368
+ });
369
+ }
370
+ /**
371
+ * `POST /api/ontology/oauth/requests/:id/approve` and `/deny`: the member's decision, once. The
372
+ * answer is where the app sends the browser: the client's redirect URI with a code, or with
373
+ * `access_denied`. A member may narrow the scope to reading only, never widen it.
374
+ */
375
+ function decideRequest(store, decision, request) {
376
+ return Effect.gen(function* () {
377
+ const requestId = yield* RequestId;
378
+ const member = yield* requireMember();
379
+ if (member === undefined) {
380
+ return notMember(requestId);
381
+ }
382
+ const body = decision === "approve" ? yield* jsonBody(request) : undefined;
383
+ const pending = yield* store.takeRequest(yield* routeId());
384
+ if (pending === undefined) {
385
+ return requestNotFound(requestId);
386
+ }
387
+ // The issuer the client discovered: the origin of the MCP server it asked for. The app calls this
388
+ // endpoint itself, possibly on another origin in development.
389
+ const origin = new URL(pending.resource).origin;
390
+ if (decision === "deny") {
391
+ return HttpServerResponse.jsonUnsafe({
392
+ redirect: redirectWith(pending.redirectUri, {
393
+ error: "access_denied",
394
+ error_description: "The member did not authorize the client.",
395
+ state: pending.state,
396
+ iss: origin,
397
+ }),
398
+ });
399
+ }
400
+ const narrowed = typeof body === "object" &&
401
+ body !== null &&
402
+ body.scope === READ_SCOPE;
403
+ const grant = {
404
+ id: randomUUID(),
405
+ clientId: pending.clientId,
406
+ userId: member.id,
407
+ scope: narrowed ? READ_SCOPE : pending.scope,
408
+ resource: pending.resource,
409
+ };
410
+ const code = isLoopback(new URL(pending.redirectUri).host)
411
+ ? `${CODE_PREFIX}${humanCode(3)}`
412
+ : newSecret(CODE_PREFIX);
413
+ yield* store.saveGrant(grant, {
414
+ hash: secretHash(code),
415
+ grantId: grant.id,
416
+ kind: "code",
417
+ expiresAt: new Date(Date.now() + CODE_TTL_MS),
418
+ redirectUri: pending.redirectUri,
419
+ codeChallenge: pending.codeChallenge,
420
+ });
421
+ return HttpServerResponse.jsonUnsafe({
422
+ redirect: redirectWith(pending.redirectUri, { code, state: pending.state, iss: origin }),
423
+ });
424
+ });
425
+ }
426
+ /** The client a token or revocation request authenticates as (RFC 6749 §2.3). */
427
+ function authenticateClient(store, request, params) {
428
+ return Effect.gen(function* () {
429
+ const authorization = request.headers.authorization ?? "";
430
+ let clientId = params.client_id;
431
+ let secret = params.client_secret;
432
+ let method = secret === undefined ? "none" : "client_secret_post";
433
+ if (authorization.toLowerCase().startsWith("basic ")) {
434
+ const decoded = Buffer.from(authorization.slice(6).trim(), "base64").toString("utf8");
435
+ const separator = decoded.indexOf(":");
436
+ if (separator > 0) {
437
+ try {
438
+ clientId = decodeURIComponent(decoded.slice(0, separator));
439
+ secret = decodeURIComponent(decoded.slice(separator + 1));
440
+ }
441
+ catch {
442
+ return undefined;
443
+ }
444
+ method = "client_secret_basic";
445
+ }
446
+ }
447
+ const client = clientId === undefined ? undefined : yield* store.findClient(clientId);
448
+ if (client === undefined) {
449
+ return undefined;
450
+ }
451
+ if (client.authMethod === "none") {
452
+ return client;
453
+ }
454
+ return method !== "none" &&
455
+ secret !== undefined &&
456
+ client.secretHash !== null &&
457
+ sameSecret(secret, client.secretHash)
458
+ ? client
459
+ : undefined;
460
+ });
461
+ }
462
+ function issueTokens(store, grant, previous) {
463
+ return Effect.gen(function* () {
464
+ const accessToken = newSecret(ACCESS_TOKEN_PREFIX);
465
+ const refreshToken = newSecret(REFRESH_TOKEN_PREFIX);
466
+ const now = Date.now();
467
+ yield* store.saveTokens([
468
+ {
469
+ hash: secretHash(accessToken),
470
+ grantId: grant.id,
471
+ kind: "access",
472
+ expiresAt: new Date(now + ACCESS_TOKEN_TTL_MS),
473
+ },
474
+ {
475
+ hash: secretHash(refreshToken),
476
+ grantId: grant.id,
477
+ kind: "refresh",
478
+ expiresAt: new Date(now + REFRESH_TOKEN_TTL_MS),
479
+ },
480
+ ]);
481
+ const response = {
482
+ access_token: accessToken,
483
+ token_type: "Bearer",
484
+ expires_in: Math.floor(ACCESS_TOKEN_TTL_MS / 1000),
485
+ refresh_token: refreshToken,
486
+ scope: grant.scope,
487
+ };
488
+ if (previous !== undefined) {
489
+ yield* store.saveRefreshReplay(secretHash(previous), encryptReplay(previous, {
490
+ ...response,
491
+ access_token_expires_at: now + ACCESS_TOKEN_TTL_MS,
492
+ }), secretHash(refreshToken));
493
+ }
494
+ return json(response, 200, NO_STORE);
495
+ });
496
+ }
497
+ function replayTokens(store, grant, previous, encrypted, graceMs) {
498
+ return Effect.gen(function* () {
499
+ const { access_token_expires_at: expiresAt, ...saved } = decryptReplay(previous, encrypted);
500
+ const now = Date.now();
501
+ if (expiresAt !== undefined &&
502
+ expiresAt > now &&
503
+ now < expiresAt - ACCESS_TOKEN_TTL_MS + graceMs) {
504
+ return json({ ...saved, expires_in: Math.ceil((expiresAt - now) / 1000) }, 200, NO_STORE);
505
+ }
506
+ // A delayed retry can outlive its access token. Keep the same unused refresh successor:
507
+ // rotating it here would make another lost response unrecoverable again.
508
+ const response = {
509
+ ...saved,
510
+ access_token: newSecret(ACCESS_TOKEN_PREFIX),
511
+ expires_in: Math.floor(ACCESS_TOKEN_TTL_MS / 1000),
512
+ };
513
+ yield* store.saveTokens([
514
+ {
515
+ hash: secretHash(response.access_token),
516
+ grantId: grant.id,
517
+ kind: "access",
518
+ expiresAt: new Date(now + ACCESS_TOKEN_TTL_MS),
519
+ },
520
+ ]);
521
+ yield* store.saveRefreshReplay(secretHash(previous), encryptReplay(previous, { ...response, access_token_expires_at: now + ACCESS_TOKEN_TTL_MS }), secretHash(response.refresh_token));
522
+ return json(response, 200, NO_STORE);
523
+ });
524
+ }
525
+ /**
526
+ * `POST /api/ontology/oauth/token`: a code with its PKCE verifier, or a refresh token, for an access
527
+ * token and a new refresh token. Refresh retries recover their immediate unused successor; reuse
528
+ * of an older generation revokes the grant. A member who may no longer sign in gets nothing.
529
+ */
530
+ function token(store, graceMs) {
531
+ return (request) => Effect.gen(function* () {
532
+ const params = yield* bodyParams(request);
533
+ const client = yield* authenticateClient(store, request, params);
534
+ if (client === undefined) {
535
+ return oauthError("invalid_client", "The client is unknown or its secret is wrong.", 401);
536
+ }
537
+ if (params.grant_type === DEVICE_GRANT) {
538
+ if (!params.device_code) {
539
+ return oauthError("invalid_request", "device_code is required.");
540
+ }
541
+ const result = yield* store.pollDevice(secretHash(params.device_code), client.id, params.resource);
542
+ if (result.status !== "approved") {
543
+ return oauthError(result.status, "The device authorization has not completed.");
544
+ }
545
+ const device = result.device;
546
+ const member = device.userId === null ? undefined : yield* store.memberPrincipal(device.userId);
547
+ if (member === undefined) {
548
+ return oauthError("access_denied", "The member can no longer use this app.");
549
+ }
550
+ const grant = {
551
+ id: randomUUID(),
552
+ clientId: client.id,
553
+ userId: member.id,
554
+ resource: device.resource,
555
+ scope: device.scope,
556
+ };
557
+ yield* store.saveGrant(grant);
558
+ return yield* issueTokens(store, grant);
559
+ }
560
+ const kind = params.grant_type === "authorization_code"
561
+ ? "code"
562
+ : params.grant_type === "refresh_token"
563
+ ? "refresh"
564
+ : undefined;
565
+ if (kind === undefined) {
566
+ return oauthError("unsupported_grant_type", "This server supports authorization_code, refresh_token and device_code.");
567
+ }
568
+ const presented = kind === "code" ? params.code : params.refresh_token;
569
+ if (presented === undefined) {
570
+ return oauthError("invalid_request", kind === "code" ? "code is required." : "refresh_token is required.");
571
+ }
572
+ const hash = secretHash(presented);
573
+ return yield* store.withTokenLock(hash, Effect.gen(function* () {
574
+ const owner = yield* store.findGrantOfToken(hash);
575
+ // Authenticate the binding before consumption or reuse detection.
576
+ if (owner === undefined || owner.clientId !== client.id) {
577
+ return oauthError("invalid_grant", "The grant is invalid, expired or revoked.");
578
+ }
579
+ if (params.resource !== undefined && !sameResource(params.resource, owner.resource)) {
580
+ return oauthError("invalid_target", "The grant is for a different resource.");
581
+ }
582
+ if ((yield* store.memberPrincipal(owner.userId)) === undefined) {
583
+ // Deny access without permanently destroying authorization on an inconclusive lookup.
584
+ return oauthError("invalid_grant", "The member can no longer use this app.");
585
+ }
586
+ const used = yield* store.useToken(hash, kind);
587
+ if (used.status === "reused") {
588
+ const replay = kind === "refresh" ? yield* store.refreshReplay(hash, graceMs) : undefined;
589
+ if (replay !== undefined) {
590
+ return yield* replayTokens(store, used.grant, presented, replay, graceMs);
591
+ }
592
+ if (kind === "code" || used.successorUsed === true) {
593
+ yield* store.revokeGrant(used.grant.id);
594
+ yield* Effect.logWarning("ontology.oauth.token_reused").pipe(Effect.annotateLogs({ grantId: used.grant.id, kind }));
595
+ }
596
+ }
597
+ if (used.status !== "valid") {
598
+ return oauthError("invalid_grant", "The grant is invalid, expired or revoked.");
599
+ }
600
+ const { grant, token: stored } = used;
601
+ if (kind === "code") {
602
+ if (params.redirect_uri !== undefined && params.redirect_uri !== stored.redirectUri) {
603
+ return oauthError("invalid_grant", "redirect_uri does not match the authorization.");
604
+ }
605
+ if (params.code_verifier === undefined ||
606
+ stored.codeChallenge === undefined ||
607
+ !verifierMatches(params.code_verifier, stored.codeChallenge)) {
608
+ return oauthError("invalid_grant", "code_verifier does not match the code challenge.");
609
+ }
610
+ }
611
+ return yield* issueTokens(store, grant, kind === "refresh" ? presented : undefined);
612
+ }));
613
+ });
614
+ }
615
+ /** `POST /api/ontology/oauth/revoke` (RFC 7009): revokes the grant of a token of the client's. */
616
+ function revoke(store) {
617
+ return (request) => Effect.gen(function* () {
618
+ const params = yield* bodyParams(request);
619
+ const client = yield* authenticateClient(store, request, params);
620
+ if (client === undefined) {
621
+ return oauthError("invalid_client", "The client is unknown or its secret is wrong.", 401);
622
+ }
623
+ if (params.token !== undefined) {
624
+ const grant = yield* store.findGrantOfToken(secretHash(params.token));
625
+ if (grant !== undefined && grant.clientId === client.id) {
626
+ yield* store.revokeGrant(grant.id);
627
+ }
628
+ }
629
+ // Answered alike whether the token was known, so that revocation reveals nothing.
630
+ return json({}, 200, NO_STORE);
631
+ });
632
+ }
633
+ /** RFC 8628: the device secret never appears on a browser URL or in storage. */
634
+ function deviceAuthorization(store, limiter) {
635
+ return (request) => Effect.gen(function* () {
636
+ if (limiter.take(clientAddress(request)) !== undefined) {
637
+ return oauthError("too_many_requests", "Try again in a minute.", 429);
638
+ }
639
+ const params = yield* bodyParams(request);
640
+ const client = yield* authenticateClient(store, request, params);
641
+ if (client === undefined) {
642
+ return oauthError("invalid_client", "The client is unknown or its secret is wrong.", 401);
643
+ }
644
+ const origin = publicOrigin(request);
645
+ const resource = mcpResource(origin);
646
+ if (params.resource !== undefined && !sameResource(params.resource, resource)) {
647
+ return oauthError("invalid_target", "Use this app's MCP resource.");
648
+ }
649
+ const code = newSecret("ssd_");
650
+ let userCode;
651
+ let saved;
652
+ do {
653
+ userCode = humanCode();
654
+ saved = yield* store.saveDevice({
655
+ hash: secretHash(code),
656
+ userCodeHash: secretHash(normalizedUserCode(userCode)),
657
+ clientId: client.id,
658
+ scope: grantedScope(params.scope),
659
+ resource,
660
+ expiresAt: new Date(Date.now() + DEVICE_TTL_MS),
661
+ interval: DEVICE_INTERVAL,
662
+ status: "pending",
663
+ userId: null,
664
+ });
665
+ } while (!saved);
666
+ const verification = `${origin}${CONSENT_PATH}?device=1`;
667
+ return json({
668
+ device_code: code,
669
+ user_code: userCode,
670
+ verification_uri: verification,
671
+ verification_uri_complete: `${verification}&user_code=${encodeURIComponent(userCode)}`,
672
+ expires_in: DEVICE_TTL_MS / 1000,
673
+ interval: DEVICE_INTERVAL,
674
+ }, 200, NO_STORE);
675
+ });
676
+ }
677
+ function verifyDevice(store, request, decision, limiter) {
678
+ return Effect.gen(function* () {
679
+ const requestId = yield* RequestId;
680
+ const member = yield* requireMember();
681
+ if (member === undefined) {
682
+ return notMember(requestId);
683
+ }
684
+ if (limiter.take(clientAddress(request)) !== undefined ||
685
+ !(yield* store.deviceAttempt(member.id))) {
686
+ return oauthError("too_many_requests", "Too many verification attempts. Try again in ten minutes.", 429);
687
+ }
688
+ const body = yield* bodyParams(request);
689
+ const code = normalizedUserCode(body.user_code ?? "");
690
+ const hash = secretHash(code);
691
+ const pending = /^[A-HJ-NP-Z2-9]{8}$/.test(code) ? yield* store.findDevice(hash) : undefined;
692
+ const unavailable = unavailableDevice(pending);
693
+ if (pending === undefined || unavailable !== undefined) {
694
+ return requestNotFound(requestId, unavailable);
695
+ }
696
+ if (decision !== "lookup") {
697
+ const decided = yield* store.decideDevice(hash, member.id, body.scope, decision);
698
+ return decided
699
+ ? json({ status: decision === "approve" ? "approved" : "denied" }, 200, NO_STORE)
700
+ : requestNotFound(requestId);
701
+ }
702
+ const client = yield* store.findClient(pending.clientId);
703
+ return json({
704
+ id: `device:${code}`,
705
+ client: {
706
+ name: client?.name ?? "MCP client",
707
+ uri: client?.clientUri ?? null,
708
+ redirect_uri: "",
709
+ redirect_host: client?.clientUri ? new URL(client.clientUri).host : "unverified client",
710
+ },
711
+ scope: pending.scope,
712
+ permissions: member.permissions,
713
+ expires_at: pending.expiresAt.toISOString(),
714
+ }, 200, NO_STORE);
715
+ });
716
+ }
717
+ const PREFLIGHT = HttpServerResponse.empty({ status: 204, headers: CORS });
718
+ /**
719
+ * The MCP server's OAuth 2.1 authorization server, on the app's own origin: the protected resource
720
+ * and authorization server metadata, dynamic client registration, the authorization endpoint that
721
+ * hands the member to the app's consent page, the endpoints the consent page decides with, and the
722
+ * token and revocation endpoints. Without the OAuth tables, it serves nothing.
723
+ */
724
+ export function oauthLayer(options) {
725
+ return Layer.effectDiscard(Effect.gen(function* () {
726
+ const router = yield* HttpRouter.HttpRouter;
727
+ const backend = yield* OntologyBackend;
728
+ const store = backend.oauth;
729
+ if (store === undefined) {
730
+ return;
731
+ }
732
+ const limiter = fixedWindowLimiter(REGISTRATION_LIMIT);
733
+ const deviceLimiter = fixedWindowLimiter(REGISTRATION_LIMIT);
734
+ const verificationLimiter = fixedWindowLimiter({
735
+ limit: 20,
736
+ windowMs: 600_000,
737
+ maxKeys: 10_000,
738
+ });
739
+ const credential = HttpApiBuilder.securityDecode(HttpApiSecurity.bearer);
740
+ const asMember = (answer) => (request) => Effect.gen(function* () {
741
+ const bearer = yield* Effect.provideService(credential, HttpServerRequest.HttpServerRequest, request);
742
+ return yield* withPrincipal(bearer, options.verifyToken, backend, answer(request), {
743
+ oauthResource: appSessionResource(publicOrigin(request)),
744
+ });
745
+ });
746
+ const metadata = (document) => (request) => Effect.succeed(json(document(publicOrigin(request))));
747
+ for (const path of [PROTECTED_RESOURCE_PATH, `${PROTECTED_RESOURCE_PATH}/mcp`]) {
748
+ yield* router.add("GET", path, metadata(protectedResourceMetadata));
749
+ yield* router.add("OPTIONS", path, PREFLIGHT);
750
+ }
751
+ yield* router.add("GET", AUTHORIZATION_SERVER_PATH, metadata(authorizationServerMetadata));
752
+ yield* router.add("OPTIONS", AUTHORIZATION_SERVER_PATH, PREFLIGHT);
753
+ yield* router.add("POST", REGISTER_PATH, register(store, limiter));
754
+ yield* router.add("OPTIONS", REGISTER_PATH, PREFLIGHT);
755
+ yield* router.add("GET", AUTHORIZE_PATH, authorize(store));
756
+ yield* router.add("POST", DEVICE_PATH, deviceAuthorization(store, deviceLimiter));
757
+ yield* router.add("OPTIONS", DEVICE_PATH, PREFLIGHT);
758
+ for (const decision of ["lookup", "approve", "deny"]) {
759
+ yield* router.add("POST", `${DEVICE_REQUEST_PATH}/${decision}`, asMember((request) => verifyDevice(store, request, decision, verificationLimiter)));
760
+ }
761
+ yield* router.add("POST", TOKEN_PATH, token(store, options.refreshReuseGraceMs ?? 45_000));
762
+ yield* router.add("OPTIONS", TOKEN_PATH, PREFLIGHT);
763
+ yield* router.add("POST", REVOKE_PATH, revoke(store));
764
+ yield* router.add("OPTIONS", REVOKE_PATH, PREFLIGHT);
765
+ yield* router.add("GET", `${REQUESTS_PATH}/:id`, asMember(() => describeRequest(store)));
766
+ yield* router.add("POST", `${REQUESTS_PATH}/:id/approve`, asMember((request) => decideRequest(store, "approve", request)));
767
+ yield* router.add("POST", `${REQUESTS_PATH}/:id/deny`, asMember((request) => decideRequest(store, "deny", request)));
768
+ }));
769
+ }