@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,597 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { Cause, Data, Duration, Effect, Option, Schema } from "effect";
3
+ import { SqlClient } from "effect/unstable/sql";
4
+ import { isSqlError } from "effect/unstable/sql/SqlError";
5
+ import { ActionIdentity } from "../action.js";
6
+ import { ActionConfirmation } from "../confirmation.js";
7
+ import { ConnectionError, ConnectionTransport, connectionContext } from "../connection.js";
8
+ import { Files } from "../files.js";
9
+ import { FileAccess, unavailableFiles } from "../storage/file-access.js";
10
+ import { Conflict, PermissionDenied, } from "../errors.js";
11
+ import { canonicalJson } from "../manifest.js";
12
+ import { CHANNEL_USERS_TABLE, USER_TABLE } from "../migrate/storage.js";
13
+ import { CHANNEL_IDENTITIES_FROM, LIVE_CHANNEL_IDENTITY, SIGN_IN_ORIGIN_SQL, USER_IDENTITY_TABLE, } from "./user-identity-sql.js";
14
+ import { ATTACHMENTS_TABLE } from "../storage/tables.js";
15
+ import { beginReplicationWrite } from "../replication/transaction.js";
16
+ import { RuntimeDeployment } from "./deployment.js";
17
+ import { requireDeploymentCapability } from "../deployment.js";
18
+ import { authorizeBlobOperation } from "../storage/authorization.js";
19
+ import { effectiveScope, generatedActionPermissions, missingPermission, parsePermission, } from "../permissions.js";
20
+ import { OntologyReads, OntologyRuntime } from "../runtime.js";
21
+ import { UnknownAction, ValidationIssue, WorkflowRecoveryUnavailable, } from "./errors.js";
22
+ import { generatedActions, writesOnlyThroughActions } from "./generated-actions.js";
23
+ import { Edit } from "./history.js";
24
+ import { canonicalInstant, isRecordId } from "./records.js";
25
+ import { makeOntologyRuntime } from "./sql-runtime.js";
26
+ import { AgentFileRecords, resolveFileRecord } from "./files.js";
27
+ import { validate } from "./validation.js";
28
+ import { evaluateTriggers, insertStarts, matchingTriggers, startCommitted, WorkflowStarter, } from "./workflow-starts.js";
29
+ import { sendQueuedSignInEmails, SignInLinks } from "./sign-in-links.js";
30
+ import { ACTION_TRANSACTION_LIMITS, ActionTransactions } from "./action-transactions.js";
31
+ import { actionTransaction } from "./action-deadlocks.js";
32
+ /** Keep every primary, cleanup and interruption reason when hiding SQL failures from callers. */
33
+ const sqlFailuresAsDefects = (effect) => effect.pipe(Effect.catchCause((cause) => Effect.failCause(Cause.fromReasons(cause.reasons.map((reason) => reason._tag === "Fail" && isSqlError(reason.error)
34
+ ? Cause.makeDieReason(reason.error)
35
+ : reason)))));
36
+ /** How long an action's `confirm` may take: a person waits for the card it describes. */
37
+ export const CONFIRM_TIMEOUT = Duration.seconds(15);
38
+ /** How long `prepare` may take, connection calls included; each call has its own 30 s deadline. */
39
+ export const PREPARE_TIMEOUT = Duration.seconds(60);
40
+ export const ActionValidation = Schema.Struct({
41
+ ok: Schema.Boolean,
42
+ issues: Schema.Array(ValidationIssue),
43
+ });
44
+ /** The response of an action: its result, the input's validation, and the records it changed. */
45
+ export const ActionOutcome = Schema.Struct({
46
+ result: Schema.Json,
47
+ validation: ActionValidation,
48
+ edits: Schema.Array(Edit),
49
+ });
50
+ const VALID = { ok: true, issues: [] };
51
+ /** Rolls back the transaction of a write that ran only to be validated. */
52
+ class ValidationRollback extends Data.TaggedError("ValidationRollback") {
53
+ }
54
+ /**
55
+ * A validated write's NotFound or ScopeViolated as a validation issue. A record that was not found
56
+ * is at the input key that holds its id; a scope the change would leave is at the input's root.
57
+ */
58
+ function writeIssue(input, error) {
59
+ const key = error._tag === "NotFound" && typeof input === "object" && input !== null
60
+ ? Object.entries(input).find(([, value]) => value === error.id)?.[0]
61
+ : undefined;
62
+ return { path: key === undefined ? [] : [key], message: error.message };
63
+ }
64
+ /**
65
+ * The entity's authored action of that name with the permission it requires, or else its generated
66
+ * one with the permissions named after it.
67
+ */
68
+ export function resolveAction(ontology, entityName, actionName) {
69
+ const entity = ontology.entities.find((candidate) => candidate.name === entityName);
70
+ if (entity === undefined) {
71
+ return undefined;
72
+ }
73
+ const authored = entity.actions.find((candidate) => candidate.name === actionName);
74
+ if (authored !== undefined) {
75
+ return { action: authored.action, permissions: [authored.permission], generated: false };
76
+ }
77
+ const generated = generatedActions(ontology, entityName)[actionName];
78
+ return generated === undefined
79
+ ? undefined
80
+ : {
81
+ action: generated,
82
+ permissions: generatedActionPermissions(entityName, actionName),
83
+ generated: true,
84
+ };
85
+ }
86
+ /**
87
+ * The scopes the principal's grants put on an action's writes of its own entity. An authored action
88
+ * checks every write of its entity against the scope of its permission. A generated action checks
89
+ * records it creates against `<entity>:create` and records it changes against the permission of its
90
+ * verb; `upsert_by_<property>` checks against `create` or `update`, whichever it does. `undefined`
91
+ * when every permission is held unscoped, so that unscoped principals write as before.
92
+ */
93
+ export function writeGuard(entity, found, principal) {
94
+ const check = (permission) => {
95
+ const where = effectiveScope(permission, principal);
96
+ return where === undefined ? undefined : { permission, scope: { reader: principal, where } };
97
+ };
98
+ let create;
99
+ let change;
100
+ if (principal.scopes === undefined || principal.scopes.length === 0) {
101
+ return undefined;
102
+ }
103
+ for (const permission of found.permissions) {
104
+ const scoped = check(permission);
105
+ if (!found.generated) {
106
+ create = scoped;
107
+ change = scoped;
108
+ }
109
+ else if (parsePermission(permission)?.verb === "create") {
110
+ create = scoped;
111
+ }
112
+ else {
113
+ change = scoped;
114
+ }
115
+ }
116
+ return create === undefined && change === undefined
117
+ ? undefined
118
+ : {
119
+ entity,
120
+ ...(create === undefined ? {} : { create }),
121
+ ...(change === undefined ? {} : { change }),
122
+ };
123
+ }
124
+ /** The entity's authored action of that name, or else its generated one. */
125
+ export function findAction(ontology, entityName, actionName) {
126
+ return resolveAction(ontology, entityName, actionName)?.action;
127
+ }
128
+ /** A transport for a service that has none: every call is refused as a platform fault. */
129
+ const NO_CONNECTIONS = {
130
+ request: (call) => Effect.fail(new ConnectionError({
131
+ connection: call.connection,
132
+ reason: "not_granted",
133
+ message: "This ontology service has no connection transport.",
134
+ retryable: false,
135
+ })),
136
+ };
137
+ /**
138
+ * Runs an action the way every action runs, authored or generated:
139
+ *
140
+ * 1. decode the input with the action's schema; issues are returned, not raised;
141
+ * 2. check that the principal's permissions cover the action's (PermissionDenied);
142
+ * 3. with `validateOnly`, stop, unless the action is generated, the principal's permission for it is
143
+ * scoped and the input holds no upload: then run step 6 in a transaction that is
144
+ * always rolled back, and answer a NotFound or ScopeViolated of the writes as a validation issue;
145
+ * 4. reauthorize and replay a committed blob action, if its idempotency key matches;
146
+ * otherwise run `prepare`, when the action has one, without a transaction: reads and the declared
147
+ * connections only, under {@link PREPARE_TIMEOUT};
148
+ * 5. without a handler, answer with what `prepare` returned; when a trigger matches the action, make
149
+ * sure through the {@link WorkflowStarter} in context that a recovery run will sweep after the
150
+ * transaction's deadline, and refuse the action with WorkflowRecoveryUnavailable when it cannot;
151
+ * 6. open a transaction and run the handler with what `prepare` returned and the runtime, which
152
+ * records history rows for every write, under one action id, with `created_by`/`updated_by` set to
153
+ * the principal;
154
+ * 7. evaluate the action triggers that match the action, and insert the starts they decide, in the
155
+ * same transaction: a trigger function that throws rolls the action back, an input its workflow
156
+ * does not accept fails it with TriggerInputInvalid;
157
+ * 8. commit, or roll back on any failure, defect or interruption; an action explicitly declared
158
+ * retryOnDeadlock may repeat steps 6–8 after a confirmed deadlock rollback, with fresh state;
159
+ * 9. start the decided runs through the {@link WorkflowStarter} in context, then run the
160
+ * after-commit effects, outside the transaction.
161
+ *
162
+ * Database failures are defects.
163
+ */
164
+ export function runAction(ontology, request) {
165
+ return Effect.gen(function* () {
166
+ const sql = yield* SqlClient.SqlClient;
167
+ const deployment = Option.getOrUndefined(yield* Effect.serviceOption(RuntimeDeployment));
168
+ if (deployment) {
169
+ yield* Effect.sync(() => requireDeploymentCapability(deployment));
170
+ }
171
+ const qualified = `${request.entity}.${request.action}`;
172
+ const found = resolveAction(ontology, request.entity, request.action);
173
+ if (found === undefined) {
174
+ return yield* new UnknownAction({
175
+ entity: request.entity,
176
+ action: request.action,
177
+ message: writesOnlyThroughActions(ontology, request.entity, request.action) ??
178
+ `${qualified} is not an action of this ontology.`,
179
+ });
180
+ }
181
+ const { action } = found;
182
+ // An authored action that declares the entities it writes may write only those.
183
+ const declaredTargets = found.generated
184
+ ? undefined
185
+ : ontology.manifest.entities
186
+ .find((candidate) => candidate.name === request.entity)
187
+ ?.actions.find((candidate) => candidate.name === request.action)?.writes;
188
+ const declaredWrites = declaredTargets === undefined ? undefined : new Set(declaredTargets);
189
+ if (deployment?.target === "preview" && action.connections.length > 0) {
190
+ yield* Effect.sync(() => requireDeploymentCapability(deployment, "connections"));
191
+ }
192
+ const newUserHook = request.options?.newUserHook === true;
193
+ if (newUserHook &&
194
+ (ontology.signIn.onNewUser !== `${request.entity}:${request.action}` ||
195
+ action.prepare !== undefined ||
196
+ action.connections.length > 0 ||
197
+ action.hints?.idempotent !== true ||
198
+ (request.afterCommit?.length ?? 0) > 0)) {
199
+ return yield* Effect.die(new Error("Invalid onNewUser action."));
200
+ }
201
+ const decoded = validate(action.input, request.input);
202
+ if (!decoded.ok) {
203
+ return { result: null, validation: { ok: false, issues: decoded.issues }, edits: [] };
204
+ }
205
+ const missing = missingPermission(found.permissions, request.principal);
206
+ if (missing !== undefined) {
207
+ return yield* new PermissionDenied({
208
+ permission: missing,
209
+ message: `${qualified} requires ${missing}, which the principal's roles do not grant.`,
210
+ });
211
+ }
212
+ const confirming = request.options?.confirm;
213
+ // A principal whose permission for the action is scoped may not read what `confirm` reads
214
+ // about a record outside the scope: it gets the action's fields, read as it may read them.
215
+ if (confirming !== undefined) {
216
+ return {
217
+ result: action.confirm === undefined ||
218
+ writeGuard(request.entity, found, request.principal) !== undefined
219
+ ? null
220
+ : yield* confirmation(ontology, sql, action, qualified, {
221
+ input: decoded.value,
222
+ principal: request.principal,
223
+ locale: confirming.locale,
224
+ requestId: request.requestId ?? randomUUID(),
225
+ }),
226
+ validation: VALID,
227
+ edits: [],
228
+ };
229
+ }
230
+ const hasUploads = (value) => typeof value === "object" &&
231
+ value !== null &&
232
+ ("uploadId" in value || Object.values(value).some(hasUploads));
233
+ // The tickets the caller handed this action, which it settles when it commits.
234
+ const suppliedUploads = (value, found = new Set()) => {
235
+ if (typeof value === "object" && value !== null) {
236
+ const uploadId = "uploadId" in value ? value.uploadId : undefined;
237
+ if (typeof uploadId === "string" && isRecordId(uploadId)) {
238
+ found.add(uploadId.toLowerCase());
239
+ }
240
+ for (const item of Object.values(value)) {
241
+ suppliedUploads(item, found);
242
+ }
243
+ }
244
+ return found;
245
+ };
246
+ const key = request.options?.idempotencyKey;
247
+ // A UUID in either case names one record; the uuid column answers in lower case.
248
+ const createIntent = request.options?.createIntent?.toLowerCase();
249
+ const hasBlobProperties = ontology.manifest.entities.some((entity) => entity.properties.some((property) => property.type === "blob"));
250
+ const consumesUpload = action.transactional &&
251
+ hasBlobProperties &&
252
+ (hasUploads(decoded.value) || key !== undefined || (action.files?.length ?? 0) > 0);
253
+ const guard = writeGuard(request.entity, found, request.principal);
254
+ // A scoped generated write is validated by running it and rolling it back: its scope checks
255
+ // need the record as the write would leave it. Authored handlers run only when executed.
256
+ const validateOnly = request.options?.validateOnly === true;
257
+ if (validateOnly && (guard === undefined || !found.generated || consumesUpload)) {
258
+ return { result: null, validation: VALID, edits: [] };
259
+ }
260
+ // Inside a caller's transaction, the commit would come after the after-commit effects, and
261
+ // `prepare` would hold the caller's locks while it waits for a provider.
262
+ if (Option.isSome(yield* Effect.serviceOption(sql.transactionService))) {
263
+ return yield* Effect.die(new Error(`${qualified} must run outside any transaction.`));
264
+ }
265
+ const actionId = randomUUID();
266
+ const requestId = request.requestId ?? actionId;
267
+ const context = {
268
+ input: decoded.value,
269
+ principal: request.principal,
270
+ requestId,
271
+ ...(request.runtime === undefined ? {} : { runtime: request.runtime }),
272
+ };
273
+ if (consumesUpload && (!key || key.length > 128 || !request.branchId)) {
274
+ return yield* new Conflict({
275
+ entity: request.entity,
276
+ message: "Upload actions require an idempotency key.",
277
+ });
278
+ }
279
+ const fingerprint = consumesUpload
280
+ ? createHash("sha256")
281
+ .update(canonicalJson({
282
+ qualified,
283
+ manifestHash: ontology.manifest.hash,
284
+ branchId: request.branchId ?? null,
285
+ input: request.input,
286
+ createIntent: createIntent ?? null,
287
+ }))
288
+ .digest("hex")
289
+ : undefined;
290
+ // A committed retry must not depend on preparation's external services being available.
291
+ // The handler transaction below still locks and rechecks the key for concurrent requests.
292
+ if (consumesUpload) {
293
+ const saved = yield* sql
294
+ .withTransaction(Effect.gen(function* () {
295
+ yield* authorizeBlobOperation(ontology, sql, request.principal.id, found.permissions, request.principal.execution, request.principal.workflow);
296
+ const [saved] = yield* sql.unsafe(`SELECT fingerprint, outcome FROM "_blob_action_results"
297
+ WHERE principal_id = $1::uuid AND key = $2`, [request.principal.id, key]);
298
+ if (saved && saved.fingerprint !== fingerprint) {
299
+ return yield* new Conflict({
300
+ entity: request.entity,
301
+ message: "Idempotency key was used for another action.",
302
+ });
303
+ }
304
+ return saved?.outcome;
305
+ }))
306
+ .pipe(sqlFailuresAsDefects);
307
+ if (saved) {
308
+ return saved;
309
+ }
310
+ }
311
+ const prepared = action.prepare === undefined
312
+ ? undefined
313
+ : yield* prepare(ontology, sql, action, context, request.connections, qualified, {
314
+ principal: request.principal,
315
+ action: qualified,
316
+ idempotencyKey: key,
317
+ createIntent,
318
+ });
319
+ if (!action.transactional) {
320
+ return { result: prepared ?? null, validation: VALID, edits: [] };
321
+ }
322
+ const admission = Option.getOrUndefined(yield* Effect.serviceOption(ActionTransactions));
323
+ const configuredLimits = admission?.limits ?? ACTION_TRANSACTION_LIMITS;
324
+ const limits = newUserHook
325
+ ? {
326
+ handlerTimeoutMs: Math.min(5_000, configuredLimits.handlerTimeoutMs),
327
+ statementTimeoutMs: Math.min(5_000, configuredLimits.statementTimeoutMs),
328
+ lockTimeoutMs: Math.min(5_000, configuredLimits.lockTimeoutMs),
329
+ }
330
+ : configuredLimits;
331
+ // Triggers are definitions; all mutable runtime and trigger state belongs to one attempt.
332
+ const triggers = matchingTriggers(ontology, request.entity, request.action, request.principal);
333
+ const starter = Option.getOrUndefined(yield* Effect.serviceOption(WorkflowStarter));
334
+ // Before the transaction: whatever it commits must be swept if this request does not start it.
335
+ if (triggers.length > 0 && !validateOnly && starter !== undefined) {
336
+ yield* starter.ensureRecovery({ commitBy: Date.now() + limits.handlerTimeoutMs }).pipe(Effect.mapError((error) => new WorkflowRecoveryUnavailable({
337
+ message: `${qualified} was not run: ${error.message}`,
338
+ cause: error,
339
+ })));
340
+ }
341
+ const transaction = actionTransaction(sql, () => {
342
+ const edits = [];
343
+ const held = new Map();
344
+ let starts = [];
345
+ const signInEmails = [];
346
+ const runtime = makeOntologyRuntime(ontology, sql, {
347
+ action: qualified,
348
+ actionId,
349
+ principalId: request.principal.id,
350
+ ...(request.principal.execution ? { execution: request.principal.execution } : {}),
351
+ ...(request.principal.workflow ? { workflow: request.principal.workflow } : {}),
352
+ ...(key ? { blobActionKey: key } : {}),
353
+ ...(request.branchId ? { branchId: request.branchId } : {}),
354
+ ...(createIntent ? { createIntent } : {}),
355
+ ...(declaredWrites ? { declaredWrites } : {}),
356
+ onEdit: (edit) => edits.push(edit),
357
+ onSignInEmail: (email) => signInEmails.push(email),
358
+ ...(triggers.length > 0
359
+ ? {
360
+ onSnapshot: (snapshot) => {
361
+ if (snapshot.entity !== request.entity) {
362
+ return;
363
+ }
364
+ const previous = held.get(snapshot.id);
365
+ held.set(snapshot.id, {
366
+ before: previous === undefined ? snapshot.before : previous.before,
367
+ after: snapshot.after,
368
+ });
369
+ },
370
+ }
371
+ : {}),
372
+ replicationInitialized: true,
373
+ ...(newUserHook ? { protectPrincipals: true } : {}),
374
+ ...(guard === undefined ? {} : { guard }),
375
+ });
376
+ const handle = action.handler;
377
+ const handler = Effect.gen(function* () {
378
+ const identities = isRecordId(context.principal.id)
379
+ ? yield* sql
380
+ .unsafe(`SELECT "i"."provider", "i"."subject", true AS "verified", "i"."username" ` +
381
+ `FROM ${CHANNEL_IDENTITIES_FROM} ` +
382
+ `WHERE "i"."user_id" = $1::uuid AND ${LIVE_CHANNEL_IDENTITY}`, [context.principal.id])
383
+ .pipe(Effect.map((found) => Schema.decodeUnknownSync(Schema.Array(ActionIdentity))(found.map(({ username, ...identity }) => ({
384
+ ...identity,
385
+ ...(username === null ? {} : { username }),
386
+ })))))
387
+ : [];
388
+ const [provenance] = isRecordId(context.principal.id)
389
+ ? yield* sql.unsafe(`SELECT COALESCE(c."created_via", CASE
390
+ WHEN u."kind"::text = 'service' THEN 'service'
391
+ WHEN NOT EXISTS (SELECT 1 FROM "${USER_IDENTITY_TABLE}" i WHERE i."user_id" = u."id"
392
+ AND i."origin"::text IN ${SIGN_IN_ORIGIN_SQL} AND i."revoked_at" IS NULL) OR EXISTS (
393
+ SELECT 1 FROM "user_history" h WHERE h."record_id" = u."id"
394
+ AND h."action" = 'user.invite' AND h."kind"::text = 'create'
395
+ ) THEN 'invite' ELSE 'email' END) AS "created_via"
396
+ FROM "${USER_TABLE}" u
397
+ LEFT JOIN "${CHANNEL_USERS_TABLE}" c ON c."user_id" = u."id"
398
+ WHERE u."id" = $1::uuid`, [context.principal.id])
399
+ : [];
400
+ return yield* handle({
401
+ ...context,
402
+ principal: {
403
+ ...context.principal,
404
+ identities,
405
+ createdVia: provenance?.created_via ?? "unknown",
406
+ authenticatedVia: context.principal.authenticatedVia ?? "unknown",
407
+ },
408
+ prepared,
409
+ });
410
+ });
411
+ let replay;
412
+ const transactionalHandler = Effect.gen(function* () {
413
+ if (newUserHook) {
414
+ // Administrative mutations lock User first too. Keep this order before the lifecycle row
415
+ // so handler writes that reference the user cannot deadlock with blocking/deactivation.
416
+ yield* sql.unsafe(`SELECT "id" FROM "${USER_TABLE}" WHERE "id" = $1::uuid FOR UPDATE`, [
417
+ request.principal.id,
418
+ ]);
419
+ const [pending] = yield* sql.unsafe(`SELECT 1 FROM "${CHANNEL_USERS_TABLE}" c JOIN "${USER_TABLE}" u ON u."id" = c."user_id"
420
+ WHERE c."user_id" = $1::uuid AND c."created_via" NOT IN ('invite', 'email')
421
+ AND c."blocked_at" IS NULL AND c."on_new_user_completed_at" IS NULL AND u."active" FOR UPDATE OF c`, [request.principal.id]);
422
+ if (pending === undefined) {
423
+ return null;
424
+ }
425
+ }
426
+ // Workloads and workflow users are re-checked against the database in the transaction.
427
+ if (request.principal.execution !== undefined ||
428
+ request.principal.workflow !== undefined) {
429
+ yield* authorizeBlobOperation(ontology, sql, request.principal.id, found.permissions, request.principal.execution, request.principal.workflow);
430
+ }
431
+ if (consumesUpload) {
432
+ yield* authorizeBlobOperation(ontology, sql, request.principal.id, found.permissions, request.principal.execution, request.principal.workflow);
433
+ yield* sql.unsafe(`INSERT INTO "_blob_action_results" (principal_id, key, fingerprint)
434
+ VALUES ($1::uuid, $2, $3) ON CONFLICT DO NOTHING`, [request.principal.id, key, fingerprint]);
435
+ const [saved] = yield* sql.unsafe(`SELECT fingerprint, outcome FROM "_blob_action_results" WHERE principal_id = $1::uuid AND key = $2
436
+ FOR UPDATE`, [request.principal.id, key]);
437
+ if (saved.fingerprint !== fingerprint) {
438
+ return yield* new Conflict({
439
+ entity: request.entity,
440
+ message: "Idempotency key was used for another action.",
441
+ });
442
+ }
443
+ if (saved.outcome) {
444
+ replay = saved.outcome;
445
+ return replay.result;
446
+ }
447
+ }
448
+ const result = yield* handler.pipe(OntologyRuntime.provide(runtime));
449
+ if (validateOnly) {
450
+ return yield* new ValidationRollback();
451
+ }
452
+ if (triggers.length > 0 && edits.some((edit) => edit.entity === request.entity)) {
453
+ const [now] = yield* sql.unsafe(`SELECT to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"') AS "at"`);
454
+ starts = yield* evaluateTriggers(triggers, {
455
+ ontology,
456
+ entity: request.entity,
457
+ action: request.action,
458
+ definition: action,
459
+ generated: found.generated,
460
+ actionId,
461
+ at: canonicalInstant(now.at),
462
+ principal: request.principal,
463
+ input: decoded.value,
464
+ result,
465
+ edits,
466
+ held,
467
+ load: (id) => runtime.get({ entity: request.entity, id }).pipe(Effect.map((record) => record), Effect.catchTag("NotFound", () => Effect.succeed(undefined))),
468
+ });
469
+ yield* insertStarts(sql, starts);
470
+ }
471
+ if (newUserHook) {
472
+ yield* sql.unsafe(`UPDATE "${CHANNEL_USERS_TABLE}" SET "on_new_user_completed_at" = now() WHERE "user_id" = $1::uuid`, [request.principal.id]);
473
+ }
474
+ if (consumesUpload) {
475
+ // A ticket this action was given and did not store, such as a file it found already
476
+ // kept, is released with the commit: it stops counting towards the caller's open
477
+ // uploads, and storage maintenance removes its bytes. A rejected action rolls this
478
+ // back and leaves the ticket for a retry; a retry of this committed action replays
479
+ // its saved outcome. Promoted chat attachments keep their file and their upload.
480
+ for (const uploadId of suppliedUploads(decoded.value)) {
481
+ yield* sql.unsafe(`UPDATE "_blob_uploads" u SET state = 'canceled', expires_at = now(),
482
+ claim = NULL, claimed_at = NULL
483
+ WHERE u.id = $1::uuid AND u.principal_id = $2::uuid AND u.action = $3
484
+ AND u.state = 'ready'
485
+ AND NOT EXISTS (SELECT 1 FROM "${ATTACHMENTS_TABLE}" a WHERE a.blob_id = u.blob_id)`, [uploadId, request.principal.id, qualified]);
486
+ }
487
+ yield* sql.unsafe(`UPDATE "_blob_action_results" SET outcome = $1::jsonb
488
+ WHERE principal_id = $2::uuid AND key = $3`, [
489
+ JSON.stringify({ result: result ?? null, validation: VALID, edits }),
490
+ request.principal.id,
491
+ key,
492
+ ]);
493
+ }
494
+ return result;
495
+ });
496
+ const transactionBody = Effect.gen(function* () {
497
+ // Server deadlines also protect the reserved connection if client cancellation cannot arrive.
498
+ yield* sql.unsafe(`SELECT set_config('statement_timeout', $1, true), set_config('lock_timeout', $2, true)`, [`${limits.statementTimeoutMs}ms`, `${limits.lockTimeoutMs}ms`]);
499
+ yield* beginReplicationWrite(sql);
500
+ return yield* transactionalHandler;
501
+ });
502
+ return transactionBody.pipe(Effect.map((result) => ({ result, edits, starts, signInEmails, replay })));
503
+ }, {
504
+ qualified,
505
+ actionId,
506
+ requestId,
507
+ retryOnDeadlock: action.retryOnDeadlock === true,
508
+ // A resent request runs prepare again; only without connections does that repeat nothing.
509
+ conflictRetryable: action.connections.length === 0,
510
+ handlerTimeoutMs: limits.handlerTimeoutMs,
511
+ });
512
+ const settled = (admission ? admission.admit(transaction) : transaction).pipe(Effect.annotateLogs({ action: qualified, actionId, requestId }), sqlFailuresAsDefects);
513
+ if (validateOnly) {
514
+ return yield* settled.pipe(Effect.as(VALID), Effect.catchTag("ValidationRollback", () => Effect.succeed(VALID)), Effect.catchTag(["NotFound", "ScopeViolated"], (error) => Effect.succeed({ ok: false, issues: [writeIssue(request.input, error)] })), Effect.map((validation) => ({ result: null, validation, edits: [] })));
515
+ }
516
+ const { result, edits, starts, signInEmails, replay } = yield* settled.pipe(Effect.catchTag("ValidationRollback", (rollback) => Effect.die(rollback)));
517
+ if (replay) {
518
+ return replay;
519
+ }
520
+ // The decided runs start before the after-commit effects; a failure leaves them pending for the
521
+ // recovery run armed above.
522
+ yield* startCommitted(sql, starter, starts, requestId);
523
+ yield* sendQueuedSignInEmails(sql, Option.getOrUndefined(yield* Effect.serviceOption(SignInLinks)), signInEmails, requestId);
524
+ const committed = {
525
+ entity: request.entity,
526
+ action: request.action,
527
+ actionId,
528
+ principal: request.principal,
529
+ input: decoded.value,
530
+ result,
531
+ edits,
532
+ };
533
+ for (const afterCommit of request.afterCommit ?? []) {
534
+ yield* Effect.suspend(() => afterCommit(committed)).pipe(Effect.catchCause((cause) => Effect.logWarning("An after-commit effect failed; the action had committed.", Cause.pretty(cause)).pipe(Effect.annotateLogs({
535
+ operation: "ontology.after_commit",
536
+ action: qualified,
537
+ actionId,
538
+ }))));
539
+ }
540
+ return { result: result ?? null, validation: VALID, edits };
541
+ });
542
+ }
543
+ /**
544
+ * Runs an action's `confirm` outside any transaction, with reads only, and checks what it describes.
545
+ * A confirmation the schema refuses is the action's defect, as a handler's would be.
546
+ */
547
+ function confirmation(ontology, sql, action, qualified, context) {
548
+ const runtime = makeOntologyRuntime(ontology, sql);
549
+ const reads = {
550
+ get: ({ entity, id }) => runtime.get({ entity, id }),
551
+ find: ({ entity, options }) => runtime.find({ entity, options: { ...options, forUpdate: false } }),
552
+ queryMetrics: (input) => runtime.queryMetrics(input),
553
+ };
554
+ return Effect.suspend(() => action.confirm(context)).pipe(Effect.provideService(OntologyReads, reads), Effect.timeoutOrElse({
555
+ duration: CONFIRM_TIMEOUT,
556
+ orElse: () => Effect.die(new Error(`${qualified} confirm exceeded its ${Duration.format(CONFIRM_TIMEOUT)} deadline.`)),
557
+ }), Effect.flatMap((described) => Schema.decodeUnknownEffect(ActionConfirmation)(described, {
558
+ onExcessProperty: "error",
559
+ }).pipe(Effect.mapError((issue) => new Error(`${qualified} confirm described an invalid confirmation: ${issue}`)), Effect.orDie)), sqlFailuresAsDefects);
560
+ }
561
+ /**
562
+ * Runs `prepare` outside any transaction, with reads, declared connections and file access.
563
+ * Reads take no locks here: `forUpdate` is dropped, since a lock
564
+ * outside a transaction would be released at once.
565
+ */
566
+ function prepare(ontology, sql, action, context, connections, qualified, fileInvocation) {
567
+ return Effect.gen(function* () {
568
+ const transport = connections ?? Option.getOrUndefined(yield* Effect.serviceOption(ConnectionTransport));
569
+ const fileAccess = Option.getOrUndefined(yield* Effect.serviceOption(FileAccess));
570
+ const files = fileAccess?.forInvocation(fileInvocation) ?? unavailableFiles;
571
+ const runtime = makeOntologyRuntime(ontology, sql);
572
+ const reads = {
573
+ get: ({ entity, id }) => runtime.get({ entity, id }),
574
+ find: ({ entity, options }) => runtime.find({ entity, options: { ...options, forUpdate: false } }),
575
+ queryMetrics: (input) => runtime.queryMetrics(input),
576
+ };
577
+ const run = Effect.suspend(() => action.prepare(context));
578
+ return yield* run.pipe(Effect.provideService(OntologyReads, reads), Effect.provideService(Files, action.hints?.readOnly === true
579
+ ? {
580
+ ...files,
581
+ stage: () => Effect.fail(new Conflict({ entity: "upload", message: "file_write_not_permitted" })),
582
+ }
583
+ : files), Effect.provideService(AgentFileRecords, {
584
+ resolve: (reference, principal) => resolveFileRecord({ manifest: ontology.manifest, reads, reference, principal }),
585
+ }), Effect.provideContext(connectionContext(action.connections, transport ?? NO_CONNECTIONS, {
586
+ readOnly: action.hints?.readOnly === true || action.hints?.connectionsReadOnly === true,
587
+ })), Effect.timeoutOrElse({
588
+ duration: PREPARE_TIMEOUT,
589
+ orElse: () => Effect.fail(new ConnectionError({
590
+ connection: action.connections.map((handle) => handle.key).join(","),
591
+ reason: "timeout",
592
+ message: `${qualified} prepare exceeded its ${Duration.format(PREPARE_TIMEOUT)} deadline.`,
593
+ retryable: true,
594
+ })),
595
+ }), sqlFailuresAsDefects);
596
+ });
597
+ }
@@ -0,0 +1,10 @@
1
+ import { Redacted } from "effect";
2
+ /**
3
+ * The TLS options for a connection string. A Neon endpoint routes by TLS server name and the
4
+ * pinned driver does not send one on its own, so the service and the migrate command would fail
5
+ * to connect without it. Other hosts keep the driver's defaults.
6
+ */
7
+ export declare function postgresTls(connection: Redacted.Redacted<string>): {
8
+ readonly servername: string;
9
+ readonly rejectUnauthorized: true;
10
+ } | undefined;
@@ -0,0 +1,14 @@
1
+ import { Redacted } from "effect";
2
+ /**
3
+ * The TLS options for a connection string. A Neon endpoint routes by TLS server name and the
4
+ * pinned driver does not send one on its own, so the service and the migrate command would fail
5
+ * to connect without it. Other hosts keep the driver's defaults.
6
+ */
7
+ export function postgresTls(connection) {
8
+ const value = Redacted.value(connection);
9
+ const hostname = URL.canParse(value) ? new URL(value).hostname : "";
10
+ if (!hostname.endsWith(".neon.tech")) {
11
+ return undefined;
12
+ }
13
+ return { servername: hostname, rejectUnauthorized: true };
14
+ }