@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,120 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Effect } from "effect";
3
+ import { AGENT_TASKS_TABLE } from "../storage/tables.js";
4
+ /** How long tasks are kept after their deadline, for diagnosis, before the next start deletes them. */
5
+ export const AGENT_TASK_RETENTION_DAYS = 30;
6
+ const COLUMNS = `"id"::text AS "id", "workflow", "run_id", "hook_token", "prompt", "status", "result", ` +
7
+ `"deadline_at"`;
8
+ const LIVE = `"status" IN ('pending', 'started')`;
9
+ /** The terminal outcome a row's status and `result` fields describe. */
10
+ function resultOf(status, stored) {
11
+ const fields = (typeof stored === "string" ? JSON.parse(stored) : (stored ?? {}));
12
+ switch (status) {
13
+ case "pending":
14
+ case "started":
15
+ return undefined;
16
+ case "completed":
17
+ case "needs_input":
18
+ return { status, text: String(fields.text ?? ""), truncated: fields.truncated === true };
19
+ case "failed":
20
+ return {
21
+ status,
22
+ reason: fields.reason,
23
+ };
24
+ case "timed_out":
25
+ return { status };
26
+ }
27
+ }
28
+ /** The fields of a terminal outcome that `result` stores; the status has its own column. */
29
+ function storedFields(result) {
30
+ switch (result.status) {
31
+ case "completed":
32
+ case "needs_input":
33
+ return { text: result.text, truncated: result.truncated };
34
+ case "failed":
35
+ return { reason: result.reason };
36
+ case "timed_out":
37
+ return null;
38
+ }
39
+ }
40
+ function recordOf(row) {
41
+ return {
42
+ id: row.id,
43
+ workflow: row.workflow,
44
+ runId: row.run_id,
45
+ hookToken: row.hook_token,
46
+ prompt: row.prompt,
47
+ status: row.status,
48
+ result: resultOf(row.status, row.result),
49
+ deadlineAt: row.deadline_at instanceof Date ? row.deadline_at : new Date(row.deadline_at),
50
+ };
51
+ }
52
+ /** The task store over `_agent_tasks`. Database failures are defects. */
53
+ export function sqlAgentTaskStore(sql) {
54
+ const one = (text, params) => sql
55
+ .unsafe(text, params)
56
+ .pipe(Effect.map(([row]) => (row === undefined ? undefined : recordOf(row))));
57
+ const byHook = (hookToken) => one(`SELECT ${COLUMNS} FROM "${AGENT_TASKS_TABLE}" WHERE "hook_token" = $1`, [hookToken]);
58
+ const byId = (id) => one(`SELECT ${COLUMNS} FROM "${AGENT_TASKS_TABLE}" WHERE "id" = $1::uuid`, [id]);
59
+ return {
60
+ byHook: (hookToken) => byHook(hookToken).pipe(Effect.orDie),
61
+ live: (secretSha256) => one(`SELECT ${COLUMNS} FROM "${AGENT_TASKS_TABLE}" ` +
62
+ `WHERE "secret_sha256" = $1 AND ${LIVE} AND "deadline_at" > now()`, [secretSha256]).pipe(Effect.orDie),
63
+ create: (input) => sql
64
+ .withTransaction(Effect.gen(function* () {
65
+ const existing = yield* byHook(input.hookToken);
66
+ if (existing !== undefined) {
67
+ return { status: "existing", task: existing };
68
+ }
69
+ // Concurrent starts count the live tasks one at a time, so that at most `limit` are.
70
+ yield* sql.unsafe(`SELECT pg_advisory_xact_lock(hashtextextended($1, 0))`, [
71
+ AGENT_TASKS_TABLE,
72
+ ]);
73
+ yield* sql.unsafe(`DELETE FROM "${AGENT_TASKS_TABLE}" ` +
74
+ `WHERE "deadline_at" < now() - make_interval(days => $1)`, [AGENT_TASK_RETENTION_DAYS]);
75
+ const [counted] = yield* sql.unsafe(`SELECT count(*)::text AS "live" FROM "${AGENT_TASKS_TABLE}" ` +
76
+ `WHERE ${LIVE} AND "deadline_at" > now()`);
77
+ if (Number(counted?.live ?? 0) >= input.limit) {
78
+ return { status: "busy" };
79
+ }
80
+ const created = yield* one(`INSERT INTO "${AGENT_TASKS_TABLE}" ` +
81
+ `("id", "workflow", "run_id", "hook_token", "secret_sha256", "prompt", "status", ` +
82
+ `"deadline_at") VALUES ($1::uuid, $2, $3, $4, $5, $6, 'pending', ` +
83
+ `now() + make_interval(secs => $7::double precision / 1000)) ` +
84
+ `ON CONFLICT ("hook_token") DO NOTHING RETURNING ${COLUMNS}`, [
85
+ randomUUID(),
86
+ input.workflow,
87
+ input.runId,
88
+ input.hookToken,
89
+ input.secretSha256,
90
+ input.prompt,
91
+ input.timeoutMs,
92
+ ]);
93
+ if (created !== undefined) {
94
+ return { status: "created", task: created };
95
+ }
96
+ // Another attempt of the same step inserted it first.
97
+ const raced = yield* byHook(input.hookToken);
98
+ return raced === undefined
99
+ ? yield* Effect.die(new Error("The agent task's row disappeared after a conflict."))
100
+ : { status: "existing", task: raced };
101
+ }))
102
+ .pipe(Effect.orDie),
103
+ rekey: (id, secretSha256) => sql
104
+ .unsafe(`UPDATE "${AGENT_TASKS_TABLE}" SET "secret_sha256" = $2 ` +
105
+ `WHERE "id" = $1::uuid AND "status" = 'pending' RETURNING "id"::text AS "id"`, [id, secretSha256])
106
+ .pipe(Effect.map((rows) => rows.length > 0), Effect.orDie),
107
+ markStarted: (id) => sql
108
+ .unsafe(`UPDATE "${AGENT_TASKS_TABLE}" SET "status" = 'started', "started_at" = now() ` +
109
+ `WHERE "id" = $1::uuid AND "status" = 'pending' RETURNING "id"::text AS "id"`, [id])
110
+ .pipe(Effect.map((rows) => rows.length > 0), Effect.orDie),
111
+ finish: (id, result) => Effect.gen(function* () {
112
+ const fields = storedFields(result);
113
+ const finished = yield* one(`UPDATE "${AGENT_TASKS_TABLE}" SET "status" = $2, "result" = $3::jsonb, ` +
114
+ `"finished_at" = now() WHERE "id" = $1::uuid AND ${LIVE} RETURNING ${COLUMNS}`, [id, result.status, fields === null ? null : JSON.stringify(fields)]);
115
+ return finished !== undefined
116
+ ? { finished: true, task: finished }
117
+ : { finished: false, task: yield* byId(id) };
118
+ }).pipe(Effect.orDie),
119
+ };
120
+ }
@@ -0,0 +1,15 @@
1
+ import { Effect } from "effect";
2
+ import { SqlClient } from "effect/unstable/sql";
3
+ import type { Ontology } from "../ontology.js";
4
+ import { type AgentStore, type ResolveIdentityInput, type ChannelSignInInput } from "../service/runtime-contract.js";
5
+ /**
6
+ * The agent store on the runtime's agent tables, as `ontology_app`. Expiry is the database's
7
+ * `now()`; a pairing is consumed with one `UPDATE … WHERE "consumed_at" IS NULL`, so two concurrent
8
+ * approvals cannot both succeed. Ids that are not UUIDs find nothing rather than fail the cast.
9
+ * Chats the agent sees are `agent_chat` records, written as the platform with history.
10
+ */
11
+ export declare function sqlAgentStore(ontology: Ontology, sql: SqlClient.SqlClient): AgentStore;
12
+ /** Shared verified admission for agents and channel-app adapters; never expose trusted inputs to browsers. */
13
+ export declare function resolveChannelIdentity(ontology: Ontology, sql: SqlClient.SqlClient, input: ResolveIdentityInput): Effect.Effect<import("../index.js").AgentResolution, never, never>;
14
+ /** Call only after verifying a channel-app assertion. Shares admission, limits and onboarding with agents. */
15
+ export declare function resolveChannelSignIn(ontology: Ontology, sql: SqlClient.SqlClient, input: ChannelSignInInput): Effect.Effect<import("../index.js").AgentResolution, never, never>;
@@ -0,0 +1,457 @@
1
+ import { sqlConfirmationStore } from "./confirmations.js";
2
+ import { randomUUID } from "node:crypto";
3
+ import { Effect } from "effect";
4
+ import { SqlClient } from "effect/unstable/sql";
5
+ import { AgentChat } from "../agent-chat.js";
6
+ import { AGENT_IDENTITIES_TABLE, AGENT_PAIRINGS_TABLE, CHANNEL_USERS_TABLE, IDENTITY_NOTICES_TABLE, USER_TABLE, } from "../migrate/storage.js";
7
+ import { MAX_QUERY_LIMIT } from "../query.js";
8
+ import { beginReplicationWrite } from "../replication/transaction.js";
9
+ import { IdentityInUse, } from "../service/runtime-contract.js";
10
+ import { revokeChannelSessions } from "./channel-session-revocation.js";
11
+ import { resolveAgentIdentity } from "./resolve-agent-identity.js";
12
+ import { completeAgentLimitNotice } from "./agent-counters.js";
13
+ import { isMemberBlocked, setMemberBlocked, resolveMemberById } from "./principals.js";
14
+ import { isRecordId } from "./records.js";
15
+ import { makeOntologyRuntime } from "./sql-runtime.js";
16
+ import { CHANNEL_IDENTITIES_FROM, CHANNEL_ORIGIN_SQL, CHANNEL_REVOKED_AT, LIVE_CHANNEL_IDENTITY, makeIdentityWriter, USER_IDENTITY_TABLE, } from "./user-identities.js";
17
+ const PAIRINGS = `"${AGENT_PAIRINGS_TABLE}"`;
18
+ /** The legacy channel accounts, written beside `user_identity` for earlier SDKs. */
19
+ const LEGACY_IDENTITIES = `"${AGENT_IDENTITIES_TABLE}"`;
20
+ const USERS = `"${USER_TABLE}"`;
21
+ /** A timestamp as epoch milliseconds, which every driver returns as a plain number. */
22
+ function epochMs(column) {
23
+ return `(extract(epoch from ${column}) * 1000)::double precision`;
24
+ }
25
+ const PAIRING_COLUMNS = `"id"::text AS "id", "provider", "external_id", "display", ` +
26
+ `${epochMs(`"expires_at"`)} AS "expires_at"`;
27
+ /** Channel accounts are `user_identity` records `i`, with their first-contact notice `n`. */
28
+ const IDENTITIES_FROM = `${CHANNEL_IDENTITIES_FROM} LEFT JOIN "${IDENTITY_NOTICES_TABLE}" AS "n" ` +
29
+ `ON "n"."identity_id" = "i"."id"`;
30
+ const CHANNEL_ACCOUNT = `"i"."origin"::text IN ${CHANNEL_ORIGIN_SQL}`;
31
+ /** Revoked in either store: see {@link CHANNEL_IDENTITIES_FROM}. */
32
+ const REVOKED_AT = CHANNEL_REVOKED_AT;
33
+ const IDENTITY_COLUMNS = `"i"."id"::text AS "id", "i"."provider", "i"."subject" AS "external_id", ` +
34
+ `"i"."user_id"::text AS "user_id", "i"."display", ` +
35
+ `${epochMs(`"i"."created_at"`)} AS "created_at", ${epochMs(REVOKED_AT)} AS "revoked_at", ` +
36
+ `"i"."username", "i"."origin"::text AS "origin", ${epochMs(`"n"."noticed_at"`)} AS "noticed_at", ` +
37
+ `"n"."notice_sha256", "n"."notice_version"`;
38
+ /**
39
+ * How often a chat's `last_message_at` is recorded: each record is a history row, and a busy chat
40
+ * would otherwise add one per message.
41
+ */
42
+ const CHAT_MESSAGE_RECORD_INTERVAL_MS = 15 * 60 * 1000;
43
+ /** Whether a chat's latest message is recorded: it has none yet, or none this interval. */
44
+ function messageDue(lastMessageAt, now) {
45
+ const last = typeof lastMessageAt === "string" ? Date.parse(lastMessageAt) : Number.NaN;
46
+ return Number.isNaN(last) || now.getTime() - last >= CHAT_MESSAGE_RECORD_INTERVAL_MS;
47
+ }
48
+ function nullableText(value) {
49
+ return value === null || value === undefined ? null : String(value);
50
+ }
51
+ function pairingOf(row) {
52
+ return {
53
+ id: String(row.id),
54
+ provider: String(row.provider),
55
+ externalId: String(row.external_id),
56
+ display: nullableText(row.display),
57
+ expiresAt: new Date(Number(row.expires_at)),
58
+ };
59
+ }
60
+ function identityOf(row) {
61
+ return {
62
+ id: String(row.id),
63
+ provider: String(row.provider),
64
+ externalId: String(row.external_id),
65
+ userId: String(row.user_id),
66
+ display: nullableText(row.display),
67
+ ...(typeof row.username === "string" ? { username: row.username } : {}),
68
+ createdAt: new Date(Number(row.created_at)),
69
+ revokedAt: row.revoked_at === null ? null : new Date(Number(row.revoked_at)),
70
+ // The wire keeps the names `_agent_identities` gave the origins.
71
+ origin: row.origin === "channel" ? "provisioned" : "paired",
72
+ noticedAt: row.noticed_at === null ? null : new Date(Number(row.noticed_at)),
73
+ noticeSha256: nullableText(row.notice_sha256),
74
+ noticeVersion: nullableText(row.notice_version),
75
+ };
76
+ }
77
+ /**
78
+ * The agent store on the runtime's agent tables, as `ontology_app`. Expiry is the database's
79
+ * `now()`; a pairing is consumed with one `UPDATE … WHERE "consumed_at" IS NULL`, so two concurrent
80
+ * approvals cannot both succeed. Ids that are not UUIDs find nothing rather than fail the cast.
81
+ * Chats the agent sees are `agent_chat` records, written as the platform with history.
82
+ */
83
+ export function sqlAgentStore(ontology, sql) {
84
+ const rows = (statement, values = []) => sql.unsafe(statement, values).pipe(Effect.orDie);
85
+ const memberPrincipal = (userId) => resolveMemberById(ontology, userId).pipe(Effect.provideService(SqlClient.SqlClient, sql));
86
+ const store = {
87
+ confirmations: sqlConfirmationStore(sql),
88
+ savePairing: (pairing) => sql
89
+ .withTransaction(Effect.gen(function* () {
90
+ yield* rows(`DELETE FROM ${PAIRINGS} WHERE "expires_at" <= now()`);
91
+ const inserted = yield* rows([
92
+ `INSERT INTO ${PAIRINGS}`,
93
+ ` ("id", "code_hash", "provider", "external_id", "display", "expires_at")`,
94
+ `VALUES ($1::uuid, $2, $3, $4, $5, $6::timestamptz)`,
95
+ `ON CONFLICT ("code_hash") DO NOTHING`,
96
+ `RETURNING "id"`,
97
+ ].join("\n"), [
98
+ pairing.id,
99
+ pairing.codeHash,
100
+ pairing.provider,
101
+ pairing.externalId,
102
+ pairing.display,
103
+ pairing.expiresAt.toISOString(),
104
+ ]);
105
+ return inserted.length > 0;
106
+ }))
107
+ .pipe(Effect.orDie),
108
+ findPairing: (codeHash) => rows([
109
+ `SELECT ${PAIRING_COLUMNS}`,
110
+ `FROM ${PAIRINGS}`,
111
+ `WHERE "code_hash" = $1 AND "consumed_at" IS NULL AND "expires_at" > now()`,
112
+ ].join("\n"), [codeHash]).pipe(Effect.map(([row]) => (row === undefined ? undefined : pairingOf(row)))),
113
+ approvePairing: ({ codeHash, userId, identityId }) => sql
114
+ .withTransaction(Effect.gen(function* () {
115
+ // Consume once before locking; IdentityInUse must roll this transaction back to keep the code usable.
116
+ const [consumed] = yield* rows([
117
+ `UPDATE ${PAIRINGS} SET "consumed_at" = now()`,
118
+ `WHERE "code_hash" = $1 AND "consumed_at" IS NULL AND "expires_at" > now()`,
119
+ `RETURNING ${PAIRING_COLUMNS}`,
120
+ ].join("\n"), [codeHash]);
121
+ if (consumed === undefined) {
122
+ return undefined;
123
+ }
124
+ const pairing = pairingOf(consumed);
125
+ // Two approvals that replace the same account's or the same member's identity run one
126
+ // after the other, so the partial unique indexes never refuse a valid one.
127
+ yield* rows(`SELECT pg_advisory_xact_lock(hashtext($1)), pg_advisory_xact_lock(hashtext($2))`, [
128
+ `account:${pairing.provider}:${pairing.externalId}`,
129
+ `member:${userId}:${pairing.provider}`,
130
+ ]);
131
+ // Blocking locks User FOR UPDATE. Keep both the new member and previous account
132
+ // owners stable until approval commits, then recheck their block state. An owner only
133
+ // the legacy store knows, as an earlier SDK may have paired, counts too.
134
+ const owners = yield* rows(`SELECT "id"::text AS "id", "kind"::text AS "kind", "active" FROM ${USERS}
135
+ WHERE "id" = $3::uuid OR "id" IN (
136
+ SELECT "user_id" FROM "${USER_IDENTITY_TABLE}" AS "i"
137
+ WHERE "i"."provider" = $1 AND "i"."subject" = $2 AND ${CHANNEL_ACCOUNT}
138
+ ) OR "id" IN (
139
+ SELECT "user_id" FROM ${LEGACY_IDENTITIES} WHERE "provider" = $1 AND "external_id" = $2
140
+ ) ORDER BY "id" FOR SHARE`, [pairing.provider, pairing.externalId, userId]);
141
+ const target = owners.find((owner) => owner.id === userId);
142
+ if (target?.kind !== "member" ||
143
+ !target.active ||
144
+ (yield* isMemberBlocked(sql, userId))) {
145
+ return yield* new IdentityInUse({});
146
+ }
147
+ // Any member who ever held the account and is blocked keeps it from being paired.
148
+ const [blocked] = yield* rows(`SELECT 1 FROM "${CHANNEL_USERS_TABLE}" c WHERE c."user_id" IN (` +
149
+ owners.map((_, index) => `$${index + 1}::uuid`).join(", ") +
150
+ `) AND c."blocked_at" IS NOT NULL LIMIT 1`, owners.map((owner) => String(owner.id)));
151
+ if (blocked !== undefined) {
152
+ return yield* new IdentityInUse({});
153
+ }
154
+ const [bound] = yield* rows(`SELECT ${IDENTITY_COLUMNS} FROM ${IDENTITIES_FROM} ` +
155
+ `WHERE "i"."provider" = $1 AND "i"."subject" = $2 AND ${LIVE_CHANNEL_IDENTITY}`, [pairing.provider, pairing.externalId]);
156
+ if (bound !== undefined) {
157
+ if (String(bound.user_id) !== userId) {
158
+ return yield* new IdentityInUse({});
159
+ }
160
+ return identityOf(bound);
161
+ }
162
+ const [legacyBound] = yield* rows(`SELECT "user_id"::text AS "user_id" FROM ${LEGACY_IDENTITIES}
163
+ WHERE "provider" = $1 AND "external_id" = $2 AND "revoked_at" IS NULL`, [pairing.provider, pairing.externalId]);
164
+ // Paired only in the legacy store, by an earlier SDK: the next migration copies it.
165
+ if (legacyBound !== undefined && String(legacyBound.user_id) !== userId) {
166
+ return yield* new IdentityInUse({});
167
+ }
168
+ const at = new Date().toISOString();
169
+ const writer = makeIdentityWriter(ontology, sql, {
170
+ action: `${USER_IDENTITY_TABLE}.pair`,
171
+ actionId: randomUUID(),
172
+ });
173
+ // The member's live account of the provider is displaced, and the account's own record
174
+ // that the legacy store revoked or no longer holds is revoked too, freeing its key.
175
+ const replaced = yield* rows(`SELECT "i"."id"::text AS "id" FROM ${CHANNEL_IDENTITIES_FROM}
176
+ WHERE "i"."revoked_at" IS NULL AND ${CHANNEL_ACCOUNT} AND "i"."provider" = $1
177
+ AND ("i"."user_id" = $2::uuid OR ("i"."subject" = $3
178
+ AND ("a"."id" IS NULL OR "a"."revoked_at" IS NOT NULL)))
179
+ ORDER BY "i"."id" FOR UPDATE OF "i"`, [pairing.provider, userId, pairing.externalId]);
180
+ for (const identity of replaced) {
181
+ yield* writer.revoke(String(identity.id), at);
182
+ }
183
+ const displaced = yield* rows([
184
+ `UPDATE ${LEGACY_IDENTITIES} SET "revoked_at" = $3::timestamptz`,
185
+ `WHERE "revoked_at" IS NULL AND "provider" = $1`,
186
+ ` AND "user_id" = $2::uuid RETURNING "id"::text AS "id"`,
187
+ ].join("\n"), [pairing.provider, userId, at]);
188
+ for (const id of new Set([...replaced, ...displaced].map((row) => String(row.id)))) {
189
+ yield* revokeChannelSessions(sql, id);
190
+ }
191
+ yield* writer.create({
192
+ id: identityId,
193
+ provider: pairing.provider,
194
+ issuer: null,
195
+ subject: pairing.externalId,
196
+ userId,
197
+ origin: "pairing",
198
+ display: pairing.display,
199
+ });
200
+ yield* rows([
201
+ `INSERT INTO ${LEGACY_IDENTITIES} ("id", "provider", "external_id", "user_id", "display")`,
202
+ `VALUES ($1::uuid, $2, $3, $4::uuid, $5)`,
203
+ ].join("\n"), [identityId, pairing.provider, pairing.externalId, userId, pairing.display]);
204
+ const [created] = yield* rows(`SELECT ${IDENTITY_COLUMNS} FROM ${IDENTITIES_FROM} WHERE "i"."id" = $1::uuid`, [identityId]);
205
+ return created === undefined ? undefined : identityOf(created);
206
+ }))
207
+ .pipe(Effect.catchIf((error) => error._tag !== "IdentityInUse", (error) => Effect.die(error))),
208
+ resolveIdentity: (input) => resolveAgentIdentity(ontology, sql, store, input),
209
+ completeLimitNotice: (input) => completeAgentLimitNotice(sql, input),
210
+ setMemberBlocked: (input) => setMemberBlocked(ontology, input).pipe(Effect.provideService(SqlClient.SqlClient, sql), Effect.as(true), Effect.catchTag("MemberNotFound", () => Effect.succeed(false))),
211
+ // The notice is operational state beside the identity; the legacy columns are kept in step.
212
+ recordNotice: ({ provider, externalId, sha256, version }) => sql
213
+ .withTransaction(Effect.gen(function* () {
214
+ const noticed = yield* rows(`INSERT INTO "${IDENTITY_NOTICES_TABLE}" ` +
215
+ `("identity_id", "noticed_at", "notice_sha256", "notice_version") ` +
216
+ `SELECT "i"."id", now(), $3, $4 FROM ${CHANNEL_IDENTITIES_FROM} ` +
217
+ `WHERE "i"."provider" = $1 AND "i"."subject" = $2 AND ${LIVE_CHANNEL_IDENTITY} ` +
218
+ `AND EXISTS (SELECT 1 FROM "${CHANNEL_USERS_TABLE}" c WHERE c."user_id" = "i"."user_id"
219
+ AND c."created_via" NOT IN ('invite', 'email')) ` +
220
+ `ON CONFLICT ("identity_id") DO UPDATE SET "noticed_at" = now(), ` +
221
+ `"notice_sha256" = EXCLUDED."notice_sha256", ` +
222
+ `"notice_version" = EXCLUDED."notice_version" ` +
223
+ `WHERE "${IDENTITY_NOTICES_TABLE}"."notice_version" IS DISTINCT FROM EXCLUDED."notice_version" ` +
224
+ `OR "${IDENTITY_NOTICES_TABLE}"."notice_sha256" IS DISTINCT FROM EXCLUDED."notice_sha256" ` +
225
+ `RETURNING "identity_id"`, [provider, externalId, sha256, version ?? null]);
226
+ yield* rows(`UPDATE ${LEGACY_IDENTITIES} SET "noticed_at" = now(), "notice_sha256" = $3, "notice_version" = $4 ` +
227
+ `WHERE "provider" = $1 AND "external_id" = $2 AND "revoked_at" IS NULL ` +
228
+ `AND EXISTS (SELECT 1 FROM "${CHANNEL_USERS_TABLE}" c WHERE c."user_id" = ${LEGACY_IDENTITIES}."user_id"
229
+ AND c."created_via" NOT IN ('invite', 'email')) AND ("noticed_at" IS NULL
230
+ OR "notice_version" IS DISTINCT FROM $4 OR "notice_sha256" IS DISTINCT FROM $3)`, [provider, externalId, sha256, version ?? null]);
231
+ return noticed.length > 0;
232
+ }))
233
+ .pipe(Effect.orDie),
234
+ findIdentity: ({ provider, externalId }) => rows([
235
+ `SELECT ${IDENTITY_COLUMNS}`,
236
+ `FROM ${IDENTITIES_FROM}`,
237
+ `WHERE "i"."provider" = $1 AND "i"."subject" = $2 AND ${CHANNEL_ACCOUNT}`,
238
+ `ORDER BY ${REVOKED_AT} IS NOT NULL, ${REVOKED_AT} DESC`,
239
+ `LIMIT 1`,
240
+ ].join("\n"), [provider, externalId]).pipe(Effect.map(([row]) => (row === undefined ? undefined : identityOf(row)))),
241
+ listIdentities: (userId) => isRecordId(userId)
242
+ ? rows([
243
+ `SELECT ${IDENTITY_COLUMNS}`,
244
+ `FROM ${IDENTITIES_FROM}`,
245
+ `WHERE "i"."user_id" = $1::uuid AND ${LIVE_CHANNEL_IDENTITY}`,
246
+ `ORDER BY "i"."created_at", "i"."id"`,
247
+ ].join("\n"), [userId]).pipe(Effect.map((found) => found.map(identityOf)))
248
+ : Effect.succeed([]),
249
+ revokeIdentity: ({ id, userId }) => isRecordId(id) && isRecordId(userId)
250
+ ? sql
251
+ .withTransaction(Effect.gen(function* () {
252
+ const [live] = yield* rows(`SELECT "i"."id"::text AS "id" FROM ${CHANNEL_IDENTITIES_FROM}
253
+ WHERE "i"."id" = $1::uuid AND "i"."user_id" = $2::uuid AND ${LIVE_CHANNEL_IDENTITY}
254
+ FOR UPDATE OF "i"`, [id, userId]);
255
+ if (live === undefined) {
256
+ return false;
257
+ }
258
+ const at = new Date().toISOString();
259
+ yield* makeIdentityWriter(ontology, sql, {
260
+ action: `${USER_IDENTITY_TABLE}.revoke`,
261
+ actionId: randomUUID(),
262
+ }).revoke(id, at);
263
+ // @legacy identities.legacy-stores-dual-write
264
+ yield* rows(`UPDATE ${LEGACY_IDENTITIES} SET "revoked_at" = $3::timestamptz
265
+ WHERE "id" = $1::uuid AND "user_id" = $2::uuid AND "revoked_at" IS NULL`, [id, userId, at]);
266
+ yield* revokeChannelSessions(sql, id);
267
+ return true;
268
+ }))
269
+ .pipe(Effect.orDie)
270
+ : Effect.succeed(false),
271
+ member: (userId) => Effect.gen(function* () {
272
+ if (!isRecordId(userId)) {
273
+ return undefined;
274
+ }
275
+ const principal = yield* memberPrincipal(userId);
276
+ if (principal === undefined) {
277
+ return undefined;
278
+ }
279
+ const [user] = yield* rows(`SELECT "name" FROM ${USERS} WHERE "id" = $1::uuid`, [userId]);
280
+ return { name: String(user?.name ?? ""), principal };
281
+ }),
282
+ actingMember: (userId, provider) => Effect.gen(function* () {
283
+ if (!isRecordId(userId)) {
284
+ return undefined;
285
+ }
286
+ const [paired] = yield* rows(`SELECT "i"."provider" FROM ${CHANNEL_IDENTITIES_FROM}
287
+ WHERE "i"."user_id" = $1::uuid AND ${LIVE_CHANNEL_IDENTITY}
288
+ AND ($2::text IS NULL OR "i"."provider" = $2) ORDER BY "i"."created_at" LIMIT 1`, [userId, provider ?? null]);
289
+ const principal = paired === undefined ? undefined : yield* memberPrincipal(userId);
290
+ return principal === undefined || provider === undefined
291
+ ? principal
292
+ : { ...principal, authenticatedVia: provider };
293
+ }),
294
+ seeChat: ({ provider, externalId, title, memberId, leftMemberId, agentLeft, migratedFrom }) => sql
295
+ .withTransaction(Effect.gen(function* () {
296
+ yield* beginReplicationWrite(sql);
297
+ const previous = migratedFrom === undefined || migratedFrom === externalId ? undefined : migratedFrom;
298
+ // Calls for one chat run one after the other: the first creates it, the rest find it. A
299
+ // migration locks both chats, in one order, so that two calls never wait on each other.
300
+ for (const id of [externalId, ...(previous === undefined ? [] : [previous])].sort()) {
301
+ yield* rows(`SELECT pg_advisory_xact_lock(hashtext($1))`, [`chat:${provider}:${id}`]);
302
+ }
303
+ const runtime = makeOntologyRuntime(ontology, sql, {
304
+ action: `${AgentChat.name}.seen`,
305
+ actionId: randomUUID(),
306
+ principalId: null,
307
+ });
308
+ const now = new Date();
309
+ const chatOf = (id) => runtime
310
+ .find({
311
+ entity: AgentChat.name,
312
+ options: { where: { provider, external_id: id }, limit: 1, forUpdate: true },
313
+ })
314
+ .pipe(Effect.map(([chat]) => chat));
315
+ const membersOf = (id) => runtime
316
+ .related({
317
+ entity: AgentChat.name,
318
+ id,
319
+ relationship: "members",
320
+ query: { limit: MAX_QUERY_LIMIT },
321
+ })
322
+ .pipe(Effect.map((page) => page.items.map((member) => String(member.id))));
323
+ // Unlinks every member of the chat, linking each to `to` first when given. Each page
324
+ // unlinked is gone, so the first page is read until it is empty.
325
+ const releaseMembers = (id, to) => Effect.gen(function* () {
326
+ for (;;) {
327
+ const members = yield* membersOf(id);
328
+ if (members.length === 0) {
329
+ return;
330
+ }
331
+ for (const targetId of members) {
332
+ if (to !== undefined) {
333
+ yield* runtime.link({
334
+ entity: AgentChat.name,
335
+ relationship: "members",
336
+ id: to,
337
+ targetId,
338
+ });
339
+ }
340
+ yield* runtime.unlink({
341
+ entity: AgentChat.name,
342
+ relationship: "members",
343
+ id,
344
+ targetId,
345
+ });
346
+ }
347
+ }
348
+ });
349
+ let found = yield* chatOf(externalId);
350
+ if (previous !== undefined) {
351
+ const old = yield* chatOf(previous);
352
+ if (old !== undefined && found === undefined) {
353
+ // The group became a supergroup: the chat keeps its record under its new id.
354
+ found = yield* runtime.update({
355
+ entity: AgentChat.name,
356
+ id: String(old.id),
357
+ values: { external_id: externalId },
358
+ });
359
+ }
360
+ else if (old !== undefined && found !== undefined) {
361
+ // Both were recorded: the new one keeps what members said and gains the members,
362
+ // and the old one is deleted.
363
+ const kept = {};
364
+ for (const key of ["purpose", "when_to_use"]) {
365
+ if (nullableText(found[key]) === null && nullableText(old[key]) !== null) {
366
+ kept[key] = old[key];
367
+ }
368
+ }
369
+ if (Object.keys(kept).length > 0) {
370
+ found = yield* runtime.update({
371
+ entity: AgentChat.name,
372
+ id: String(found.id),
373
+ values: kept,
374
+ });
375
+ }
376
+ yield* releaseMembers(String(old.id), String(found.id));
377
+ yield* runtime.delete({ entity: AgentChat.name, id: String(old.id) });
378
+ }
379
+ }
380
+ const changes = {
381
+ ...(found?.title === title ? {} : { title }),
382
+ ...(messageDue(found?.last_message_at, now)
383
+ ? { last_message_at: now.toISOString() }
384
+ : {}),
385
+ };
386
+ const chat = found === undefined
387
+ ? yield* runtime.create({
388
+ entity: AgentChat.name,
389
+ values: { provider, external_id: externalId, ...changes },
390
+ })
391
+ : Object.keys(changes).length === 0
392
+ ? found
393
+ : yield* runtime.update({
394
+ entity: AgentChat.name,
395
+ id: String(found.id),
396
+ values: changes,
397
+ });
398
+ if (memberId !== undefined && isRecordId(memberId)) {
399
+ const [member] = yield* rows(`SELECT 1 FROM ${USERS} WHERE "id" = $1::uuid AND "kind"::text = 'member' AND "active"`, [memberId]);
400
+ // A link already there changes nothing and records no history.
401
+ if (member !== undefined) {
402
+ yield* runtime.link({
403
+ entity: AgentChat.name,
404
+ relationship: "members",
405
+ id: String(chat.id),
406
+ targetId: memberId,
407
+ });
408
+ }
409
+ }
410
+ if (leftMemberId !== undefined && isRecordId(leftMemberId)) {
411
+ const [user] = yield* rows(`SELECT 1 FROM ${USERS} WHERE "id" = $1::uuid`, [
412
+ leftMemberId,
413
+ ]);
414
+ // Whatever their state now; a member who is not linked changes nothing and records no
415
+ // history.
416
+ if (user !== undefined) {
417
+ yield* runtime.unlink({
418
+ entity: AgentChat.name,
419
+ relationship: "members",
420
+ id: String(chat.id),
421
+ targetId: leftMemberId,
422
+ });
423
+ }
424
+ }
425
+ if (agentLeft === true) {
426
+ // The agent left: no member is in the chat with it any more. The chat stays; members
427
+ // link again when they write after the agent is back.
428
+ yield* releaseMembers(String(chat.id));
429
+ }
430
+ return {
431
+ id: String(chat.id),
432
+ title: String(chat.title),
433
+ purpose: nullableText(chat.purpose),
434
+ whenToUse: nullableText(chat.when_to_use),
435
+ };
436
+ }))
437
+ .pipe(Effect.orDie),
438
+ };
439
+ return store;
440
+ }
441
+ /** Shared verified admission for agents and channel-app adapters; never expose trusted inputs to browsers. */
442
+ export function resolveChannelIdentity(ontology, sql, input) {
443
+ return sqlAgentStore(ontology, sql).resolveIdentity(input);
444
+ }
445
+ /** Call only after verifying a channel-app assertion. Shares admission, limits and onboarding with agents. */
446
+ export function resolveChannelSignIn(ontology, sql, input) {
447
+ const { provider, externalId, display, username } = input;
448
+ const identity = {
449
+ provider,
450
+ externalId,
451
+ chat: "private",
452
+ turn: false,
453
+ ...(display === undefined ? {} : { display }),
454
+ ...(username === undefined ? {} : { username }),
455
+ };
456
+ return resolveAgentIdentity(ontology, sql, sqlAgentStore(ontology, sql), identity, "channel_app");
457
+ }
@@ -0,0 +1,22 @@
1
+ import { Effect } from "effect";
2
+ import { type SqlError } from "effect/unstable/sql/SqlError";
3
+ import type { EntityModel } from "./model.js";
4
+ interface CauseDiagnostic {
5
+ readonly tag: string;
6
+ readonly message: string;
7
+ readonly messageRedacted: boolean;
8
+ readonly stack?: string;
9
+ }
10
+ /** A safe projection of every wrapper; the original driver cause stays on the Conflict itself. */
11
+ export declare function batchConflictDiagnostic(entity: EntityModel, error: SqlError): {
12
+ causeChain: CauseDiagnostic[];
13
+ constraint?: string | undefined;
14
+ sqlState: string;
15
+ };
16
+ /** Emit before mapping the error, so even a handler-caught conflict has a correlated diagnostic. */
17
+ export declare function logBatchConflict(entity: EntityModel, error: SqlError, scope: {
18
+ readonly operation: string;
19
+ readonly action: string;
20
+ readonly actionId: string;
21
+ }): Effect.Effect<void>;
22
+ export {};