@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.
- package/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +179 -0
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/api/object-storage.d.ts +69 -0
- package/dist/api/object-storage.d.ts.map +1 -0
- package/dist/api/object-storage.js +199 -0
- package/dist/api/object-storage.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +108 -0
- package/dist/config.js.map +1 -0
- package/dist/core/append-logs.d.ts +28 -0
- package/dist/core/append-logs.d.ts.map +1 -0
- package/dist/core/append-logs.js +318 -0
- package/dist/core/append-logs.js.map +1 -0
- package/dist/core/budget.d.ts +12 -0
- package/dist/core/budget.d.ts.map +1 -0
- package/dist/core/budget.js +9 -0
- package/dist/core/budget.js.map +1 -0
- package/dist/core/close-stream.d.ts +27 -0
- package/dist/core/close-stream.d.ts.map +1 -0
- package/dist/core/close-stream.js +59 -0
- package/dist/core/close-stream.js.map +1 -0
- package/dist/core/compaction.d.ts +28 -0
- package/dist/core/compaction.d.ts.map +1 -0
- package/dist/core/compaction.js +49 -0
- package/dist/core/compaction.js.map +1 -0
- package/dist/core/entities/attempt-stream.d.ts +37 -0
- package/dist/core/entities/attempt-stream.d.ts.map +1 -0
- package/dist/core/entities/attempt-stream.js +15 -0
- package/dist/core/entities/attempt-stream.js.map +1 -0
- package/dist/core/entities/job-accounting.d.ts +12 -0
- package/dist/core/entities/job-accounting.d.ts.map +1 -0
- package/dist/core/entities/job-accounting.js +6 -0
- package/dist/core/entities/job-accounting.js.map +1 -0
- package/dist/core/entities/log-object.d.ts +13 -0
- package/dist/core/entities/log-object.d.ts.map +1 -0
- package/dist/core/entities/log-object.js +9 -0
- package/dist/core/entities/log-object.js.map +1 -0
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +31 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/finalize-attempt-stream.d.ts +22 -0
- package/dist/core/finalize-attempt-stream.d.ts.map +1 -0
- package/dist/core/finalize-attempt-stream.js +48 -0
- package/dist/core/finalize-attempt-stream.js.map +1 -0
- package/dist/core/read-logs.d.ts +33 -0
- package/dist/core/read-logs.d.ts.map +1 -0
- package/dist/core/read-logs.js +49 -0
- package/dist/core/read-logs.js.map +1 -0
- package/dist/core/reap-stale-open-streams.d.ts +27 -0
- package/dist/core/reap-stale-open-streams.d.ts.map +1 -0
- package/dist/core/reap-stale-open-streams.js +50 -0
- package/dist/core/reap-stale-open-streams.js.map +1 -0
- package/dist/core/retention.d.ts +32 -0
- package/dist/core/retention.d.ts.map +1 -0
- package/dist/core/retention.js +148 -0
- package/dist/core/retention.js.map +1 -0
- package/dist/core/session/claude/rows.d.ts +6 -0
- package/dist/core/session/claude/rows.d.ts.map +1 -0
- package/dist/core/session/claude/rows.js +145 -0
- package/dist/core/session/claude/rows.js.map +1 -0
- package/dist/core/session/claude-parser.d.ts +4 -0
- package/dist/core/session/claude-parser.d.ts.map +1 -0
- package/dist/core/session/claude-parser.js +42 -0
- package/dist/core/session/claude-parser.js.map +1 -0
- package/dist/core/session/entry-schema.d.ts +51 -0
- package/dist/core/session/entry-schema.d.ts.map +1 -0
- package/dist/core/session/entry-schema.js +61 -0
- package/dist/core/session/entry-schema.js.map +1 -0
- package/dist/core/session/object.d.ts +12 -0
- package/dist/core/session/object.d.ts.map +1 -0
- package/dist/core/session/object.js +50 -0
- package/dist/core/session/object.js.map +1 -0
- package/dist/core/session/parse-session.d.ts +5 -0
- package/dist/core/session/parse-session.d.ts.map +1 -0
- package/dist/core/session/parse-session.js +18 -0
- package/dist/core/session/parse-session.js.map +1 -0
- package/dist/core/session/pi/message-rows.d.ts +4 -0
- package/dist/core/session/pi/message-rows.d.ts.map +1 -0
- package/dist/core/session/pi/message-rows.js +113 -0
- package/dist/core/session/pi/message-rows.js.map +1 -0
- package/dist/core/session/pi/metadata.d.ts +18 -0
- package/dist/core/session/pi/metadata.d.ts.map +1 -0
- package/dist/core/session/pi/metadata.js +120 -0
- package/dist/core/session/pi/metadata.js.map +1 -0
- package/dist/core/session/pi/text.d.ts +12 -0
- package/dist/core/session/pi/text.d.ts.map +1 -0
- package/dist/core/session/pi/text.js +59 -0
- package/dist/core/session/pi/text.js.map +1 -0
- package/dist/core/session/pi-parser.d.ts +5 -0
- package/dist/core/session/pi-parser.d.ts.map +1 -0
- package/dist/core/session/pi-parser.js +73 -0
- package/dist/core/session/pi-parser.js.map +1 -0
- package/dist/core/session/rows.d.ts +7 -0
- package/dist/core/session/rows.d.ts.map +1 -0
- package/dist/core/session/rows.js +39 -0
- package/dist/core/session/rows.js.map +1 -0
- package/dist/core/session/session-record.d.ts +5 -0
- package/dist/core/session/session-record.d.ts.map +1 -0
- package/dist/core/session/session-record.js +3 -0
- package/dist/core/session/session-record.js.map +1 -0
- package/dist/db/accounting.d.ts +33 -0
- package/dist/db/accounting.d.ts.map +1 -0
- package/dist/db/accounting.js +52 -0
- package/dist/db/accounting.js.map +1 -0
- package/dist/db/chunks.d.ts +62 -0
- package/dist/db/chunks.d.ts.map +1 -0
- package/dist/db/chunks.js +88 -0
- package/dist/db/chunks.js.map +1 -0
- package/dist/db/db.d.ts +752 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +24 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +5 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema/attempt-streams.d.ts +304 -0
- package/dist/db/schema/attempt-streams.d.ts.map +1 -0
- package/dist/db/schema/attempt-streams.js +100 -0
- package/dist/db/schema/attempt-streams.js.map +1 -0
- package/dist/db/schema/chunks.d.ts +166 -0
- package/dist/db/schema/chunks.d.ts.map +1 -0
- package/dist/db/schema/chunks.js +47 -0
- package/dist/db/schema/chunks.js.map +1 -0
- package/dist/db/schema/common.d.ts +29 -0
- package/dist/db/schema/common.d.ts.map +1 -0
- package/dist/db/schema/common.js +11 -0
- package/dist/db/schema/common.js.map +1 -0
- package/dist/db/schema/job-accounting.d.ts +143 -0
- package/dist/db/schema/job-accounting.d.ts.map +1 -0
- package/dist/db/schema/job-accounting.js +43 -0
- package/dist/db/schema/job-accounting.js.map +1 -0
- package/dist/db/schema/outbox.d.ts +195 -0
- package/dist/db/schema/outbox.d.ts.map +1 -0
- package/dist/db/schema/outbox.js +5 -0
- package/dist/db/schema/outbox.js.map +1 -0
- package/dist/db/streams.d.ts +141 -0
- package/dist/db/streams.d.ts.map +1 -0
- package/dist/db/streams.js +197 -0
- package/dist/db/streams.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +3 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/instance.d.ts +14 -0
- package/dist/metrics/instance.d.ts.map +1 -0
- package/dist/metrics/instance.js +16 -0
- package/dist/metrics/instance.js.map +1 -0
- package/dist/metrics/service.d.ts +2 -0
- package/dist/metrics/service.d.ts.map +1 -0
- package/dist/metrics/service.js +20 -0
- package/dist/metrics/service.js.map +1 -0
- package/dist/presentation/dto/read-logs.d.ts +4 -0
- package/dist/presentation/dto/read-logs.d.ts.map +1 -0
- package/dist/presentation/dto/read-logs.js +22 -0
- package/dist/presentation/dto/read-logs.js.map +1 -0
- package/dist/presentation/routes/append-logs.d.ts +2 -0
- package/dist/presentation/routes/append-logs.d.ts.map +1 -0
- package/dist/presentation/routes/append-logs.js +71 -0
- package/dist/presentation/routes/append-logs.js.map +1 -0
- package/dist/presentation/routes/index.d.ts +3 -0
- package/dist/presentation/routes/index.d.ts.map +1 -0
- package/dist/presentation/routes/index.js +32 -0
- package/dist/presentation/routes/index.js.map +1 -0
- package/dist/presentation/routes/read-logs.d.ts +2 -0
- package/dist/presentation/routes/read-logs.d.ts.map +1 -0
- package/dist/presentation/routes/read-logs.js +41 -0
- package/dist/presentation/routes/read-logs.js.map +1 -0
- package/dist/presentation/subscribers/on-job-terminated.d.ts +8 -0
- package/dist/presentation/subscribers/on-job-terminated.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-job-terminated.js +32 -0
- package/dist/presentation/subscribers/on-job-terminated.js.map +1 -0
- package/dist/presentation/subscribers/on-log-stream-closed.d.ts +9 -0
- package/dist/presentation/subscribers/on-log-stream-closed.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-log-stream-closed.js +31 -0
- package/dist/presentation/subscribers/on-log-stream-closed.js.map +1 -0
- package/dist/presentation/subscribers/on-step-attempt-terminated.d.ts +3 -0
- package/dist/presentation/subscribers/on-step-attempt-terminated.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-step-attempt-terminated.js +14 -0
- package/dist/presentation/subscribers/on-step-attempt-terminated.js.map +1 -0
- package/dist/temporal/activities/close-abandoned-streams.d.ts +12 -0
- package/dist/temporal/activities/close-abandoned-streams.d.ts.map +1 -0
- package/dist/temporal/activities/close-abandoned-streams.js +33 -0
- package/dist/temporal/activities/close-abandoned-streams.js.map +1 -0
- package/dist/temporal/activities/compact-stream.d.ts +33 -0
- package/dist/temporal/activities/compact-stream.d.ts.map +1 -0
- package/dist/temporal/activities/compact-stream.js +95 -0
- package/dist/temporal/activities/compact-stream.js.map +1 -0
- package/dist/temporal/activities/compaction-reconcile.d.ts +16 -0
- package/dist/temporal/activities/compaction-reconcile.d.ts.map +1 -0
- package/dist/temporal/activities/compaction-reconcile.js +52 -0
- package/dist/temporal/activities/compaction-reconcile.js.map +1 -0
- package/dist/temporal/activities/index.d.ts +14 -0
- package/dist/temporal/activities/index.d.ts.map +1 -0
- package/dist/temporal/activities/index.js +16 -0
- package/dist/temporal/activities/index.js.map +1 -0
- package/dist/temporal/activities/reap-stale-open-streams.d.ts +4 -0
- package/dist/temporal/activities/reap-stale-open-streams.d.ts.map +1 -0
- package/dist/temporal/activities/reap-stale-open-streams.js +11 -0
- package/dist/temporal/activities/reap-stale-open-streams.js.map +1 -0
- package/dist/temporal/activities/retention-sweep.d.ts +7 -0
- package/dist/temporal/activities/retention-sweep.d.ts.map +1 -0
- package/dist/temporal/activities/retention-sweep.js +19 -0
- package/dist/temporal/activities/retention-sweep.js.map +1 -0
- package/dist/temporal/constants.d.ts +7 -0
- package/dist/temporal/constants.d.ts.map +1 -0
- package/dist/temporal/constants.js +13 -0
- package/dist/temporal/constants.js.map +1 -0
- package/dist/temporal/workflows/close-abandoned-streams.d.ts +11 -0
- package/dist/temporal/workflows/close-abandoned-streams.d.ts.map +1 -0
- package/dist/temporal/workflows/close-abandoned-streams.js +22 -0
- package/dist/temporal/workflows/close-abandoned-streams.js.map +1 -0
- package/dist/temporal/workflows/compact-stream.d.ts +6 -0
- package/dist/temporal/workflows/compact-stream.d.ts.map +1 -0
- package/dist/temporal/workflows/compact-stream.js +25 -0
- package/dist/temporal/workflows/compact-stream.js.map +1 -0
- package/dist/temporal/workflows/compaction-reconcile-cron.d.ts +3 -0
- package/dist/temporal/workflows/compaction-reconcile-cron.d.ts.map +1 -0
- package/dist/temporal/workflows/compaction-reconcile-cron.js +15 -0
- package/dist/temporal/workflows/compaction-reconcile-cron.js.map +1 -0
- package/dist/temporal/workflows/index.d.ts +6 -0
- package/dist/temporal/workflows/index.d.ts.map +1 -0
- package/dist/temporal/workflows/index.js +7 -0
- package/dist/temporal/workflows/index.js.map +1 -0
- package/dist/temporal/workflows/reap-stale-open-streams-cron.d.ts +2 -0
- package/dist/temporal/workflows/reap-stale-open-streams-cron.d.ts.map +1 -0
- package/dist/temporal/workflows/reap-stale-open-streams-cron.js +15 -0
- package/dist/temporal/workflows/reap-stale-open-streams-cron.js.map +1 -0
- package/dist/temporal/workflows/retention-sweep-cron.d.ts +2 -0
- package/dist/temporal/workflows/retention-sweep-cron.d.ts.map +1 -0
- package/dist/temporal/workflows/retention-sweep-cron.js +23 -0
- package/dist/temporal/workflows/retention-sweep-cron.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/drizzle/0000_initial.sql +65 -0
- package/drizzle/meta/0000_snapshot.json +529 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/package.json +84 -0
- package/src/api/object-storage-credentials.test.ts +70 -0
- package/src/api/object-storage.test.ts +64 -0
- package/src/api/object-storage.ts +226 -0
- package/src/config.test.ts +118 -0
- package/src/config.ts +130 -0
- package/src/core/append-logs.test.ts +563 -0
- package/src/core/append-logs.ts +384 -0
- package/src/core/budget.test.ts +30 -0
- package/src/core/budget.ts +19 -0
- package/src/core/close-stream.ts +72 -0
- package/src/core/compaction.ts +68 -0
- package/src/core/entities/attempt-stream.ts +38 -0
- package/src/core/entities/job-accounting.ts +11 -0
- package/src/core/entities/log-object.test.ts +25 -0
- package/src/core/entities/log-object.ts +18 -0
- package/src/core/errors.ts +37 -0
- package/src/core/finalize-attempt-stream.test.ts +90 -0
- package/src/core/finalize-attempt-stream.ts +59 -0
- package/src/core/read-logs.ts +77 -0
- package/src/core/reap-stale-open-streams.test.ts +137 -0
- package/src/core/reap-stale-open-streams.ts +60 -0
- package/src/core/retention.test.ts +388 -0
- package/src/core/retention.ts +184 -0
- package/src/core/session/claude/rows.ts +223 -0
- package/src/core/session/claude-parser.test.ts +199 -0
- package/src/core/session/claude-parser.ts +38 -0
- package/src/core/session/entry-schema.ts +82 -0
- package/src/core/session/object.ts +57 -0
- package/src/core/session/parse-session.ts +23 -0
- package/src/core/session/pi/message-rows.ts +211 -0
- package/src/core/session/pi/metadata.ts +148 -0
- package/src/core/session/pi/text.ts +83 -0
- package/src/core/session/pi-parser.test.ts +451 -0
- package/src/core/session/pi-parser.ts +107 -0
- package/src/core/session/rows.ts +38 -0
- package/src/core/session/session-record.ts +4 -0
- package/src/db/accounting.ts +81 -0
- package/src/db/chunks.ts +143 -0
- package/src/db/db.ts +22 -0
- package/src/db/index.ts +4 -0
- package/src/db/schema/attempt-streams.ts +106 -0
- package/src/db/schema/chunks.ts +43 -0
- package/src/db/schema/common.ts +12 -0
- package/src/db/schema/job-accounting.ts +38 -0
- package/src/db/schema/outbox.ts +4 -0
- package/src/db/streams.test.ts +47 -0
- package/src/db/streams.ts +368 -0
- package/src/index.ts +77 -0
- package/src/metrics/index.ts +1 -0
- package/src/metrics/instance.ts +33 -0
- package/src/metrics/service.ts +23 -0
- package/src/presentation/dto/read-logs.ts +24 -0
- package/src/presentation/routes/append-logs.test.ts +279 -0
- package/src/presentation/routes/append-logs.ts +66 -0
- package/src/presentation/routes/index.ts +27 -0
- package/src/presentation/routes/read-logs.test.ts +504 -0
- package/src/presentation/routes/read-logs.ts +38 -0
- package/src/presentation/subscribers/on-job-terminated.test.ts +64 -0
- package/src/presentation/subscribers/on-job-terminated.ts +26 -0
- package/src/presentation/subscribers/on-log-stream-closed.test.ts +63 -0
- package/src/presentation/subscribers/on-log-stream-closed.ts +26 -0
- package/src/presentation/subscribers/on-step-attempt-terminated.ts +16 -0
- package/src/temporal/activities/close-abandoned-streams.test.ts +84 -0
- package/src/temporal/activities/close-abandoned-streams.ts +30 -0
- package/src/temporal/activities/compact-stream.test.ts +221 -0
- package/src/temporal/activities/compact-stream.ts +123 -0
- package/src/temporal/activities/compaction-reconcile.test.ts +143 -0
- package/src/temporal/activities/compaction-reconcile.ts +48 -0
- package/src/temporal/activities/index.ts +15 -0
- package/src/temporal/activities/reap-stale-open-streams.test.ts +48 -0
- package/src/temporal/activities/reap-stale-open-streams.ts +14 -0
- package/src/temporal/activities/retention-sweep.test.ts +38 -0
- package/src/temporal/activities/retention-sweep.ts +23 -0
- package/src/temporal/constants.ts +14 -0
- package/src/temporal/workflows/close-abandoned-streams.ts +25 -0
- package/src/temporal/workflows/compact-stream.ts +26 -0
- package/src/temporal/workflows/compaction-reconcile-cron.ts +14 -0
- package/src/temporal/workflows/index.ts +5 -0
- package/src/temporal/workflows/reap-stale-open-streams-cron.ts +13 -0
- package/src/temporal/workflows/retention-sweep-cron.ts +23 -0
- package/test/env.ts +37 -0
- package/test/factories/job-accounting.ts +38 -0
- package/test/fixtures/closed-stream.ts +53 -0
- package/test/fixtures/lease-token.ts +42 -0
- package/test/fixtures/ndjson.ts +34 -0
- package/test/globalSetup.ts +44 -0
- package/test/index.ts +9 -0
- package/test/queries.ts +54 -0
- package/test/setup.ts +17 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- 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 @@
|
|
|
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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"}
|