@segmentstream/ontology 0.0.0-stage → 0.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,614 @@
1
+ import { replicationIdentities } from "./identities.js";
2
+ import { queryFields } from "../query.js";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { Effect } from "effect";
5
+ import { canonicalJson } from "../manifest.js";
6
+ import { ReplicationBaselineFailed } from "./baseline.js";
7
+ import { initialReplicationLineage, renamedReplicationField } from "./lineage.js";
8
+ import { replicationScanScopes, scheduleReplicationScans, } from "./scans.js";
9
+ import { lockReplicationLifecycle } from "./transaction.js";
10
+ export const SHADOW_HANDOFF_MS = 30_000;
11
+ export const SHADOW_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
12
+ export const SHADOW_QUERY_LIFETIME_MS = 60 * 60 * 1000;
13
+ const shadowJson = (value) => JSON.stringify(value, (_key, item) => (typeof item === "bigint" ? item.toString() : item));
14
+ const epochFields = `id::text, source_id::text, desired_hash, target, routes, state,
15
+ predecessor::text, boundary::text, catchup_boundary::text, token::text, fence::text,
16
+ handoff_until::text, operation_id::text, installed, cancel_requested`;
17
+ const segmentFields = `id::text, epoch::text, generation::text, source_id::text,
18
+ through_revision::text, events, event_ids, digest, object_uri, job_id, attempt, state, retry_after::text`;
19
+ /** Names the target keys a stored route omits because its epoch target holds the same value. */
20
+ const SHARED_FROM_EPOCH = "shared_from_epoch";
21
+ /** SQL reads these keys from stored routes, for example retention checks on route generations. */
22
+ const STORED_ROUTE_KEYS = new Set(["generation", "source_id"]);
23
+ const sameSharedValue = (key, route, epoch) => {
24
+ if (route === undefined || epoch === undefined) {
25
+ return false;
26
+ }
27
+ if (route === epoch) {
28
+ return true;
29
+ }
30
+ if (key === "manifest") {
31
+ const routeHash = route?.hash;
32
+ return typeof routeHash === "string" && routeHash === epoch?.hash;
33
+ }
34
+ try {
35
+ return canonicalJson(route) === canonicalJson(epoch);
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ };
41
+ /**
42
+ * Every route carries a full target, and most routes repeat the epoch target's manifest and
43
+ * projection. One copy per scope grows with entities times manifest size, past what a single
44
+ * PostgreSQL message may carry, so a stored route names the keys it takes from its epoch target.
45
+ */
46
+ export function compactShadowRoutes(routes, target) {
47
+ const epoch = target;
48
+ return routes.map((route) => {
49
+ const record = route.target;
50
+ const shared = Object.keys(record).filter((key) => !STORED_ROUTE_KEYS.has(key) && sameSharedValue(key, record[key], epoch[key]));
51
+ if (shared.length === 0) {
52
+ return route;
53
+ }
54
+ const stored = { [SHARED_FROM_EPOCH]: shared };
55
+ for (const [key, value] of Object.entries(record)) {
56
+ if (!shared.includes(key)) {
57
+ stored[key] = value;
58
+ }
59
+ }
60
+ return { ...route, target: stored };
61
+ });
62
+ }
63
+ /** Restores the keys a stored route took from its epoch target. Full stored routes pass through. */
64
+ export function expandShadowRoutes(routes, target) {
65
+ const epoch = target;
66
+ return routes.map((stored) => {
67
+ const route = stored;
68
+ const record = route.target;
69
+ const shared = record[SHARED_FROM_EPOCH];
70
+ if (!Array.isArray(shared)) {
71
+ return route;
72
+ }
73
+ const expanded = {};
74
+ for (const key of shared) {
75
+ expanded[key] = epoch[key];
76
+ }
77
+ for (const [key, value] of Object.entries(record)) {
78
+ if (key !== SHARED_FROM_EPOCH) {
79
+ expanded[key] = value;
80
+ }
81
+ }
82
+ return { ...route, target: expanded };
83
+ });
84
+ }
85
+ const expandEpoch = (row) => row && { ...row, routes: expandShadowRoutes(row.routes, row.target) };
86
+ export const shadowEpoch = (sql, id) => sql
87
+ .unsafe(`SELECT ${epochFields} FROM _ontology_replication_epochs WHERE id=$1::uuid`, [id])
88
+ .pipe(Effect.map((rows) => expandEpoch(rows[0])));
89
+ export const servingShadowEpoch = (sql) => sql
90
+ .unsafe(`SELECT ${epochFields} FROM _ontology_replication_epochs
91
+ WHERE id=(SELECT serving_epoch FROM _ontology_replication WHERE id)`)
92
+ .pipe(Effect.map((rows) => expandEpoch(rows[0])));
93
+ export const candidateShadowEpoch = (sql) => sql
94
+ .unsafe(`SELECT ${epochFields} FROM _ontology_replication_epochs WHERE state='candidate'`)
95
+ .pipe(Effect.map((rows) => expandEpoch(rows[0])));
96
+ export const shadowProjectionHash = (target) => createHash("sha256")
97
+ .update(canonicalJson({
98
+ manifest: target.manifest.hash,
99
+ selection: target.selection,
100
+ fills: target.fills ?? {},
101
+ identities: replicationIdentities(target),
102
+ }))
103
+ .digest("hex");
104
+ /** Called under exclusive lifecycle admission; no provider I/O is permitted here. */
105
+ export const adoptShadowServing = (sql, target) => Effect.gen(function* () {
106
+ const existing = yield* servingShadowEpoch(sql);
107
+ if (existing) {
108
+ return existing;
109
+ }
110
+ target = { ...target, identities: replicationIdentities(target) };
111
+ const routes = replicationScanScopes(target).map((scope) => ({ ...scope, target }));
112
+ yield* sql.unsafe(`INSERT INTO _ontology_replication_epochs
113
+ (id,source_id,desired_hash,target,routes,state) VALUES ($1::uuid,$2::uuid,$3,$4::jsonb,$5::jsonb,'serving')
114
+ ON CONFLICT (id) DO UPDATE SET state='serving'`, [
115
+ target.generation,
116
+ target.source_id,
117
+ shadowProjectionHash(target),
118
+ shadowJson(target),
119
+ shadowJson(compactShadowRoutes(routes, target)),
120
+ ]);
121
+ yield* sql.unsafe(`UPDATE _ontology_replication SET serving_epoch=$1::uuid WHERE id`, [
122
+ target.generation,
123
+ ]);
124
+ yield* enableShadowCapture(sql, target, replicationScanScopes(target));
125
+ return (yield* shadowEpoch(sql, target.generation));
126
+ });
127
+ /** Capture bindings name wire fields, not public columns. Renames never rewrite historical JSON. */
128
+ export const enableShadowCapture = (sql, target, scopes) => sql
129
+ .unsafe(`UPDATE _ontology_replication_targets SET capturing=true,
130
+ identities=COALESCE(identities,$4::jsonb),
131
+ capture_scopes=$2::jsonb, capture_bindings=COALESCE(capture_bindings,$3::jsonb),
132
+ capture_versions=COALESCE(capture_versions,jsonb_build_array(jsonb_build_object('bindings',$3::jsonb)))
133
+ WHERE generation=$1::uuid`, [
134
+ target.generation,
135
+ JSON.stringify(scopes),
136
+ JSON.stringify(Object.fromEntries(target.selection.map((item) => [
137
+ item.entityId,
138
+ Object.fromEntries([...new Set(["id", ...item.fields])].map((field) => [field, field])),
139
+ ]))),
140
+ JSON.stringify(replicationIdentities(target)),
141
+ ])
142
+ .pipe(Effect.andThen(refreshShadowCapturePolicy(sql)));
143
+ /**
144
+ * Immutable epochs may share unaffected generations. Only complete affected entity scopes get a
145
+ * fresh incarnation. Generation-zero snapshots cannot overwrite mutations in another incarnation.
146
+ */
147
+ export const prepareShadowEpoch = (sql, input) => Effect.gen(function* () {
148
+ if (input.predecessor) {
149
+ const previous = input.predecessor;
150
+ yield* sql.unsafe(`INSERT INTO _ontology_replication_epochs
151
+ (id,source_id,desired_hash,target,routes,state)
152
+ VALUES ($1::uuid,$2::uuid,$3,$4::jsonb,$5::jsonb,'retired') ON CONFLICT DO NOTHING`, [
153
+ previous.id,
154
+ previous.source_id,
155
+ previous.desired_hash,
156
+ shadowJson(previous.target),
157
+ shadowJson(compactShadowRoutes(previous.routes, previous.target)),
158
+ ]);
159
+ }
160
+ const desiredHash = shadowProjectionHash(input.target);
161
+ const pending = yield* candidateShadowEpoch(sql);
162
+ if (!pending?.cancel_requested &&
163
+ pending?.desired_hash === desiredHash &&
164
+ pending.predecessor === (input.predecessor?.id ?? null) &&
165
+ (!input.force || pending.routes.every((route) => route.target.generation === pending.id))) {
166
+ const [capture] = yield* sql.unsafe("SELECT enabled FROM _ontology_replication WHERE id");
167
+ if (capture?.enabled) {
168
+ return pending;
169
+ }
170
+ // Pause interrupted capture admission. A fresh incarnation scans authoritative rows and
171
+ // fences late old loads; reusing this candidate would leave its source disabled forever.
172
+ }
173
+ // Supersession with an installed handoff must first reconcile its destination fence. A migration
174
+ // can commit desired metadata, but cannot make another candidate publication-eligible yet.
175
+ if (pending?.token) {
176
+ return yield* new ReplicationBaselineFailed({
177
+ message: "replication_publication_reconciliation_pending",
178
+ });
179
+ }
180
+ if (pending) {
181
+ yield* sql.unsafe(`UPDATE _ontology_replication_scans SET complete=true,required=false
182
+ WHERE generation=$1::uuid`, [pending.id]);
183
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET state='cancelled',owner=NULL,owner_until=NULL
184
+ WHERE id=$1::uuid`, [pending.id]);
185
+ }
186
+ const id = input.target.generation === input.predecessor?.id || input.target.generation === pending?.id
187
+ ? randomUUID()
188
+ : input.target.generation;
189
+ const target = {
190
+ ...input.target,
191
+ generation: id,
192
+ schema_version: 6,
193
+ identities: replicationIdentities(input.target),
194
+ protocol: 4,
195
+ baseline_complete: input.affected.length === 0,
196
+ scans_complete: input.affected.length === 0,
197
+ lineage: initialReplicationLineage(input.target),
198
+ };
199
+ yield* sql.unsafe(`INSERT INTO _ontology_replication_targets
200
+ (generation,source_id,from_revision,manifest,selection,protocol,baseline_complete,
201
+ scans_complete,lineage,fills,identities)
202
+ VALUES ($1::uuid,$2::uuid,0,$3::jsonb,$4::jsonb,4,$5,$5,$6::jsonb,$7::jsonb,$8::jsonb) ON CONFLICT DO NOTHING`, [
203
+ id,
204
+ target.source_id,
205
+ JSON.stringify(target.manifest),
206
+ JSON.stringify(target.selection),
207
+ input.affected.length === 0,
208
+ JSON.stringify(target.lineage),
209
+ JSON.stringify(target.fills ?? {}),
210
+ JSON.stringify(target.identities),
211
+ ]);
212
+ const affectedEntities = new Set(input.affected.map((scope) => scope.entityId));
213
+ const scopes = replicationScanScopes(target).filter((scope) => affectedEntities.has(scope.entityId));
214
+ const captures = yield* sql.unsafe("SELECT generation::text,capture_bindings FROM _ontology_replication_targets WHERE capturing");
215
+ const routes = replicationScanScopes(target).map((scope) => {
216
+ const old = input.predecessor?.routes.find((route) => route.entityId === scope.entityId && route.kind === scope.kind);
217
+ if (!old || affectedEntities.has(scope.entityId)) {
218
+ return { ...scope, target };
219
+ }
220
+ // Reuse retained events through a schema-aware projection, without changing old epoch metadata.
221
+ const projected = {
222
+ ...old.target,
223
+ manifest: target.manifest,
224
+ identities: target.identities,
225
+ selection: target.selection,
226
+ fills: target.fills,
227
+ };
228
+ const bindings = captures.find((capture) => capture.generation === old.target.generation)
229
+ ?.capture_bindings ?? {};
230
+ const previousLineage = old.target.lineage ?? initialReplicationLineage(old.target);
231
+ const last = previousLineage.epochs.at(-1);
232
+ const lineage = {
233
+ ...previousLineage,
234
+ epochs: previousLineage.epochs.map((epoch) => ({
235
+ ...epoch,
236
+ fields: Object.fromEntries(target.selection.map((selected) => [
237
+ selected.entityId,
238
+ Object.fromEntries([...new Set(["id", ...selected.fields])].map((field) => {
239
+ const slot = Object.entries(bindings[selected.entityId] ?? {}).find(([, current]) => current === field)?.[0];
240
+ const previousField = Object.entries(last.fields[selected.entityId] ?? {}).find(([, binding]) => binding.key === slot)?.[0];
241
+ const binding = previousField
242
+ ? epoch.fields[selected.entityId]?.[previousField]
243
+ : undefined;
244
+ const fills = target.fills?.[selected.entityId] ?? {};
245
+ return [
246
+ field,
247
+ binding ?? {
248
+ key: slot ?? null,
249
+ ...(Object.hasOwn(fills, field) ? { fill: fills[field] } : {}),
250
+ },
251
+ ];
252
+ })),
253
+ ])),
254
+ })),
255
+ };
256
+ return {
257
+ ...scope,
258
+ target: {
259
+ ...projected,
260
+ lineage: {
261
+ ...lineage,
262
+ epochs: lineage.epochs.map((epoch, index, epochs) => index === epochs.length - 1 ? { ...epoch, throughRevision: undefined } : epoch),
263
+ },
264
+ },
265
+ };
266
+ });
267
+ yield* sql.unsafe(`INSERT INTO _ontology_replication_epochs
268
+ (id,source_id,desired_hash,target,routes,state,predecessor)
269
+ VALUES ($1::uuid,$2::uuid,$3,$4::jsonb,$5::jsonb,'candidate',$6::uuid)`, [
270
+ id,
271
+ target.source_id,
272
+ desiredHash,
273
+ shadowJson(target),
274
+ shadowJson(compactShadowRoutes(routes, target)),
275
+ input.predecessor?.id ?? null,
276
+ ]);
277
+ yield* enableShadowCapture(sql, target, scopes);
278
+ yield* scheduleReplicationScans(sql, id, scopes, { initial: true });
279
+ yield* sql.unsafe(`UPDATE _ontology_replication SET active_generation=$1::uuid, enabled=true WHERE id`, [id]);
280
+ return (yield* shadowEpoch(sql, id));
281
+ });
282
+ /** Remap destination wire bindings before installing the next source snapshot trigger. */
283
+ export const migrateShadowCapture = (sql, current, next, selection, identities) => Effect.gen(function* () {
284
+ const targets = yield* sql.unsafe(`SELECT generation::text,capture_bindings FROM _ontology_replication_targets WHERE capturing`);
285
+ const [boundary] = yield* sql.unsafe("SELECT (CASE WHEN is_called THEN last_value ELSE 0 END)::text AS revision FROM _ontology_replication_revision");
286
+ for (const target of targets) {
287
+ const bindings = Object.fromEntries(Object.entries(target.capture_bindings ?? {}).map(([entity, fields]) => [
288
+ entity,
289
+ Object.fromEntries(Object.entries(fields).map(([wire, key]) => {
290
+ const declaration = next.entities.find((item) => item.id === entity);
291
+ const renamed = declaration?.properties.find((property) => renamedReplicationField(current, next, entity, property.name) === key)?.name;
292
+ return [wire, renamed ?? key];
293
+ })),
294
+ ]));
295
+ for (const selected of selection) {
296
+ const fields = bindings[selected.entityId];
297
+ if (!fields) {
298
+ continue;
299
+ }
300
+ const entity = next.entities.find((item) => item.id === selected.entityId);
301
+ for (const field of queryFields(entity).filter((field) => selected.fields.includes(field.name))) {
302
+ if (!Object.values(fields).includes(field.name)) {
303
+ fields[`__ss_${createHash("sha256")
304
+ .update(next.hash + entity.id + field.name + identities[entity.id]?.[field.name])
305
+ .digest("hex")
306
+ .slice(0, 24)}`] = field.name;
307
+ }
308
+ }
309
+ }
310
+ yield* sql.unsafe(`UPDATE _ontology_replication_targets SET capture_bindings=$2::jsonb,
311
+ capture_versions=(SELECT jsonb_agg(CASE WHEN NOT item ? 'through'
312
+ THEN item || jsonb_build_object('through',$3::text) ELSE item END ORDER BY n)
313
+ FROM jsonb_array_elements(COALESCE(capture_versions,
314
+ jsonb_build_array(jsonb_build_object('bindings',capture_bindings)))) WITH ORDINALITY AS versions(item,n))
315
+ || jsonb_build_array(jsonb_build_object('bindings',$2::jsonb))
316
+ WHERE generation=$1::uuid`, [target.generation, JSON.stringify(bindings), boundary.revision]);
317
+ }
318
+ yield* refreshShadowCapturePolicy(sql);
319
+ });
320
+ /** Every pass has a source-side lease as well as the product lease; stale completions are rejected. */
321
+ export const claimShadowEpoch = (sql, id, owner) => sql
322
+ .unsafe(`UPDATE _ontology_replication_epochs SET owner=$2::uuid,owner_until=now()+interval '2 minutes'
323
+ WHERE id=$1::uuid AND state='candidate' AND NOT cancel_requested
324
+ AND EXISTS(SELECT 1 FROM _ontology_replication WHERE id AND enabled AND NOT destination_repair_pending)
325
+ AND (owner=$2::uuid OR owner_until IS NULL OR owner_until<now())
326
+ RETURNING id`, [id, owner])
327
+ .pipe(Effect.map((rows) => rows.length === 1));
328
+ export const releaseShadowEpoch = (sql, id, owner) => sql.unsafe(`UPDATE _ontology_replication_epochs SET owner=NULL,owner_until=NULL WHERE id=$1::uuid AND owner=$2::uuid`, [id, owner]);
329
+ /** A closed source boundary is selected only after all admitted writers and scans have drained. */
330
+ export const beginShadowHandoff = (sql, id, owner, minimumFence = "0") => sql.withTransaction(Effect.gen(function* () {
331
+ yield* sql.unsafe("SET LOCAL lock_timeout='5s'");
332
+ yield* lockReplicationLifecycle(sql);
333
+ yield* sql.unsafe(`SELECT setval('_ontology_replication_cutover_fence',GREATEST(
334
+ (SELECT last_value FROM _ontology_replication_cutover_fence),$1::bigint),true)`, [minimumFence]);
335
+ const [epoch] = yield* sql.unsafe(`UPDATE _ontology_replication_epochs
336
+ SET boundary=(SELECT CASE WHEN is_called THEN last_value ELSE 0 END FROM _ontology_replication_revision),
337
+ token=gen_random_uuid(),fence=nextval('_ontology_replication_cutover_fence'),
338
+ operation_id=gen_random_uuid(),handoff_until=now()+interval '30 seconds'
339
+ WHERE id=$1::uuid AND owner=$2::uuid AND owner_until>now() AND state='candidate'
340
+ AND NOT cancel_requested AND token IS NULL AND installed
341
+ AND id=(SELECT active_generation FROM _ontology_replication WHERE id AND enabled)
342
+ AND NOT EXISTS(SELECT 1 FROM _ontology_replication_scans WHERE generation=$1::uuid AND NOT complete)
343
+ RETURNING ${epochFields}`, [id, owner]);
344
+ return expandEpoch(epoch);
345
+ }));
346
+ /** Destination invalidation must have succeeded (or switched) before this transaction runs. */
347
+ export const abandonShadowHandoff = (sql, epoch) => sql.withTransaction(Effect.gen(function* () {
348
+ yield* lockReplicationLifecycle(sql);
349
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET catchup_boundary=GREATEST(COALESCE(catchup_boundary,0),boundary),
350
+ token=NULL,boundary=NULL,
351
+ handoff_until=NULL,operation_id=NULL WHERE id=$1::uuid AND token=$2::uuid AND state='candidate'`, [epoch.id, epoch.token]);
352
+ }));
353
+ export const completeShadowEpoch = (sql, epoch) => sql.withTransaction(Effect.gen(function* () {
354
+ yield* lockReplicationLifecycle(sql);
355
+ const [current] = yield* sql.unsafe(`SELECT e.state,e.operation_id::text,r.active_generation::text,r.destination_repair_pending
356
+ FROM _ontology_replication_epochs e
357
+ CROSS JOIN _ontology_replication r WHERE e.id=$1::uuid AND r.id FOR UPDATE OF e`, [epoch.id]);
358
+ if (current?.state === "serving") {
359
+ return;
360
+ }
361
+ if (!current ||
362
+ current.destination_repair_pending ||
363
+ current.state !== "candidate" ||
364
+ current.operation_id !== epoch.operation_id ||
365
+ current.active_generation !== epoch.id) {
366
+ return yield* new ReplicationBaselineFailed({
367
+ message: "replication_publication_superseded",
368
+ });
369
+ }
370
+ // An external switch has already committed. Adopt its immutable epoch even after a lost local
371
+ // completion, before considering any newer desired state. Never revert the warehouse here.
372
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET state='retired',retired_at=now()
373
+ WHERE state='serving' AND id<>$1::uuid`, [epoch.id]);
374
+ yield* sql.unsafe("UPDATE _ontology_replication_epochs SET retired_at=now() WHERE state='retired' AND retired_at IS NULL");
375
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET state='serving',owner=NULL,owner_until=NULL
376
+ WHERE id=$1::uuid AND operation_id=$2::uuid`, [epoch.id, epoch.operation_id]);
377
+ yield* sql.unsafe(`UPDATE _ontology_replication SET serving_epoch=$1::uuid,destination_rebuilding=false,
378
+ destination_repair_pending=false
379
+ WHERE id AND source_id=$2::uuid`, [epoch.id, epoch.source_id]);
380
+ const generations = [...new Set(epoch.routes.map((route) => route.target.generation))];
381
+ for (const generation of generations) {
382
+ yield* sql.unsafe(`UPDATE _ontology_replication_targets SET capture_scopes=$2::jsonb
383
+ WHERE generation=$1::uuid`, [
384
+ generation,
385
+ JSON.stringify(epoch.routes
386
+ .filter((route) => route.target.generation === generation)
387
+ .map(({ entityId, kind }) => ({ entityId, kind }))),
388
+ ]);
389
+ }
390
+ yield* sql.unsafe(`UPDATE _ontology_replication_targets SET capturing=false
391
+ WHERE NOT (generation IN (SELECT value::uuid FROM jsonb_array_elements_text($1::jsonb)))`, [JSON.stringify(generations)]);
392
+ }));
393
+ export const pendingShadowSegment = (sql, epoch) => sql
394
+ .unsafe(`SELECT ${segmentFields} FROM _ontology_replication_segments
395
+ WHERE epoch=$1::uuid AND state<>'committed' ORDER BY created_at,id LIMIT 1`, [epoch])
396
+ .pipe(Effect.map((rows) => rows[0]));
397
+ /** Source events, immutable object names and job identities commit before the first upload. */
398
+ export const journalShadowSegment = (sql, input) => sql.withTransaction(Effect.gen(function* () {
399
+ const id = randomUUID();
400
+ const events = input.events.map((item) => item.event);
401
+ if (!events.length) {
402
+ return undefined;
403
+ }
404
+ const digest = createHash("sha256").update(JSON.stringify(events)).digest("hex");
405
+ const through = input.events
406
+ .reduce((maximum, item) => BigInt(item.event.revision) > maximum ? BigInt(item.event.revision) : maximum, 0n)
407
+ .toString();
408
+ const [segment] = yield* sql.unsafe(`INSERT INTO _ontology_replication_segments
409
+ (id,epoch,generation,source_id,through_revision,events,event_ids,digest,object_uri,job_id)
410
+ SELECT $1::uuid,$2::uuid,$3::uuid,$4::uuid,$5::bigint,$6::jsonb,$7::jsonb,$8,$9,$10
411
+ WHERE EXISTS(SELECT 1 FROM _ontology_replication_epochs WHERE id=$2::uuid
412
+ AND owner=$11::uuid AND owner_until>now() AND state='candidate') RETURNING ${segmentFields}`, [
413
+ id,
414
+ input.epoch.id,
415
+ events[0].generation,
416
+ input.epoch.source_id,
417
+ through,
418
+ JSON.stringify(events),
419
+ JSON.stringify(input.events.map((item) => item.historyId)),
420
+ digest,
421
+ `gs://${input.projectId}-staging/ontology-replication/${input.epoch.source_id}/${id}-${digest}.ndjson`,
422
+ `ontology_load_${id.replaceAll("-", "")}_0`,
423
+ input.owner,
424
+ ]);
425
+ if (!segment) {
426
+ return undefined;
427
+ }
428
+ yield* sql.unsafe(`UPDATE _ontology_replication_delivery SET segment_id=$3::uuid
429
+ WHERE generation=$1::uuid AND event_id IN (SELECT value::uuid FROM jsonb_array_elements_text($2::jsonb))
430
+ AND committed_at IS NULL`, [segment.generation, JSON.stringify(segment.event_ids), id]);
431
+ return segment;
432
+ }));
433
+ export const finishShadowSegment = (sql, segment, owner) => sql.withTransaction(Effect.gen(function* () {
434
+ const [completed] = yield* sql.unsafe(`UPDATE _ontology_replication_segments SET state='committed',committed_at=now()
435
+ WHERE id=$1::uuid AND job_id=$2 AND EXISTS(SELECT 1 FROM _ontology_replication_epochs
436
+ WHERE id=$3::uuid AND owner=$4::uuid AND owner_until>now() AND state='candidate') RETURNING id`, [segment.id, segment.job_id, segment.epoch, owner]);
437
+ if (!completed) {
438
+ return false;
439
+ }
440
+ yield* sql.unsafe(`UPDATE _ontology_replication_delivery SET committed_at=now()
441
+ WHERE segment_id=$1::uuid`, [segment.id]);
442
+ return true;
443
+ }));
444
+ export const retryShadowSegment = (sql, segment, owner, failure) => sql.unsafe(`UPDATE _ontology_replication_segments SET attempt=attempt+1,
445
+ retry_after=now()+make_interval(secs=>least(3600,30*power(2,least(attempt,7)))::integer),
446
+ job_id='ontology_load_' || replace(id::text,'-','') || '_' || (attempt+1)::text,failure=$5::jsonb
447
+ WHERE id=$1::uuid AND job_id=$2 AND EXISTS(SELECT 1 FROM _ontology_replication_epochs
448
+ WHERE id=$3::uuid AND owner=$4::uuid AND owner_until>now() AND state='candidate')`, [segment.id, segment.job_id, segment.epoch, owner, JSON.stringify(failure)]);
449
+ /** Recheck references under the lifecycle fence. Audit journals and immutable epoch routes survive. */
450
+ export const retireShadowCapture = (sql) => sql.withTransaction(Effect.gen(function* () {
451
+ yield* lockReplicationLifecycle(sql);
452
+ yield* sql.unsafe(`UPDATE _ontology_replication_targets t SET capturing=false
453
+ WHERE NOT EXISTS(SELECT 1 FROM _ontology_replication_epochs e,
454
+ jsonb_array_elements(e.routes) r WHERE e.state IN ('serving','candidate')
455
+ AND r->'target'->>'generation'=t.generation::text)`);
456
+ }));
457
+ /** Filter by the destination's immutable wire schema, including missing keys and explicit nulls. */
458
+ export function shadowWireEvent(event, bindings, selection) {
459
+ const allowed = selection.find((item) => item.entityId === event.entity_id);
460
+ if (!allowed || event.deleted || event.record_kind !== "entity") {
461
+ return event;
462
+ }
463
+ const source = JSON.parse(event.payload);
464
+ const fields = bindings[event.entity_id] ??
465
+ Object.fromEntries(["id", ...allowed.fields].map((field) => [field, field]));
466
+ return {
467
+ ...event,
468
+ payload: JSON.stringify(Object.fromEntries(Object.entries(fields)
469
+ .filter(([, key]) => Object.hasOwn(source, key))
470
+ .map(([wire, key]) => [wire, source[key]]))),
471
+ };
472
+ }
473
+ /** Capture is the union needed by live destinations; export shaping remains destination-specific. */
474
+ export const refreshShadowCapturePolicy = (sql) => sql.unsafe(`UPDATE _ontology_replication SET selection=COALESCE((
475
+ SELECT jsonb_object_agg(entity_id,
476
+ jsonb_build_object('entityId',entity_id,'fields',fields,'relationships',relationships))
477
+ FROM (
478
+ SELECT entity_id,
479
+ (SELECT COALESCE(jsonb_agg(DISTINCT value),'[]'::jsonb) FROM jsonb_array_elements(all_fields) value) AS fields,
480
+ (SELECT COALESCE(jsonb_agg(DISTINCT value),'[]'::jsonb)
481
+ FROM jsonb_array_elements(all_relationships) value) AS relationships
482
+ FROM (
483
+ SELECT binding.key AS entity_id,jsonb_agg(DISTINCT field.value) AS all_fields,
484
+ COALESCE((SELECT jsonb_agg(DISTINCT substring(scope->>'kind' FROM 6))
485
+ FILTER (WHERE scope->>'kind' LIKE 'edge:%')
486
+ FROM _ontology_replication_targets other,jsonb_array_elements(other.capture_scopes) scope
487
+ WHERE other.capturing AND scope->>'entityId'=binding.key),'[]'::jsonb) AS all_relationships
488
+ FROM _ontology_replication_targets t,jsonb_each(t.capture_bindings) binding,
489
+ jsonb_each_text(binding.value) field WHERE t.capturing
490
+ AND t.source_id=(SELECT source_id FROM _ontology_replication WHERE id)
491
+ AND NOT EXISTS (
492
+ SELECT 1 FROM _ontology_replication state,jsonb_array_elements(state.exclusions) exclusion
493
+ WHERE exclusion->>'entityId'=binding.key AND
494
+ (COALESCE((exclusion->>'disabled')::boolean,false) OR exclusion->'fields' ? field.value))
495
+ GROUP BY binding.key
496
+ ) union_fields
497
+ ) selections),'{}'::jsonb) WHERE id`);
498
+ /** Only generations retired for seven days qualify; creation time is never a query-safety fence. */
499
+ export const retiredShadowGenerations = (sql) => sql.withTransaction(Effect.gen(function* () {
500
+ yield* lockReplicationLifecycle(sql);
501
+ return yield* sql.unsafe(`SELECT t.generation::text,t.source_id::text
502
+ FROM _ontology_replication_targets t WHERE NOT t.capturing
503
+ AND t.source_id=(SELECT source_id FROM _ontology_replication WHERE id)
504
+ AND t.created_at<now()-interval '31 days'
505
+ AND NOT EXISTS (SELECT 1 FROM _ontology_replication_epochs e,jsonb_array_elements(e.routes) route
506
+ WHERE route->'target'->>'generation'=t.generation::text AND
507
+ (e.state IN ('serving','candidate') OR e.retired_at>=now()-interval '7 days'))
508
+ AND NOT EXISTS(SELECT 1 FROM _ontology_replication_segments segment
509
+ JOIN _ontology_replication_epochs epoch ON epoch.id=segment.epoch
510
+ WHERE segment.generation=t.generation AND (epoch.state='candidate' OR segment.state='pending'))
511
+ ORDER BY t.generation LIMIT 20`);
512
+ }));
513
+ /** The destination has already fenced and deselected an observably destroyed event table. */
514
+ export const replaceDestroyedShadowDestination = (sql, input) => sql.withTransaction(Effect.gen(function* () {
515
+ yield* lockReplicationLifecycle(sql);
516
+ const [current] = yield* sql.unsafe("SELECT active_generation::text,source_id::text FROM _ontology_replication WHERE id AND enabled");
517
+ if (current?.active_generation !== input.target.generation ||
518
+ current.source_id !== input.target.source_id) {
519
+ return yield* new ReplicationBaselineFailed({
520
+ message: "replication_destination_repair_superseded",
521
+ });
522
+ }
523
+ yield* sql.unsafe(`SELECT setval('_ontology_replication_cutover_fence',GREATEST(
524
+ (SELECT last_value FROM _ontology_replication_cutover_fence),$1::bigint),true)`, [input.fence]);
525
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET state=CASE WHEN state='serving'
526
+ THEN 'retired' ELSE 'cancelled' END,retired_at=now(),token=NULL,owner=NULL,owner_until=NULL
527
+ WHERE state IN ('serving','candidate')`);
528
+ yield* sql.unsafe(`UPDATE _ontology_replication SET serving_epoch=NULL,destination_rebuilding=true,
529
+ destination_repair_pending=false WHERE id`);
530
+ yield* sql.unsafe("UPDATE _ontology_replication_targets SET capturing=false");
531
+ return yield* prepareShadowEpoch(sql, {
532
+ target: { ...input.target, generation: randomUUID() },
533
+ affected: replicationScanScopes(input.target),
534
+ });
535
+ }));
536
+ export const installShadowEpoch = (sql, id, owner) => sql
537
+ .unsafe(`UPDATE _ontology_replication_epochs SET installed=true
538
+ WHERE id=$1::uuid AND owner=$2::uuid AND owner_until>now() AND state='candidate'
539
+ AND id=(SELECT active_generation FROM _ontology_replication WHERE id AND enabled) RETURNING id`, [id, owner])
540
+ .pipe(Effect.map((rows) => rows.length === 1));
541
+ /** Strict warehouse job completion, not Pub/Sub acceptance, is the publication prerequisite. */
542
+ export const shadowPublicationReady = (sql, epoch, owner) => sql
543
+ .unsafe(`SELECT EXISTS(SELECT 1 FROM _ontology_replication_epochs e
544
+ WHERE id=$1::uuid AND owner=$2::uuid AND owner_until>now() AND state='candidate' AND installed
545
+ AND NOT cancel_requested
546
+ AND token=$3::uuid AND boundary=$4::bigint AND handoff_until>now()
547
+ AND id=(SELECT active_generation FROM _ontology_replication
548
+ WHERE id AND enabled AND NOT destination_repair_pending)
549
+ AND NOT EXISTS(SELECT 1 FROM _ontology_replication_scans WHERE generation=e.id AND NOT complete)
550
+ AND NOT EXISTS(SELECT 1 FROM _ontology_replication_delivery WHERE generation=e.id
551
+ AND revision<=e.boundary AND committed_at IS NULL AND suppressed_at IS NULL)) AS ready`, [epoch.id, owner, epoch.token, epoch.boundary])
552
+ .pipe(Effect.map((rows) => rows[0].ready));
553
+ export const unfinishedRetiredSegments = (sql) => sql.unsafe(`SELECT ${segmentFields} FROM _ontology_replication_segments
554
+ WHERE state='pending' AND created_at<now()-interval '7 days' AND epoch IN (
555
+ SELECT id FROM _ontology_replication_epochs WHERE state IN ('retired','cancelled'))
556
+ ORDER BY created_at,id LIMIT 10`);
557
+ export const settleRetiredSegment = (sql, segment, committed) => sql.unsafe(`UPDATE _ontology_replication_segments SET state=$3,
558
+ committed_at=CASE WHEN $3='committed' THEN now() ELSE committed_at END
559
+ WHERE id=$1::uuid AND job_id=$2 AND state='pending' AND epoch IN (
560
+ SELECT id FROM _ontology_replication_epochs WHERE state IN ('retired','cancelled'))`, [segment.id, segment.job_id, committed ? "committed" : "failed"]);
561
+ /** Restriction-only refresh is independent of build leases and cannot confer publication eligibility. */
562
+ export const shadowPolicyViewOwnership = (sql, generation, source, exclusions) => sql
563
+ .unsafe(`SELECT EXISTS(SELECT 1 FROM _ontology_replication
564
+ WHERE id AND enabled AND NOT destination_repair_pending AND active_generation=$1::uuid
565
+ AND source_id=$2::uuid AND exclusions=$3::jsonb) AS valid`, [generation, source, JSON.stringify(exclusions)])
566
+ .pipe(Effect.map((rows) => rows[0].valid));
567
+ export const recordShadowPolicyViews = (sql, generation, source, exclusions) => sql.unsafe(`UPDATE _ontology_replication_epochs SET policy_installed=true WHERE id=$1::uuid
568
+ AND EXISTS(SELECT 1 FROM _ontology_replication WHERE id AND enabled AND NOT destination_repair_pending
569
+ AND active_generation=$1::uuid AND source_id=$2::uuid AND exclusions=$3::jsonb)`, [generation, source, JSON.stringify(exclusions)]);
570
+ /** Used after reading a destination view's etag, before its conditional DDL update. */
571
+ export const shadowViewOwnership = (sql, id) => sql
572
+ .unsafe(`SELECT EXISTS(SELECT 1 FROM _ontology_replication_epochs e
573
+ WHERE e.id=$1::uuid
574
+ AND EXISTS(SELECT 1 FROM _ontology_replication WHERE id AND NOT destination_repair_pending)
575
+ AND (
576
+ (e.state='candidate' AND NOT e.cancel_requested
577
+ AND e.id=(SELECT active_generation FROM _ontology_replication WHERE id AND enabled))
578
+ OR (e.state='serving' AND e.id=(SELECT serving_epoch FROM _ontology_replication WHERE id AND enabled)
579
+ AND NOT EXISTS(SELECT 1 FROM _ontology_replication_epochs WHERE state='candidate')))) AS valid`, [id])
580
+ .pipe(Effect.map((rows) => rows[0].valid));
581
+ /** A finite background goal prevents continuous writes from moving initialization's finish line. */
582
+ export const closeShadowCatchup = (sql, id, owner) => sql.withTransaction(Effect.gen(function* () {
583
+ yield* sql.unsafe("SET LOCAL lock_timeout='5s'");
584
+ yield* lockReplicationLifecycle(sql);
585
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET catchup_boundary=(
586
+ SELECT CASE WHEN is_called THEN last_value ELSE 0 END FROM _ontology_replication_revision)
587
+ WHERE id=$1::uuid AND owner=$2::uuid AND owner_until>now() AND state='candidate'
588
+ AND catchup_boundary IS NULL AND installed=false
589
+ AND id=(SELECT active_generation FROM _ontology_replication WHERE id AND enabled)
590
+ AND NOT EXISTS(SELECT 1 FROM _ontology_replication_scans WHERE generation=$1::uuid AND NOT complete)`, [id, owner]);
591
+ }));
592
+ /** Persist cancellation before returning a retryable migration decision; provider fencing follows. */
593
+ export const requestShadowSupersession = (sql, manifestHash) => sql.withTransaction(Effect.gen(function* () {
594
+ yield* sql.unsafe("SET LOCAL lock_timeout='5s'");
595
+ yield* sql.unsafe("SET LOCAL statement_timeout='30s'");
596
+ yield* lockReplicationLifecycle(sql);
597
+ const rows = yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET cancel_requested=true
598
+ WHERE state='candidate' AND (token IS NOT NULL OR cancel_requested)
599
+ AND target->'manifest'->>'hash'<>$1 RETURNING id`, [manifestHash]);
600
+ if (rows.length) {
601
+ yield* sql.unsafe(`UPDATE _ontology_replication SET requested_manifest_hash=$1,
602
+ requested_manifest_until=now()+interval '5 minutes' WHERE id`, [manifestHash]);
603
+ }
604
+ return rows.length > 0;
605
+ }));
606
+ /** The destination token has been invalidated, or no token ever existed. */
607
+ export const cancelShadowEpoch = (sql, epoch) => sql.withTransaction(Effect.gen(function* () {
608
+ yield* lockReplicationLifecycle(sql);
609
+ yield* sql.unsafe(`UPDATE _ontology_replication_epochs SET state='cancelled',owner=NULL,
610
+ owner_until=NULL,token=NULL,boundary=NULL,handoff_until=NULL
611
+ WHERE id=$1::uuid AND state='candidate' AND cancel_requested`, [epoch.id]);
612
+ yield* sql.unsafe(`UPDATE _ontology_replication_scans SET complete=true,required=false
613
+ WHERE generation=$1::uuid`, [epoch.id]);
614
+ }));
@@ -0,0 +1,33 @@
1
+ import type { SourcePublicationProof } from "./model.js";
2
+ import { Effect } from "effect";
3
+ import type { SqlClient } from "effect/unstable/sql";
4
+ import { ReplicationBaselineFailed } from "./baseline.js";
5
+ export interface SourceReplacementSelector {
6
+ readonly sourceId: string;
7
+ readonly operationId: string | null;
8
+ readonly epoch: string | null;
9
+ readonly token: string | null;
10
+ readonly fence: string;
11
+ readonly incarnation: string;
12
+ }
13
+ export interface ShadowSourceReplacement {
14
+ readonly source_id: string;
15
+ readonly operation_id: string;
16
+ readonly expected: SourceReplacementSelector;
17
+ readonly proof: SourcePublicationProof | null;
18
+ readonly published: string;
19
+ }
20
+ export declare const pendingSourceReplacement: (sql: SqlClient.SqlClient) => Effect.Effect<ShadowSourceReplacement, import("effect/unstable/sql/SqlError").SqlError, never>;
21
+ /** Only the trusted product publication can justify replacing an otherwise healthy old source. */
22
+ export declare const prepareSourceReplacement: (sql: SqlClient.SqlClient, input: {
23
+ readonly sourceId: string;
24
+ readonly published: string;
25
+ readonly observed: SourceReplacementSelector;
26
+ readonly proof: SourcePublicationProof;
27
+ readonly projectId: string;
28
+ readonly workspaceId: string;
29
+ }) => Effect.Effect<ShadowSourceReplacement, import("effect/unstable/sql/SqlError").SqlError | ReplicationBaselineFailed, never>;
30
+ /** A confirmed no-op CAS may race an old-source handoff; retain its receipt before a new attempt. */
31
+ export declare const retrySourceReplacement: (sql: SqlClient.SqlClient, intent: ShadowSourceReplacement, observed: SourceReplacementSelector) => Effect.Effect<undefined, import("effect/unstable/sql/SqlError").SqlError | ReplicationBaselineFailed, never>;
32
+ /** Upgrade only an already admitted old journal; the provider evidence is read before this transaction. */
33
+ export declare const recordSourcePublicationProof: (sql: SqlClient.SqlClient, intent: ShadowSourceReplacement, proof: SourcePublicationProof) => Effect.Effect<undefined, import("effect/unstable/sql/SqlError").SqlError | ReplicationBaselineFailed, never>;