@shipfox/api-logs 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +179 -0
  5. package/LICENSE +21 -0
  6. package/README.md +151 -0
  7. package/dist/api/object-storage.d.ts +69 -0
  8. package/dist/api/object-storage.d.ts.map +1 -0
  9. package/dist/api/object-storage.js +199 -0
  10. package/dist/api/object-storage.js.map +1 -0
  11. package/dist/config.d.ts +20 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +108 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/core/append-logs.d.ts +28 -0
  16. package/dist/core/append-logs.d.ts.map +1 -0
  17. package/dist/core/append-logs.js +318 -0
  18. package/dist/core/append-logs.js.map +1 -0
  19. package/dist/core/budget.d.ts +12 -0
  20. package/dist/core/budget.d.ts.map +1 -0
  21. package/dist/core/budget.js +9 -0
  22. package/dist/core/budget.js.map +1 -0
  23. package/dist/core/close-stream.d.ts +27 -0
  24. package/dist/core/close-stream.d.ts.map +1 -0
  25. package/dist/core/close-stream.js +59 -0
  26. package/dist/core/close-stream.js.map +1 -0
  27. package/dist/core/compaction.d.ts +28 -0
  28. package/dist/core/compaction.d.ts.map +1 -0
  29. package/dist/core/compaction.js +49 -0
  30. package/dist/core/compaction.js.map +1 -0
  31. package/dist/core/entities/attempt-stream.d.ts +37 -0
  32. package/dist/core/entities/attempt-stream.d.ts.map +1 -0
  33. package/dist/core/entities/attempt-stream.js +15 -0
  34. package/dist/core/entities/attempt-stream.js.map +1 -0
  35. package/dist/core/entities/job-accounting.d.ts +12 -0
  36. package/dist/core/entities/job-accounting.d.ts.map +1 -0
  37. package/dist/core/entities/job-accounting.js +6 -0
  38. package/dist/core/entities/job-accounting.js.map +1 -0
  39. package/dist/core/entities/log-object.d.ts +13 -0
  40. package/dist/core/entities/log-object.d.ts.map +1 -0
  41. package/dist/core/entities/log-object.js +9 -0
  42. package/dist/core/entities/log-object.js.map +1 -0
  43. package/dist/core/errors.d.ts +26 -0
  44. package/dist/core/errors.d.ts.map +1 -0
  45. package/dist/core/errors.js +31 -0
  46. package/dist/core/errors.js.map +1 -0
  47. package/dist/core/finalize-attempt-stream.d.ts +22 -0
  48. package/dist/core/finalize-attempt-stream.d.ts.map +1 -0
  49. package/dist/core/finalize-attempt-stream.js +48 -0
  50. package/dist/core/finalize-attempt-stream.js.map +1 -0
  51. package/dist/core/read-logs.d.ts +33 -0
  52. package/dist/core/read-logs.d.ts.map +1 -0
  53. package/dist/core/read-logs.js +49 -0
  54. package/dist/core/read-logs.js.map +1 -0
  55. package/dist/core/reap-stale-open-streams.d.ts +27 -0
  56. package/dist/core/reap-stale-open-streams.d.ts.map +1 -0
  57. package/dist/core/reap-stale-open-streams.js +50 -0
  58. package/dist/core/reap-stale-open-streams.js.map +1 -0
  59. package/dist/core/retention.d.ts +32 -0
  60. package/dist/core/retention.d.ts.map +1 -0
  61. package/dist/core/retention.js +148 -0
  62. package/dist/core/retention.js.map +1 -0
  63. package/dist/core/session/claude/rows.d.ts +6 -0
  64. package/dist/core/session/claude/rows.d.ts.map +1 -0
  65. package/dist/core/session/claude/rows.js +145 -0
  66. package/dist/core/session/claude/rows.js.map +1 -0
  67. package/dist/core/session/claude-parser.d.ts +4 -0
  68. package/dist/core/session/claude-parser.d.ts.map +1 -0
  69. package/dist/core/session/claude-parser.js +42 -0
  70. package/dist/core/session/claude-parser.js.map +1 -0
  71. package/dist/core/session/entry-schema.d.ts +51 -0
  72. package/dist/core/session/entry-schema.d.ts.map +1 -0
  73. package/dist/core/session/entry-schema.js +61 -0
  74. package/dist/core/session/entry-schema.js.map +1 -0
  75. package/dist/core/session/object.d.ts +12 -0
  76. package/dist/core/session/object.d.ts.map +1 -0
  77. package/dist/core/session/object.js +50 -0
  78. package/dist/core/session/object.js.map +1 -0
  79. package/dist/core/session/parse-session.d.ts +5 -0
  80. package/dist/core/session/parse-session.d.ts.map +1 -0
  81. package/dist/core/session/parse-session.js +18 -0
  82. package/dist/core/session/parse-session.js.map +1 -0
  83. package/dist/core/session/pi/message-rows.d.ts +4 -0
  84. package/dist/core/session/pi/message-rows.d.ts.map +1 -0
  85. package/dist/core/session/pi/message-rows.js +113 -0
  86. package/dist/core/session/pi/message-rows.js.map +1 -0
  87. package/dist/core/session/pi/metadata.d.ts +18 -0
  88. package/dist/core/session/pi/metadata.d.ts.map +1 -0
  89. package/dist/core/session/pi/metadata.js +120 -0
  90. package/dist/core/session/pi/metadata.js.map +1 -0
  91. package/dist/core/session/pi/text.d.ts +12 -0
  92. package/dist/core/session/pi/text.d.ts.map +1 -0
  93. package/dist/core/session/pi/text.js +59 -0
  94. package/dist/core/session/pi/text.js.map +1 -0
  95. package/dist/core/session/pi-parser.d.ts +5 -0
  96. package/dist/core/session/pi-parser.d.ts.map +1 -0
  97. package/dist/core/session/pi-parser.js +73 -0
  98. package/dist/core/session/pi-parser.js.map +1 -0
  99. package/dist/core/session/rows.d.ts +7 -0
  100. package/dist/core/session/rows.d.ts.map +1 -0
  101. package/dist/core/session/rows.js +39 -0
  102. package/dist/core/session/rows.js.map +1 -0
  103. package/dist/core/session/session-record.d.ts +5 -0
  104. package/dist/core/session/session-record.d.ts.map +1 -0
  105. package/dist/core/session/session-record.js +3 -0
  106. package/dist/core/session/session-record.js.map +1 -0
  107. package/dist/db/accounting.d.ts +33 -0
  108. package/dist/db/accounting.d.ts.map +1 -0
  109. package/dist/db/accounting.js +52 -0
  110. package/dist/db/accounting.js.map +1 -0
  111. package/dist/db/chunks.d.ts +62 -0
  112. package/dist/db/chunks.d.ts.map +1 -0
  113. package/dist/db/chunks.js +88 -0
  114. package/dist/db/chunks.js.map +1 -0
  115. package/dist/db/db.d.ts +752 -0
  116. package/dist/db/db.d.ts.map +1 -0
  117. package/dist/db/db.js +24 -0
  118. package/dist/db/db.js.map +1 -0
  119. package/dist/db/index.d.ts +2 -0
  120. package/dist/db/index.d.ts.map +1 -0
  121. package/dist/db/index.js +5 -0
  122. package/dist/db/index.js.map +1 -0
  123. package/dist/db/schema/attempt-streams.d.ts +304 -0
  124. package/dist/db/schema/attempt-streams.d.ts.map +1 -0
  125. package/dist/db/schema/attempt-streams.js +100 -0
  126. package/dist/db/schema/attempt-streams.js.map +1 -0
  127. package/dist/db/schema/chunks.d.ts +166 -0
  128. package/dist/db/schema/chunks.d.ts.map +1 -0
  129. package/dist/db/schema/chunks.js +47 -0
  130. package/dist/db/schema/chunks.js.map +1 -0
  131. package/dist/db/schema/common.d.ts +29 -0
  132. package/dist/db/schema/common.d.ts.map +1 -0
  133. package/dist/db/schema/common.js +11 -0
  134. package/dist/db/schema/common.js.map +1 -0
  135. package/dist/db/schema/job-accounting.d.ts +143 -0
  136. package/dist/db/schema/job-accounting.d.ts.map +1 -0
  137. package/dist/db/schema/job-accounting.js +43 -0
  138. package/dist/db/schema/job-accounting.js.map +1 -0
  139. package/dist/db/schema/outbox.d.ts +195 -0
  140. package/dist/db/schema/outbox.d.ts.map +1 -0
  141. package/dist/db/schema/outbox.js +5 -0
  142. package/dist/db/schema/outbox.js.map +1 -0
  143. package/dist/db/streams.d.ts +141 -0
  144. package/dist/db/streams.d.ts.map +1 -0
  145. package/dist/db/streams.js +197 -0
  146. package/dist/db/streams.js.map +1 -0
  147. package/dist/index.d.ts +4 -0
  148. package/dist/index.d.ts.map +1 -0
  149. package/dist/index.js +81 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/metrics/index.d.ts +2 -0
  152. package/dist/metrics/index.d.ts.map +1 -0
  153. package/dist/metrics/index.js +3 -0
  154. package/dist/metrics/index.js.map +1 -0
  155. package/dist/metrics/instance.d.ts +14 -0
  156. package/dist/metrics/instance.d.ts.map +1 -0
  157. package/dist/metrics/instance.js +16 -0
  158. package/dist/metrics/instance.js.map +1 -0
  159. package/dist/metrics/service.d.ts +2 -0
  160. package/dist/metrics/service.d.ts.map +1 -0
  161. package/dist/metrics/service.js +20 -0
  162. package/dist/metrics/service.js.map +1 -0
  163. package/dist/presentation/dto/read-logs.d.ts +4 -0
  164. package/dist/presentation/dto/read-logs.d.ts.map +1 -0
  165. package/dist/presentation/dto/read-logs.js +22 -0
  166. package/dist/presentation/dto/read-logs.js.map +1 -0
  167. package/dist/presentation/routes/append-logs.d.ts +2 -0
  168. package/dist/presentation/routes/append-logs.d.ts.map +1 -0
  169. package/dist/presentation/routes/append-logs.js +71 -0
  170. package/dist/presentation/routes/append-logs.js.map +1 -0
  171. package/dist/presentation/routes/index.d.ts +3 -0
  172. package/dist/presentation/routes/index.d.ts.map +1 -0
  173. package/dist/presentation/routes/index.js +32 -0
  174. package/dist/presentation/routes/index.js.map +1 -0
  175. package/dist/presentation/routes/read-logs.d.ts +2 -0
  176. package/dist/presentation/routes/read-logs.d.ts.map +1 -0
  177. package/dist/presentation/routes/read-logs.js +41 -0
  178. package/dist/presentation/routes/read-logs.js.map +1 -0
  179. package/dist/presentation/subscribers/on-job-terminated.d.ts +8 -0
  180. package/dist/presentation/subscribers/on-job-terminated.d.ts.map +1 -0
  181. package/dist/presentation/subscribers/on-job-terminated.js +32 -0
  182. package/dist/presentation/subscribers/on-job-terminated.js.map +1 -0
  183. package/dist/presentation/subscribers/on-log-stream-closed.d.ts +9 -0
  184. package/dist/presentation/subscribers/on-log-stream-closed.d.ts.map +1 -0
  185. package/dist/presentation/subscribers/on-log-stream-closed.js +31 -0
  186. package/dist/presentation/subscribers/on-log-stream-closed.js.map +1 -0
  187. package/dist/presentation/subscribers/on-step-attempt-terminated.d.ts +3 -0
  188. package/dist/presentation/subscribers/on-step-attempt-terminated.d.ts.map +1 -0
  189. package/dist/presentation/subscribers/on-step-attempt-terminated.js +14 -0
  190. package/dist/presentation/subscribers/on-step-attempt-terminated.js.map +1 -0
  191. package/dist/temporal/activities/close-abandoned-streams.d.ts +12 -0
  192. package/dist/temporal/activities/close-abandoned-streams.d.ts.map +1 -0
  193. package/dist/temporal/activities/close-abandoned-streams.js +33 -0
  194. package/dist/temporal/activities/close-abandoned-streams.js.map +1 -0
  195. package/dist/temporal/activities/compact-stream.d.ts +33 -0
  196. package/dist/temporal/activities/compact-stream.d.ts.map +1 -0
  197. package/dist/temporal/activities/compact-stream.js +95 -0
  198. package/dist/temporal/activities/compact-stream.js.map +1 -0
  199. package/dist/temporal/activities/compaction-reconcile.d.ts +16 -0
  200. package/dist/temporal/activities/compaction-reconcile.d.ts.map +1 -0
  201. package/dist/temporal/activities/compaction-reconcile.js +52 -0
  202. package/dist/temporal/activities/compaction-reconcile.js.map +1 -0
  203. package/dist/temporal/activities/index.d.ts +14 -0
  204. package/dist/temporal/activities/index.d.ts.map +1 -0
  205. package/dist/temporal/activities/index.js +16 -0
  206. package/dist/temporal/activities/index.js.map +1 -0
  207. package/dist/temporal/activities/reap-stale-open-streams.d.ts +4 -0
  208. package/dist/temporal/activities/reap-stale-open-streams.d.ts.map +1 -0
  209. package/dist/temporal/activities/reap-stale-open-streams.js +11 -0
  210. package/dist/temporal/activities/reap-stale-open-streams.js.map +1 -0
  211. package/dist/temporal/activities/retention-sweep.d.ts +7 -0
  212. package/dist/temporal/activities/retention-sweep.d.ts.map +1 -0
  213. package/dist/temporal/activities/retention-sweep.js +19 -0
  214. package/dist/temporal/activities/retention-sweep.js.map +1 -0
  215. package/dist/temporal/constants.d.ts +7 -0
  216. package/dist/temporal/constants.d.ts.map +1 -0
  217. package/dist/temporal/constants.js +13 -0
  218. package/dist/temporal/constants.js.map +1 -0
  219. package/dist/temporal/workflows/close-abandoned-streams.d.ts +11 -0
  220. package/dist/temporal/workflows/close-abandoned-streams.d.ts.map +1 -0
  221. package/dist/temporal/workflows/close-abandoned-streams.js +22 -0
  222. package/dist/temporal/workflows/close-abandoned-streams.js.map +1 -0
  223. package/dist/temporal/workflows/compact-stream.d.ts +6 -0
  224. package/dist/temporal/workflows/compact-stream.d.ts.map +1 -0
  225. package/dist/temporal/workflows/compact-stream.js +25 -0
  226. package/dist/temporal/workflows/compact-stream.js.map +1 -0
  227. package/dist/temporal/workflows/compaction-reconcile-cron.d.ts +3 -0
  228. package/dist/temporal/workflows/compaction-reconcile-cron.d.ts.map +1 -0
  229. package/dist/temporal/workflows/compaction-reconcile-cron.js +15 -0
  230. package/dist/temporal/workflows/compaction-reconcile-cron.js.map +1 -0
  231. package/dist/temporal/workflows/index.d.ts +6 -0
  232. package/dist/temporal/workflows/index.d.ts.map +1 -0
  233. package/dist/temporal/workflows/index.js +7 -0
  234. package/dist/temporal/workflows/index.js.map +1 -0
  235. package/dist/temporal/workflows/reap-stale-open-streams-cron.d.ts +2 -0
  236. package/dist/temporal/workflows/reap-stale-open-streams-cron.d.ts.map +1 -0
  237. package/dist/temporal/workflows/reap-stale-open-streams-cron.js +15 -0
  238. package/dist/temporal/workflows/reap-stale-open-streams-cron.js.map +1 -0
  239. package/dist/temporal/workflows/retention-sweep-cron.d.ts +2 -0
  240. package/dist/temporal/workflows/retention-sweep-cron.d.ts.map +1 -0
  241. package/dist/temporal/workflows/retention-sweep-cron.js +23 -0
  242. package/dist/temporal/workflows/retention-sweep-cron.js.map +1 -0
  243. package/dist/tsconfig.test.tsbuildinfo +1 -0
  244. package/drizzle/0000_initial.sql +65 -0
  245. package/drizzle/meta/0000_snapshot.json +529 -0
  246. package/drizzle/meta/_journal.json +13 -0
  247. package/drizzle.config.ts +7 -0
  248. package/package.json +84 -0
  249. package/src/api/object-storage-credentials.test.ts +70 -0
  250. package/src/api/object-storage.test.ts +64 -0
  251. package/src/api/object-storage.ts +226 -0
  252. package/src/config.test.ts +118 -0
  253. package/src/config.ts +130 -0
  254. package/src/core/append-logs.test.ts +563 -0
  255. package/src/core/append-logs.ts +384 -0
  256. package/src/core/budget.test.ts +30 -0
  257. package/src/core/budget.ts +19 -0
  258. package/src/core/close-stream.ts +72 -0
  259. package/src/core/compaction.ts +68 -0
  260. package/src/core/entities/attempt-stream.ts +38 -0
  261. package/src/core/entities/job-accounting.ts +11 -0
  262. package/src/core/entities/log-object.test.ts +25 -0
  263. package/src/core/entities/log-object.ts +18 -0
  264. package/src/core/errors.ts +37 -0
  265. package/src/core/finalize-attempt-stream.test.ts +90 -0
  266. package/src/core/finalize-attempt-stream.ts +59 -0
  267. package/src/core/read-logs.ts +77 -0
  268. package/src/core/reap-stale-open-streams.test.ts +137 -0
  269. package/src/core/reap-stale-open-streams.ts +60 -0
  270. package/src/core/retention.test.ts +388 -0
  271. package/src/core/retention.ts +184 -0
  272. package/src/core/session/claude/rows.ts +223 -0
  273. package/src/core/session/claude-parser.test.ts +199 -0
  274. package/src/core/session/claude-parser.ts +38 -0
  275. package/src/core/session/entry-schema.ts +82 -0
  276. package/src/core/session/object.ts +57 -0
  277. package/src/core/session/parse-session.ts +23 -0
  278. package/src/core/session/pi/message-rows.ts +211 -0
  279. package/src/core/session/pi/metadata.ts +148 -0
  280. package/src/core/session/pi/text.ts +83 -0
  281. package/src/core/session/pi-parser.test.ts +451 -0
  282. package/src/core/session/pi-parser.ts +107 -0
  283. package/src/core/session/rows.ts +38 -0
  284. package/src/core/session/session-record.ts +4 -0
  285. package/src/db/accounting.ts +81 -0
  286. package/src/db/chunks.ts +143 -0
  287. package/src/db/db.ts +22 -0
  288. package/src/db/index.ts +4 -0
  289. package/src/db/schema/attempt-streams.ts +106 -0
  290. package/src/db/schema/chunks.ts +43 -0
  291. package/src/db/schema/common.ts +12 -0
  292. package/src/db/schema/job-accounting.ts +38 -0
  293. package/src/db/schema/outbox.ts +4 -0
  294. package/src/db/streams.test.ts +47 -0
  295. package/src/db/streams.ts +368 -0
  296. package/src/index.ts +77 -0
  297. package/src/metrics/index.ts +1 -0
  298. package/src/metrics/instance.ts +33 -0
  299. package/src/metrics/service.ts +23 -0
  300. package/src/presentation/dto/read-logs.ts +24 -0
  301. package/src/presentation/routes/append-logs.test.ts +279 -0
  302. package/src/presentation/routes/append-logs.ts +66 -0
  303. package/src/presentation/routes/index.ts +27 -0
  304. package/src/presentation/routes/read-logs.test.ts +504 -0
  305. package/src/presentation/routes/read-logs.ts +38 -0
  306. package/src/presentation/subscribers/on-job-terminated.test.ts +64 -0
  307. package/src/presentation/subscribers/on-job-terminated.ts +26 -0
  308. package/src/presentation/subscribers/on-log-stream-closed.test.ts +63 -0
  309. package/src/presentation/subscribers/on-log-stream-closed.ts +26 -0
  310. package/src/presentation/subscribers/on-step-attempt-terminated.ts +16 -0
  311. package/src/temporal/activities/close-abandoned-streams.test.ts +84 -0
  312. package/src/temporal/activities/close-abandoned-streams.ts +30 -0
  313. package/src/temporal/activities/compact-stream.test.ts +221 -0
  314. package/src/temporal/activities/compact-stream.ts +123 -0
  315. package/src/temporal/activities/compaction-reconcile.test.ts +143 -0
  316. package/src/temporal/activities/compaction-reconcile.ts +48 -0
  317. package/src/temporal/activities/index.ts +15 -0
  318. package/src/temporal/activities/reap-stale-open-streams.test.ts +48 -0
  319. package/src/temporal/activities/reap-stale-open-streams.ts +14 -0
  320. package/src/temporal/activities/retention-sweep.test.ts +38 -0
  321. package/src/temporal/activities/retention-sweep.ts +23 -0
  322. package/src/temporal/constants.ts +14 -0
  323. package/src/temporal/workflows/close-abandoned-streams.ts +25 -0
  324. package/src/temporal/workflows/compact-stream.ts +26 -0
  325. package/src/temporal/workflows/compaction-reconcile-cron.ts +14 -0
  326. package/src/temporal/workflows/index.ts +5 -0
  327. package/src/temporal/workflows/reap-stale-open-streams-cron.ts +13 -0
  328. package/src/temporal/workflows/retention-sweep-cron.ts +23 -0
  329. package/test/env.ts +37 -0
  330. package/test/factories/job-accounting.ts +38 -0
  331. package/test/fixtures/closed-stream.ts +53 -0
  332. package/test/fixtures/lease-token.ts +42 -0
  333. package/test/fixtures/ndjson.ts +34 -0
  334. package/test/globalSetup.ts +44 -0
  335. package/test/index.ts +9 -0
  336. package/test/queries.ts +54 -0
  337. package/test/setup.ts +17 -0
  338. package/tsconfig.build.json +9 -0
  339. package/tsconfig.build.tsbuildinfo +1 -0
  340. package/tsconfig.json +3 -0
  341. package/tsconfig.test.json +8 -0
  342. package/vitest.config.ts +13 -0
@@ -0,0 +1,47 @@
1
+ import { uuidv7PrimaryKey } from '@shipfox/node-drizzle';
2
+ import { bigint, bigserial, index, integer, text, timestamp, uuid } from 'drizzle-orm/pg-core';
3
+ import { attemptStreams } from './attempt-streams.js';
4
+ import { bytea, pgTable } from './common.js';
5
+ /**
6
+ * Hot, append-only log bytes for open streams, pending compaction.
7
+ *
8
+ * Two byte axes meet here and MUST stay distinct:
9
+ *
10
+ * Runner spool (CAS axis) Stored chunk stream (read axis, by seq)
11
+ * offset 0 ┌────────────┐ ───► seq 1 │ normalized chunk A │ origin=runner
12
+ * 100 ├─ chunk A ──┤ ───► seq 2 │ normalized chunk B │ origin=runner
13
+ * 250 ├─ chunk B ──┤ ───► seq 3 │ {capped} │ origin=control ← server-injected;
14
+ * └────────────┘ does NOT advance committed_length
15
+ *
16
+ * `origin` is `runner` for bytes accepted from a runner append after ingest normalization, and
17
+ * `control` for a server-injected tombstone. `stream_offset` is the runner-axis position of a
18
+ * runner chunk; for a server `control` chunk it is informational. `seq` (insertion order) is the
19
+ * read axis the reader walks, so server records interleave correctly with normalized runner
20
+ * records.
21
+ */ export const logChunks = pgTable('chunks', {
22
+ id: uuidv7PrimaryKey(),
23
+ streamId: uuid('stream_id').notNull().references(()=>attemptStreams.id, {
24
+ onDelete: 'cascade'
25
+ }),
26
+ seq: bigserial('seq', {
27
+ mode: 'number'
28
+ }).notNull(),
29
+ streamOffset: bigint('stream_offset', {
30
+ mode: 'number'
31
+ }).notNull(),
32
+ byteLen: integer('byte_len').notNull(),
33
+ data: bytea('data').notNull(),
34
+ origin: text('origin', {
35
+ enum: [
36
+ 'runner',
37
+ 'control'
38
+ ]
39
+ }).notNull(),
40
+ createdAt: timestamp('created_at', {
41
+ withTimezone: true
42
+ }).notNull().defaultNow()
43
+ }, (table)=>[
44
+ index('logs_chunks_stream_seq_idx').on(table.streamId, table.seq)
45
+ ]);
46
+
47
+ //# sourceMappingURL=chunks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db/schema/chunks.ts"],"sourcesContent":["import {uuidv7PrimaryKey} from '@shipfox/node-drizzle';\nimport {bigint, bigserial, index, integer, text, timestamp, uuid} from 'drizzle-orm/pg-core';\nimport {attemptStreams} from './attempt-streams.js';\nimport {bytea, pgTable} from './common.js';\n\n/**\n * Hot, append-only log bytes for open streams, pending compaction.\n *\n * Two byte axes meet here and MUST stay distinct:\n *\n * Runner spool (CAS axis) Stored chunk stream (read axis, by seq)\n * offset 0 ┌────────────┐ ───► seq 1 │ normalized chunk A │ origin=runner\n * 100 ├─ chunk A ──┤ ───► seq 2 │ normalized chunk B │ origin=runner\n * 250 ├─ chunk B ──┤ ───► seq 3 │ {capped} │ origin=control ← server-injected;\n * └────────────┘ does NOT advance committed_length\n *\n * `origin` is `runner` for bytes accepted from a runner append after ingest normalization, and\n * `control` for a server-injected tombstone. `stream_offset` is the runner-axis position of a\n * runner chunk; for a server `control` chunk it is informational. `seq` (insertion order) is the\n * read axis the reader walks, so server records interleave correctly with normalized runner\n * records.\n */\nexport const logChunks = pgTable(\n 'chunks',\n {\n id: uuidv7PrimaryKey(),\n streamId: uuid('stream_id')\n .notNull()\n .references(() => attemptStreams.id, {onDelete: 'cascade'}),\n seq: bigserial('seq', {mode: 'number'}).notNull(),\n streamOffset: bigint('stream_offset', {mode: 'number'}).notNull(),\n byteLen: integer('byte_len').notNull(),\n data: bytea('data').notNull(),\n origin: text('origin', {enum: ['runner', 'control']}).notNull(),\n createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),\n },\n (table) => [index('logs_chunks_stream_seq_idx').on(table.streamId, table.seq)],\n);\n\nexport type LogChunkDb = typeof logChunks.$inferSelect;\nexport type LogChunkInsertDb = typeof logChunks.$inferInsert;\n\nexport type ChunkOrigin = 'runner' | 'control';\n"],"names":["uuidv7PrimaryKey","bigint","bigserial","index","integer","text","timestamp","uuid","attemptStreams","bytea","pgTable","logChunks","id","streamId","notNull","references","onDelete","seq","mode","streamOffset","byteLen","data","origin","enum","createdAt","withTimezone","defaultNow","table","on"],"mappings":"AAAA,SAAQA,gBAAgB,QAAO,wBAAwB;AACvD,SAAQC,MAAM,EAAEC,SAAS,EAAEC,KAAK,EAAEC,OAAO,EAAEC,IAAI,EAAEC,SAAS,EAAEC,IAAI,QAAO,sBAAsB;AAC7F,SAAQC,cAAc,QAAO,uBAAuB;AACpD,SAAQC,KAAK,EAAEC,OAAO,QAAO,cAAc;AAE3C;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,MAAMC,YAAYD,QACvB,UACA;IACEE,IAAIZ;IACJa,UAAUN,KAAK,aACZO,OAAO,GACPC,UAAU,CAAC,IAAMP,eAAeI,EAAE,EAAE;QAACI,UAAU;IAAS;IAC3DC,KAAKf,UAAU,OAAO;QAACgB,MAAM;IAAQ,GAAGJ,OAAO;IAC/CK,cAAclB,OAAO,iBAAiB;QAACiB,MAAM;IAAQ,GAAGJ,OAAO;IAC/DM,SAAShB,QAAQ,YAAYU,OAAO;IACpCO,MAAMZ,MAAM,QAAQK,OAAO;IAC3BQ,QAAQjB,KAAK,UAAU;QAACkB,MAAM;YAAC;YAAU;SAAU;IAAA,GAAGT,OAAO;IAC7DU,WAAWlB,UAAU,cAAc;QAACmB,cAAc;IAAI,GAAGX,OAAO,GAAGY,UAAU;AAC/E,GACA,CAACC,QAAU;QAACxB,MAAM,8BAA8ByB,EAAE,CAACD,MAAMd,QAAQ,EAAEc,MAAMV,GAAG;KAAE,EAC9E"}
@@ -0,0 +1,29 @@
1
+ import type { Buffer } from 'node:buffer';
2
+ export declare const pgTable: import("drizzle-orm/pg-core").PgTableFn<undefined>;
3
+ export declare const bytea: {
4
+ (): import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
5
+ name: "";
6
+ dataType: "custom";
7
+ columnType: "PgCustomColumn";
8
+ data: Buffer<ArrayBufferLike>;
9
+ driverParam: Buffer<ArrayBufferLike>;
10
+ enumValues: undefined;
11
+ }>;
12
+ <TConfig extends Record<string, any>>(fieldConfig?: TConfig | undefined): import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
13
+ name: "";
14
+ dataType: "custom";
15
+ columnType: "PgCustomColumn";
16
+ data: Buffer<ArrayBufferLike>;
17
+ driverParam: Buffer<ArrayBufferLike>;
18
+ enumValues: undefined;
19
+ }>;
20
+ <TName extends string>(dbName: TName, fieldConfig?: unknown): import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
21
+ name: TName;
22
+ dataType: "custom";
23
+ columnType: "PgCustomColumn";
24
+ data: Buffer<ArrayBufferLike>;
25
+ driverParam: Buffer<ArrayBufferLike>;
26
+ enumValues: undefined;
27
+ }>;
28
+ };
29
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/db/schema/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAGxC,eAAO,MAAM,OAAO,oDAA2C,CAAC;AAIhE,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;CAIhB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { customType, pgTableCreator } from 'drizzle-orm/pg-core';
2
+ export const pgTable = pgTableCreator((name)=>`logs_${name}`);
3
+ // drizzle-orm 0.45 has no native bytea column; the node-postgres driver returns
4
+ // and accepts Buffer for bytea, so a customType is the supported path.
5
+ export const bytea = customType({
6
+ dataType () {
7
+ return 'bytea';
8
+ }
9
+ });
10
+
11
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db/schema/common.ts"],"sourcesContent":["import type {Buffer} from 'node:buffer';\nimport {customType, pgTableCreator} from 'drizzle-orm/pg-core';\n\nexport const pgTable = pgTableCreator((name) => `logs_${name}`);\n\n// drizzle-orm 0.45 has no native bytea column; the node-postgres driver returns\n// and accepts Buffer for bytea, so a customType is the supported path.\nexport const bytea = customType<{data: Buffer; driverData: Buffer}>({\n dataType() {\n return 'bytea';\n },\n});\n"],"names":["customType","pgTableCreator","pgTable","name","bytea","dataType"],"mappings":"AACA,SAAQA,UAAU,EAAEC,cAAc,QAAO,sBAAsB;AAE/D,OAAO,MAAMC,UAAUD,eAAe,CAACE,OAAS,CAAC,KAAK,EAAEA,MAAM,EAAE;AAEhE,gFAAgF;AAChF,uEAAuE;AACvE,OAAO,MAAMC,QAAQJ,WAA+C;IAClEK;QACE,OAAO;IACT;AACF,GAAG"}
@@ -0,0 +1,143 @@
1
+ import type { JobAccounting } from '#core/entities/job-accounting.js';
2
+ /**
3
+ * Accrual-budget state per job run, keyed by the job id carried in the lease.
4
+ * `stored_bytes_used` counts the normalized NDJSON bytes the server has stored for the job
5
+ * (envelope and control records included), so the budget bounds exactly what lands in Postgres.
6
+ * `started_at` is the budget clock origin (first append).
7
+ * `capped_at`, once set, makes every later append a no-op drop.
8
+ *
9
+ * Per-row `stored_bytes_used` is bounded by the per-job budget, so `mode:
10
+ * 'number'` is safe on the hot path. Any cross-row aggregate (workspace or
11
+ * system-wide totals) MUST read as bigint at the query site — the global sum
12
+ * is unbounded and would silently lose precision past 2^53 as a JS number.
13
+ */
14
+ export declare const jobAccounting: import("drizzle-orm/pg-core").PgTableWithColumns<{
15
+ name: "job_accounting";
16
+ schema: undefined;
17
+ columns: {
18
+ jobId: import("drizzle-orm/pg-core").PgColumn<{
19
+ name: "job_id";
20
+ tableName: "job_accounting";
21
+ dataType: "string";
22
+ columnType: "PgUUID";
23
+ data: string;
24
+ driverParam: string;
25
+ notNull: true;
26
+ hasDefault: false;
27
+ isPrimaryKey: true;
28
+ isAutoincrement: false;
29
+ hasRuntimeDefault: false;
30
+ enumValues: undefined;
31
+ baseColumn: never;
32
+ identity: undefined;
33
+ generated: undefined;
34
+ }, {}, {}>;
35
+ workspaceId: import("drizzle-orm/pg-core").PgColumn<{
36
+ name: "workspace_id";
37
+ tableName: "job_accounting";
38
+ dataType: "string";
39
+ columnType: "PgUUID";
40
+ data: string;
41
+ driverParam: string;
42
+ notNull: true;
43
+ hasDefault: false;
44
+ isPrimaryKey: false;
45
+ isAutoincrement: false;
46
+ hasRuntimeDefault: false;
47
+ enumValues: undefined;
48
+ baseColumn: never;
49
+ identity: undefined;
50
+ generated: undefined;
51
+ }, {}, {}>;
52
+ storedBytesUsed: import("drizzle-orm/pg-core").PgColumn<{
53
+ name: "stored_bytes_used";
54
+ tableName: "job_accounting";
55
+ dataType: "number";
56
+ columnType: "PgBigInt53";
57
+ data: number;
58
+ driverParam: string | number;
59
+ notNull: true;
60
+ hasDefault: true;
61
+ isPrimaryKey: false;
62
+ isAutoincrement: false;
63
+ hasRuntimeDefault: false;
64
+ enumValues: undefined;
65
+ baseColumn: never;
66
+ identity: undefined;
67
+ generated: undefined;
68
+ }, {}, {}>;
69
+ startedAt: import("drizzle-orm/pg-core").PgColumn<{
70
+ name: "started_at";
71
+ tableName: "job_accounting";
72
+ dataType: "date";
73
+ columnType: "PgTimestamp";
74
+ data: Date;
75
+ driverParam: string;
76
+ notNull: true;
77
+ hasDefault: true;
78
+ isPrimaryKey: false;
79
+ isAutoincrement: false;
80
+ hasRuntimeDefault: false;
81
+ enumValues: undefined;
82
+ baseColumn: never;
83
+ identity: undefined;
84
+ generated: undefined;
85
+ }, {}, {}>;
86
+ cappedAt: import("drizzle-orm/pg-core").PgColumn<{
87
+ name: "capped_at";
88
+ tableName: "job_accounting";
89
+ dataType: "date";
90
+ columnType: "PgTimestamp";
91
+ data: Date;
92
+ driverParam: string;
93
+ notNull: false;
94
+ hasDefault: false;
95
+ isPrimaryKey: false;
96
+ isAutoincrement: false;
97
+ hasRuntimeDefault: false;
98
+ enumValues: undefined;
99
+ baseColumn: never;
100
+ identity: undefined;
101
+ generated: undefined;
102
+ }, {}, {}>;
103
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
104
+ name: "created_at";
105
+ tableName: "job_accounting";
106
+ dataType: "date";
107
+ columnType: "PgTimestamp";
108
+ data: Date;
109
+ driverParam: string;
110
+ notNull: true;
111
+ hasDefault: true;
112
+ isPrimaryKey: false;
113
+ isAutoincrement: false;
114
+ hasRuntimeDefault: false;
115
+ enumValues: undefined;
116
+ baseColumn: never;
117
+ identity: undefined;
118
+ generated: undefined;
119
+ }, {}, {}>;
120
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
121
+ name: "updated_at";
122
+ tableName: "job_accounting";
123
+ dataType: "date";
124
+ columnType: "PgTimestamp";
125
+ data: Date;
126
+ driverParam: string;
127
+ notNull: true;
128
+ hasDefault: true;
129
+ isPrimaryKey: false;
130
+ isAutoincrement: false;
131
+ hasRuntimeDefault: false;
132
+ enumValues: undefined;
133
+ baseColumn: never;
134
+ identity: undefined;
135
+ generated: undefined;
136
+ }, {}, {}>;
137
+ };
138
+ dialect: "pg";
139
+ }>;
140
+ export type JobAccountingDb = typeof jobAccounting.$inferSelect;
141
+ export type JobAccountingInsertDb = typeof jobAccounting.$inferInsert;
142
+ export declare function toJobAccounting(row: JobAccountingDb): JobAccounting;
143
+ //# sourceMappingURL=job-accounting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-accounting.d.ts","sourceRoot":"","sources":["../../../src/db/schema/job-accounting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,kCAAkC,CAAC;AAGpE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQxB,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAChE,MAAM,MAAM,qBAAqB,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAEtE,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,CAQnE"}
@@ -0,0 +1,43 @@
1
+ import { bigint, timestamp, uuid } from 'drizzle-orm/pg-core';
2
+ import { pgTable } from './common.js';
3
+ /**
4
+ * Accrual-budget state per job run, keyed by the job id carried in the lease.
5
+ * `stored_bytes_used` counts the normalized NDJSON bytes the server has stored for the job
6
+ * (envelope and control records included), so the budget bounds exactly what lands in Postgres.
7
+ * `started_at` is the budget clock origin (first append).
8
+ * `capped_at`, once set, makes every later append a no-op drop.
9
+ *
10
+ * Per-row `stored_bytes_used` is bounded by the per-job budget, so `mode:
11
+ * 'number'` is safe on the hot path. Any cross-row aggregate (workspace or
12
+ * system-wide totals) MUST read as bigint at the query site — the global sum
13
+ * is unbounded and would silently lose precision past 2^53 as a JS number.
14
+ */ export const jobAccounting = pgTable('job_accounting', {
15
+ jobId: uuid('job_id').primaryKey(),
16
+ workspaceId: uuid('workspace_id').notNull(),
17
+ storedBytesUsed: bigint('stored_bytes_used', {
18
+ mode: 'number'
19
+ }).notNull().default(0),
20
+ startedAt: timestamp('started_at', {
21
+ withTimezone: true
22
+ }).notNull().defaultNow(),
23
+ cappedAt: timestamp('capped_at', {
24
+ withTimezone: true
25
+ }),
26
+ createdAt: timestamp('created_at', {
27
+ withTimezone: true
28
+ }).notNull().defaultNow(),
29
+ updatedAt: timestamp('updated_at', {
30
+ withTimezone: true
31
+ }).notNull().defaultNow()
32
+ });
33
+ export function toJobAccounting(row) {
34
+ return {
35
+ jobId: row.jobId,
36
+ workspaceId: row.workspaceId,
37
+ storedBytesUsed: row.storedBytesUsed,
38
+ startedAt: row.startedAt,
39
+ cappedAt: row.cappedAt
40
+ };
41
+ }
42
+
43
+ //# sourceMappingURL=job-accounting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db/schema/job-accounting.ts"],"sourcesContent":["import {bigint, timestamp, uuid} from 'drizzle-orm/pg-core';\nimport type {JobAccounting} from '#core/entities/job-accounting.js';\nimport {pgTable} from './common.js';\n\n/**\n * Accrual-budget state per job run, keyed by the job id carried in the lease.\n * `stored_bytes_used` counts the normalized NDJSON bytes the server has stored for the job\n * (envelope and control records included), so the budget bounds exactly what lands in Postgres.\n * `started_at` is the budget clock origin (first append).\n * `capped_at`, once set, makes every later append a no-op drop.\n *\n * Per-row `stored_bytes_used` is bounded by the per-job budget, so `mode:\n * 'number'` is safe on the hot path. Any cross-row aggregate (workspace or\n * system-wide totals) MUST read as bigint at the query site — the global sum\n * is unbounded and would silently lose precision past 2^53 as a JS number.\n */\nexport const jobAccounting = pgTable('job_accounting', {\n jobId: uuid('job_id').primaryKey(),\n workspaceId: uuid('workspace_id').notNull(),\n storedBytesUsed: bigint('stored_bytes_used', {mode: 'number'}).notNull().default(0),\n startedAt: timestamp('started_at', {withTimezone: true}).notNull().defaultNow(),\n cappedAt: timestamp('capped_at', {withTimezone: true}),\n createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', {withTimezone: true}).notNull().defaultNow(),\n});\n\nexport type JobAccountingDb = typeof jobAccounting.$inferSelect;\nexport type JobAccountingInsertDb = typeof jobAccounting.$inferInsert;\n\nexport function toJobAccounting(row: JobAccountingDb): JobAccounting {\n return {\n jobId: row.jobId,\n workspaceId: row.workspaceId,\n storedBytesUsed: row.storedBytesUsed,\n startedAt: row.startedAt,\n cappedAt: row.cappedAt,\n };\n}\n"],"names":["bigint","timestamp","uuid","pgTable","jobAccounting","jobId","primaryKey","workspaceId","notNull","storedBytesUsed","mode","default","startedAt","withTimezone","defaultNow","cappedAt","createdAt","updatedAt","toJobAccounting","row"],"mappings":"AAAA,SAAQA,MAAM,EAAEC,SAAS,EAAEC,IAAI,QAAO,sBAAsB;AAE5D,SAAQC,OAAO,QAAO,cAAc;AAEpC;;;;;;;;;;;CAWC,GACD,OAAO,MAAMC,gBAAgBD,QAAQ,kBAAkB;IACrDE,OAAOH,KAAK,UAAUI,UAAU;IAChCC,aAAaL,KAAK,gBAAgBM,OAAO;IACzCC,iBAAiBT,OAAO,qBAAqB;QAACU,MAAM;IAAQ,GAAGF,OAAO,GAAGG,OAAO,CAAC;IACjFC,WAAWX,UAAU,cAAc;QAACY,cAAc;IAAI,GAAGL,OAAO,GAAGM,UAAU;IAC7EC,UAAUd,UAAU,aAAa;QAACY,cAAc;IAAI;IACpDG,WAAWf,UAAU,cAAc;QAACY,cAAc;IAAI,GAAGL,OAAO,GAAGM,UAAU;IAC7EG,WAAWhB,UAAU,cAAc;QAACY,cAAc;IAAI,GAAGL,OAAO,GAAGM,UAAU;AAC/E,GAAG;AAKH,OAAO,SAASI,gBAAgBC,GAAoB;IAClD,OAAO;QACLd,OAAOc,IAAId,KAAK;QAChBE,aAAaY,IAAIZ,WAAW;QAC5BE,iBAAiBU,IAAIV,eAAe;QACpCG,WAAWO,IAAIP,SAAS;QACxBG,UAAUI,IAAIJ,QAAQ;IACxB;AACF"}
@@ -0,0 +1,195 @@
1
+ export declare const logsOutbox: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "outbox";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: "id";
7
+ tableName: "outbox";
8
+ dataType: "string";
9
+ columnType: "PgUUID";
10
+ data: string;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: true;
14
+ isPrimaryKey: true;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: undefined;
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {}>;
22
+ eventType: import("drizzle-orm/pg-core").PgColumn<{
23
+ name: "event_type";
24
+ tableName: "outbox";
25
+ dataType: "string";
26
+ columnType: "PgText";
27
+ data: string;
28
+ driverParam: string;
29
+ notNull: true;
30
+ hasDefault: false;
31
+ isPrimaryKey: false;
32
+ isAutoincrement: false;
33
+ hasRuntimeDefault: false;
34
+ enumValues: [string, ...string[]];
35
+ baseColumn: never;
36
+ identity: undefined;
37
+ generated: undefined;
38
+ }, {}, {}>;
39
+ orderingKey: import("drizzle-orm/pg-core").PgColumn<{
40
+ name: "ordering_key";
41
+ tableName: "outbox";
42
+ dataType: "string";
43
+ columnType: "PgText";
44
+ data: string;
45
+ driverParam: string;
46
+ notNull: false;
47
+ hasDefault: false;
48
+ isPrimaryKey: false;
49
+ isAutoincrement: false;
50
+ hasRuntimeDefault: false;
51
+ enumValues: [string, ...string[]];
52
+ baseColumn: never;
53
+ identity: undefined;
54
+ generated: undefined;
55
+ }, {}, {}>;
56
+ payload: import("drizzle-orm/pg-core").PgColumn<{
57
+ name: "payload";
58
+ tableName: "outbox";
59
+ dataType: "json";
60
+ columnType: "PgJsonb";
61
+ data: unknown;
62
+ driverParam: unknown;
63
+ notNull: true;
64
+ hasDefault: false;
65
+ isPrimaryKey: false;
66
+ isAutoincrement: false;
67
+ hasRuntimeDefault: false;
68
+ enumValues: undefined;
69
+ baseColumn: never;
70
+ identity: undefined;
71
+ generated: undefined;
72
+ }, {}, {}>;
73
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
74
+ name: "created_at";
75
+ tableName: "outbox";
76
+ dataType: "date";
77
+ columnType: "PgTimestamp";
78
+ data: Date;
79
+ driverParam: string;
80
+ notNull: true;
81
+ hasDefault: true;
82
+ isPrimaryKey: false;
83
+ isAutoincrement: false;
84
+ hasRuntimeDefault: false;
85
+ enumValues: undefined;
86
+ baseColumn: never;
87
+ identity: undefined;
88
+ generated: undefined;
89
+ }, {}, {}>;
90
+ dispatchedAt: import("drizzle-orm/pg-core").PgColumn<{
91
+ name: "dispatched_at";
92
+ tableName: "outbox";
93
+ dataType: "date";
94
+ columnType: "PgTimestamp";
95
+ data: Date;
96
+ driverParam: string;
97
+ notNull: false;
98
+ hasDefault: false;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: undefined;
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, {}, {}>;
107
+ dispatchAttempts: import("drizzle-orm/pg-core").PgColumn<{
108
+ name: "dispatch_attempts";
109
+ tableName: "outbox";
110
+ dataType: "number";
111
+ columnType: "PgInteger";
112
+ data: number;
113
+ driverParam: string | number;
114
+ notNull: true;
115
+ hasDefault: true;
116
+ isPrimaryKey: false;
117
+ isAutoincrement: false;
118
+ hasRuntimeDefault: false;
119
+ enumValues: undefined;
120
+ baseColumn: never;
121
+ identity: undefined;
122
+ generated: undefined;
123
+ }, {}, {}>;
124
+ nextDispatchAt: import("drizzle-orm/pg-core").PgColumn<{
125
+ name: "next_dispatch_at";
126
+ tableName: "outbox";
127
+ dataType: "date";
128
+ columnType: "PgTimestamp";
129
+ data: Date;
130
+ driverParam: string;
131
+ notNull: true;
132
+ hasDefault: true;
133
+ isPrimaryKey: false;
134
+ isAutoincrement: false;
135
+ hasRuntimeDefault: false;
136
+ enumValues: undefined;
137
+ baseColumn: never;
138
+ identity: undefined;
139
+ generated: undefined;
140
+ }, {}, {}>;
141
+ lastDispatchError: import("drizzle-orm/pg-core").PgColumn<{
142
+ name: "last_dispatch_error";
143
+ tableName: "outbox";
144
+ dataType: "json";
145
+ columnType: "PgJsonb";
146
+ data: unknown;
147
+ driverParam: unknown;
148
+ notNull: false;
149
+ hasDefault: false;
150
+ isPrimaryKey: false;
151
+ isAutoincrement: false;
152
+ hasRuntimeDefault: false;
153
+ enumValues: undefined;
154
+ baseColumn: never;
155
+ identity: undefined;
156
+ generated: undefined;
157
+ }, {}, {}>;
158
+ lastDispatchFailedAt: import("drizzle-orm/pg-core").PgColumn<{
159
+ name: "last_dispatch_failed_at";
160
+ tableName: "outbox";
161
+ dataType: "date";
162
+ columnType: "PgTimestamp";
163
+ data: Date;
164
+ driverParam: string;
165
+ notNull: false;
166
+ hasDefault: false;
167
+ isPrimaryKey: false;
168
+ isAutoincrement: false;
169
+ hasRuntimeDefault: false;
170
+ enumValues: undefined;
171
+ baseColumn: never;
172
+ identity: undefined;
173
+ generated: undefined;
174
+ }, {}, {}>;
175
+ deadLetteredAt: import("drizzle-orm/pg-core").PgColumn<{
176
+ name: "dead_lettered_at";
177
+ tableName: "outbox";
178
+ dataType: "date";
179
+ columnType: "PgTimestamp";
180
+ data: Date;
181
+ driverParam: string;
182
+ notNull: false;
183
+ hasDefault: false;
184
+ isPrimaryKey: false;
185
+ isAutoincrement: false;
186
+ hasRuntimeDefault: false;
187
+ enumValues: undefined;
188
+ baseColumn: never;
189
+ identity: undefined;
190
+ generated: undefined;
191
+ }, {}, {}>;
192
+ };
193
+ dialect: "pg";
194
+ }>;
195
+ //# sourceMappingURL=outbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../../src/db/schema/outbox.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA6B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { createOutboxTable } from '@shipfox/node-outbox';
2
+ import { pgTable } from './common.js';
3
+ export const logsOutbox = createOutboxTable(pgTable);
4
+
5
+ //# sourceMappingURL=outbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db/schema/outbox.ts"],"sourcesContent":["import {createOutboxTable} from '@shipfox/node-outbox';\nimport {pgTable} from './common.js';\n\nexport const logsOutbox = createOutboxTable(pgTable);\n"],"names":["createOutboxTable","pgTable","logsOutbox"],"mappings":"AAAA,SAAQA,iBAAiB,QAAO,uBAAuB;AACvD,SAAQC,OAAO,QAAO,cAAc;AAEpC,OAAO,MAAMC,aAAaF,kBAAkBC,SAAS"}
@@ -0,0 +1,141 @@
1
+ import type { AttemptStream, StreamCloseReason } from '#core/entities/attempt-stream.js';
2
+ import { type Transaction } from './db.js';
3
+ export interface AttemptStreamIdentity {
4
+ jobId: string;
5
+ stepId: string;
6
+ attempt: number;
7
+ workspaceId: string;
8
+ projectId: string;
9
+ workflowRunAttemptId: string;
10
+ }
11
+ export interface AttemptStreamLookup {
12
+ jobId: string;
13
+ stepId: string;
14
+ attempt: number;
15
+ }
16
+ /**
17
+ * Reads the stream for `(job, step, attempt)` without creating it. Used by the
18
+ * empty-body heartbeat path so a runner cannot mint rows with empty appends.
19
+ */
20
+ export declare function getAttemptStream(tx: Transaction, lookup: AttemptStreamLookup): Promise<AttemptStream | null>;
21
+ /**
22
+ * Reads the stream for `(step, attempt)` for the session read path, which holds no lease
23
+ * and so has no `jobId`. `stepId` is a globally unique uuidv7, so `(stepId, attempt)`
24
+ * selects at most one row even though stream identity is `(jobId, stepId, attempt)`. The
25
+ * caller authorizes against the row's denormalized `workspaceId`.
26
+ */
27
+ export declare function getStreamByStepAttempt(lookup: {
28
+ stepId: string;
29
+ attempt: number;
30
+ }): Promise<AttemptStream | null>;
31
+ export interface GetOrCreateAttemptStreamResult {
32
+ stream: AttemptStream;
33
+ created: boolean;
34
+ }
35
+ /**
36
+ * Loads the stream for `(job, step, attempt)`, creating it on first append.
37
+ * Scoped by `jobId` from the lease, so a lease never reaches another job's stream.
38
+ * The create path reports whether the row was inserted so callers can record
39
+ * first-open side effects only after their enclosing transaction commits.
40
+ */
41
+ export declare function getOrCreateAttemptStreamWithStatus(tx: Transaction, identity: AttemptStreamIdentity): Promise<GetOrCreateAttemptStreamResult>;
42
+ export declare function getOrCreateAttemptStream(tx: Transaction, identity: AttemptStreamIdentity): Promise<AttemptStream>;
43
+ export type CasOutcome = 'extended' | 'retry' | 'gap';
44
+ export interface CasResult {
45
+ outcome: CasOutcome;
46
+ committedLength: number;
47
+ }
48
+ /**
49
+ * Offset-CAS extend: advances `committed_length` by `byteLen` iff it currently
50
+ * equals `offset`. On mismatch, re-reads the committed length and classifies the
51
+ * caller's chunk: a retry (fully already applied) only when `offset + byteLen`
52
+ * does not run past the committed length; otherwise a gap. A chunk that straddles
53
+ * the committed point (offset behind it, but extending past it) is a gap too, so
54
+ * the runner rewinds rather than getting a 200 that silently drops its tail.
55
+ */
56
+ export declare function casExtendCommittedLength(tx: Transaction, params: {
57
+ streamId: string;
58
+ offset: number;
59
+ byteLen: number;
60
+ }): Promise<CasResult>;
61
+ export declare function setDeclaredTotalBytes(tx: Transaction, params: {
62
+ streamId: string;
63
+ declaredTotalBytes: number;
64
+ }): Promise<void>;
65
+ /**
66
+ * Guarded close: flips `open → closed` and stamps `closed_at` iff the stream is
67
+ * still open, returning the closed row (or null when another path already closed
68
+ * it). The `WHERE state='open'` predicate is both the row lock and the
69
+ * exactly-once gate. `committed_length` is left untouched; it stays equal to the
70
+ * runner spool bytes. `truncated` is set only on the timeout path.
71
+ */
72
+ export declare function markStreamClosed(tx: Transaction, params: {
73
+ streamId: string;
74
+ reason: StreamCloseReason;
75
+ markTruncated: boolean;
76
+ }): Promise<AttemptStream | null>;
77
+ /** Open streams of a job, for the timeout sweep to force-close after the grace period. */
78
+ export declare function listOpenStreamsByJob(jobId: string): Promise<AttemptStream[]>;
79
+ /** For compaction, which is driven by the closed event that carries the stream id. */
80
+ export declare function getAttemptStreamById(streamId: string): Promise<AttemptStream | null>;
81
+ export declare function getAttemptStreamByIdInTransaction(tx: Transaction, streamId: string): Promise<AttemptStream | null>;
82
+ /**
83
+ * Final compaction step: records the object key and deletes the now-cold chunk rows in one
84
+ * transaction. The guard is `state='closed' AND object_key IS NULL`, so the publish is a
85
+ * single winner even when two compaction attempts (e.g. a heartbeat-timed-out run and its
86
+ * retry) race: each uploads to its own key, and only the first to land here writes a key and
87
+ * drops the chunks. A 0-row result means the row was either hard-deleted by retention or
88
+ * already published by another attempt; the caller re-reads to tell those apart and deletes
89
+ * its own now-orphaned upload either way. Returns whether this attempt won the publish.
90
+ */
91
+ export declare function setObjectKeyAndDeleteChunks(tx: Transaction, params: {
92
+ streamId: string;
93
+ objectKey: string;
94
+ }): Promise<{
95
+ updated: boolean;
96
+ }>;
97
+ /**
98
+ * Closed streams that never got an object key and have sat that way past the stale
99
+ * window: the reconcile cron re-drives compaction for these. Hits the partial index
100
+ * `logs_attempt_streams_uncompacted_idx`; ordered by `closed_at` so the oldest backlog
101
+ * drains first, bounded by `limit` per tick.
102
+ */
103
+ export declare function listStaleUncompactedStreams(params: {
104
+ olderThanSeconds: number;
105
+ limit: number;
106
+ }): Promise<AttemptStream[]>;
107
+ /**
108
+ * Lists open streams old enough to force-close. The age check is safe only when
109
+ * `olderThanSeconds` exceeds the lease TTL: leases are minted before a stream can
110
+ * be created, so no valid append can arrive after `created_at + leaseTTL`.
111
+ */
112
+ export declare function listStaleOpenStreams(params: {
113
+ olderThanSeconds: number;
114
+ limit: number;
115
+ }): Promise<AttemptStream[]>;
116
+ export declare function getOpenStreamCount(): Promise<bigint>;
117
+ /**
118
+ * Lists expired closed streams for retention. `excludeIds` keeps failed or raced rows from
119
+ * starving younger rows in the same run, and avoids cursoring on `closed_at`, whose microsecond
120
+ * precision would be lost through JS `Date`.
121
+ *
122
+ * No `object_key` filter: retention deletes compacted and never-compacted streams alike.
123
+ */
124
+ export declare function listExpiredClosedStreams(params: {
125
+ retentionDays: number;
126
+ limit: number;
127
+ excludeIds?: string[] | undefined;
128
+ }): Promise<AttemptStream[]>;
129
+ /**
130
+ * Hard-deletes one expired stream row, guarded on the observed `object_key` so a racing
131
+ * compaction publish leaves the row for the next sweep.
132
+ */
133
+ export declare function deleteExpiredStream(tx: Transaction, params: {
134
+ streamId: string;
135
+ observedObjectKey: string | null;
136
+ }): Promise<{
137
+ deleted: boolean;
138
+ jobId: string | null;
139
+ }>;
140
+ export declare function accountingHasNoStreams(tx: Transaction, jobId: string): Promise<boolean>;
141
+ //# sourceMappingURL=streams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.d.ts","sourceRoot":"","sources":["../../src/db/streams.ts"],"names":[],"mappings":"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"}