@sixb/core 0.1.2 → 0.1.4

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 (383) hide show
  1. package/dist/actions/index.js +19 -17
  2. package/dist/actions/index.js.map +1 -1
  3. package/dist/actions/worker.js +4 -4
  4. package/dist/actions/worker.js.map +1 -1
  5. package/dist/agents/adapters.d.ts +11 -1
  6. package/dist/agents/adapters.d.ts.map +1 -1
  7. package/dist/agents/context-compaction.d.ts +40 -0
  8. package/dist/agents/context-compaction.d.ts.map +1 -0
  9. package/dist/agents/context.js +1 -1
  10. package/dist/agents/errors.d.ts +1 -1
  11. package/dist/agents/errors.d.ts.map +1 -1
  12. package/dist/agents/execution.d.ts +3 -0
  13. package/dist/agents/execution.d.ts.map +1 -1
  14. package/dist/agents/ids.d.ts +2 -0
  15. package/dist/agents/ids.d.ts.map +1 -1
  16. package/dist/agents/index.d.ts +10 -6
  17. package/dist/agents/index.d.ts.map +1 -1
  18. package/dist/agents/index.js +51 -35
  19. package/dist/agents/index.js.map +1 -1
  20. package/dist/agents/request.d.ts.map +1 -1
  21. package/dist/agents/streams.d.ts +17 -1
  22. package/dist/agents/streams.d.ts.map +1 -1
  23. package/dist/agents/streams.js +5 -3
  24. package/dist/agents/streams.js.map +1 -1
  25. package/dist/agents/thread-context-projection.d.ts +19 -0
  26. package/dist/agents/thread-context-projection.d.ts.map +1 -0
  27. package/dist/agents/tool-definition.d.ts.map +1 -1
  28. package/dist/agents/tool-result.d.ts +6 -0
  29. package/dist/agents/tool-result.d.ts.map +1 -0
  30. package/dist/agents/types.d.ts +46 -1
  31. package/dist/agents/types.d.ts.map +1 -1
  32. package/dist/agents/validation.d.ts +2 -2
  33. package/dist/agents/validation.d.ts.map +1 -1
  34. package/dist/auth/index.js +11 -5
  35. package/dist/auth/index.js.map +1 -1
  36. package/dist/authorization/index.js +6 -2
  37. package/dist/authorization/index.js.map +1 -1
  38. package/dist/bootstrap/index.js +33 -31
  39. package/dist/bootstrap/index.js.map +1 -1
  40. package/dist/{chunk-ys1nse2v.js → chunk-1wk20wn3.js} +438 -246
  41. package/dist/{chunk-ys1nse2v.js.map → chunk-1wk20wn3.js.map} +11 -11
  42. package/dist/{chunk-sa4340y1.js → chunk-1yz3x65y.js} +7 -7
  43. package/dist/{chunk-gqdd7508.js → chunk-4rh2m6zg.js} +1 -1
  44. package/dist/{chunk-fmx1sz2h.js → chunk-72q2y8hn.js} +3 -3
  45. package/dist/{chunk-fmx1sz2h.js.map → chunk-72q2y8hn.js.map} +4 -4
  46. package/dist/{chunk-nnyp53zt.js → chunk-7gw7mepb.js} +259 -9
  47. package/dist/chunk-7gw7mepb.js.map +14 -0
  48. package/dist/{chunk-nten49ta.js → chunk-819wnjz8.js} +11 -5
  49. package/dist/chunk-819wnjz8.js.map +12 -0
  50. package/dist/chunk-96swp2wd.js +47 -0
  51. package/dist/chunk-96swp2wd.js.map +10 -0
  52. package/dist/{chunk-4x43bkbp.js → chunk-a09jx26t.js} +1 -1
  53. package/dist/{chunk-st4xgxey.js → chunk-afjpa2hs.js} +205 -48
  54. package/dist/chunk-afjpa2hs.js.map +45 -0
  55. package/dist/{chunk-0mbx247x.js → chunk-c43qr6s0.js} +427 -99
  56. package/dist/chunk-c43qr6s0.js.map +46 -0
  57. package/dist/{chunk-zg9yryhz.js → chunk-cbkm2vam.js} +3 -3
  58. package/dist/{chunk-57zpb99z.js → chunk-dm72y8wt.js} +26 -3
  59. package/dist/chunk-dm72y8wt.js.map +10 -0
  60. package/dist/chunk-drjqm1aa.js +913 -0
  61. package/dist/chunk-drjqm1aa.js.map +15 -0
  62. package/dist/chunk-dysw7nsm.js.map +1 -1
  63. package/dist/{chunk-8ryen3p3.js → chunk-f6erf2vv.js} +1 -1
  64. package/dist/{chunk-34bqh420.js → chunk-f83ka50g.js} +188 -44
  65. package/dist/chunk-f83ka50g.js.map +23 -0
  66. package/dist/{chunk-bct7hmfc.js → chunk-g13869yf.js} +3 -3
  67. package/dist/{chunk-0k4avqr2.js → chunk-hbeh8j9w.js} +2 -2
  68. package/dist/{chunk-qvybnnpe.js → chunk-nzw7sm3b.js} +2 -2
  69. package/dist/{chunk-k9pts48t.js → chunk-pn8n8sba.js} +16 -15
  70. package/dist/{chunk-k9pts48t.js.map → chunk-pn8n8sba.js.map} +3 -3
  71. package/dist/{chunk-63te770v.js → chunk-qewtks41.js} +8 -8
  72. package/dist/{chunk-63te770v.js.map → chunk-qewtks41.js.map} +2 -2
  73. package/dist/{chunk-85j5ybfj.js → chunk-rdeagz6b.js} +2 -2
  74. package/dist/{chunk-85j5ybfj.js.map → chunk-rdeagz6b.js.map} +3 -3
  75. package/dist/chunk-rhrbz7d4.js +36 -0
  76. package/dist/chunk-rhrbz7d4.js.map +10 -0
  77. package/dist/{chunk-bh6k3nc6.js → chunk-rs1wbvy6.js} +1 -1
  78. package/dist/{chunk-88ppkr54.js → chunk-rte5sm3z.js} +26 -2
  79. package/dist/chunk-rte5sm3z.js.map +12 -0
  80. package/dist/{chunk-n8herkry.js → chunk-s31d0qmq.js} +57 -20
  81. package/dist/{chunk-n8herkry.js.map → chunk-s31d0qmq.js.map} +8 -7
  82. package/dist/{chunk-7pc8b818.js → chunk-sxwk41qa.js} +1 -1
  83. package/dist/{chunk-663csy96.js → chunk-t0jjkep3.js} +2 -1
  84. package/dist/chunk-t0jjkep3.js.map +10 -0
  85. package/dist/{chunk-c6qd89g5.js → chunk-tek1qwgm.js} +6 -6
  86. package/dist/{chunk-c6qd89g5.js.map → chunk-tek1qwgm.js.map} +1 -1
  87. package/dist/{chunk-jaj13078.js → chunk-tkdscva6.js} +3 -33
  88. package/dist/{chunk-jaj13078.js.map → chunk-tkdscva6.js.map} +3 -4
  89. package/dist/{chunk-5egfka8j.js → chunk-tycbzedm.js} +2 -2
  90. package/dist/{chunk-g9t3kdtx.js → chunk-x2yw73hy.js} +1 -1
  91. package/dist/{chunk-57r1cpxx.js → chunk-xc7hq65b.js} +3 -2
  92. package/dist/{chunk-57r1cpxx.js.map → chunk-xc7hq65b.js.map} +3 -3
  93. package/dist/chunk-xdf9yswn.js +133 -0
  94. package/dist/chunk-xdf9yswn.js.map +11 -0
  95. package/dist/execution/agent.js +29 -27
  96. package/dist/execution/agent.js.map +1 -1
  97. package/dist/execution/primitive.js +29 -27
  98. package/dist/execution/primitive.js.map +2 -2
  99. package/dist/execution/request.js +30 -28
  100. package/dist/execution/request.js.map +2 -2
  101. package/dist/http/index.js +1 -1
  102. package/dist/index.d.ts +6 -5
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +60 -58
  105. package/dist/index.js.map +1 -1
  106. package/dist/lake-storage/types.d.ts +2 -1
  107. package/dist/lake-storage/types.d.ts.map +1 -1
  108. package/dist/materialization/model.d.ts +4 -0
  109. package/dist/materialization/model.d.ts.map +1 -1
  110. package/dist/materializer/edits/apply.d.ts +6 -1
  111. package/dist/materializer/edits/apply.d.ts.map +1 -1
  112. package/dist/materializer/edits/working-state.d.ts +2 -0
  113. package/dist/materializer/edits/working-state.d.ts.map +1 -1
  114. package/dist/materializer/effective/resolve.d.ts +3 -1
  115. package/dist/materializer/effective/resolve.d.ts.map +1 -1
  116. package/dist/materializer/execution/work-records.d.ts.map +1 -1
  117. package/dist/materializer/index.js +19 -17
  118. package/dist/materializer/index.js.map +1 -1
  119. package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
  120. package/dist/materializer/shared/normalize.d.ts.map +1 -1
  121. package/dist/models/index.d.ts +40 -0
  122. package/dist/models/index.d.ts.map +1 -0
  123. package/dist/objects/execution.d.ts +6 -1
  124. package/dist/objects/execution.d.ts.map +1 -1
  125. package/dist/objects/index.js +21 -19
  126. package/dist/objects/index.js.map +1 -1
  127. package/dist/objects/link/endpoints.d.ts.map +1 -1
  128. package/dist/objects/query/executor.d.ts +1 -0
  129. package/dist/objects/query/executor.d.ts.map +1 -1
  130. package/dist/objects/query/explain.d.ts +1 -0
  131. package/dist/objects/query/explain.d.ts.map +1 -1
  132. package/dist/objects/query/index.d.ts +3 -1
  133. package/dist/objects/query/index.d.ts.map +1 -1
  134. package/dist/objects/query/index.js +30 -5
  135. package/dist/objects/query/index.js.map +1 -1
  136. package/dist/objects/query/ir.d.ts +14 -1
  137. package/dist/objects/query/ir.d.ts.map +1 -1
  138. package/dist/objects/query/links.d.ts +25 -0
  139. package/dist/objects/query/links.d.ts.map +1 -0
  140. package/dist/objects/query/normalize.d.ts.map +1 -1
  141. package/dist/objects/query/planner.d.ts.map +1 -1
  142. package/dist/objects/query/validate.d.ts +1 -0
  143. package/dist/objects/query/validate.d.ts.map +1 -1
  144. package/dist/pipelines/index.js +16 -15
  145. package/dist/pipelines/index.js.map +1 -1
  146. package/dist/projections/builders.d.ts +52 -10
  147. package/dist/projections/builders.d.ts.map +1 -1
  148. package/dist/projections/index.d.ts +2 -1
  149. package/dist/projections/index.d.ts.map +1 -1
  150. package/dist/projections/internal.d.ts +4 -1
  151. package/dist/projections/internal.d.ts.map +1 -1
  152. package/dist/projections/internal.js +22 -17
  153. package/dist/projections/internal.js.map +1 -1
  154. package/dist/projections/run-dispatch.d.ts +1 -0
  155. package/dist/projections/run-dispatch.d.ts.map +1 -1
  156. package/dist/projections/timestamp.d.ts +3 -0
  157. package/dist/projections/timestamp.d.ts.map +1 -0
  158. package/dist/projections/types.d.ts +21 -9
  159. package/dist/projections/types.d.ts.map +1 -1
  160. package/dist/projections/validation.d.ts +6 -5
  161. package/dist/projections/validation.d.ts.map +1 -1
  162. package/dist/query.d.ts +2 -1
  163. package/dist/query.d.ts.map +1 -1
  164. package/dist/query.js +2 -2
  165. package/dist/queues/index.d.ts +1 -1
  166. package/dist/queues/index.d.ts.map +1 -1
  167. package/dist/queues/types.d.ts +7 -0
  168. package/dist/queues/types.d.ts.map +1 -1
  169. package/dist/runtime/ai-cost.d.ts +8 -0
  170. package/dist/runtime/ai-cost.d.ts.map +1 -0
  171. package/dist/runtime/create.d.ts +3 -0
  172. package/dist/runtime/create.d.ts.map +1 -1
  173. package/dist/runtime/definitions.d.ts +3 -0
  174. package/dist/runtime/definitions.d.ts.map +1 -1
  175. package/dist/runtime/host.d.ts +2 -0
  176. package/dist/runtime/host.d.ts.map +1 -1
  177. package/dist/runtime/resolve-definitions.d.ts +2 -0
  178. package/dist/runtime/resolve-definitions.d.ts.map +1 -1
  179. package/dist/storage/agents/in-memory.d.ts +22 -4
  180. package/dist/storage/agents/in-memory.d.ts.map +1 -1
  181. package/dist/storage/agents/index.d.ts +1 -1
  182. package/dist/storage/agents/index.d.ts.map +1 -1
  183. package/dist/storage/agents/provider.d.ts +31 -0
  184. package/dist/storage/agents/provider.d.ts.map +1 -1
  185. package/dist/storage/agents/provider.js +22 -7
  186. package/dist/storage/agents/provider.js.map +1 -1
  187. package/dist/storage/agents/types.d.ts +75 -4
  188. package/dist/storage/agents/types.d.ts.map +1 -1
  189. package/dist/storage/ai-cost/analytics.d.ts +61 -0
  190. package/dist/storage/ai-cost/analytics.d.ts.map +1 -0
  191. package/dist/storage/ai-cost/codec.d.ts +14 -0
  192. package/dist/storage/ai-cost/codec.d.ts.map +1 -0
  193. package/dist/storage/ai-cost/errors.d.ts +7 -0
  194. package/dist/storage/ai-cost/errors.d.ts.map +1 -0
  195. package/dist/storage/ai-cost/in-memory.d.ts +32 -0
  196. package/dist/storage/ai-cost/in-memory.d.ts.map +1 -0
  197. package/dist/storage/ai-cost/index.d.ts +6 -0
  198. package/dist/storage/ai-cost/index.d.ts.map +1 -0
  199. package/dist/storage/ai-cost/provider.d.ts +7 -0
  200. package/dist/storage/ai-cost/provider.d.ts.map +1 -0
  201. package/dist/storage/ai-cost/provider.js +132 -0
  202. package/dist/storage/ai-cost/provider.js.map +10 -0
  203. package/dist/storage/ai-cost/types.d.ts +154 -0
  204. package/dist/storage/ai-cost/types.d.ts.map +1 -0
  205. package/dist/storage/ai-cost/validation.d.ts +7 -0
  206. package/dist/storage/ai-cost/validation.d.ts.map +1 -0
  207. package/dist/storage/ai-usage/in-memory.d.ts +2 -1
  208. package/dist/storage/ai-usage/in-memory.d.ts.map +1 -1
  209. package/dist/storage/ai-usage/index.d.ts +1 -1
  210. package/dist/storage/ai-usage/index.d.ts.map +1 -1
  211. package/dist/storage/ai-usage/types.d.ts +6 -0
  212. package/dist/storage/ai-usage/types.d.ts.map +1 -1
  213. package/dist/storage/in-memory/index.d.ts +5 -0
  214. package/dist/storage/in-memory/index.d.ts.map +1 -1
  215. package/dist/storage/index.d.ts +6 -3
  216. package/dist/storage/index.d.ts.map +1 -1
  217. package/dist/storage/index.js +33 -21
  218. package/dist/storage/index.js.map +1 -1
  219. package/dist/storage/objects/in-memory.d.ts +6 -3
  220. package/dist/storage/objects/in-memory.d.ts.map +1 -1
  221. package/dist/storage/objects/index.d.ts +3 -1
  222. package/dist/storage/objects/index.d.ts.map +1 -1
  223. package/dist/storage/objects/keys.d.ts +16 -0
  224. package/dist/storage/objects/keys.d.ts.map +1 -0
  225. package/dist/storage/objects/types.d.ts +33 -6
  226. package/dist/storage/objects/types.d.ts.map +1 -1
  227. package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
  228. package/dist/storage/ontology/materializations.d.ts +3 -0
  229. package/dist/storage/ontology/materializations.d.ts.map +1 -1
  230. package/dist/storage/ontology/provider.js +1 -1
  231. package/dist/storage/operation-scope.d.ts.map +1 -1
  232. package/dist/storage/operation-scope.js +1 -1
  233. package/dist/storage/types.d.ts +2 -0
  234. package/dist/storage/types.d.ts.map +1 -1
  235. package/dist/storage/workflow-runs/provider.js +10 -5
  236. package/dist/storage/workflow-runs/provider.js.map +1 -1
  237. package/dist/syncs/index.js +16 -15
  238. package/dist/syncs/index.js.map +1 -1
  239. package/dist/testing/agent-storage-contract.d.ts +3 -2
  240. package/dist/testing/agent-storage-contract.d.ts.map +1 -1
  241. package/dist/testing/ai-cost-storage-contract.d.ts +12 -0
  242. package/dist/testing/ai-cost-storage-contract.d.ts.map +1 -0
  243. package/dist/testing/ai-usage-storage-contract.d.ts.map +1 -1
  244. package/dist/testing/effective-storage-contract.d.ts +1 -1
  245. package/dist/testing/effective-storage-contract.d.ts.map +1 -1
  246. package/dist/testing/index.d.ts +1 -0
  247. package/dist/testing/index.d.ts.map +1 -1
  248. package/dist/testing/index.js +2525 -1480
  249. package/dist/testing/index.js.map +10 -9
  250. package/dist/testing/lake-storage-contract.d.ts.map +1 -1
  251. package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
  252. package/dist/testing/object-query-contract.d.ts +1 -1
  253. package/dist/testing/object-query-contract.d.ts.map +1 -1
  254. package/dist/webhooks/internal.js +14 -13
  255. package/dist/webhooks/internal.js.map +2 -2
  256. package/dist/workers/index.js +12 -2
  257. package/dist/workers/index.js.map +3 -3
  258. package/dist/workers/queue-worker.d.ts +2 -0
  259. package/dist/workers/queue-worker.d.ts.map +1 -1
  260. package/dist/workflows/execution.d.ts +3 -0
  261. package/dist/workflows/execution.d.ts.map +1 -1
  262. package/dist/workflows/index.js +30 -28
  263. package/dist/workflows/index.js.map +1 -1
  264. package/package.json +7 -1
  265. package/src/agents/adapters.ts +64 -23
  266. package/src/agents/builders.ts +3 -3
  267. package/src/agents/context-compaction.ts +261 -0
  268. package/src/agents/errors.ts +2 -2
  269. package/src/agents/execution.ts +14 -2
  270. package/src/agents/ids.ts +5 -0
  271. package/src/agents/index.ts +32 -6
  272. package/src/agents/request.ts +5 -0
  273. package/src/agents/streams.ts +56 -0
  274. package/src/agents/thread-context-projection.ts +93 -0
  275. package/src/agents/tool-definition.ts +17 -2
  276. package/src/agents/tool-result.ts +61 -0
  277. package/src/agents/types.ts +57 -1
  278. package/src/agents/validation.ts +36 -6
  279. package/src/http/api-routes.ts +7 -7
  280. package/src/index.ts +27 -0
  281. package/src/lake-storage/types.ts +2 -1
  282. package/src/materialization/model.ts +4 -0
  283. package/src/materializer/edits/apply.ts +55 -2
  284. package/src/materializer/edits/operations.ts +8 -1
  285. package/src/materializer/edits/working-state.ts +7 -0
  286. package/src/materializer/effective/resolve.ts +78 -9
  287. package/src/materializer/execution/work-records.ts +3 -1
  288. package/src/materializer/projections/entry-validator.ts +23 -1
  289. package/src/materializer/projections/replacement-plan.ts +2 -0
  290. package/src/materializer/shared/normalize.ts +16 -0
  291. package/src/materializer/telemetry/append.ts +33 -16
  292. package/src/models/index.ts +71 -0
  293. package/src/objects/execution.ts +20 -0
  294. package/src/objects/link/endpoints.ts +2 -1
  295. package/src/objects/query/executor.ts +42 -11
  296. package/src/objects/query/explain.ts +11 -0
  297. package/src/objects/query/index.ts +6 -0
  298. package/src/objects/query/ir.ts +16 -0
  299. package/src/objects/query/links.ts +308 -0
  300. package/src/objects/query/normalize.ts +40 -1
  301. package/src/objects/query/planner.ts +5 -0
  302. package/src/objects/query/validate.ts +58 -2
  303. package/src/projections/builders.ts +320 -50
  304. package/src/projections/index.ts +7 -0
  305. package/src/projections/internal.ts +4 -1
  306. package/src/projections/ownership.ts +5 -5
  307. package/src/projections/registry.ts +16 -3
  308. package/src/projections/revision.ts +35 -5
  309. package/src/projections/run-dispatch.ts +10 -1
  310. package/src/projections/timestamp.ts +66 -0
  311. package/src/projections/types.ts +20 -9
  312. package/src/projections/validation.ts +85 -19
  313. package/src/query.ts +2 -0
  314. package/src/queues/index.ts +1 -0
  315. package/src/queues/types.ts +8 -0
  316. package/src/runtime/ai-cost.ts +15 -0
  317. package/src/runtime/create.ts +4 -0
  318. package/src/runtime/definitions.ts +3 -0
  319. package/src/runtime/host.ts +2 -0
  320. package/src/runtime/resolve-definitions.ts +28 -0
  321. package/src/storage/agents/in-memory.ts +186 -4
  322. package/src/storage/agents/index.ts +5 -0
  323. package/src/storage/agents/provider.ts +225 -0
  324. package/src/storage/agents/types.ts +82 -3
  325. package/src/storage/ai-cost/analytics.ts +602 -0
  326. package/src/storage/ai-cost/codec.ts +136 -0
  327. package/src/storage/ai-cost/errors.ts +12 -0
  328. package/src/storage/ai-cost/in-memory.ts +164 -0
  329. package/src/storage/ai-cost/index.ts +35 -0
  330. package/src/storage/ai-cost/provider.ts +20 -0
  331. package/src/storage/ai-cost/types.ts +193 -0
  332. package/src/storage/ai-cost/validation.ts +337 -0
  333. package/src/storage/ai-usage/in-memory.ts +23 -0
  334. package/src/storage/ai-usage/index.ts +1 -0
  335. package/src/storage/ai-usage/types.ts +10 -0
  336. package/src/storage/in-memory/index.ts +50 -0
  337. package/src/storage/index.ts +48 -0
  338. package/src/storage/objects/in-memory.ts +103 -16
  339. package/src/storage/objects/index.ts +9 -0
  340. package/src/storage/objects/keys.ts +36 -0
  341. package/src/storage/objects/types.ts +34 -6
  342. package/src/storage/ontology/in-memory/materializations.ts +1 -0
  343. package/src/storage/ontology/materializations.ts +3 -0
  344. package/src/storage/ontology/provider-header-validation.ts +2 -2
  345. package/src/storage/operation-scope.ts +1 -0
  346. package/src/storage/types.ts +2 -0
  347. package/src/testing/agent-storage-contract.ts +353 -2
  348. package/src/testing/ai-cost-storage-contract.ts +320 -0
  349. package/src/testing/ai-usage-storage-contract.ts +35 -0
  350. package/src/testing/effective-storage-contract.ts +194 -4
  351. package/src/testing/index.ts +5 -0
  352. package/src/testing/lake-storage-contract.ts +56 -0
  353. package/src/testing/materializer-storage-contract.ts +120 -2
  354. package/src/testing/object-query-contract.ts +208 -1
  355. package/src/workers/queue-worker.ts +14 -1
  356. package/src/workflows/execution.ts +31 -10
  357. package/dist/agents/prompt.d.ts +0 -15
  358. package/dist/agents/prompt.d.ts.map +0 -1
  359. package/dist/chunk-0mbx247x.js.map +0 -43
  360. package/dist/chunk-34bqh420.js.map +0 -23
  361. package/dist/chunk-57zpb99z.js.map +0 -10
  362. package/dist/chunk-663csy96.js.map +0 -10
  363. package/dist/chunk-6wetht33.js +0 -89
  364. package/dist/chunk-6wetht33.js.map +0 -10
  365. package/dist/chunk-88ppkr54.js.map +0 -12
  366. package/dist/chunk-nnyp53zt.js.map +0 -13
  367. package/dist/chunk-nten49ta.js.map +0 -12
  368. package/dist/chunk-st4xgxey.js.map +0 -45
  369. package/dist/chunk-vp1vc6ee.js +0 -35
  370. package/dist/chunk-vp1vc6ee.js.map +0 -11
  371. package/src/agents/prompt.ts +0 -57
  372. /package/dist/{chunk-sa4340y1.js.map → chunk-1yz3x65y.js.map} +0 -0
  373. /package/dist/{chunk-gqdd7508.js.map → chunk-4rh2m6zg.js.map} +0 -0
  374. /package/dist/{chunk-4x43bkbp.js.map → chunk-a09jx26t.js.map} +0 -0
  375. /package/dist/{chunk-zg9yryhz.js.map → chunk-cbkm2vam.js.map} +0 -0
  376. /package/dist/{chunk-8ryen3p3.js.map → chunk-f6erf2vv.js.map} +0 -0
  377. /package/dist/{chunk-bct7hmfc.js.map → chunk-g13869yf.js.map} +0 -0
  378. /package/dist/{chunk-0k4avqr2.js.map → chunk-hbeh8j9w.js.map} +0 -0
  379. /package/dist/{chunk-qvybnnpe.js.map → chunk-nzw7sm3b.js.map} +0 -0
  380. /package/dist/{chunk-bh6k3nc6.js.map → chunk-rs1wbvy6.js.map} +0 -0
  381. /package/dist/{chunk-7pc8b818.js.map → chunk-sxwk41qa.js.map} +0 -0
  382. /package/dist/{chunk-5egfka8j.js.map → chunk-tycbzedm.js.map} +0 -0
  383. /package/dist/{chunk-g9t3kdtx.js.map → chunk-x2yw73hy.js.map} +0 -0
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/storage/ai-usage/errors.ts", "../src/storage/ai-usage/usage.ts", "../src/storage/ai-usage/record.ts", "../src/storage/ai-usage/in-memory.ts", "../src/storage/ai-cost/analytics.ts", "../src/storage/ai-cost/validation.ts"],
4
+ "sourcesContent": [
5
+ "export type AiUsageStorageErrorCode = \"duplicate_id\" | \"missing_execution\"\n\n/** Storage failure specific to the AI model-call usage ledger. */\nexport class AiUsageStorageError extends Error {\n readonly name = \"AiUsageStorageError\"\n\n constructor(\n readonly code: AiUsageStorageErrorCode,\n message: string\n ) {\n super(message)\n }\n}\n",
6
+ "import type { AiModelCallUsage, AiModelCallUsageInput } from \"./types\"\n\nconst USAGE_FIELDS = [\n \"inputTokens\",\n \"outputTokens\",\n \"uncachedInputTokens\",\n \"cacheReadInputTokens\",\n \"cacheWriteInputTokens\",\n \"textOutputTokens\",\n \"reasoningOutputTokens\",\n] as const\n\ntype AiUsageField = (typeof USAGE_FIELDS)[number]\n\n/** Validate provider-neutral counts and derive total/reporting fields without inventing zeroes. */\nexport function normalizeAiModelCallUsage(input: AiModelCallUsageInput): AiModelCallUsage {\n for (const field of USAGE_FIELDS) {\n assertUsageCount(input[field], field)\n }\n\n const totalTokens =\n input.inputTokens === undefined || input.outputTokens === undefined\n ? undefined\n : addUsageCounts(input.inputTokens, input.outputTokens, \"totalTokens\")\n const reportingStatus =\n input.inputTokens !== undefined && input.outputTokens !== undefined\n ? \"complete\"\n : USAGE_FIELDS.some((field) => input[field] !== undefined)\n ? \"partial\"\n : \"unavailable\"\n\n return {\n ...(input.inputTokens === undefined ? {} : { inputTokens: input.inputTokens }),\n ...(input.outputTokens === undefined ? {} : { outputTokens: input.outputTokens }),\n ...(totalTokens === undefined ? {} : { totalTokens }),\n ...(input.uncachedInputTokens === undefined\n ? {}\n : { uncachedInputTokens: input.uncachedInputTokens }),\n ...(input.cacheReadInputTokens === undefined\n ? {}\n : { cacheReadInputTokens: input.cacheReadInputTokens }),\n ...(input.cacheWriteInputTokens === undefined\n ? {}\n : { cacheWriteInputTokens: input.cacheWriteInputTokens }),\n ...(input.textOutputTokens === undefined ? {} : { textOutputTokens: input.textOutputTokens }),\n ...(input.reasoningOutputTokens === undefined\n ? {}\n : { reasoningOutputTokens: input.reasoningOutputTokens }),\n reportingStatus,\n }\n}\n\n/**\n * Aggregate model-call usage without treating a missing count as zero.\n *\n * A field is present only when every call reported it. This prevents a partial provider response\n * from becoming an apparently complete execution total. Zero remains a reported value.\n */\nexport function aggregateAiModelCallUsage(\n usages: Iterable<AiModelCallUsageInput>\n): AiModelCallUsage {\n const normalized = Array.from(usages, normalizeAiModelCallUsage)\n const fields = Object.fromEntries(\n USAGE_FIELDS.map((field) => [field, sumUsageField(normalized, field)])\n ) as Record<AiUsageField, number | undefined>\n const aggregate = normalizeAiModelCallUsage(fields)\n\n if (\n aggregate.reportingStatus === \"unavailable\" &&\n normalized.some((usage) => usage.reportingStatus !== \"unavailable\")\n ) {\n return { ...aggregate, reportingStatus: \"partial\" }\n }\n return aggregate\n}\n\nfunction sumUsageField(\n usages: readonly AiModelCallUsage[],\n field: AiUsageField\n): number | undefined {\n if (usages.length === 0) return undefined\n\n let total = 0\n for (const usage of usages) {\n const value = usage[field]\n if (value === undefined) return undefined\n total = addUsageCounts(total, value, `aggregate ${field}`)\n }\n return total\n}\n\nfunction assertUsageCount(value: number | undefined, field: AiUsageField): void {\n if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {\n throw new TypeError(`[Sixb] AI model-call usage ${field} must be a non-negative safe integer.`)\n }\n}\n\nfunction addUsageCounts(left: number, right: number, field: string): number {\n const result = left + right\n if (!Number.isSafeInteger(result)) {\n throw new TypeError(`[Sixb] AI model-call usage ${field} exceeds the safe integer range.`)\n }\n return result\n}\n",
7
+ "import { normalizeRequesterGroupIds } from \"../../auth/attribution\"\nimport { assertJsonValue, isPlainRecord } from \"../../json\"\nimport type { AiModelCallUsageRecord, RecordAiModelCallInput } from \"./types\"\nimport { normalizeAiModelCallUsage } from \"./usage\"\n\n/** Validate and defensively snapshot one provider-neutral model-call ledger input. */\nexport function normalizeAiModelCallRecord(input: RecordAiModelCallInput): AiModelCallUsageRecord {\n assertNonBlank(input.id, \"id\")\n assertNonBlank(input.projectId, \"projectId\")\n assertAiUsageExecutionId(input.executionId)\n assertPositiveSafeInteger(input.attempt, \"attempt\")\n assertNonBlank(input.callId, \"callId\")\n assertNonBlank(input.providerId, \"providerId\")\n assertNonBlank(input.requestedModelId, \"requestedModelId\")\n if (input.responseModelId !== undefined) {\n assertNonBlank(input.responseModelId, \"responseModelId\")\n }\n assertNonBlank(input.responseId, \"responseId\")\n\n const occurredAt = cloneValidDate(input.occurredAt, \"occurredAt\")\n const recordedAt = cloneValidDate(input.recordedAt ?? new Date(), \"recordedAt\")\n const requesterGroupIds = normalizeRequesterGroupIds(input.requesterGroupIds)\n const rawUsage = cloneRawUsage(input.rawUsage)\n\n return {\n id: input.id,\n projectId: input.projectId,\n executionId: input.executionId,\n attempt: input.attempt,\n callId: input.callId,\n requesterGroupIds,\n providerId: input.providerId,\n requestedModelId: input.requestedModelId,\n ...(input.responseModelId === undefined ? {} : { responseModelId: input.responseModelId }),\n responseId: input.responseId,\n usage: normalizeAiModelCallUsage(input.usage),\n ...(rawUsage === undefined ? {} : { rawUsage }),\n occurredAt,\n recordedAt,\n }\n}\n\n/** Validate a durable execution reference at storage and query boundaries. */\nexport function assertAiUsageExecutionId(executionId: string): void {\n assertNonBlank(executionId, \"executionId\")\n}\n\nfunction cloneRawUsage(rawUsage: RecordAiModelCallInput[\"rawUsage\"]) {\n if (rawUsage === undefined) return undefined\n if (!isPlainRecord(rawUsage)) {\n throw new TypeError(\"[Sixb] AI usage rawUsage must be a JSON object.\")\n }\n assertJsonValue(rawUsage, \"AI usage rawUsage\")\n return structuredClone(rawUsage)\n}\n\nfunction assertNonBlank(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`[Sixb] AI usage ${field} must be nonblank.`)\n }\n}\n\nfunction assertPositiveSafeInteger(value: number, field: string): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new TypeError(`[Sixb] AI usage ${field} must be a positive safe integer.`)\n }\n}\n\nfunction cloneValidDate(value: Date, field: string): Date {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {\n throw new TypeError(`[Sixb] AI usage ${field} must be a valid Date.`)\n }\n return new Date(value)\n}\n",
8
+ "import type { ExecutionStorage } from \"../executions\"\nimport { AiUsageStorageError } from \"./errors\"\nimport { assertAiUsageExecutionId, normalizeAiModelCallRecord } from \"./record\"\nimport type {\n AiModelCallUsageRecord,\n AiUsageExecutionSummary,\n AiUsageStorage,\n GetLatestAiModelCallForExecutionInput,\n RecordAiModelCallInput,\n RecordAiModelCallResult,\n SummarizeAiUsageExecutionInput,\n SummarizeAiUsageExecutionsInput,\n} from \"./types\"\nimport { aggregateAiModelCallUsage } from \"./usage\"\n\nexport interface InMemoryAiUsageGroupRow {\n readonly projectId: string\n readonly usageRecordId: string\n readonly groupId: string\n readonly occurredAt: Date\n}\n\nexport interface InMemoryAiUsageStorageSnapshot {\n readonly records: Map<string, AiModelCallUsageRecord>\n readonly recordKeysByIdempotencyKey: Map<string, string>\n readonly groupRows: Map<string, InMemoryAiUsageGroupRow>\n}\n\n/** In-memory model-call ledger used by development runtimes and storage contract tests. */\nexport class InMemoryAiUsageStorage implements AiUsageStorage {\n private readonly records = new Map<string, AiModelCallUsageRecord>()\n private readonly recordKeysByIdempotencyKey = new Map<string, string>()\n private readonly groupRows = new Map<string, InMemoryAiUsageGroupRow>()\n\n constructor(private readonly executions: Pick<ExecutionStorage, \"getById\">) {}\n\n async recordModelCall(input: RecordAiModelCallInput): Promise<RecordAiModelCallResult> {\n const record = normalizeAiModelCallRecord(input)\n await this.assertExecutionExists(record.projectId, record.executionId)\n const idempotencyKey = modelCallIdempotencyKey(record)\n const existingRecordKey = this.recordKeysByIdempotencyKey.get(idempotencyKey)\n if (existingRecordKey !== undefined) {\n const existing = this.records.get(existingRecordKey)\n if (!existing) {\n throw new Error(\"[Sixb] In-memory AI usage idempotency index is inconsistent.\")\n }\n return { record: structuredClone(existing), created: false }\n }\n\n const recordKey = modelCallRecordKey(record.projectId, record.id)\n if (this.records.has(recordKey)) {\n throw new AiUsageStorageError(\n \"duplicate_id\",\n `[Sixb] AI usage record '${record.id}' already exists for project '${record.projectId}'.`\n )\n }\n\n this.records.set(recordKey, structuredClone(record))\n this.recordKeysByIdempotencyKey.set(idempotencyKey, recordKey)\n for (const groupId of record.requesterGroupIds) {\n const row: InMemoryAiUsageGroupRow = {\n projectId: record.projectId,\n usageRecordId: record.id,\n groupId,\n occurredAt: record.occurredAt,\n }\n this.groupRows.set(groupRowKey(row), row)\n }\n\n return { record: structuredClone(record), created: true }\n }\n\n async getLatestForExecution(\n input: GetLatestAiModelCallForExecutionInput\n ): Promise<AiModelCallUsageRecord | null> {\n assertAiUsageExecutionId(input.executionId)\n if (typeof input.projectId !== \"string\" || input.projectId.trim().length === 0) {\n throw new TypeError(\"[Sixb] AI usage projectId must be nonblank.\")\n }\n\n let latest: AiModelCallUsageRecord | null = null\n for (const record of this.records.values()) {\n if (record.projectId !== input.projectId || record.executionId !== input.executionId) continue\n if (\n !latest ||\n record.occurredAt.getTime() > latest.occurredAt.getTime() ||\n (record.occurredAt.getTime() === latest.occurredAt.getTime() && record.id > latest.id)\n ) {\n latest = record\n }\n }\n return latest ? structuredClone(latest) : null\n }\n\n async summarizeExecution(\n input: SummarizeAiUsageExecutionInput\n ): Promise<AiUsageExecutionSummary> {\n const [summary] = await this.summarizeExecutions({\n projectId: input.projectId,\n executionIds: [input.executionId],\n })\n return summary!\n }\n\n async summarizeExecutions(\n input: SummarizeAiUsageExecutionsInput\n ): Promise<readonly AiUsageExecutionSummary[]> {\n if (typeof input.projectId !== \"string\" || input.projectId.trim().length === 0) {\n throw new TypeError(\"[Sixb] AI usage projectId must be nonblank.\")\n }\n\n const usageByExecutionId = new Map<string, AiModelCallUsageRecord[\"usage\"][]>()\n for (const executionId of input.executionIds) {\n assertAiUsageExecutionId(executionId)\n usageByExecutionId.set(executionId, [])\n }\n if (usageByExecutionId.size === 0) return []\n\n for (const record of this.records.values()) {\n if (record.projectId !== input.projectId) continue\n usageByExecutionId.get(record.executionId)?.push(record.usage)\n }\n\n return input.executionIds.map((executionId) => {\n const usages = usageByExecutionId.get(executionId) ?? []\n return {\n modelCallCount: usages.length,\n usage: aggregateAiModelCallUsage(usages),\n }\n })\n }\n\n snapshot(): InMemoryAiUsageStorageSnapshot {\n return structuredClone({\n records: this.records,\n recordKeysByIdempotencyKey: this.recordKeysByIdempotencyKey,\n groupRows: this.groupRows,\n })\n }\n\n restore(snapshot: InMemoryAiUsageStorageSnapshot): void {\n replaceMap(this.records, snapshot.records)\n replaceMap(this.recordKeysByIdempotencyKey, snapshot.recordKeysByIdempotencyKey)\n replaceMap(this.groupRows, snapshot.groupRows)\n }\n\n private async assertExecutionExists(projectId: string, executionId: string): Promise<void> {\n const execution = await this.executions.getById({ projectId, id: executionId })\n if (execution) return\n throw new AiUsageStorageError(\n \"missing_execution\",\n `[Sixb] AI usage execution '${executionId}' does not exist in project '${projectId}'.`\n )\n }\n}\n\nfunction modelCallRecordKey(projectId: string, id: string): string {\n return JSON.stringify([projectId, id])\n}\n\nfunction modelCallIdempotencyKey(\n record: Pick<\n AiModelCallUsageRecord,\n \"projectId\" | \"executionId\" | \"attempt\" | \"callId\" | \"responseId\"\n >\n): string {\n return JSON.stringify([\n record.projectId,\n record.executionId,\n record.attempt,\n record.callId,\n record.responseId,\n ])\n}\n\nfunction groupRowKey(row: InMemoryAiUsageGroupRow): string {\n return JSON.stringify([row.projectId, row.usageRecordId, row.groupId])\n}\n\nfunction replaceMap<TKey, TValue>(target: Map<TKey, TValue>, source: Map<TKey, TValue>): void {\n target.clear()\n for (const [key, value] of structuredClone(source)) {\n target.set(key, value)\n }\n}\n",
9
+ "import {\n type AiModelCallUsage,\n type AiModelCallUsageRecord,\n aggregateAiModelCallUsage,\n normalizeAiModelCallUsage,\n} from \"../ai-usage\"\nimport type {\n AiAccountingAgentBreakdown,\n AiAccountingAggregate,\n AiAccountingAttribution,\n AiAccountingBucket,\n AiAccountingModelBreakdown,\n AiAccountingOverview,\n AiAccountingTimeBucket,\n AiAccountingWorkflowBreakdown,\n AiCostSummary,\n AiModelCallAccountingItem,\n AiModelCallCostRecord,\n AiMoney,\n ListAiModelCallAccountingInput,\n ListAiModelCallAccountingResult,\n QueryAiAccountingOverviewInput,\n} from \"./types\"\n\nconst DEFAULT_MODEL_CALL_PAGE_SIZE = 50\nconst MAX_MODEL_CALL_PAGE_SIZE = 200\nconst MAX_CHART_BUCKETS = 10_000\n\n/** One joined immutable model-call row used by in-memory analytics and bounded SQL pages. */\nexport interface AiAccountingRecordSetItem {\n readonly usage: AiModelCallUsageRecord\n readonly attribution?: AiAccountingAttribution\n readonly cost?: AiModelCallCostRecord\n}\n\nexport interface NormalizedAiAccountingQuery {\n readonly projectId: string\n readonly from: Date\n readonly to: Date\n readonly providerId?: string\n readonly modelId?: string\n}\n\nexport interface NormalizedAiModelCallAccountingQuery extends NormalizedAiAccountingQuery {\n readonly executionId?: string\n readonly valuationStatus?: ListAiModelCallAccountingInput[\"valuationStatus\"]\n readonly limit: number\n readonly offset: number\n}\n\ninterface AiAccountingUsageMeterFragment {\n readonly presentCallCount: string\n readonly total: string | null\n}\n\n/** One SQL-aggregated currency fragment; providers merge fragments without loading model calls. */\nexport interface AiAccountingAggregateFragment {\n readonly dimension: \"totals\" | \"series\" | \"model\" | \"agent\" | \"workflow\"\n readonly start?: Date\n readonly providerId?: string\n readonly modelId?: string\n readonly agentId?: string\n readonly workflowId?: string\n readonly modelCallCount: string\n readonly usage: {\n readonly reportedCallCount: string\n readonly inputTokens: AiAccountingUsageMeterFragment\n readonly outputTokens: AiAccountingUsageMeterFragment\n readonly uncachedInputTokens: AiAccountingUsageMeterFragment\n readonly cacheReadInputTokens: AiAccountingUsageMeterFragment\n readonly cacheWriteInputTokens: AiAccountingUsageMeterFragment\n readonly textOutputTokens: AiAccountingUsageMeterFragment\n readonly reasoningOutputTokens: AiAccountingUsageMeterFragment\n }\n readonly costs: {\n readonly amount?: AiMoney\n readonly ratedCallCount: string\n readonly unpriceableCallCount: string\n readonly unvaluedCallCount: string\n }\n}\n\nexport function normalizeAiAccountingQuery(\n input: Omit<QueryAiAccountingOverviewInput, \"bucket\"> | ListAiModelCallAccountingInput\n): NormalizedAiAccountingQuery {\n assertNonBlank(input.projectId, \"accounting projectId\")\n assertDate(input.from, \"accounting from\")\n assertDate(input.to, \"accounting to\")\n if (input.from.getTime() >= input.to.getTime()) {\n throw new TypeError(\"[Sixb] AI accounting from must be before to.\")\n }\n if (input.providerId !== undefined) assertNonBlank(input.providerId, \"accounting providerId\")\n if (input.modelId !== undefined) assertNonBlank(input.modelId, \"accounting modelId\")\n return {\n projectId: input.projectId,\n from: new Date(input.from),\n to: new Date(input.to),\n ...(input.providerId === undefined ? {} : { providerId: input.providerId }),\n ...(input.modelId === undefined ? {} : { modelId: input.modelId }),\n }\n}\n\nexport function normalizeAiModelCallAccountingQuery(\n input: ListAiModelCallAccountingInput\n): NormalizedAiModelCallAccountingQuery {\n const query = normalizeAiAccountingQuery(input)\n if (input.executionId !== undefined) {\n assertNonBlank(input.executionId, \"accounting executionId\")\n }\n const { limit, offset } = normalizePage(input.limit, input.offset)\n return {\n ...query,\n ...(input.executionId === undefined ? {} : { executionId: input.executionId }),\n ...(input.valuationStatus === undefined ? {} : { valuationStatus: input.valuationStatus }),\n limit,\n offset,\n }\n}\n\nexport function aiAccountingItemMatchesQuery(\n item: AiAccountingRecordSetItem,\n query: NormalizedAiAccountingQuery\n): boolean {\n const occurredAt = item.usage.occurredAt.getTime()\n return (\n item.usage.projectId === query.projectId &&\n occurredAt >= query.from.getTime() &&\n occurredAt < query.to.getTime() &&\n (query.providerId === undefined || item.usage.providerId === query.providerId) &&\n (query.modelId === undefined || item.usage.requestedModelId === query.modelId)\n )\n}\n\nexport function buildAiAccountingOverview(\n input: QueryAiAccountingOverviewInput,\n source: Iterable<AiAccountingRecordSetItem>\n): AiAccountingOverview {\n const query = normalizeAiAccountingQuery(input)\n assertAiAccountingBucket(input.bucket)\n const items = Array.from(source).filter((item) => aiAccountingItemMatchesQuery(item, query))\n const periods = accountingPeriods(query.from, query.to, input.bucket)\n const periodItems = new Map<number, AiAccountingRecordSetItem[]>(\n periods.map((period) => [period.start.getTime(), []])\n )\n const modelItems = new Map<string, AiAccountingRecordSetItem[]>()\n const agentItems = new Map<string, AiAccountingRecordSetItem[]>()\n const workflowItems = new Map<string, AiAccountingRecordSetItem[]>()\n\n for (const item of items) {\n const periodStart = aiAccountingBucketStart(item.usage.occurredAt, input.bucket).getTime()\n periodItems.get(periodStart)?.push(item)\n appendGrouped(\n modelItems,\n JSON.stringify([item.usage.providerId, item.usage.requestedModelId]),\n item\n )\n if (item.attribution) appendGrouped(agentItems, item.attribution.agentId, item)\n if (item.attribution?.kind === \"workflowAgent\") {\n appendGrouped(workflowItems, item.attribution.workflowId, item)\n }\n }\n\n const series: AiAccountingTimeBucket[] = periods.map((period) => ({\n ...period,\n ...aggregateAccountingItems(periodItems.get(period.start.getTime()) ?? []),\n }))\n const models: AiAccountingModelBreakdown[] = [...modelItems]\n .map(([key, grouped]) => {\n const [providerId, modelId] = JSON.parse(key) as [string, string]\n return { providerId, modelId, ...aggregateAccountingItems(grouped) }\n })\n .sort(compareModelBreakdowns)\n const agents: AiAccountingAgentBreakdown[] = [...agentItems]\n .map(([agentId, grouped]) => ({ agentId, ...aggregateAccountingItems(grouped) }))\n .sort(compareAgentBreakdowns)\n const workflows: AiAccountingWorkflowBreakdown[] = [...workflowItems]\n .map(([workflowId, grouped]) => ({ workflowId, ...aggregateAccountingItems(grouped) }))\n .sort(compareWorkflowBreakdowns)\n\n return structuredClone({\n range: { from: query.from, to: query.to },\n bucket: input.bucket,\n totals: aggregateAccountingItems(items),\n series,\n models,\n agents,\n workflows,\n })\n}\n\nexport function buildAiAccountingOverviewFromFragments(\n input: QueryAiAccountingOverviewInput,\n fragments: Iterable<AiAccountingAggregateFragment>\n): AiAccountingOverview {\n const query = normalizeAiAccountingQuery(input)\n const periods = accountingPeriods(query.from, query.to, input.bucket)\n const totals = aggregateFragmentAccumulator()\n const series = new Map<number, AggregateFragmentAccumulator>(\n periods.map((period) => [period.start.getTime(), aggregateFragmentAccumulator()])\n )\n const models = new Map<string, AggregateFragmentAccumulator>()\n const agents = new Map<string, AggregateFragmentAccumulator>()\n const workflows = new Map<string, AggregateFragmentAccumulator>()\n\n for (const fragment of fragments) {\n let target: AggregateFragmentAccumulator\n switch (fragment.dimension) {\n case \"totals\":\n target = totals\n break\n case \"series\": {\n const start = requiredFragmentDate(fragment.start, \"series start\")\n const existing = series.get(start.getTime())\n if (!existing) {\n throw new TypeError(\"[Sixb] AI accounting SQL series returned an unexpected bucket.\")\n }\n target = existing\n break\n }\n case \"model\":\n target = getFragmentAccumulator(\n models,\n JSON.stringify([\n requiredFragmentString(fragment.providerId, \"providerId\"),\n requiredFragmentString(fragment.modelId, \"modelId\"),\n ])\n )\n break\n case \"agent\":\n target = getFragmentAccumulator(agents, requiredFragmentString(fragment.agentId, \"agentId\"))\n break\n case \"workflow\":\n target = getFragmentAccumulator(\n workflows,\n requiredFragmentString(fragment.workflowId, \"workflowId\")\n )\n break\n }\n appendAggregateFragment(target, fragment)\n }\n\n return structuredClone({\n range: { from: query.from, to: query.to },\n bucket: input.bucket,\n totals: finishAggregateFragment(totals),\n series: periods.map((period) => ({\n ...period,\n ...finishAggregateFragment(series.get(period.start.getTime())!),\n })),\n models: [...models]\n .map(([key, value]) => {\n const [providerId, modelId] = JSON.parse(key) as [string, string]\n return { providerId, modelId, ...finishAggregateFragment(value) }\n })\n .sort(compareModelBreakdowns),\n agents: [...agents]\n .map(([agentId, value]) => ({ agentId, ...finishAggregateFragment(value) }))\n .sort(compareAgentBreakdowns),\n workflows: [...workflows]\n .map(([workflowId, value]) => ({ workflowId, ...finishAggregateFragment(value) }))\n .sort(compareWorkflowBreakdowns),\n })\n}\n\nexport function buildAiModelCallAccountingList(\n input: ListAiModelCallAccountingInput,\n source: Iterable<AiAccountingRecordSetItem>\n): ListAiModelCallAccountingResult {\n const query = normalizeAiModelCallAccountingQuery(input)\n const { limit, offset } = query\n const items = Array.from(source)\n .filter((item) => aiAccountingItemMatchesQuery(item, query))\n .map(toAccountingItem)\n .filter(\n (item) =>\n (input.executionId === undefined || item.usage.executionId === input.executionId) &&\n (input.valuationStatus === undefined || item.valuationStatus === input.valuationStatus)\n )\n .sort(compareAccountingItems)\n const page = items.slice(offset, offset + limit)\n return structuredClone({\n items: page,\n hasMore: offset + page.length < items.length,\n total: items.length,\n })\n}\n\nexport function toAccountingItem(item: AiAccountingRecordSetItem): AiModelCallAccountingItem {\n return {\n usage: item.usage,\n ...(item.attribution === undefined ? {} : { attribution: item.attribution }),\n ...(item.cost === undefined ? {} : { cost: item.cost }),\n valuationStatus: item.cost?.status ?? \"unvalued\",\n }\n}\n\nexport function aiAccountingBucketStart(at: Date, bucket: AiAccountingBucket): Date {\n assertDate(at, \"accounting bucket timestamp\")\n assertAiAccountingBucket(bucket)\n const start = new Date(at)\n start.setUTCMinutes(0, 0, 0)\n if (bucket === \"hour\") return start\n start.setUTCHours(0)\n if (bucket === \"day\") return start\n const mondayOffset = (start.getUTCDay() + 6) % 7\n start.setUTCDate(start.getUTCDate() - mondayOffset)\n return start\n}\n\nfunction aggregateAccountingItems(\n items: readonly AiAccountingRecordSetItem[]\n): AiAccountingAggregate {\n return {\n modelCallCount: items.length,\n usage: aggregateAiModelCallUsage(items.map((item) => item.usage.usage)),\n costs: aggregateCosts(items),\n }\n}\n\nfunction aggregateCosts(items: readonly AiAccountingRecordSetItem[]): AiCostSummary {\n const amounts = new Map<string, bigint>()\n let ratedCallCount = 0\n let unpriceableCallCount = 0\n let unvaluedCallCount = 0\n for (const item of items) {\n if (item.cost?.status === \"rated\") {\n ratedCallCount += 1\n addAmount(amounts, item.cost.money.currency, item.cost.money.amountNanos)\n } else if (item.cost?.status === \"unpriceable\") {\n unpriceableCallCount += 1\n } else {\n unvaluedCallCount += 1\n }\n }\n return {\n amounts: [...amounts]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([currency, amountNanos]) => ({ currency, amountNanos: amountNanos.toString() })),\n ratedCallCount,\n unpriceableCallCount,\n unvaluedCallCount,\n }\n}\n\nconst AGGREGATE_USAGE_FIELDS = [\n \"inputTokens\",\n \"outputTokens\",\n \"uncachedInputTokens\",\n \"cacheReadInputTokens\",\n \"cacheWriteInputTokens\",\n \"textOutputTokens\",\n \"reasoningOutputTokens\",\n] as const\n\ntype AggregateUsageField = (typeof AGGREGATE_USAGE_FIELDS)[number]\n\ninterface AggregateFragmentAccumulator {\n modelCallCount: bigint\n reportedUsageCallCount: bigint\n usage: Record<AggregateUsageField, { presentCallCount: bigint; total: bigint }>\n amounts: Map<string, bigint>\n ratedCallCount: bigint\n unpriceableCallCount: bigint\n unvaluedCallCount: bigint\n}\n\nfunction aggregateFragmentAccumulator(): AggregateFragmentAccumulator {\n return {\n modelCallCount: 0n,\n reportedUsageCallCount: 0n,\n usage: Object.fromEntries(\n AGGREGATE_USAGE_FIELDS.map((field) => [field, { presentCallCount: 0n, total: 0n }])\n ) as AggregateFragmentAccumulator[\"usage\"],\n amounts: new Map(),\n ratedCallCount: 0n,\n unpriceableCallCount: 0n,\n unvaluedCallCount: 0n,\n }\n}\n\nfunction getFragmentAccumulator(\n values: Map<string, AggregateFragmentAccumulator>,\n key: string\n): AggregateFragmentAccumulator {\n const existing = values.get(key)\n if (existing) return existing\n const created = aggregateFragmentAccumulator()\n values.set(key, created)\n return created\n}\n\nfunction appendAggregateFragment(\n target: AggregateFragmentAccumulator,\n fragment: AiAccountingAggregateFragment\n): void {\n target.modelCallCount += naturalBigInt(fragment.modelCallCount, \"modelCallCount\")\n target.reportedUsageCallCount += naturalBigInt(\n fragment.usage.reportedCallCount,\n \"reported usage call count\"\n )\n for (const field of AGGREGATE_USAGE_FIELDS) {\n const source = fragment.usage[field]\n const presentCallCount = naturalBigInt(source.presentCallCount, `${field} call count`)\n target.usage[field].presentCallCount += presentCallCount\n if (source.total !== null) {\n target.usage[field].total += naturalBigInt(source.total, `${field} total`)\n } else if (presentCallCount !== 0n) {\n throw new TypeError(`[Sixb] AI accounting SQL ${field} total is missing.`)\n }\n }\n target.ratedCallCount += naturalBigInt(fragment.costs.ratedCallCount, \"rated call count\")\n target.unpriceableCallCount += naturalBigInt(\n fragment.costs.unpriceableCallCount,\n \"unpriceable call count\"\n )\n target.unvaluedCallCount += naturalBigInt(fragment.costs.unvaluedCallCount, \"unvalued call count\")\n if (fragment.costs.amount) {\n addAmount(target.amounts, fragment.costs.amount.currency, fragment.costs.amount.amountNanos)\n }\n}\n\nfunction finishAggregateFragment(value: AggregateFragmentAccumulator): AiAccountingAggregate {\n const classifiedCallCount =\n value.ratedCallCount + value.unpriceableCallCount + value.unvaluedCallCount\n if (\n classifiedCallCount !== value.modelCallCount ||\n value.reportedUsageCallCount > value.modelCallCount ||\n AGGREGATE_USAGE_FIELDS.some(\n (field) => value.usage[field].presentCallCount > value.modelCallCount\n )\n ) {\n throw new TypeError(\"[Sixb] AI accounting SQL aggregate counts are inconsistent.\")\n }\n const modelCallCount = safeAggregateNumber(value.modelCallCount, \"model-call count\")\n const usageInput: Partial<Record<AggregateUsageField, number>> = {}\n if (value.modelCallCount > 0n) {\n for (const field of AGGREGATE_USAGE_FIELDS) {\n const aggregate = value.usage[field]\n if (aggregate.presentCallCount === value.modelCallCount) {\n usageInput[field] = safeAggregateNumber(aggregate.total, field)\n }\n }\n }\n let usage: AiModelCallUsage = normalizeAiModelCallUsage(usageInput)\n if (usage.reportingStatus === \"unavailable\" && value.reportedUsageCallCount > 0n) {\n usage = { ...usage, reportingStatus: \"partial\" }\n }\n return {\n modelCallCount,\n usage,\n costs: {\n amounts: [...value.amounts]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([currency, amountNanos]) => ({ currency, amountNanos: amountNanos.toString() })),\n ratedCallCount: safeAggregateNumber(value.ratedCallCount, \"rated call count\"),\n unpriceableCallCount: safeAggregateNumber(\n value.unpriceableCallCount,\n \"unpriceable call count\"\n ),\n unvaluedCallCount: safeAggregateNumber(value.unvaluedCallCount, \"unvalued call count\"),\n },\n }\n}\n\nfunction naturalBigInt(value: string, field: string): bigint {\n if (!/^(0|[1-9]\\d*)$/.test(value)) {\n throw new TypeError(`[Sixb] AI accounting SQL ${field} must be a natural integer.`)\n }\n return BigInt(value)\n}\n\nfunction safeAggregateNumber(value: bigint, field: string): number {\n if (value > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new TypeError(`[Sixb] AI accounting ${field} exceeds the safe integer range.`)\n }\n return Number(value)\n}\n\nfunction requiredFragmentString(value: string | undefined, field: string): string {\n if (value === undefined || value.length === 0) {\n throw new TypeError(`[Sixb] AI accounting SQL ${field} is missing.`)\n }\n return value\n}\n\nfunction requiredFragmentDate(value: Date | undefined, field: string): Date {\n if (value === undefined) throw new TypeError(`[Sixb] AI accounting SQL ${field} is missing.`)\n assertDate(value, field)\n return value\n}\n\nfunction accountingPeriods(\n from: Date,\n to: Date,\n bucket: AiAccountingBucket\n): Array<{ start: Date; end: Date }> {\n const result: Array<{ start: Date; end: Date }> = []\n let cursor = aiAccountingBucketStart(from, bucket)\n while (cursor.getTime() < to.getTime()) {\n if (result.length >= MAX_CHART_BUCKETS) {\n throw new RangeError(`[Sixb] AI accounting query exceeds ${MAX_CHART_BUCKETS} chart buckets.`)\n }\n const next = nextBucket(cursor, bucket)\n result.push({ start: new Date(cursor), end: next })\n cursor = next\n }\n return result\n}\n\nfunction nextBucket(start: Date, bucket: AiAccountingBucket): Date {\n const next = new Date(start)\n if (bucket === \"hour\") next.setUTCHours(next.getUTCHours() + 1)\n else if (bucket === \"day\") next.setUTCDate(next.getUTCDate() + 1)\n else next.setUTCDate(next.getUTCDate() + 7)\n return next\n}\n\nfunction appendGrouped(\n groups: Map<string, AiAccountingRecordSetItem[]>,\n key: string,\n item: AiAccountingRecordSetItem\n): void {\n const existing = groups.get(key)\n if (existing) existing.push(item)\n else groups.set(key, [item])\n}\n\nfunction addAmount(amounts: Map<string, bigint>, currency: string, amountNanos: string): void {\n amounts.set(currency, (amounts.get(currency) ?? 0n) + BigInt(amountNanos))\n}\n\nfunction normalizePage(\n requestedLimit: number | undefined,\n requestedOffset: number | undefined\n): { limit: number; offset: number } {\n const limit = requestedLimit ?? DEFAULT_MODEL_CALL_PAGE_SIZE\n const offset = requestedOffset ?? 0\n if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_MODEL_CALL_PAGE_SIZE) {\n throw new TypeError(\n `[Sixb] AI accounting list limit must be an integer between 1 and ${MAX_MODEL_CALL_PAGE_SIZE}.`\n )\n }\n if (!Number.isSafeInteger(offset) || offset < 0) {\n throw new TypeError(\"[Sixb] AI accounting list offset must be a non-negative integer.\")\n }\n return { limit, offset }\n}\n\nfunction compareAccountingItems(\n left: AiModelCallAccountingItem,\n right: AiModelCallAccountingItem\n): number {\n return (\n right.usage.occurredAt.getTime() - left.usage.occurredAt.getTime() ||\n left.usage.id.localeCompare(right.usage.id)\n )\n}\n\nfunction compareAgentBreakdowns(\n left: AiAccountingAgentBreakdown,\n right: AiAccountingAgentBreakdown\n): number {\n return right.modelCallCount - left.modelCallCount || left.agentId.localeCompare(right.agentId)\n}\n\nfunction compareWorkflowBreakdowns(\n left: AiAccountingWorkflowBreakdown,\n right: AiAccountingWorkflowBreakdown\n): number {\n return (\n right.modelCallCount - left.modelCallCount || left.workflowId.localeCompare(right.workflowId)\n )\n}\n\nfunction compareModelBreakdowns(\n left: AiAccountingModelBreakdown,\n right: AiAccountingModelBreakdown\n): number {\n return (\n right.modelCallCount - left.modelCallCount ||\n left.providerId.localeCompare(right.providerId) ||\n left.modelId.localeCompare(right.modelId)\n )\n}\n\nfunction assertAiAccountingBucket(bucket: AiAccountingBucket): void {\n if (bucket !== \"hour\" && bucket !== \"day\" && bucket !== \"week\") {\n throw new TypeError(\"[Sixb] AI accounting bucket must be hour, day, or week.\")\n }\n}\n\nfunction assertDate(value: Date, label: string): void {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {\n throw new TypeError(`[Sixb] AI ${label} must be a valid Date.`)\n }\n}\n\nfunction assertNonBlank(value: string, label: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`[Sixb] AI ${label} must be nonblank.`)\n }\n}\n",
10
+ "import type { AiModelCallUsage, AiModelCallUsageRecord } from \"../ai-usage\"\nimport { normalizeAiModelCallUsage } from \"../ai-usage\"\nimport type {\n AiBillableMeter,\n AiBillingIdentity,\n AiCostComponent,\n AiModelCallCostRecord,\n AiPriceSource,\n AiPricingContext,\n AiRatedModelCallCostRecord,\n AiUnpriceableModelCallCostRecord,\n AiUnpriceableReason,\n} from \"./types\"\n\nconst SIGNED_INT64_MAX = 9_223_372_036_854_775_807n\nconst TOKENS_PER_MILLION = 1_000_000n\nconst HALF_MILLION = TOKENS_PER_MILLION / 2n\nconst MAX_NUMERIC_TEXT_LENGTH = 128\nconst METER_ORDER: Readonly<Record<AiBillableMeter, number>> = {\n \"tokens.input.total\": 0,\n \"tokens.input.uncached\": 1,\n \"tokens.input.cacheRead\": 2,\n \"tokens.input.cacheWrite\": 3,\n \"tokens.output.total\": 4,\n \"tokens.output.text\": 5,\n \"tokens.output.reasoning\": 6,\n}\nconst METERS = new Set(Object.keys(METER_ORDER))\nconst UNPRICEABLE_REASONS = new Set<AiUnpriceableReason>([\n \"missingBillingIdentity\",\n \"missingCatalogEntry\",\n \"missingUsageMeter\",\n \"unsupportedPricingDimension\",\n \"invalidUsageForFormula\",\n])\nconst CONTEXT_STRING_FIELDS = [\n \"serviceTier\",\n \"region\",\n \"inferenceGeo\",\n \"routedProviderId\",\n \"deploymentId\",\n \"inferenceProfileId\",\n \"mode\",\n] as const\n\nexport function normalizeAiPricingContext(input: AiPricingContext): AiPricingContext {\n if (typeof input !== \"object\" || input === null || Array.isArray(input)) {\n throw new TypeError(\"[Sixb] AI pricing context must be an object.\")\n }\n const result: Record<string, string | boolean | number> = {}\n for (const field of CONTEXT_STRING_FIELDS) {\n const value = input[field]\n if (value !== undefined) {\n assertNonBlank(value, `pricingContext.${field}`)\n result[field] = value\n }\n }\n if (input.batch !== undefined) {\n if (typeof input.batch !== \"boolean\") {\n throw new TypeError(\"[Sixb] AI pricingContext.batch must be boolean.\")\n }\n result.batch = input.batch\n }\n if (input.cacheWriteTtlSeconds !== undefined) {\n if (!Number.isSafeInteger(input.cacheWriteTtlSeconds) || input.cacheWriteTtlSeconds <= 0) {\n throw new TypeError(\n \"[Sixb] AI pricingContext.cacheWriteTtlSeconds must be a positive safe integer.\"\n )\n }\n result.cacheWriteTtlSeconds = input.cacheWriteTtlSeconds\n }\n return result\n}\n\nexport function normalizeAiModelCallCostRecord(\n input: AiModelCallCostRecord\n): AiModelCallCostRecord {\n assertNonBlank(input.projectId, \"cost record projectId\")\n assertNonBlank(input.usageRecordId, \"cost record usageRecordId\")\n const base = {\n projectId: input.projectId,\n usageRecordId: input.usageRecordId,\n pricingContext: normalizeAiPricingContext(input.pricingContext),\n priceSource: normalizePriceSource(input.priceSource),\n ratedAt: cloneDate(input.ratedAt, \"cost record ratedAt\"),\n }\n\n if (input.status === \"rated\") return normalizeRatedCost(input, base)\n if (input.status === \"unpriceable\") return normalizeUnpriceableCost(input, base)\n throw new TypeError(\"[Sixb] AI cost status is invalid.\")\n}\n\n/** Verify that a normalized valuation's billed quantities describe its usage record. */\nexport function aiModelCallCostMatchesUsage(\n record: AiModelCallCostRecord,\n usageRecord: AiModelCallUsageRecord\n): boolean {\n if (record.projectId !== usageRecord.projectId || record.usageRecordId !== usageRecord.id) {\n return false\n }\n if (record.status === \"unpriceable\") return true\n\n const usage = normalizeAiModelCallUsage(usageRecord.usage)\n const components = new Map(record.components.map((component) => [component.meter, component]))\n return (\n inputComponentsMatchUsage(components, usage) && outputComponentsMatchUsage(components, usage)\n )\n}\n\nfunction inputComponentsMatchUsage(\n components: ReadonlyMap<AiBillableMeter, AiCostComponent>,\n usage: AiModelCallUsage\n): boolean {\n if (usage.inputTokens === undefined) return false\n const total = components.get(\"tokens.input.total\")\n const partitions = [\n [\"tokens.input.uncached\", usage.uncachedInputTokens],\n [\"tokens.input.cacheRead\", usage.cacheReadInputTokens],\n [\"tokens.input.cacheWrite\", usage.cacheWriteInputTokens],\n ] as const\n const presentPartitions = partitions.filter(([meter]) => components.has(meter))\n\n if (total) {\n return presentPartitions.length === 0 && BigInt(total.quantity) === BigInt(usage.inputTokens)\n }\n if (presentPartitions.length === 0) return false\n\n let quantity = 0n\n for (const [meter, expected] of presentPartitions) {\n if (expected === undefined) return false\n const component = components.get(meter)!\n if (BigInt(component.quantity) !== BigInt(expected)) return false\n quantity += BigInt(component.quantity)\n }\n return quantity === BigInt(usage.inputTokens)\n}\n\nfunction outputComponentsMatchUsage(\n components: ReadonlyMap<AiBillableMeter, AiCostComponent>,\n usage: AiModelCallUsage\n): boolean {\n if (usage.outputTokens === undefined) return false\n const total = components.get(\"tokens.output.total\")\n const partitions = [\n [\"tokens.output.text\", usage.textOutputTokens],\n [\"tokens.output.reasoning\", usage.reasoningOutputTokens],\n ] as const\n const presentPartitions = partitions.filter(([meter]) => components.has(meter))\n\n if (total) {\n return presentPartitions.length === 0 && BigInt(total.quantity) === BigInt(usage.outputTokens)\n }\n if (presentPartitions.length === 0) return false\n\n let quantity = 0n\n for (const [meter, expected] of presentPartitions) {\n if (expected === undefined) return false\n const component = components.get(meter)!\n if (BigInt(component.quantity) !== BigInt(expected)) return false\n quantity += BigInt(component.quantity)\n }\n return quantity === BigInt(usage.outputTokens)\n}\n\nfunction normalizeRatedCost(\n input: AiRatedModelCallCostRecord,\n base: Pick<\n AiRatedModelCallCostRecord,\n \"projectId\" | \"usageRecordId\" | \"pricingContext\" | \"priceSource\" | \"ratedAt\"\n >\n): AiRatedModelCallCostRecord {\n const billingIdentity = normalizeBillingIdentity(input.billingIdentity)\n const components = input.components.map(normalizeCostComponent).sort(compareComponents)\n if (components.length === 0) throw new TypeError(\"[Sixb] AI rated cost requires components.\")\n if (new Set(components.map((component) => component.meter)).size !== components.length) {\n throw new TypeError(\"[Sixb] AI rated cost cannot contain duplicate meters.\")\n }\n const amountNanos = parseNonnegativeInt64(input.money.amountNanos, \"money amountNanos\").toString()\n if (amountNanos !== sumComponents(components)) {\n throw new TypeError(\"[Sixb] AI cost total does not equal its component charges.\")\n }\n return {\n ...base,\n status: \"rated\",\n billingIdentity,\n money: { currency: normalizeCurrency(input.money.currency), amountNanos },\n components,\n }\n}\n\nfunction normalizeUnpriceableCost(\n input: AiUnpriceableModelCallCostRecord,\n base: Pick<\n AiUnpriceableModelCallCostRecord,\n \"projectId\" | \"usageRecordId\" | \"pricingContext\" | \"priceSource\" | \"ratedAt\"\n >\n): AiUnpriceableModelCallCostRecord {\n if (!UNPRICEABLE_REASONS.has(input.reason)) {\n throw new TypeError(`[Sixb] AI unpriceable reason '${String(input.reason)}' is invalid.`)\n }\n const billingIdentity = input.billingIdentity\n ? normalizeBillingIdentity(input.billingIdentity)\n : undefined\n if (input.reason === \"missingBillingIdentity\" && billingIdentity !== undefined) {\n throw new TypeError(\"[Sixb] AI missingBillingIdentity cannot contain a billing identity.\")\n }\n if (input.reason !== \"missingBillingIdentity\" && billingIdentity === undefined) {\n throw new TypeError(`[Sixb] AI ${input.reason} requires a billing identity.`)\n }\n const missingMeters = normalizeMissingMeters(input.missingMeters)\n if (input.reason === \"missingUsageMeter\" && !missingMeters) {\n throw new TypeError(\"[Sixb] AI missingUsageMeter requires missingMeters.\")\n }\n return {\n ...base,\n status: \"unpriceable\",\n ...(billingIdentity ? { billingIdentity } : {}),\n reason: input.reason,\n ...(missingMeters ? { missingMeters } : {}),\n }\n}\n\nfunction normalizeCostComponent(input: AiCostComponent): AiCostComponent {\n if (!METERS.has(input.meter)) {\n throw new TypeError(`[Sixb] AI cost meter '${String(input.meter)}' is invalid.`)\n }\n const expected = calculateComponent(input.meter, input.quantity, input.rateAmountNanosPerMillion)\n if (expected.chargeAmountNanos !== input.chargeAmountNanos) {\n throw new TypeError(`[Sixb] AI cost component '${input.meter}' charge is invalid.`)\n }\n return expected\n}\n\nfunction calculateComponent(\n meter: AiBillableMeter,\n quantity: number | string,\n rateAmountNanosPerMillion: string\n): AiCostComponent {\n const normalizedQuantity = parseQuantity(quantity, `${meter} quantity`)\n const rate = parseNonnegativeInt64(rateAmountNanosPerMillion, `${meter} rate`)\n const charge = (normalizedQuantity * rate + HALF_MILLION) / TOKENS_PER_MILLION\n assertSignedInt64(charge, `${meter} charge`)\n return {\n meter,\n quantity: normalizedQuantity.toString(),\n rateAmountNanosPerMillion: rate.toString(),\n chargeAmountNanos: charge.toString(),\n }\n}\n\nfunction normalizePriceSource(input: AiPriceSource): AiPriceSource {\n assertNonBlank(input.sourceId, \"price sourceId\")\n assertNonBlank(input.sourceEntryId, \"price sourceEntryId\")\n assertNonBlank(input.sourceVersion, \"price sourceVersion\")\n assertNonBlank(input.sourceUrl, \"price sourceUrl\")\n return { ...input, observedAt: cloneDate(input.observedAt, \"price source observedAt\") }\n}\n\nfunction normalizeBillingIdentity(input: AiBillingIdentity): AiBillingIdentity {\n assertNonBlank(input.providerId, \"billingIdentity.providerId\")\n assertNonBlank(input.modelId, \"billingIdentity.modelId\")\n return { providerId: input.providerId, modelId: input.modelId }\n}\n\nfunction normalizeMissingMeters(\n input: readonly AiBillableMeter[] | undefined\n): readonly AiBillableMeter[] | undefined {\n if (!input?.length) return undefined\n const result = [...new Set(input)]\n for (const meter of result) {\n if (!METERS.has(meter)) throw new TypeError(`[Sixb] AI missing meter '${meter}' is invalid.`)\n }\n return result.sort((left, right) => METER_ORDER[left] - METER_ORDER[right])\n}\n\nfunction sumComponents(components: readonly AiCostComponent[]): string {\n let total = 0n\n for (const component of components) {\n total += parseNonnegativeInt64(component.chargeAmountNanos, \"component charge\")\n assertSignedInt64(total, \"cost total\")\n }\n return total.toString()\n}\n\nfunction parseQuantity(value: number | string, field: string): bigint {\n if (typeof value === \"number\") {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(`[Sixb] AI ${field} must be a non-negative safe integer.`)\n }\n return BigInt(value)\n }\n return parseNonnegativeInt64(value, field)\n}\n\nfunction parseNonnegativeInt64(value: string, field: string): bigint {\n if (\n typeof value !== \"string\" ||\n value.length === 0 ||\n value.length > MAX_NUMERIC_TEXT_LENGTH ||\n !/^\\d+$/.test(value)\n ) {\n throw new TypeError(`[Sixb] AI ${field} must be a non-negative integer string.`)\n }\n const parsed = BigInt(value)\n assertSignedInt64(parsed, field)\n return parsed\n}\n\nfunction compareComponents(left: AiCostComponent, right: AiCostComponent): number {\n return METER_ORDER[left.meter] - METER_ORDER[right.meter]\n}\n\nfunction normalizeCurrency(value: string): string {\n if (!/^[A-Z]{3}$/.test(value)) {\n throw new TypeError(\"[Sixb] AI currency must be a three-letter uppercase code.\")\n }\n return value\n}\n\nfunction assertSignedInt64(value: bigint, field: string): void {\n if (value < 0n || value > SIGNED_INT64_MAX) {\n throw new TypeError(`[Sixb] AI ${field} exceeds the signed 64-bit range.`)\n }\n}\n\nfunction assertNonBlank(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`[Sixb] AI ${field} must be nonblank.`)\n }\n}\n\nfunction cloneDate(value: Date, field: string): Date {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {\n throw new TypeError(`[Sixb] AI ${field} must be a valid Date.`)\n }\n return new Date(value)\n}\n"
11
+ ],
12
+ "mappings": "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",
13
+ "debugId": "084861E374895B3F64756E2164756E21",
14
+ "names": []
15
+ }
@@ -3,7 +3,7 @@
3
3
  "sources": ["../src/storage/projection-runs/errors.ts", "../src/projections/types.ts", "../src/storage/projection-runs/types.ts", "../src/storage/projection-runs/lifecycle.ts", "../src/storage/projection-runs/provider.ts"],
4
4
  "sourcesContent": [
5
5
  "import {\n MaterializationConflictError,\n type MaterializationConflictKind,\n} from \"../../materialization/errors\"\n\n/**\n * Base error for projection-run storage operations.\n */\nexport class ProjectionRunError extends MaterializationConflictError {\n readonly name = \"ProjectionRunError\"\n\n constructor(message: string, kind: MaterializationConflictKind = \"run-correlation\") {\n super(kind, message)\n }\n}\n",
6
- "import type { SixbErrorCode } from \"../errors/types\"\n\n/** Error codes a projection run can persist and expose through its public contract. */\nexport const PROJECTION_RUN_FAILURE_CODES = [\n \"internal.unexpected\",\n \"runtime.cancelled\",\n \"queue.enqueue_failed\",\n \"projection.execution_failed\",\n] as const satisfies readonly [SixbErrorCode, ...SixbErrorCode[]]\n\nexport type ProjectionRunFailureCode = (typeof PROJECTION_RUN_FAILURE_CODES)[number]\n\n/**\n * Lowered, serializable definition interfaces for projection DSL.\n *\n * These are the runtime-inspectable data structures that projection builders\n * lower into. They use plain string ids (no tokens, no methods) so they can\n * be stored, serialized, and introspected by tooling.\n */\n\n/**\n * Describes how a foreign key column in a dataset resolves to a link target.\n *\n * The source can be either a projected source property or a raw dataset field.\n * Its value equals the target object's primary property value, creating an\n * implicit link between source and target.\n *\n * `targetObjectTypeId` declares the concrete target type for this projection.\n * It must be the same type or a subtype (via `extends`) of the link's declared\n * target at the ontology level. Validation of the subtype relationship happens\n * at Sixb startup (Increment 7), not at DSL build time.\n */\nexport interface ForeignKeyDescriptor {\n readonly linkId: string\n /** Object property holding the target id. Mutually exclusive with sourceField. */\n readonly sourcePropertyId?: string\n /** Dataset column holding the target id. Mutually exclusive with sourcePropertyId. */\n readonly sourceField?: string\n readonly targetObjectTypeId: string\n}\n\n/**\n * Lowered, serializable definition for projecting a dataset into object instances.\n *\n * Each row contributes one complete object root to an authoritative replacement snapshot, with\n * properties mapped from dataset columns to object type properties. Duplicate roots are rejected.\n * FK links are resolved from source property or dataset field values to target object primary\n * values.\n */\nexport interface ObjectProjectionDefinition {\n readonly _tag: \"ObjectProjectionDefinition\"\n readonly id: string\n readonly objectTypeId: string\n readonly datasetId: string\n /** Maps object type property id -> dataset column name. */\n readonly properties: Readonly<Record<string, string>>\n /** Maps link id -> FK descriptor. Empty `{}` when no FK links are projected. */\n readonly links: Readonly<Record<string, ForeignKeyDescriptor>>\n}\n\n/**\n * Lowered, serializable definition for projecting a join dataset into link instances.\n *\n * Each row in the join dataset contributes one complete link root to an authoritative replacement\n * snapshot, identified by its source, link id, and target. Duplicate roots are rejected.\n */\nexport interface LinkProjectionDefinition {\n readonly _tag: \"LinkProjectionDefinition\"\n readonly id: string\n readonly linkId: string\n readonly sourceObjectTypeId: string\n readonly targetObjectTypeId: string\n readonly datasetId: string\n /** Dataset column holding the source object's primary property value. */\n readonly sourceField: string\n /** Dataset column holding the target object's primary property value. */\n readonly targetField: string\n}\n\n/**\n * Lowered, serializable definition for projecting dataset rows into telemetry history.\n *\n * Each row in the dataset becomes one telemetry point for a single object type property.\n * The target object type and property are fixed by the telemetry property token used by\n * the builder; the point mapping selects the dataset columns for object id, timestamp,\n * value, and optional unit.\n */\nexport interface TelemetryProjectionDefinition {\n readonly _tag: \"TelemetryProjectionDefinition\"\n readonly id: string\n readonly objectTypeId: string\n readonly propertyId: string\n readonly datasetId: string\n /** Dataset column holding the target object's primary id. */\n readonly objectIdField: string\n /** Dataset column holding the telemetry observation timestamp. */\n readonly atField: string\n /** Dataset column holding the telemetry value. */\n readonly valueField: string\n /** Dataset column holding the telemetry unit, when the property requires one. */\n readonly unitField?: string\n}\n\n/** Union of all projection definition types. */\nexport type ProjectionDefinition =\n | ObjectProjectionDefinition\n | LinkProjectionDefinition\n | TelemetryProjectionDefinition\n\nexport interface ProjectionOwnership {\n readonly objects: readonly {\n readonly objectTypeId: string\n readonly existence: boolean\n readonly propertyIds: readonly string[]\n }[]\n readonly links: readonly {\n readonly sourceObjectTypeId: string\n readonly linkId: string\n }[]\n readonly telemetry: readonly {\n readonly objectTypeId: string\n readonly propertyId: string\n }[]\n}\n\n/** Canonical correlation between a projection kind and its materialization protocol. */\nexport type ProjectionProtocolIdentity =\n | { readonly projectionKind: \"object\"; readonly protocol: \"replacement\" }\n | { readonly projectionKind: \"link\"; readonly protocol: \"replacement\" }\n | { readonly projectionKind: \"telemetry\"; readonly protocol: \"telemetry\" }\n\nexport type ProjectionKind = ProjectionProtocolIdentity[\"projectionKind\"]\n\nexport interface ObjectProjectionTarget {\n readonly objectTypeId: string\n}\n\nexport interface LinkProjectionTarget {\n readonly sourceObjectTypeId: string\n readonly targetObjectTypeId: string\n}\n\nexport interface ProjectionTargetByKind {\n readonly object: ObjectProjectionTarget\n readonly link: LinkProjectionTarget\n readonly telemetry: ObjectProjectionTarget\n}\n\n/** Object types affected by one projection, correlated with its projection kind. */\nexport type ProjectionTarget<TKind extends ProjectionKind = ProjectionKind> =\n ProjectionTargetByKind[TKind]\n\n/**\n * Frozen semantic identity used to dispatch one registered projection.\n *\n * Dataset version metadata is attached only when a committed dataset event is routed. Keeping the\n * registry-owned fields together prevents the orchestrator from recomputing ontology semantics.\n */\nexport type ProjectionDispatchDescriptor = ProjectionDispatchDescriptorBase &\n ProjectionProtocolIdentity\n\ninterface ProjectionDispatchDescriptorBase {\n readonly projectionId: string\n readonly datasetId: string\n readonly ontologyRevision: string\n readonly projectionRevision: string\n readonly ownershipHash: string\n}\n\nexport interface ResolvedProjection<TDefinition extends ProjectionDefinition> {\n readonly projectionId: string\n readonly datasetId: string\n readonly projectionRevision: string\n readonly ownershipHash: string\n readonly ownership: ProjectionOwnership\n readonly definition: TDefinition\n}\n",
6
+ "import type { SixbErrorCode } from \"../errors/types\"\n\n/** Error codes a projection run can persist and expose through its public contract. */\nexport const PROJECTION_RUN_FAILURE_CODES = [\n \"internal.unexpected\",\n \"runtime.cancelled\",\n \"queue.enqueue_failed\",\n \"projection.execution_failed\",\n] as const satisfies readonly [SixbErrorCode, ...SixbErrorCode[]]\n\nexport type ProjectionRunFailureCode = (typeof PROJECTION_RUN_FAILURE_CODES)[number]\n\n/**\n * Lowered, serializable definition interfaces for projection DSL.\n *\n * These are the runtime-inspectable data structures that projection builders\n * lower into. They use plain string ids (no tokens, no methods) so they can\n * be stored, serialized, and introspected by tooling.\n */\n\n/**\n * Describes how a foreign key column in a dataset resolves to a link target.\n *\n * The source can be either a projected source property or a raw dataset field.\n * Its value equals the target object's primary property value, creating an\n * implicit link between source and target.\n *\n * `targetObjectTypeId` declares the concrete target type for this projection.\n * It must be the same type or a subtype (via `extends`) of the link's declared\n * target at the ontology level. Validation of the subtype relationship happens\n * at Sixb startup (Increment 7), not at DSL build time.\n */\nexport interface ForeignKeyDescriptor {\n readonly linkId: string\n /** Object property holding the target id. Mutually exclusive with sourceField. */\n readonly sourcePropertyId?: string\n /** Dataset column holding the target id. Mutually exclusive with sourcePropertyId. */\n readonly sourceField?: string\n readonly targetObjectTypeId: string\n}\n\n/** Resolves competing source-projection and managed-edit values for projected properties. */\nexport type SourceEditConflictResolution =\n | { readonly strategy: \"editsWin\" }\n | { readonly strategy: \"mostRecent\"; readonly sourceTimestamp: string }\n\n/**\n * Lowered, serializable definition for projecting a dataset into object instances.\n *\n * Each row contributes one complete object root to an authoritative replacement snapshot, with\n * properties mapped from dataset columns to object type properties. Duplicate roots are rejected.\n * FK links are resolved from source property or dataset field values to target object primary\n * values.\n */\nexport interface ObjectProjectionDefinition {\n readonly _tag: \"ObjectProjectionDefinition\"\n readonly id: string\n readonly objectTypeId: string\n readonly datasetId: string\n /** Maps object type property id -> dataset column name. */\n readonly properties: Readonly<Record<string, string>>\n /** Maps link id -> FK descriptor. Empty `{}` when no FK links are projected. */\n readonly links: Readonly<Record<string, ForeignKeyDescriptor>>\n /** Defaults to `editsWin` when omitted by a legacy lowered definition. */\n readonly conflictResolution?: SourceEditConflictResolution\n}\n\n/**\n * Lowered, serializable definition for projecting a join dataset into link instances.\n *\n * Each row in the join dataset contributes one complete link root to an authoritative replacement\n * snapshot, identified by its source, link id, and target. Duplicate roots are rejected.\n */\nexport interface LinkProjectionDefinition {\n readonly _tag: \"LinkProjectionDefinition\"\n readonly id: string\n readonly linkId: string\n readonly sourceObjectTypeId: string\n readonly targetObjectTypeId: string\n readonly datasetId: string\n /** Dataset column holding the source object's primary property value. */\n readonly sourceField: string\n /** Dataset column holding the target object's primary property value. */\n readonly targetField: string\n}\n\n/** Dataset columns that produce one telemetry property value. */\nexport interface TelemetryProjectionPropertyMapping {\n /** Dataset column holding the telemetry value. */\n readonly valueField: string\n /** Dataset column holding the telemetry unit, when the property requires one. */\n readonly unitField?: string\n}\n\n/**\n * Lowered, serializable definition for projecting dataset rows into telemetry history.\n *\n * Each row shares one target object id and observation timestamp, then contributes up to one\n * telemetry point for every mapped property. A property-token projection is lowered to the same\n * shape with one entry, so execution and ownership have one canonical contract.\n */\nexport interface TelemetryProjectionDefinition {\n readonly _tag: \"TelemetryProjectionDefinition\"\n readonly id: string\n readonly objectTypeId: string\n readonly datasetId: string\n /** Dataset column holding the target object's primary id. */\n readonly objectIdField: string\n /** Dataset column holding the telemetry observation timestamp. */\n readonly atField: string\n /** Maps telemetry property id -> value and optional unit dataset columns. */\n readonly properties: Readonly<Record<string, TelemetryProjectionPropertyMapping>>\n}\n\n/** Union of all projection definition types. */\nexport type ProjectionDefinition =\n | ObjectProjectionDefinition\n | LinkProjectionDefinition\n | TelemetryProjectionDefinition\n\nexport interface ProjectionOwnership {\n readonly objects: readonly {\n readonly objectTypeId: string\n readonly existence: boolean\n readonly propertyIds: readonly string[]\n }[]\n readonly links: readonly {\n readonly sourceObjectTypeId: string\n readonly linkId: string\n }[]\n readonly telemetry: readonly {\n readonly objectTypeId: string\n readonly propertyId: string\n }[]\n}\n\n/** Canonical correlation between a projection kind and its materialization protocol. */\nexport type ProjectionProtocolIdentity =\n | { readonly projectionKind: \"object\"; readonly protocol: \"replacement\" }\n | { readonly projectionKind: \"link\"; readonly protocol: \"replacement\" }\n | { readonly projectionKind: \"telemetry\"; readonly protocol: \"telemetry\" }\n\nexport type ProjectionKind = ProjectionProtocolIdentity[\"projectionKind\"]\n\nexport interface ObjectProjectionTarget {\n readonly objectTypeId: string\n}\n\nexport interface LinkProjectionTarget {\n readonly sourceObjectTypeId: string\n readonly targetObjectTypeId: string\n}\n\nexport interface ProjectionTargetByKind {\n readonly object: ObjectProjectionTarget\n readonly link: LinkProjectionTarget\n readonly telemetry: ObjectProjectionTarget\n}\n\n/** Object types affected by one projection, correlated with its projection kind. */\nexport type ProjectionTarget<TKind extends ProjectionKind = ProjectionKind> =\n ProjectionTargetByKind[TKind]\n\n/**\n * Frozen semantic identity used to dispatch one registered projection.\n *\n * Dataset version metadata is attached only when a committed dataset event is routed. Keeping the\n * registry-owned fields together prevents the orchestrator from recomputing ontology semantics.\n */\nexport type ProjectionDispatchDescriptor = ProjectionDispatchDescriptorBase &\n ProjectionProtocolIdentity\n\ninterface ProjectionDispatchDescriptorBase {\n readonly projectionId: string\n readonly datasetId: string\n readonly ontologyRevision: string\n readonly projectionRevision: string\n readonly ownershipHash: string\n}\n\nexport interface ResolvedProjection<TDefinition extends ProjectionDefinition> {\n readonly projectionId: string\n readonly datasetId: string\n readonly projectionRevision: string\n readonly ownershipHash: string\n readonly ownership: ProjectionOwnership\n readonly definition: TDefinition\n}\n",
7
7
  "import type { SixbFailure } from \"../../errors/types\"\nimport type {\n PinnedDatasetVersion,\n ProjectionExecution,\n ProjectionMaterializationIdentity,\n ProjectionRunTerminalDecision,\n} from \"../../materialization/model\"\nimport type {\n LinkProjectionTarget,\n ObjectProjectionTarget,\n ProjectionKind,\n ProjectionRunFailureCode,\n ProjectionTarget,\n} from \"../../projections/types\"\n\nexport type { ProjectionRunFailureCode } from \"../../projections/types\"\nexport { PROJECTION_RUN_FAILURE_CODES } from \"../../projections/types\"\n\nexport type ProjectionRunStatus = \"queued\" | \"running\" | \"succeeded\" | \"failed\" | \"cancelled\"\n\nexport interface ProjectionRunProgress {\n /** Physical immutable-version rows consumed, before normalization or semantic materialization. */\n readonly sourceRowsRead: number\n /** Physical rows intentionally skipped because a required mapped value was blank. */\n readonly sourceRowsSkipped: number\n}\n\nconst progressKeyFlags: Record<keyof ProjectionRunProgress, true> = {\n sourceRowsRead: true,\n sourceRowsSkipped: true,\n}\n\nexport const PROJECTION_RUN_PROGRESS_KEYS = Object.keys(\n progressKeyFlags\n) as readonly (keyof ProjectionRunProgress)[]\n\nexport function zeroProjectionRunProgress(): ProjectionRunProgress {\n const progress = {} as Record<keyof ProjectionRunProgress, number>\n for (const key of PROJECTION_RUN_PROGRESS_KEYS) progress[key] = 0\n return progress\n}\n\nexport interface ProjectionTelemetryCheckpoint {\n readonly fixedBatchSize: number\n readonly nextBatchOrdinal: number\n readonly nextRowOffset: number\n readonly inputExhausted: boolean\n}\n\n/**\n * The object a telemetry batch is waiting for, and when this run first found it missing.\n *\n * A projection's dataset can legitimately be materialized before the objects it references, so\n * the run waits instead of failing. The wait needs a start, and the run has no other durable one:\n * `startedAt` is when the run began, which on a batched projection is long before the batch that\n * cannot commit, and `attempt` counts every reclaim including the ones an unreachable queue caused.\n *\n * Cleared by any committed batch, so a run that is making progress never carries a stale wait.\n */\nexport interface ProjectionMissingTarget {\n readonly objectTypeId: string\n readonly objectId: string\n /** The batch that could not commit because of it. */\n readonly batchOrdinal: number\n readonly firstSeenAt: Date\n}\n\ninterface ProjectionRunRecordBase {\n readonly id: string\n readonly projectId: string\n readonly executionId: string\n readonly status: ProjectionRunStatus\n readonly attempt: number\n readonly progress: ProjectionRunProgress\n readonly queuedAt: Date\n readonly startedAt?: Date\n readonly finishedAt?: Date\n readonly error?: SixbFailure<ProjectionRunFailureCode>\n}\n\ntype ProjectionIdentity<TKind extends ProjectionKind> = Extract<\n ProjectionMaterializationIdentity,\n { readonly projectionKind: TKind }\n>\n\nexport type ObjectProjectionRunRecord = ProjectionRunRecordBase & {\n readonly identity: ProjectionIdentity<\"object\">\n readonly target: ObjectProjectionTarget\n readonly telemetryCheckpoint?: never\n readonly missingTarget?: never\n}\n\nexport type LinkProjectionRunRecord = ProjectionRunRecordBase & {\n readonly identity: ProjectionIdentity<\"link\">\n readonly target: LinkProjectionTarget\n readonly telemetryCheckpoint?: never\n readonly missingTarget?: never\n}\n\nexport type TelemetryProjectionRunRecord = ProjectionRunRecordBase & {\n readonly identity: ProjectionIdentity<\"telemetry\">\n readonly target: ObjectProjectionTarget\n readonly telemetryCheckpoint: ProjectionTelemetryCheckpoint\n /**\n * Only telemetry carries this: `MaterializationObjectNotFoundError` is raised by telemetry\n * validation alone, and only a batched protocol has a checkpoint to anchor the wait to.\n */\n readonly missingTarget?: ProjectionMissingTarget\n}\n\n/** Durable projection lifecycle state. The execution token is deliberately returned separately. */\nexport type ProjectionRunRecord =\n | ObjectProjectionRunRecord\n | LinkProjectionRunRecord\n | TelemetryProjectionRunRecord\n\nexport function projectionRunObjectTypesVisible(\n run: ProjectionRunRecord,\n canView: (objectTypeId: string) => boolean\n): boolean {\n const target: ProjectionTarget = run.target\n if (\"sourceObjectTypeId\" in target) {\n return canView(target.sourceObjectTypeId) && canView(target.targetObjectTypeId)\n }\n return canView(target.objectTypeId)\n}\n\ninterface ProjectionRunAdmissionBase {\n readonly id: string\n readonly projectId: string\n readonly executionId: string\n readonly queuedAt?: Date\n}\n\nexport type QueueProjectionRunInput =\n | (ProjectionRunAdmissionBase & {\n readonly identity: ProjectionIdentity<\"object\">\n readonly target: ObjectProjectionRunRecord[\"target\"]\n readonly fixedBatchSize?: never\n })\n | (ProjectionRunAdmissionBase & {\n readonly identity: ProjectionIdentity<\"link\">\n readonly target: LinkProjectionRunRecord[\"target\"]\n readonly fixedBatchSize?: never\n })\n | (ProjectionRunAdmissionBase & {\n readonly identity: ProjectionIdentity<\"telemetry\">\n readonly target: TelemetryProjectionRunRecord[\"target\"]\n readonly fixedBatchSize: number\n })\n\nexport type StartOrReclaimProjectionRunInput = QueueProjectionRunInput extends infer TInput\n ? TInput extends QueueProjectionRunInput\n ? Omit<TInput, \"executionId\" | \"queuedAt\"> & { readonly startedAt?: Date }\n : never\n : never\n\nexport interface FailProjectionRunEnqueueInput {\n readonly id: string\n readonly projectId: string\n readonly finishedAt?: Date\n readonly error: SixbFailure<ProjectionRunFailureCode>\n}\n\nexport interface ProjectionRunClaim {\n readonly run: ProjectionRunRecord\n readonly execution: ProjectionExecution\n}\n\nexport interface LockProjectionRunForMaterializationInput {\n readonly id: string\n readonly projectId: string\n readonly executionToken: string\n readonly identity: ProjectionMaterializationIdentity\n}\n\nexport interface UpdateProjectionRunInput extends LockProjectionRunForMaterializationInput {\n readonly progress: Partial<ProjectionRunProgress>\n}\n\nexport type FinishProjectionRunInput = ProjectionRunTerminalDecision &\n LockProjectionRunForMaterializationInput & {\n readonly finishedAt?: Date\n readonly progress?: Partial<ProjectionRunProgress>\n }\n\nexport interface AdvanceProjectionTelemetryCheckpointInput\n extends LockProjectionRunForMaterializationInput {\n /** Must equal the run's current nextBatchOrdinal. */\n readonly batchOrdinal: number\n /** Physical dataset rows consumed by this batch, including skipped rows. */\n readonly batchRowCount: number\n /** Physical rows intentionally skipped inside this batch. */\n readonly batchRowsSkipped: number\n /** True when this batch consumed the final row of the immutable dataset version. */\n readonly inputExhausted: boolean\n}\n\nexport interface RecordProjectionMissingTargetInput\n extends LockProjectionRunForMaterializationInput {\n readonly missingTarget: ProjectionMissingTarget\n}\n\nexport interface ListProjectionRunsInput {\n readonly projectId: string\n readonly projectionId?: string\n readonly projectionKind?: ProjectionKind\n readonly datasetId?: string\n readonly datasetVersionId?: string\n /**\n * Viewable object type ids. A run is included only if every target type is present. Omit for an\n * unrestricted internal execution; an empty set matches no runs.\n */\n readonly objectTypeIds?: readonly string[]\n readonly statuses?: readonly ProjectionRunStatus[]\n readonly startedAfter?: Date\n readonly startedBefore?: Date\n readonly limit?: number\n readonly offset?: number\n readonly order?: \"asc\" | \"desc\"\n}\n\nexport interface ListProjectionRunsResult {\n readonly runs: readonly ProjectionRunRecord[]\n readonly hasMore: boolean\n readonly total: number\n}\n\nexport interface ListLatestProjectionRunsInput {\n readonly projectId: string\n readonly projectionIds: readonly string[]\n}\n\nexport interface ListLatestProjectionRunsResult {\n readonly runs: readonly ProjectionRunRecord[]\n}\n\nexport interface ProjectionRunStorage {\n queue(input: QueueProjectionRunInput): Promise<ProjectionRunRecord>\n startOrReclaim(input: StartOrReclaimProjectionRunInput): Promise<ProjectionRunClaim>\n failEnqueue(input: FailProjectionRunEnqueueInput): Promise<ProjectionRunRecord>\n /** Transactionally fences the current execution before ontology materialization writes. */\n lockForMaterialization(\n input: LockProjectionRunForMaterializationInput\n ): Promise<ProjectionRunRecord>\n /** Updates physical source progress only. */\n update(input: UpdateProjectionRunInput): Promise<ProjectionRunRecord>\n /**\n * Advances telemetry progress atomically with the corresponding ontology commit.\n *\n * Clears any recorded missing target: a batch that commits is a batch that was not waiting.\n */\n advanceTelemetryCheckpoint(\n input: AdvanceProjectionTelemetryCheckpointInput\n ): Promise<TelemetryProjectionRunRecord>\n /** Records the object a telemetry batch is waiting for, so the wait has a durable start. */\n recordMissingTarget(\n input: RecordProjectionMissingTargetInput\n ): Promise<TelemetryProjectionRunRecord>\n /** Telemetry success also records the worker's EOF observation atomically. */\n finish(input: FinishProjectionRunInput): Promise<ProjectionRunRecord>\n getById(params: { projectId: string; id: string }): Promise<ProjectionRunRecord | null>\n list(input: ListProjectionRunsInput): Promise<ListProjectionRunsResult>\n listLatestByProjectionIds(\n input: ListLatestProjectionRunsInput\n ): Promise<ListLatestProjectionRunsResult>\n}\n\nexport type {\n LinkProjectionTarget,\n ObjectProjectionTarget,\n PinnedDatasetVersion,\n ProjectionExecution,\n ProjectionKind,\n ProjectionMaterializationIdentity,\n ProjectionTarget,\n}\n",
8
8
  "import { parseSixbFailure } from \"../../errors/internal\"\nimport type { SixbFailure } from \"../../errors/types\"\nimport type {\n ProjectionMaterializationIdentity,\n ProjectionRunTerminalDecision,\n} from \"../../materialization/model\"\nimport type {\n ProjectionKind,\n ProjectionRunFailureCode,\n ProjectionTarget,\n} from \"../../projections/types\"\nimport { PROJECTION_RUN_FAILURE_CODES } from \"../../projections/types\"\nimport { ProjectionRunError } from \"./errors\"\nimport type {\n AdvanceProjectionTelemetryCheckpointInput,\n FailProjectionRunEnqueueInput,\n FinishProjectionRunInput,\n ProjectionMissingTarget,\n ProjectionRunClaim,\n ProjectionRunProgress,\n ProjectionRunRecord,\n ProjectionRunStatus,\n ProjectionTelemetryCheckpoint,\n QueueProjectionRunInput,\n StartOrReclaimProjectionRunInput,\n TelemetryProjectionRunRecord,\n} from \"./types\"\nimport { PROJECTION_RUN_PROGRESS_KEYS, zeroProjectionRunProgress } from \"./types\"\n\nexport type StoredProjectionRunRecord = ProjectionRunRecord & {\n readonly executionToken?: string\n}\n\nexport interface PersistedProjectionRunRecord {\n readonly id: string\n readonly projectId: string\n readonly executionId: string\n readonly projectionId: string\n readonly projectionKind: ProjectionKind\n readonly protocol?: \"replacement\" | \"telemetry\"\n readonly datasetId: string\n readonly datasetVersionId: string\n readonly datasetVersionCreatedAt?: string\n readonly ontologyRevision?: string\n readonly projectionRevision?: string\n readonly ownershipHash?: string\n readonly objectTypeId?: string\n readonly sourceObjectTypeId?: string\n readonly targetObjectTypeId?: string\n readonly status: ProjectionRunStatus\n readonly queuedAt: Date\n readonly startedAt?: Date\n readonly finishedAt?: Date\n readonly attempt: number\n readonly executionToken?: string\n readonly fixedBatchSize?: number\n readonly nextBatchOrdinal?: number\n readonly nextRowOffset?: number\n readonly inputExhausted?: boolean\n readonly missingTargetObjectTypeId?: string\n readonly missingTargetObjectId?: string\n readonly missingTargetBatchOrdinal?: number\n readonly missingTargetFirstSeenAt?: Date\n readonly progress: ProjectionRunProgress\n readonly error?: unknown\n}\n\nexport interface ProjectionTelemetryAdvance {\n readonly progress: ProjectionRunProgress\n readonly checkpoint: ProjectionTelemetryCheckpoint\n}\n\nexport interface ProjectionRunFinishPlan {\n readonly status: Exclude<ProjectionRunStatus, \"queued\" | \"running\">\n readonly finishedAt: Date\n readonly progress: ProjectionRunProgress\n readonly inputExhausted?: true\n readonly error?: SixbFailure<ProjectionRunFailureCode>\n}\n\n// ── Scalar and identity validation ──────────────────────────\n\nexport function assertProjectionRunNonEmpty(value: string, fieldName: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new ProjectionRunError(`[Sixb] Projection run ${fieldName} must not be empty.`)\n }\n}\n\nexport function assertProjectionRunCounter(value: number, fieldName: string): void {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new ProjectionRunError(\n `[Sixb] Projection run ${fieldName} must be a non-negative safe integer.`\n )\n }\n}\n\nexport function assertProjectionRunListWindow(value: number | undefined, fieldName: string): void {\n if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {\n throw new ProjectionRunError(`[Sixb] Projection run list ${fieldName} must be >= 0.`)\n }\n}\n\nexport function addProjectionRunCounter(left: number, right: number, fieldName: string): number {\n const result = left + right\n if (!Number.isSafeInteger(result)) {\n throw new ProjectionRunError(`[Sixb] Projection run ${fieldName} exceeds safe integer range.`)\n }\n return result\n}\n\nexport function assertProjectionRunIdentity(identity: ProjectionMaterializationIdentity): void {\n assertProjectionRunNonEmpty(identity.projectionId, \"projectionId\")\n if (!isProjectionKind(identity.projectionKind)) {\n throw new ProjectionRunError(\n \"[Sixb] Projection run projectionKind must be 'object', 'link', or 'telemetry'.\"\n )\n }\n if (identity.protocol !== \"replacement\" && identity.protocol !== \"telemetry\") {\n throw new ProjectionRunError(\n \"[Sixb] Projection run protocol must be 'replacement' or 'telemetry'.\"\n )\n }\n assertProjectionRunNonEmpty(identity.datasetVersion.datasetId, \"datasetId\")\n assertProjectionRunNonEmpty(identity.datasetVersion.versionId, \"datasetVersionId\")\n assertCanonicalTimestamp(identity.datasetVersion.createdAt, \"datasetVersionCreatedAt\")\n assertProjectionRunNonEmpty(identity.ontologyRevision, \"ontologyRevision\")\n assertProjectionRunNonEmpty(identity.projectionRevision, \"projectionRevision\")\n assertProjectionRunNonEmpty(identity.ownershipHash, \"ownershipHash\")\n if ((identity.protocol === \"telemetry\") !== (identity.projectionKind === \"telemetry\")) {\n throw new ProjectionRunError(\n `[Sixb] Projection run protocol '${identity.protocol}' is incompatible with kind '${identity.projectionKind}'.`\n )\n }\n}\n\nexport function assertProjectionRunIdentityMatches(\n record: Pick<ProjectionRunRecord, \"id\" | \"identity\">,\n identity: ProjectionMaterializationIdentity\n): void {\n if (projectionRunIdentitiesEqual(record.identity, identity)) return\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' materialization identity does not match.`\n )\n}\n\nexport function assertProjectionRunTargetMatches(\n record: Pick<ProjectionRunRecord, \"id\" | \"target\">,\n target: ProjectionTarget\n): void {\n if (projectionTargetsEqual(record.target, target)) return\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' target object types do not match.`\n )\n}\n\nexport function assertProjectionRunStartInput(input: StartOrReclaimProjectionRunInput): void {\n assertProjectionRunNonEmpty(input.id, \"id\")\n assertProjectionRunNonEmpty(input.projectId, \"projectId\")\n assertProjectionRunIdentityAndTarget(input)\n if (input.startedAt) assertProjectionRunDate(input.startedAt, \"startedAt\")\n}\n\nexport function assertProjectionRunQueueInput(input: QueueProjectionRunInput): void {\n assertProjectionRunNonEmpty(input.id, \"id\")\n assertProjectionRunNonEmpty(input.projectId, \"projectId\")\n assertProjectionRunNonEmpty(input.executionId, \"executionId\")\n assertProjectionRunIdentityAndTarget(input)\n if (input.queuedAt) assertProjectionRunDate(input.queuedAt, \"queuedAt\")\n}\n\nfunction assertProjectionRunIdentityAndTarget(\n input: QueueProjectionRunInput | StartOrReclaimProjectionRunInput\n): void {\n assertProjectionRunIdentity(input.identity)\n assertProjectionTarget(input.identity.projectionKind, input.target)\n if (input.identity.projectionKind === \"telemetry\") {\n const telemetry = input as ProjectionRunIdentityInput<\"telemetry\">\n assertPositiveCounter(telemetry.fixedBatchSize, \"fixedBatchSize\")\n } else if (input.fixedBatchSize !== undefined) {\n throw new ProjectionRunError(\n \"[Sixb] Replacement projection runs cannot declare a telemetry fixedBatchSize.\"\n )\n }\n}\n\nexport function planProjectionRunReclaim(\n record: StoredProjectionRunRecord,\n input: StartOrReclaimProjectionRunInput\n): { readonly attempt: number } {\n if (record.status !== \"queued\" && record.status !== \"running\") {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' cannot start from status '${record.status}'.`\n )\n }\n assertProjectionRunIdentityMatches(record, input.identity)\n assertProjectionRunTargetMatches(record, input.target)\n if (record.telemetryCheckpoint?.fixedBatchSize !== input.fixedBatchSize) {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${input.id}' fixed batch size does not match.`\n )\n }\n return { attempt: record.status === \"queued\" ? 1 : nextProjectionRunAttempt(record.attempt) }\n}\n\n// ── Lifecycle transitions ───────────────────────────────────\n\nexport function createProjectionRunRecord(\n input: QueueProjectionRunInput,\n now: Date = new Date()\n): ProjectionRunRecord {\n assertProjectionRunQueueInput(input)\n const base = {\n id: input.id,\n projectId: input.projectId,\n executionId: input.executionId,\n status: \"queued\" as const,\n attempt: 0,\n progress: zeroProjectionRunProgress(),\n queuedAt: new Date(input.queuedAt ?? now),\n }\n switch (input.identity.projectionKind) {\n case \"object\": {\n const object = input as ProjectionRunAdmission<\"object\">\n return { ...base, identity: object.identity, target: object.target }\n }\n case \"link\": {\n const link = input as ProjectionRunAdmission<\"link\">\n return { ...base, identity: link.identity, target: link.target }\n }\n case \"telemetry\": {\n const telemetry = input as ProjectionRunAdmission<\"telemetry\">\n return {\n ...base,\n identity: telemetry.identity,\n target: telemetry.target,\n telemetryCheckpoint: {\n fixedBatchSize: telemetry.fixedBatchSize,\n nextBatchOrdinal: 0,\n nextRowOffset: 0,\n inputExhausted: false,\n },\n }\n }\n }\n}\n\nexport function assertProjectionRunRunning(\n record: Pick<ProjectionRunRecord, \"id\" | \"projectId\" | \"status\">\n): void {\n if (record.status === \"running\") return\n if (record.status !== \"queued\") {\n throw new ProjectionRunError(`[Sixb] Projection run '${record.id}' is already terminal.`)\n }\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' for project '${record.projectId}' is not running.`\n )\n}\n\nexport function assertProjectionRunAttempt(\n record: StoredProjectionRunRecord,\n input: {\n readonly id: string\n readonly executionToken: string\n readonly identity: ProjectionMaterializationIdentity\n }\n): asserts record is StoredProjectionRunRecord & { readonly executionToken: string } {\n assertProjectionRunNonEmpty(input.executionToken, \"executionToken\")\n assertProjectionRunIdentity(input.identity)\n assertProjectionRunRunning(record)\n assertProjectionRunIdentityMatches(record, input.identity)\n if (record.executionToken !== input.executionToken) {\n throw staleProjectionRunExecution(input.id)\n }\n}\n\nexport function nextProjectionRunAttempt(current: number): number {\n assertProjectionRunCounter(current, \"attempt\")\n return addProjectionRunCounter(current, 1, \"attempt\")\n}\n\nexport function mergeProjectionRunProgress(\n current: ProjectionRunProgress,\n patch: Partial<ProjectionRunProgress>\n): ProjectionRunProgress {\n const progress = { ...current }\n for (const key of PROJECTION_RUN_PROGRESS_KEYS) {\n const value = patch[key]\n if (value === undefined) continue\n assertProjectionRunCounter(value, key)\n if (value < current[key]) {\n throw new ProjectionRunError(`[Sixb] Projection run ${key} must not decrease.`)\n }\n progress[key] = value\n }\n assertProjectionRunProgress(progress)\n return progress\n}\n\nexport function assertGenericProgressDoesNotAdvanceTelemetry(\n record: Pick<ProjectionRunRecord, \"id\" | \"identity\" | \"progress\">,\n patch: Partial<ProjectionRunProgress>\n): void {\n if (record.identity.protocol !== \"telemetry\") return\n for (const key of PROJECTION_RUN_PROGRESS_KEYS) {\n if (patch[key] !== undefined && patch[key] !== record.progress[key]) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' progress can only advance with its checkpoint.`\n )\n }\n }\n}\n\nexport function advanceProjectionTelemetry(\n record: ProjectionRunRecord,\n input: AdvanceProjectionTelemetryCheckpointInput\n): ProjectionTelemetryAdvance {\n const telemetry = requireTelemetryProjectionRun(record)\n const checkpoint = telemetry.telemetryCheckpoint\n assertProjectionRunCounter(input.batchOrdinal, \"batchOrdinal\")\n assertPositiveCounter(input.batchRowCount, \"batchRowCount\")\n assertProjectionRunCounter(input.batchRowsSkipped, \"batchRowsSkipped\")\n if (input.batchRowsSkipped > input.batchRowCount) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' skipped rows exceed its batch row count.`\n )\n }\n if (input.batchOrdinal !== checkpoint.nextBatchOrdinal) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' expected batch ordinal ${checkpoint.nextBatchOrdinal}, got ${input.batchOrdinal}.`\n )\n }\n if (input.batchRowCount > checkpoint.fixedBatchSize) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' batch exceeds its fixed size.`\n )\n }\n if (!input.inputExhausted && input.batchRowCount !== checkpoint.fixedBatchSize) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' cannot advance past a partial non-final batch.`\n )\n }\n if (checkpoint.inputExhausted) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' has already exhausted its input.`\n )\n }\n\n const nextRowOffset = addProjectionRunCounter(\n checkpoint.nextRowOffset,\n input.batchRowCount,\n \"nextRowOffset\"\n )\n return {\n progress: {\n sourceRowsRead: nextRowOffset,\n sourceRowsSkipped: addProjectionRunCounter(\n telemetry.progress.sourceRowsSkipped,\n input.batchRowsSkipped,\n \"sourceRowsSkipped\"\n ),\n },\n checkpoint: {\n ...checkpoint,\n nextBatchOrdinal: addProjectionRunCounter(checkpoint.nextBatchOrdinal, 1, \"nextBatchOrdinal\"),\n nextRowOffset,\n inputExhausted: input.inputExhausted,\n },\n }\n}\n\nexport function planProjectionRunFinish(\n record: ProjectionRunRecord,\n input: FinishProjectionRunInput,\n now: Date = new Date()\n): ProjectionRunFinishPlan {\n assertFinishDecision(record, input)\n const patch = input.progress ?? {}\n assertGenericProgressDoesNotAdvanceTelemetry(record, patch)\n const progress = mergeProjectionRunProgress(record.progress, patch)\n const finishedAt = new Date(input.finishedAt ?? now)\n assertProjectionRunDate(finishedAt, \"finishedAt\")\n return {\n status: input.status,\n finishedAt,\n progress,\n ...(input.status === \"succeeded\" && input.protocol === \"telemetry\"\n ? { inputExhausted: true as const }\n : {}),\n ...(input.status === \"succeeded\" || input.error === undefined\n ? {}\n : { error: parseSixbFailure(input.error, PROJECTION_RUN_FAILURE_CODES) }),\n }\n}\n\nexport function finishProjectionRunRecord(\n record: StoredProjectionRunRecord,\n input: FinishProjectionRunInput,\n now: Date = new Date()\n): StoredProjectionRunRecord {\n const plan = planProjectionRunFinish(record, input, now)\n const terminal = {\n executionToken: undefined,\n status: plan.status,\n finishedAt: plan.finishedAt,\n progress: plan.progress,\n error: plan.error,\n }\n if (plan.inputExhausted) {\n const telemetry = requireTelemetryProjectionRun(record)\n return {\n ...telemetry,\n ...terminal,\n telemetryCheckpoint: { ...telemetry.telemetryCheckpoint, inputExhausted: true },\n }\n }\n return { ...record, ...terminal }\n}\n\nexport function failProjectionRunEnqueue(\n record: StoredProjectionRunRecord,\n input: FailProjectionRunEnqueueInput,\n now: Date = new Date()\n): StoredProjectionRunRecord {\n if (record.status !== \"queued\") {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' cannot fail enqueue from status '${record.status}'.`\n )\n }\n const error = parseSixbFailure(input.error, PROJECTION_RUN_FAILURE_CODES)\n if (error.code !== \"queue.enqueue_failed\") {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' enqueue failure must use code 'queue.enqueue_failed'.`\n )\n }\n const finishedAt = new Date(input.finishedAt ?? now)\n assertProjectionRunDate(finishedAt, \"finishedAt\")\n return {\n ...record,\n status: \"failed\",\n finishedAt,\n error,\n }\n}\n\nexport function canRequeueProjectionRunAfterEnqueueFailure(\n record: ProjectionRunRecord,\n input: QueueProjectionRunInput\n): boolean {\n return (\n record.status === \"failed\" &&\n record.error?.code === \"queue.enqueue_failed\" &&\n record.error.retryable &&\n record.executionId === input.executionId &&\n projectionRunIdentitiesEqual(record.identity, input.identity) &&\n projectionTargetsEqual(record.target, input.target) &&\n record.telemetryCheckpoint?.fixedBatchSize === input.fixedBatchSize\n )\n}\n\n// ── Persistence mapping ─────────────────────────────────────\n\nexport function restoreProjectionRun(row: PersistedProjectionRunRecord): StoredProjectionRunRecord {\n assertProjectionRunNonEmpty(row.id, \"id\")\n assertProjectionRunNonEmpty(row.projectId, \"projectId\")\n assertProjectionRunNonEmpty(row.executionId, \"executionId\")\n assertProjectionRunCounter(row.attempt, \"attempt\")\n assertProjectionRunProgress(row.progress)\n assertValidDate(row.queuedAt, \"queuedAt\")\n if (row.startedAt) assertValidDate(row.startedAt, \"startedAt\")\n if (row.finishedAt) assertValidDate(row.finishedAt, \"finishedAt\")\n assertPersistedLifecycle(row)\n\n const identity = restoreIdentity(row)\n const base = {\n id: row.id,\n projectId: row.projectId,\n executionId: row.executionId,\n identity,\n status: row.status,\n queuedAt: new Date(row.queuedAt),\n startedAt: row.startedAt ? new Date(row.startedAt) : undefined,\n finishedAt: row.finishedAt ? new Date(row.finishedAt) : undefined,\n attempt: row.attempt,\n progress: { ...row.progress },\n error:\n row.error === undefined\n ? undefined\n : parseSixbFailure(row.error, PROJECTION_RUN_FAILURE_CODES),\n executionToken: row.executionToken,\n }\n\n if (identity.projectionKind === \"link\") {\n if (!row.sourceObjectTypeId || !row.targetObjectTypeId || row.objectTypeId) {\n throw invalidProjectionRunTarget(row.id)\n }\n assertNoCheckpoint(row)\n return {\n ...base,\n identity,\n target: {\n sourceObjectTypeId: row.sourceObjectTypeId,\n targetObjectTypeId: row.targetObjectTypeId,\n },\n }\n }\n if (!row.objectTypeId || row.sourceObjectTypeId || row.targetObjectTypeId) {\n throw invalidProjectionRunTarget(row.id)\n }\n if (identity.projectionKind === \"telemetry\") {\n const telemetryCheckpoint = restoreCheckpoint(row)\n if (row.progress.sourceRowsRead !== telemetryCheckpoint.nextRowOffset) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${row.id}' progress does not match its checkpoint.`\n )\n }\n if (row.status === \"succeeded\" && !telemetryCheckpoint.inputExhausted) {\n throw incompleteProjectionRun(row.id)\n }\n const missingTarget = restoreMissingTarget(row, telemetryCheckpoint)\n return {\n ...base,\n identity,\n target: { objectTypeId: row.objectTypeId },\n telemetryCheckpoint,\n ...(missingTarget ? { missingTarget } : {}),\n }\n }\n assertNoCheckpoint(row)\n return { ...base, identity, target: { objectTypeId: row.objectTypeId } }\n}\n\nexport function publicProjectionRunRecord(record: StoredProjectionRunRecord): ProjectionRunRecord {\n const cloned = structuredClone(record)\n Reflect.deleteProperty(cloned, \"executionToken\")\n return cloned\n}\n\nexport function createProjectionRunClaim(record: StoredProjectionRunRecord): ProjectionRunClaim {\n assertProjectionRunRunning(record)\n const executionToken = requireProjectionRunExecutionToken(record)\n return {\n run: publicProjectionRunRecord(record),\n execution: { projectionRunId: record.id, executionToken },\n }\n}\n\nexport function requireProjectionRunExecutionToken(record: StoredProjectionRunRecord): string {\n if (record.executionToken) return record.executionToken\n throw incompleteProjectionRun(record.id)\n}\n\nexport function staleProjectionRunExecution(id: string): ProjectionRunError {\n return new ProjectionRunError(\n `[Sixb] Projection run '${id}' execution token is stale.`,\n \"execution-lost\"\n )\n}\n\nexport function projectionRunNotFound(projectId: string, id: string): ProjectionRunError {\n return new ProjectionRunError(\n `[Sixb] Projection run '${id}' not found for project '${projectId}'.`\n )\n}\n\nexport function immutableDatasetVersionConflict(\n identity: ProjectionMaterializationIdentity\n): ProjectionRunError {\n return new ProjectionRunError(\n `[Sixb] Dataset version '${identity.datasetVersion.versionId}' reused an immutable dataset version id with different metadata.`\n )\n}\n\n// ── Private helpers ─────────────────────────────────────────\n\nfunction assertPositiveCounter(value: number, fieldName: string): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new ProjectionRunError(\n `[Sixb] Projection run ${fieldName} must be a positive safe integer.`\n )\n }\n}\n\nfunction assertCanonicalTimestamp(value: string, fieldName: string): void {\n const milliseconds = Date.parse(value)\n if (!Number.isFinite(milliseconds) || new Date(milliseconds).toISOString() !== value) {\n throw new ProjectionRunError(\n `[Sixb] Projection run ${fieldName} must be a canonical UTC timestamp.`\n )\n }\n}\n\nfunction assertValidDate(value: Date, fieldName: string): void {\n if (!Number.isFinite(value.getTime())) {\n throw new ProjectionRunError(`[Sixb] Projection run persisted ${fieldName} is invalid.`)\n }\n}\n\nfunction assertPersistedLifecycle(row: PersistedProjectionRunRecord): void {\n const hasError = row.error !== undefined\n\n if (row.status === \"queued\") {\n if (\n row.attempt !== 0 ||\n row.startedAt !== undefined ||\n row.finishedAt !== undefined ||\n row.executionToken !== undefined ||\n hasError\n ) {\n throw incompleteProjectionRun(row.id)\n }\n return\n }\n\n if (row.status === \"running\") {\n if (\n row.attempt < 1 ||\n row.startedAt === undefined ||\n row.finishedAt !== undefined ||\n row.executionToken === undefined ||\n hasError\n ) {\n throw incompleteProjectionRun(row.id)\n }\n return\n }\n\n if (row.finishedAt === undefined || row.executionToken !== undefined) {\n throw incompleteProjectionRun(row.id)\n }\n if (row.error !== undefined) {\n const failure = parseSixbFailure(row.error, PROJECTION_RUN_FAILURE_CODES)\n if (failure.code === \"queue.enqueue_failed\") {\n if (\n !failure.retryable ||\n row.status !== \"failed\" ||\n row.attempt !== 0 ||\n row.startedAt !== undefined\n ) {\n throw incompleteProjectionRun(row.id)\n }\n return\n }\n }\n if (row.attempt < 1 || row.startedAt === undefined || (row.status === \"succeeded\" && hasError)) {\n throw incompleteProjectionRun(row.id)\n }\n}\n\nfunction assertProjectionRunDate(value: Date, fieldName: string): void {\n if (!Number.isFinite(value.getTime())) {\n throw new ProjectionRunError(`[Sixb] Projection run ${fieldName} is invalid.`)\n }\n}\n\nfunction isProjectionKind(value: unknown): value is ProjectionKind {\n return value === \"object\" || value === \"link\" || value === \"telemetry\"\n}\n\nfunction assertProjectionTarget(kind: ProjectionKind, target: ProjectionTarget): void {\n if (kind === \"link\") {\n if (!(\"sourceObjectTypeId\" in target)) {\n throw new ProjectionRunError(\n \"[Sixb] Link projection runs must declare source and target object types.\"\n )\n }\n assertProjectionRunNonEmpty(target.sourceObjectTypeId, \"sourceObjectTypeId\")\n assertProjectionRunNonEmpty(target.targetObjectTypeId, \"targetObjectTypeId\")\n return\n }\n if (!(\"objectTypeId\" in target)) {\n throw new ProjectionRunError(\n \"[Sixb] Object and telemetry projection runs must declare one object type.\"\n )\n }\n assertProjectionRunNonEmpty(target.objectTypeId, \"objectTypeId\")\n}\n\nfunction projectionRunIdentitiesEqual(\n left: ProjectionMaterializationIdentity,\n right: ProjectionMaterializationIdentity\n): boolean {\n return (\n left.projectionId === right.projectionId &&\n left.projectionKind === right.projectionKind &&\n left.protocol === right.protocol &&\n left.datasetVersion.datasetId === right.datasetVersion.datasetId &&\n left.datasetVersion.versionId === right.datasetVersion.versionId &&\n left.datasetVersion.createdAt === right.datasetVersion.createdAt &&\n left.ontologyRevision === right.ontologyRevision &&\n left.projectionRevision === right.projectionRevision &&\n left.ownershipHash === right.ownershipHash\n )\n}\n\nfunction projectionTargetsEqual(left: ProjectionTarget, right: ProjectionTarget): boolean {\n if (\"sourceObjectTypeId\" in left || \"sourceObjectTypeId\" in right) {\n return (\n \"sourceObjectTypeId\" in left &&\n \"sourceObjectTypeId\" in right &&\n left.sourceObjectTypeId === right.sourceObjectTypeId &&\n left.targetObjectTypeId === right.targetObjectTypeId\n )\n }\n return left.objectTypeId === right.objectTypeId\n}\n\nfunction assertProjectionRunProgress(progress: ProjectionRunProgress): void {\n for (const key of PROJECTION_RUN_PROGRESS_KEYS) {\n assertProjectionRunCounter(progress[key], key)\n }\n if (progress.sourceRowsSkipped > progress.sourceRowsRead) {\n throw new ProjectionRunError(\n \"[Sixb] Projection run sourceRowsSkipped must not exceed sourceRowsRead.\"\n )\n }\n}\n\nfunction assertFinishDecision(\n record: ProjectionRunRecord,\n input: ProjectionRunTerminalDecision\n): void {\n if (input.status !== \"succeeded\" && input.status !== \"failed\" && input.status !== \"cancelled\") {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' finish status must be terminal.`\n )\n }\n if (input.protocol !== \"replacement\" && input.protocol !== \"telemetry\") {\n throw new ProjectionRunError(`[Sixb] Projection run '${record.id}' finish protocol is invalid.`)\n }\n if (input.protocol !== record.identity.protocol) {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' finish protocol does not match its identity.`\n )\n }\n const inputExhausted = \"inputExhausted\" in input ? input.inputExhausted : undefined\n if (input.status === \"succeeded\" && input.protocol === \"telemetry\") {\n if (inputExhausted === true) return\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' cannot succeed before input exhaustion.`\n )\n }\n if (inputExhausted !== undefined) {\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' contains telemetry-only completion metadata.`\n )\n }\n}\n\nfunction restoreIdentity(row: PersistedProjectionRunRecord): ProjectionMaterializationIdentity {\n if (\n !row.protocol ||\n !row.datasetVersionCreatedAt ||\n !row.ontologyRevision ||\n !row.projectionRevision ||\n !row.ownershipHash\n ) {\n throw incompleteProjectionRun(row.id)\n }\n const identity = {\n projectionId: row.projectionId,\n projectionKind: row.projectionKind,\n protocol: row.protocol,\n datasetVersion: {\n datasetId: row.datasetId,\n versionId: row.datasetVersionId,\n createdAt: row.datasetVersionCreatedAt,\n },\n ontologyRevision: row.ontologyRevision,\n projectionRevision: row.projectionRevision,\n ownershipHash: row.ownershipHash,\n } as ProjectionMaterializationIdentity\n assertProjectionRunIdentity(identity)\n return identity\n}\n\nfunction restoreCheckpoint(row: PersistedProjectionRunRecord): ProjectionTelemetryCheckpoint {\n if (\n row.fixedBatchSize === undefined ||\n row.nextBatchOrdinal === undefined ||\n row.nextRowOffset === undefined ||\n row.inputExhausted === undefined\n ) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${row.id}' has incomplete checkpoint state.`\n )\n }\n assertPositiveCounter(row.fixedBatchSize, \"fixedBatchSize\")\n assertProjectionRunCounter(row.nextBatchOrdinal, \"nextBatchOrdinal\")\n assertProjectionRunCounter(row.nextRowOffset, \"nextRowOffset\")\n return {\n fixedBatchSize: row.fixedBatchSize,\n nextBatchOrdinal: row.nextBatchOrdinal,\n nextRowOffset: row.nextRowOffset,\n inputExhausted: row.inputExhausted,\n }\n}\n\n/**\n * A wait is either fully persisted or absent. A partially written one would read as \"waiting since\n * the epoch\" or \"waiting for nothing\", and both would decide a run's fate.\n */\nfunction restoreMissingTarget(\n row: PersistedProjectionRunRecord,\n checkpoint: ProjectionTelemetryCheckpoint\n): ProjectionMissingTarget | undefined {\n const columns = [\n row.missingTargetObjectTypeId,\n row.missingTargetObjectId,\n row.missingTargetBatchOrdinal,\n row.missingTargetFirstSeenAt,\n ]\n if (columns.every((column) => column === undefined)) return undefined\n if (\n row.missingTargetObjectTypeId === undefined ||\n row.missingTargetObjectId === undefined ||\n row.missingTargetBatchOrdinal === undefined ||\n row.missingTargetFirstSeenAt === undefined\n ) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${row.id}' has a partially persisted missing target.`\n )\n }\n const missingTarget: ProjectionMissingTarget = {\n objectTypeId: row.missingTargetObjectTypeId,\n objectId: row.missingTargetObjectId,\n batchOrdinal: row.missingTargetBatchOrdinal,\n firstSeenAt: new Date(row.missingTargetFirstSeenAt),\n }\n assertValidDate(missingTarget.firstSeenAt, \"missingTarget.firstSeenAt\")\n assertProjectionRunCounter(missingTarget.batchOrdinal, \"missingTarget.batchOrdinal\")\n if (missingTarget.batchOrdinal !== checkpoint.nextBatchOrdinal) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${row.id}' is waiting on a batch it has already passed.`\n )\n }\n if (missingTarget.objectTypeId !== row.objectTypeId) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${row.id}' is waiting on an object type it does not write.`\n )\n }\n return missingTarget\n}\n\nfunction assertNoCheckpoint(row: PersistedProjectionRunRecord): void {\n if (\n row.fixedBatchSize === undefined &&\n row.nextBatchOrdinal === undefined &&\n row.nextRowOffset === undefined &&\n row.inputExhausted === undefined\n ) {\n return\n }\n throw new ProjectionRunError(\n `[Sixb] Replacement projection run '${row.id}' contains a telemetry checkpoint.`\n )\n}\n\nfunction incompleteProjectionRun(id: string): ProjectionRunError {\n return new ProjectionRunError(\n `[Sixb] Projection run '${id}' has incomplete materialization state.`\n )\n}\n\nfunction invalidProjectionRunTarget(id: string): ProjectionRunError {\n return new ProjectionRunError(`[Sixb] Projection run '${id}' has an invalid target.`)\n}\n\n/**\n * Validates a wait before it is stored, so every adapter refuses the same shapes and the SQL\n * `CHECK` behind them never has to be the thing that catches it.\n *\n * The ordinal has to be the batch the run is actually stuck on: anchored to a stale one, a wait\n * would survive the progress that resolved it and fail a run that is working. The object type\n * has to be the one this run writes, since that is the only type its telemetry can reference.\n */\nexport function assertProjectionMissingTarget(\n record: TelemetryProjectionRunRecord,\n missingTarget: ProjectionMissingTarget\n): ProjectionMissingTarget {\n assertProjectionRunNonEmpty(missingTarget.objectTypeId, \"missingTarget.objectTypeId\")\n assertProjectionRunNonEmpty(missingTarget.objectId, \"missingTarget.objectId\")\n assertProjectionRunCounter(missingTarget.batchOrdinal, \"missingTarget.batchOrdinal\")\n if (Number.isNaN(missingTarget.firstSeenAt.getTime())) {\n throw new ProjectionRunError(\"[Sixb] Projection run missingTarget.firstSeenAt is invalid.\")\n }\n if (missingTarget.objectTypeId !== record.target.objectTypeId) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' cannot wait on '${missingTarget.objectTypeId}'; it writes '${record.target.objectTypeId}'.`\n )\n }\n if (missingTarget.batchOrdinal !== record.telemetryCheckpoint.nextBatchOrdinal) {\n throw new ProjectionRunError(\n `[Sixb] Telemetry projection run '${record.id}' cannot wait on batch ${missingTarget.batchOrdinal}; it is at ${record.telemetryCheckpoint.nextBatchOrdinal}.`\n )\n }\n return missingTarget\n}\n\nexport function requireTelemetryProjectionRun<TRecord extends ProjectionRunRecord>(\n record: TRecord\n): TRecord & TelemetryProjectionRunRecord {\n if (isTelemetryProjectionRun(record)) return record as TRecord & TelemetryProjectionRunRecord\n throw new ProjectionRunError(\n `[Sixb] Projection run '${record.id}' does not have a telemetry checkpoint.`\n )\n}\n\ntype ProjectionRunIdentityInput<TKind extends ProjectionKind> = Extract<\n QueueProjectionRunInput | StartOrReclaimProjectionRunInput,\n { readonly identity: { readonly projectionKind: TKind } }\n>\n\ntype ProjectionRunAdmission<TKind extends ProjectionKind> = Extract<\n QueueProjectionRunInput,\n { readonly identity: { readonly projectionKind: TKind } }\n>\n\nfunction isTelemetryProjectionRun(\n record: ProjectionRunRecord\n): record is TelemetryProjectionRunRecord {\n return record.identity.projectionKind === \"telemetry\"\n}\n",
9
9
  "import type { ExecutionStorage } from \"../executions\"\nimport { findPrimitiveRunExecution } from \"../executions/run-link\"\nimport { ProjectionRunError } from \"./errors\"\n\nexport * from \"./lifecycle\"\n\n/** Validate the semantic link between a durable Projection run and its immutable execution. */\nexport async function assertProjectionRunDurableExecution(input: {\n readonly executions: ExecutionStorage\n readonly projectId: string\n readonly executionId: string\n readonly runId: string\n readonly projectionId: string\n readonly datasetId: string\n readonly datasetVersionId: string\n}): Promise<void> {\n const execution = await findPrimitiveRunExecution({\n executions: input.executions,\n projectId: input.projectId,\n executionId: input.executionId,\n primitive: { kind: \"projection\", id: input.projectionId, runId: input.runId },\n sourceTypes: [\"datasetVersion\"],\n })\n if (\n !execution ||\n execution.source.type !== \"datasetVersion\" ||\n execution.source.datasetId !== input.datasetId ||\n execution.source.versionId !== input.datasetVersionId\n ) {\n throw new ProjectionRunError(\n `[Sixb] Execution '${input.executionId}' does not authorize Projection run '${input.runId}'.`\n )\n }\n}\n"
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  createTrustedPrimitiveRuntimeAuthorization,
7
7
  getAuthorizationRef
8
- } from "./chunk-34bqh420.js";
8
+ } from "./chunk-f83ka50g.js";
9
9
 
10
10
  // src/execution/durable.ts
11
11
  import { isDeepStrictEqual } from "util";