@sixb/core 0.1.13 → 0.1.15
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/dist/actions/index.js +22 -22
- package/dist/agents/index.js +34 -34
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/streams/index.js +2 -2
- package/dist/agents/streams/internal.js +2 -2
- package/dist/auth/errors.d.ts +12 -0
- package/dist/auth/errors.d.ts.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +7 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/runtime.d.ts.map +1 -1
- package/dist/auth/strategy.d.ts +2 -0
- package/dist/auth/strategy.d.ts.map +1 -1
- package/dist/auth/strategy.js +4 -2
- package/dist/auth/strategy.js.map +1 -1
- package/dist/auth/types.d.ts +8 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/authorization/index.js +2 -2
- package/dist/bootstrap/index.js +37 -37
- package/dist/{chunk-693f3zn8.js → chunk-1jvq82rp.js} +3 -3
- package/dist/{chunk-0321g649.js → chunk-2jntasmh.js} +13 -2
- package/dist/{chunk-0321g649.js.map → chunk-2jntasmh.js.map} +3 -3
- package/dist/{chunk-cvrbhvtr.js → chunk-2tz5vnvz.js} +28 -28
- package/dist/{chunk-cvrbhvtr.js.map → chunk-2tz5vnvz.js.map} +1 -1
- package/dist/{chunk-898y24dd.js → chunk-3c90jvfj.js} +2 -2
- package/dist/{chunk-vn3yh259.js → chunk-4gmng3vf.js} +1 -1
- package/dist/{chunk-91wthfwe.js → chunk-4jph1t3v.js} +7 -7
- package/dist/{chunk-znw0zvy4.js → chunk-4wn7bxxa.js} +25 -7
- package/dist/chunk-4wn7bxxa.js.map +12 -0
- package/dist/{chunk-3qpcrcj8.js → chunk-6aawea28.js} +2 -4
- package/dist/chunk-6aawea28.js.map +10 -0
- package/dist/{chunk-rzkr70gr.js → chunk-6fsr7y93.js} +5 -1
- package/dist/{chunk-rzkr70gr.js.map → chunk-6fsr7y93.js.map} +3 -3
- package/dist/{chunk-y487ywrv.js → chunk-6q7c68yx.js} +4 -4
- package/dist/{chunk-ypj2wqtj.js → chunk-70jmg2zx.js} +2 -2
- package/dist/{chunk-s24qbp32.js → chunk-7jc21943.js} +3 -3
- package/dist/{chunk-rzcjp5m2.js → chunk-8fjmqjyx.js} +1 -1
- package/dist/{chunk-m8zkvep1.js → chunk-8w27xf9e.js} +1 -1
- package/dist/{chunk-z9h698s8.js → chunk-a4g5yjm0.js} +1 -1
- package/dist/{chunk-gmt22nxx.js → chunk-adbve9zt.js} +1 -1
- package/dist/{chunk-mf6hwpzh.js → chunk-dqkd3kdj.js} +41 -23
- package/dist/{chunk-mf6hwpzh.js.map → chunk-dqkd3kdj.js.map} +3 -3
- package/dist/{chunk-gbcrz0gr.js → chunk-ex8s8wsk.js} +6 -6
- package/dist/{chunk-4tnrzqqh.js → chunk-fj1dvp37.js} +1 -1
- package/dist/{chunk-gc226ten.js → chunk-fjw417jf.js} +127 -69
- package/dist/{chunk-gc226ten.js.map → chunk-fjw417jf.js.map} +4 -4
- package/dist/{chunk-ht4a7mjg.js → chunk-g4rbm4a6.js} +42 -8
- package/dist/{chunk-ht4a7mjg.js.map → chunk-g4rbm4a6.js.map} +3 -3
- package/dist/{chunk-qma80ych.js → chunk-hn2r7z41.js} +3 -2
- package/dist/chunk-hn2r7z41.js.map +11 -0
- package/dist/{chunk-bdhfn0ww.js → chunk-kkqwzy6h.js} +1 -1
- package/dist/{chunk-bep5rrdq.js → chunk-mmac1mp6.js} +2 -2
- package/dist/{chunk-w9bp61e7.js → chunk-n5t4mq6z.js} +5 -5
- package/dist/{chunk-n33e8dz8.js → chunk-p0nbkys4.js} +1 -1
- package/dist/{chunk-04h4t2b5.js → chunk-py2dw8cw.js} +3 -3
- package/dist/{chunk-jhyc777j.js → chunk-q3grgzp1.js} +2 -2
- package/dist/{chunk-9pfw47qx.js → chunk-qne45xqq.js} +53 -48
- package/dist/{chunk-9pfw47qx.js.map → chunk-qne45xqq.js.map} +7 -7
- package/dist/{chunk-cbn96bve.js → chunk-r5sc1d2b.js} +2 -2
- package/dist/{chunk-y6vnvayj.js → chunk-vjcd8d27.js} +1 -1
- package/dist/{chunk-jmwy25mf.js → chunk-wd34wnsy.js} +6 -6
- package/dist/{chunk-63fp9x3q.js → chunk-wem5vqjw.js} +7 -7
- package/dist/{chunk-darm7eeg.js → chunk-xr7y35yj.js} +3 -3
- package/dist/{chunk-a69fkrtr.js → chunk-y0zmae99.js} +5 -5
- package/dist/{chunk-xgptywp0.js → chunk-y2aq6ag9.js} +1 -1
- package/dist/{chunk-2hbhn1ff.js → chunk-yfppyaty.js} +1 -1
- package/dist/{chunk-rqtdtm43.js → chunk-z708gemf.js} +129 -70
- package/dist/{chunk-rqtdtm43.js.map → chunk-z708gemf.js.map} +5 -5
- package/dist/deploy/define.d.ts +4 -0
- package/dist/deploy/define.d.ts.map +1 -0
- package/dist/deploy/index.d.ts +3 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js +10 -0
- package/dist/deploy/index.js.map +10 -0
- package/dist/deploy/internal.d.ts +3 -0
- package/dist/deploy/internal.d.ts.map +1 -0
- package/dist/deploy/internal.js +244 -0
- package/dist/deploy/internal.js.map +11 -0
- package/dist/deploy/services.d.ts +8 -0
- package/dist/deploy/services.d.ts.map +1 -0
- package/dist/deploy/types.d.ts +309 -0
- package/dist/deploy/types.d.ts.map +1 -0
- package/dist/deploy/validation.d.ts +7 -0
- package/dist/deploy/validation.d.ts.map +1 -0
- package/dist/error-reporting/internal.js +3 -3
- package/dist/errors/catalog.d.ts +4 -0
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/internal.js +1 -1
- package/dist/events/index.js +3 -3
- package/dist/execution/agent.js +33 -33
- package/dist/execution/primitive.js +29 -29
- package/dist/execution/request.js +31 -31
- package/dist/execution/request.js.map +1 -1
- package/dist/index.js +49 -49
- package/dist/index.js.map +1 -1
- package/dist/maintenance/ontology-maintenance.d.ts +2 -0
- package/dist/maintenance/ontology-maintenance.d.ts.map +1 -1
- package/dist/maintenance/types.d.ts +8 -2
- package/dist/maintenance/types.d.ts.map +1 -1
- package/dist/materialization/dataset-watermark.d.ts +6 -1
- package/dist/materialization/dataset-watermark.d.ts.map +1 -1
- package/dist/materialization/index.js +1 -1
- package/dist/materialization/model.d.ts +6 -0
- package/dist/materialization/model.d.ts.map +1 -1
- package/dist/materializer/index.js +18 -18
- package/dist/materializer/index.js.map +1 -1
- package/dist/materializer/projections/finish-run.d.ts.map +1 -1
- package/dist/materializer/projections/replace.d.ts.map +1 -1
- package/dist/materializer/projections/source-materialization.d.ts +6 -2
- package/dist/materializer/projections/source-materialization.d.ts.map +1 -1
- package/dist/models/execution/index.js +14 -14
- package/dist/objects/index.js +21 -21
- package/dist/objects/query/index.js +15 -15
- package/dist/pipelines/index.js +19 -19
- package/dist/projections/internal.js +16 -16
- package/dist/projections/types.d.ts +1 -1
- package/dist/projections/types.d.ts.map +1 -1
- package/dist/queues/in-memory.d.ts +1 -1
- package/dist/queues/in-memory.d.ts.map +1 -1
- package/dist/runtime/internal.js +19 -19
- package/dist/shares/internal.js +14 -14
- package/dist/shares/internal.js.map +1 -1
- package/dist/storage/action-runs/failure.js +2 -2
- package/dist/storage/ai-limits/enforcement.js +2 -2
- package/dist/storage/auth/errors.d.ts +1 -1
- package/dist/storage/auth/errors.d.ts.map +1 -1
- package/dist/storage/auth/in-memory/auth-storage.d.ts +2 -1
- package/dist/storage/auth/in-memory/auth-storage.d.ts.map +1 -1
- package/dist/storage/auth/types.d.ts +15 -7
- package/dist/storage/auth/types.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider.js +1 -1
- package/dist/storage/file-upload-sessions/provider.js +5 -5
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +29 -29
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/internal.js +1 -1
- package/dist/storage/ontology/in-memory/sources.d.ts +6 -3
- package/dist/storage/ontology/in-memory/sources.d.ts.map +1 -1
- package/dist/storage/ontology/index.d.ts +1 -1
- package/dist/storage/ontology/index.d.ts.map +1 -1
- package/dist/storage/ontology/provider.d.ts +16 -3
- package/dist/storage/ontology/provider.d.ts.map +1 -1
- package/dist/storage/ontology/provider.js +8 -4
- package/dist/storage/ontology/provider.js.map +1 -1
- package/dist/storage/ontology/sources.d.ts +36 -8
- package/dist/storage/ontology/sources.d.ts.map +1 -1
- package/dist/storage/projection-runs/in-memory.d.ts +3 -1
- package/dist/storage/projection-runs/in-memory.d.ts.map +1 -1
- package/dist/storage/projection-runs/index.d.ts +1 -1
- package/dist/storage/projection-runs/index.d.ts.map +1 -1
- package/dist/storage/projection-runs/lifecycle.d.ts +12 -0
- package/dist/storage/projection-runs/lifecycle.d.ts.map +1 -1
- package/dist/storage/projection-runs/provider.js +10 -4
- package/dist/storage/projection-runs/provider.js.map +1 -1
- package/dist/storage/projection-runs/types.d.ts +32 -1
- package/dist/storage/projection-runs/types.d.ts.map +1 -1
- package/dist/storage/workflow-runs/provider.js +5 -5
- package/dist/syncs/index.js +20 -20
- package/dist/testing/auth-storage-contract.d.ts.map +1 -1
- package/dist/testing/index.js +381 -171
- package/dist/testing/index.js.map +5 -5
- package/dist/testing/ontology-storage-contract.d.ts.map +1 -1
- package/dist/testing/projection-run-storage-contract.d.ts.map +1 -1
- package/dist/webhooks/internal.js +15 -15
- package/dist/webhooks/internal.js.map +1 -1
- package/dist/workers/index.js +1 -1
- package/dist/workflows/index.js +34 -34
- package/package.json +13 -1
- package/src/auth/errors.ts +23 -0
- package/src/auth/index.ts +1 -1
- package/src/auth/runtime.ts +56 -22
- package/src/auth/strategy.ts +2 -0
- package/src/auth/types.ts +8 -0
- package/src/deploy/define.ts +6 -0
- package/src/deploy/index.ts +41 -0
- package/src/deploy/internal.ts +7 -0
- package/src/deploy/services.ts +51 -0
- package/src/deploy/types.ts +338 -0
- package/src/deploy/validation.ts +261 -0
- package/src/errors/catalog.ts +4 -0
- package/src/maintenance/ontology-maintenance.ts +32 -2
- package/src/maintenance/types.ts +8 -2
- package/src/materialization/dataset-watermark.ts +6 -4
- package/src/materialization/model.ts +7 -0
- package/src/materializer/README.md +26 -6
- package/src/materializer/projections/finish-run.ts +129 -26
- package/src/materializer/projections/replace.ts +67 -49
- package/src/materializer/projections/source-materialization.ts +11 -6
- package/src/projections/types.ts +1 -0
- package/src/storage/auth/errors.ts +0 -1
- package/src/storage/auth/in-memory/auth-storage.ts +44 -65
- package/src/storage/auth/types.ts +15 -7
- package/src/storage/index.ts +6 -1
- package/src/storage/ontology/in-memory/sources.ts +119 -55
- package/src/storage/ontology/index.ts +4 -1
- package/src/storage/ontology/provider.ts +64 -7
- package/src/storage/ontology/sources.ts +42 -8
- package/src/storage/projection-runs/in-memory.ts +41 -2
- package/src/storage/projection-runs/index.ts +2 -0
- package/src/storage/projection-runs/lifecycle.ts +61 -4
- package/src/storage/projection-runs/types.ts +41 -1
- package/src/testing/auth-storage-contract.ts +104 -130
- package/src/testing/ontology-storage-contract.ts +141 -15
- package/src/testing/projection-run-storage-contract.ts +174 -1
- package/dist/chunk-3qpcrcj8.js.map +0 -10
- package/dist/chunk-qma80ych.js.map +0 -11
- package/dist/chunk-znw0zvy4.js.map +0 -12
- /package/dist/{chunk-693f3zn8.js.map → chunk-1jvq82rp.js.map} +0 -0
- /package/dist/{chunk-898y24dd.js.map → chunk-3c90jvfj.js.map} +0 -0
- /package/dist/{chunk-vn3yh259.js.map → chunk-4gmng3vf.js.map} +0 -0
- /package/dist/{chunk-91wthfwe.js.map → chunk-4jph1t3v.js.map} +0 -0
- /package/dist/{chunk-y487ywrv.js.map → chunk-6q7c68yx.js.map} +0 -0
- /package/dist/{chunk-ypj2wqtj.js.map → chunk-70jmg2zx.js.map} +0 -0
- /package/dist/{chunk-s24qbp32.js.map → chunk-7jc21943.js.map} +0 -0
- /package/dist/{chunk-rzcjp5m2.js.map → chunk-8fjmqjyx.js.map} +0 -0
- /package/dist/{chunk-m8zkvep1.js.map → chunk-8w27xf9e.js.map} +0 -0
- /package/dist/{chunk-z9h698s8.js.map → chunk-a4g5yjm0.js.map} +0 -0
- /package/dist/{chunk-gmt22nxx.js.map → chunk-adbve9zt.js.map} +0 -0
- /package/dist/{chunk-gbcrz0gr.js.map → chunk-ex8s8wsk.js.map} +0 -0
- /package/dist/{chunk-4tnrzqqh.js.map → chunk-fj1dvp37.js.map} +0 -0
- /package/dist/{chunk-bdhfn0ww.js.map → chunk-kkqwzy6h.js.map} +0 -0
- /package/dist/{chunk-bep5rrdq.js.map → chunk-mmac1mp6.js.map} +0 -0
- /package/dist/{chunk-w9bp61e7.js.map → chunk-n5t4mq6z.js.map} +0 -0
- /package/dist/{chunk-n33e8dz8.js.map → chunk-p0nbkys4.js.map} +0 -0
- /package/dist/{chunk-04h4t2b5.js.map → chunk-py2dw8cw.js.map} +0 -0
- /package/dist/{chunk-jhyc777j.js.map → chunk-q3grgzp1.js.map} +0 -0
- /package/dist/{chunk-cbn96bve.js.map → chunk-r5sc1d2b.js.map} +0 -0
- /package/dist/{chunk-y6vnvayj.js.map → chunk-vjcd8d27.js.map} +0 -0
- /package/dist/{chunk-jmwy25mf.js.map → chunk-wd34wnsy.js.map} +0 -0
- /package/dist/{chunk-63fp9x3q.js.map → chunk-wem5vqjw.js.map} +0 -0
- /package/dist/{chunk-darm7eeg.js.map → chunk-xr7y35yj.js.map} +0 -0
- /package/dist/{chunk-a69fkrtr.js.map → chunk-y0zmae99.js.map} +0 -0
- /package/dist/{chunk-xgptywp0.js.map → chunk-y2aq6ag9.js.map} +0 -0
- /package/dist/{chunk-2hbhn1ff.js.map → chunk-yfppyaty.js.map} +0 -0
|
@@ -128,7 +128,7 @@ interface BaseAbandonSourceMaterializationInput {
|
|
|
128
128
|
readonly abandonedAt: string
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
/** Abandon the current execution's exact candidate
|
|
131
|
+
/** Abandon the current execution's exact candidate, e.g. an adopted one whose delta base moved. */
|
|
132
132
|
export interface AbandonSourceMaterializationCandidateInput
|
|
133
133
|
extends BaseAbandonSourceMaterializationInput {
|
|
134
134
|
readonly kind: "candidate"
|
|
@@ -136,20 +136,38 @@ export interface AbandonSourceMaterializationCandidateInput
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
139
|
+
* Release whatever candidate a run still holds, whichever execution staged it. Called in the same
|
|
140
|
+
* transaction as the run's terminal transition, so no candidate outlives its run.
|
|
141
141
|
*/
|
|
142
|
-
export interface
|
|
143
|
-
|
|
142
|
+
export interface AbandonRunSourceMaterializationInput
|
|
143
|
+
extends BaseAbandonSourceMaterializationInput {
|
|
144
|
+
readonly kind: "run"
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
export type AbandonSourceMaterializationInput =
|
|
147
148
|
| AbandonSourceMaterializationCandidateInput
|
|
148
|
-
|
|
|
149
|
+
| AbandonRunSourceMaterializationInput
|
|
150
|
+
|
|
151
|
+
export interface AdoptSourceMaterializationInput {
|
|
152
|
+
readonly projectId: string
|
|
153
|
+
readonly source: ProjectionSourceRef
|
|
154
|
+
readonly execution: ProjectionExecution
|
|
155
|
+
readonly adoptedAt: string
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface AdoptedSourceMaterialization {
|
|
159
|
+
readonly record: OntologySourceRecord
|
|
160
|
+
/**
|
|
161
|
+
* Where staging resumes. Every root before this ordinal is complete; the root at it may be
|
|
162
|
+
* partial and is staged again, which staging accepts for identical rows. Equals the root count
|
|
163
|
+
* once the candidate is ready.
|
|
164
|
+
*/
|
|
165
|
+
readonly resumeStagingOrdinal: number
|
|
166
|
+
}
|
|
149
167
|
|
|
150
168
|
export interface CleanupTerminalSourceMaterializationsInput {
|
|
151
169
|
readonly projectId: string
|
|
152
|
-
/** Exclusive cutoff for retired roots in
|
|
170
|
+
/** Exclusive cutoff for retired roots in superseded manifests, and for empty ones. */
|
|
153
171
|
readonly terminalBefore: string
|
|
154
172
|
/** Maximum total assertion, root-reference, and manifest deletions performed by one call. */
|
|
155
173
|
readonly limit: number
|
|
@@ -161,6 +179,12 @@ export interface CleanupTerminalSourceMaterializationsResult {
|
|
|
161
179
|
readonly materializationsDeleted: number
|
|
162
180
|
}
|
|
163
181
|
|
|
182
|
+
export interface PurgeAbandonedSourceMaterializationsInput {
|
|
183
|
+
readonly projectId: string
|
|
184
|
+
/** Maximum total assertion, root-reference, and manifest deletions performed by one call. */
|
|
185
|
+
readonly limit: number
|
|
186
|
+
}
|
|
187
|
+
|
|
164
188
|
export interface SummarizeTerminalSourceMaterializationsInput {
|
|
165
189
|
readonly projectId: string
|
|
166
190
|
}
|
|
@@ -195,11 +219,21 @@ export interface OntologySourceStorage {
|
|
|
195
219
|
stageRows(input: StageSourceRowsInput): Promise<StageSourceRowsResult>
|
|
196
220
|
markReady(input: MarkSourceMaterializationReadyInput): Promise<OntologySourceRecord>
|
|
197
221
|
getActive(input: GetActiveOntologySourceInput): Promise<OntologySourceRecord | null>
|
|
222
|
+
/** Hands a redelivered run's candidate to its current execution; null when it has none. */
|
|
223
|
+
adopt(input: AdoptSourceMaterializationInput): Promise<AdoptedSourceMaterialization | null>
|
|
198
224
|
abandon(input: AbandonSourceMaterializationCandidateInput): Promise<OntologySourceRecord>
|
|
199
|
-
abandon(input:
|
|
225
|
+
abandon(input: AbandonRunSourceMaterializationInput): Promise<OntologySourceRecord | null>
|
|
226
|
+
/** Retired roots of superseded manifests, after their retention. */
|
|
200
227
|
cleanupTerminal(
|
|
201
228
|
input: CleanupTerminalSourceMaterializationsInput
|
|
202
229
|
): Promise<CleanupTerminalSourceMaterializationsResult>
|
|
230
|
+
/**
|
|
231
|
+
* Abandoned candidates, whole and oldest first. Nothing reads an abandoned candidate, so it has
|
|
232
|
+
* no retention; deleting one manifest at a time keeps each delete on the source-version index.
|
|
233
|
+
*/
|
|
234
|
+
purgeAbandoned(
|
|
235
|
+
input: PurgeAbandonedSourceMaterializationsInput
|
|
236
|
+
): Promise<CleanupTerminalSourceMaterializationsResult>
|
|
203
237
|
summarizeTerminal(
|
|
204
238
|
input: SummarizeTerminalSourceMaterializationsInput
|
|
205
239
|
): Promise<TerminalSourceMaterializationSummary>
|
|
@@ -26,8 +26,10 @@ import {
|
|
|
26
26
|
finishProjectionRunRecord,
|
|
27
27
|
immutableDatasetVersionConflict,
|
|
28
28
|
mergeProjectionRunProgress,
|
|
29
|
+
parseProjectionAttemptFailure,
|
|
29
30
|
planProjectionRunReclaim,
|
|
30
31
|
projectionRunNotFound,
|
|
32
|
+
projectionRunSupersedes,
|
|
31
33
|
publicProjectionRunRecord,
|
|
32
34
|
requireTelemetryProjectionRun,
|
|
33
35
|
type StoredProjectionRunRecord,
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
import {
|
|
37
39
|
type AdvanceProjectionTelemetryCheckpointInput,
|
|
38
40
|
type FailProjectionRunEnqueueInput,
|
|
41
|
+
type FindSupersedingProjectionRunInput,
|
|
39
42
|
type FinishProjectionRunInput,
|
|
40
43
|
type ListLatestProjectionRunsInput,
|
|
41
44
|
type ListLatestProjectionRunsResult,
|
|
@@ -47,6 +50,7 @@ import {
|
|
|
47
50
|
type ProjectionRunStorage,
|
|
48
51
|
projectionRunObjectTypesVisible,
|
|
49
52
|
type QueueProjectionRunInput,
|
|
53
|
+
type RecordProjectionAttemptFailureInput,
|
|
50
54
|
type RecordProjectionMissingTargetInput,
|
|
51
55
|
type StartOrReclaimProjectionRunInput,
|
|
52
56
|
type TelemetryProjectionRunRecord,
|
|
@@ -60,6 +64,10 @@ function projectionRunKey(projectId: string, id: string): string {
|
|
|
60
64
|
return JSON.stringify([projectId, id])
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
function compareText(left: string, right: string): number {
|
|
68
|
+
return left < right ? -1 : left > right ? 1 : 0
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
function compareRuns(a: ProjectionRunRecord, b: ProjectionRunRecord, order: "asc" | "desc") {
|
|
64
72
|
return compareStartedAt(a, b, order)
|
|
65
73
|
}
|
|
@@ -152,7 +160,6 @@ export class InMemoryProjectionRunStorage implements ProjectionRunStorage {
|
|
|
152
160
|
executionToken,
|
|
153
161
|
startedAt: existing.startedAt ?? new Date(input.startedAt ?? new Date()),
|
|
154
162
|
finishedAt: undefined,
|
|
155
|
-
error: undefined,
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
this.rows.set(key, structuredClone(record))
|
|
@@ -246,6 +253,17 @@ export class InMemoryProjectionRunStorage implements ProjectionRunStorage {
|
|
|
246
253
|
})
|
|
247
254
|
}
|
|
248
255
|
|
|
256
|
+
async recordAttemptFailure(
|
|
257
|
+
input: RecordProjectionAttemptFailureInput
|
|
258
|
+
): Promise<ProjectionRunRecord> {
|
|
259
|
+
return this.runRootOperation(() => {
|
|
260
|
+
const existing = this.requireExecution(input)
|
|
261
|
+
const next = { ...existing, error: parseProjectionAttemptFailure(existing, input.error) }
|
|
262
|
+
this.rows.set(projectionRunKey(input.projectId, input.id), structuredClone(next))
|
|
263
|
+
return publicProjectionRunRecord(next)
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
|
|
249
267
|
async finish(input: FinishProjectionRunInput): Promise<ProjectionRunRecord> {
|
|
250
268
|
return this.runRootOperation(() => {
|
|
251
269
|
const existing = this.requireExecution(input)
|
|
@@ -311,12 +329,33 @@ export class InMemoryProjectionRunStorage implements ProjectionRunStorage {
|
|
|
311
329
|
})
|
|
312
330
|
}
|
|
313
331
|
|
|
332
|
+
async findSupersedingRun(
|
|
333
|
+
input: FindSupersedingProjectionRunInput
|
|
334
|
+
): Promise<ProjectionRunRecord | null> {
|
|
335
|
+
return this.runRootOperation(() => {
|
|
336
|
+
const run = this.rows.get(projectionRunKey(input.projectId, input.id))
|
|
337
|
+
if (!run) throw projectionRunNotFound(input.projectId, input.id)
|
|
338
|
+
const newest = [...this.rows.values()]
|
|
339
|
+
.filter((candidate) => projectionRunSupersedes(candidate, run))
|
|
340
|
+
.sort(
|
|
341
|
+
(left, right) =>
|
|
342
|
+
compareText(
|
|
343
|
+
right.identity.datasetVersion.createdAt,
|
|
344
|
+
left.identity.datasetVersion.createdAt
|
|
345
|
+
) || compareText(right.id, left.id)
|
|
346
|
+
)[0]
|
|
347
|
+
return newest ? publicProjectionRunRecord(newest) : null
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
|
|
314
351
|
async listLatestByProjectionIds(
|
|
315
352
|
input: ListLatestProjectionRunsInput
|
|
316
353
|
): Promise<ListLatestProjectionRunsResult> {
|
|
317
354
|
return this.runRootOperation(() => {
|
|
318
355
|
const runs = latestStartedAtByOwnerId(
|
|
319
|
-
[...this.rows.values()].filter(
|
|
356
|
+
[...this.rows.values()].filter(
|
|
357
|
+
(record) => record.projectId === input.projectId && record.status !== "superseded"
|
|
358
|
+
),
|
|
320
359
|
input.projectionIds,
|
|
321
360
|
(record) => record.identity.projectionId
|
|
322
361
|
)
|
|
@@ -3,6 +3,7 @@ export { InMemoryProjectionRunStorage } from "./in-memory"
|
|
|
3
3
|
export type {
|
|
4
4
|
AdvanceProjectionTelemetryCheckpointInput,
|
|
5
5
|
FailProjectionRunEnqueueInput,
|
|
6
|
+
FindSupersedingProjectionRunInput,
|
|
6
7
|
FinishProjectionRunInput,
|
|
7
8
|
LinkProjectionRunRecord,
|
|
8
9
|
LinkProjectionTarget,
|
|
@@ -27,6 +28,7 @@ export type {
|
|
|
27
28
|
ProjectionTarget,
|
|
28
29
|
ProjectionTelemetryCheckpoint,
|
|
29
30
|
QueueProjectionRunInput,
|
|
31
|
+
RecordProjectionAttemptFailureInput,
|
|
30
32
|
RecordProjectionMissingTargetInput,
|
|
31
33
|
StartOrReclaimProjectionRunInput,
|
|
32
34
|
TelemetryProjectionRunRecord,
|
|
@@ -442,6 +442,15 @@ export function failProjectionRunEnqueue(
|
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
/** Validates the failure of an attempt that leaves its run running, before it is stored. */
|
|
446
|
+
export function parseProjectionAttemptFailure(
|
|
447
|
+
record: Pick<ProjectionRunRecord, "id" | "projectId" | "status">,
|
|
448
|
+
error: SixbFailure<ProjectionRunFailureCode>
|
|
449
|
+
): SixbFailure<ProjectionRunFailureCode> {
|
|
450
|
+
assertProjectionRunRunning(record)
|
|
451
|
+
return parseSixbFailure(error, PROJECTION_RUN_FAILURE_CODES)
|
|
452
|
+
}
|
|
453
|
+
|
|
445
454
|
export function canRequeueProjectionRunAfterEnqueueFailure(
|
|
446
455
|
record: ProjectionRunRecord,
|
|
447
456
|
input: QueueProjectionRunInput
|
|
@@ -457,6 +466,34 @@ export function canRequeueProjectionRunAfterEnqueueFailure(
|
|
|
457
466
|
)
|
|
458
467
|
}
|
|
459
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Statuses of a run that still stands to replace its projection's source. A later run in one of
|
|
471
|
+
* them makes an earlier run stale; a failed or cancelled one replaces nothing.
|
|
472
|
+
*/
|
|
473
|
+
export const SUPERSEDING_PROJECTION_RUN_STATUSES = [
|
|
474
|
+
"queued",
|
|
475
|
+
"running",
|
|
476
|
+
"succeeded",
|
|
477
|
+
] as const satisfies readonly ProjectionRunStatus[]
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Whether `newer` makes `run` stale. Dataset version timestamps are canonical UTC ISO strings, so
|
|
481
|
+
* they order as text; SQL adapters compare them under a binary collation for the same reason.
|
|
482
|
+
*/
|
|
483
|
+
export function projectionRunSupersedes(
|
|
484
|
+
newer: ProjectionRunRecord,
|
|
485
|
+
run: ProjectionRunRecord
|
|
486
|
+
): boolean {
|
|
487
|
+
return (
|
|
488
|
+
run.identity.protocol === "replacement" &&
|
|
489
|
+
newer.identity.protocol === "replacement" &&
|
|
490
|
+
newer.projectId === run.projectId &&
|
|
491
|
+
newer.identity.projectionId === run.identity.projectionId &&
|
|
492
|
+
newer.identity.datasetVersion.createdAt > run.identity.datasetVersion.createdAt &&
|
|
493
|
+
(SUPERSEDING_PROJECTION_RUN_STATUSES as readonly ProjectionRunStatus[]).includes(newer.status)
|
|
494
|
+
)
|
|
495
|
+
}
|
|
496
|
+
|
|
460
497
|
// ── Persistence mapping ─────────────────────────────────────
|
|
461
498
|
|
|
462
499
|
export function restoreProjectionRun(row: PersistedProjectionRunRecord): StoredProjectionRunRecord {
|
|
@@ -616,8 +653,7 @@ function assertPersistedLifecycle(row: PersistedProjectionRunRecord): void {
|
|
|
616
653
|
row.attempt < 1 ||
|
|
617
654
|
row.startedAt === undefined ||
|
|
618
655
|
row.finishedAt !== undefined ||
|
|
619
|
-
row.executionToken === undefined
|
|
620
|
-
hasError
|
|
656
|
+
row.executionToken === undefined
|
|
621
657
|
) {
|
|
622
658
|
throw incompleteProjectionRun(row.id)
|
|
623
659
|
}
|
|
@@ -641,7 +677,12 @@ function assertPersistedLifecycle(row: PersistedProjectionRunRecord): void {
|
|
|
641
677
|
return
|
|
642
678
|
}
|
|
643
679
|
}
|
|
644
|
-
if (
|
|
680
|
+
if (
|
|
681
|
+
row.attempt < 1 ||
|
|
682
|
+
row.startedAt === undefined ||
|
|
683
|
+
((row.status === "succeeded" || row.status === "superseded") && hasError) ||
|
|
684
|
+
(row.status === "superseded" && row.protocol !== "replacement")
|
|
685
|
+
) {
|
|
645
686
|
throw incompleteProjectionRun(row.id)
|
|
646
687
|
}
|
|
647
688
|
}
|
|
@@ -652,6 +693,17 @@ function assertProjectionRunDate(value: Date, fieldName: string): void {
|
|
|
652
693
|
}
|
|
653
694
|
}
|
|
654
695
|
|
|
696
|
+
function isProjectionRunTerminalStatus(
|
|
697
|
+
status: unknown
|
|
698
|
+
): status is ProjectionRunFinishPlan["status"] {
|
|
699
|
+
return (
|
|
700
|
+
status === "succeeded" ||
|
|
701
|
+
status === "failed" ||
|
|
702
|
+
status === "cancelled" ||
|
|
703
|
+
status === "superseded"
|
|
704
|
+
)
|
|
705
|
+
}
|
|
706
|
+
|
|
655
707
|
function isProjectionKind(value: unknown): value is ProjectionKind {
|
|
656
708
|
return value === "object" || value === "link" || value === "telemetry"
|
|
657
709
|
}
|
|
@@ -722,7 +774,7 @@ function assertFinishDecision(
|
|
|
722
774
|
record: ProjectionRunRecord,
|
|
723
775
|
input: ProjectionRunTerminalDecision
|
|
724
776
|
): void {
|
|
725
|
-
if (input.status
|
|
777
|
+
if (!isProjectionRunTerminalStatus(input.status)) {
|
|
726
778
|
throw new ProjectionRunError(
|
|
727
779
|
`[Sixb] Projection run '${record.id}' finish status must be terminal.`
|
|
728
780
|
)
|
|
@@ -735,6 +787,11 @@ function assertFinishDecision(
|
|
|
735
787
|
`[Sixb] Projection run '${record.id}' finish protocol does not match its identity.`
|
|
736
788
|
)
|
|
737
789
|
}
|
|
790
|
+
if (input.status === "superseded" && input.protocol !== "replacement") {
|
|
791
|
+
throw new ProjectionRunError(
|
|
792
|
+
`[Sixb] Telemetry projection run '${record.id}' cannot be superseded.`
|
|
793
|
+
)
|
|
794
|
+
}
|
|
738
795
|
const inputExhausted = "inputExhausted" in input ? input.inputExhausted : undefined
|
|
739
796
|
if (input.status === "succeeded" && input.protocol === "telemetry") {
|
|
740
797
|
if (inputExhausted === true) return
|
|
@@ -16,7 +16,18 @@ import type {
|
|
|
16
16
|
export type { ProjectionRunFailureCode } from "../../projections/types"
|
|
17
17
|
export { PROJECTION_RUN_FAILURE_CODES } from "../../projections/types"
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* `superseded` ends a replacement run whose output would be stale on arrival: a run of the same
|
|
21
|
+
* projection pinned to a later dataset version exists and has not failed. Telemetry runs append
|
|
22
|
+
* readings rather than replace a source, so none is ever superseded.
|
|
23
|
+
*/
|
|
24
|
+
export type ProjectionRunStatus =
|
|
25
|
+
| "queued"
|
|
26
|
+
| "running"
|
|
27
|
+
| "succeeded"
|
|
28
|
+
| "failed"
|
|
29
|
+
| "cancelled"
|
|
30
|
+
| "superseded"
|
|
20
31
|
|
|
21
32
|
export interface ProjectionRunProgress {
|
|
22
33
|
/** Physical immutable-version rows consumed, before normalization or semantic materialization. */
|
|
@@ -76,6 +87,11 @@ interface ProjectionRunRecordBase {
|
|
|
76
87
|
readonly queuedAt: Date
|
|
77
88
|
readonly startedAt?: Date
|
|
78
89
|
readonly finishedAt?: Date
|
|
90
|
+
/**
|
|
91
|
+
* The run's most recent failure, read with its status: on a `running` run, why its last attempt
|
|
92
|
+
* failed while the queue retries it; on a `failed` or `cancelled` run, why it ended. Cleared when
|
|
93
|
+
* the run succeeds or is superseded, so a present error always describes something current.
|
|
94
|
+
*/
|
|
79
95
|
readonly error?: SixbFailure<ProjectionRunFailureCode>
|
|
80
96
|
}
|
|
81
97
|
|
|
@@ -202,6 +218,17 @@ export interface RecordProjectionMissingTargetInput
|
|
|
202
218
|
readonly missingTarget: ProjectionMissingTarget
|
|
203
219
|
}
|
|
204
220
|
|
|
221
|
+
export interface RecordProjectionAttemptFailureInput
|
|
222
|
+
extends LockProjectionRunForMaterializationInput {
|
|
223
|
+
readonly error: SixbFailure<ProjectionRunFailureCode>
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface FindSupersedingProjectionRunInput {
|
|
227
|
+
readonly projectId: string
|
|
228
|
+
/** The run that may be superseded. */
|
|
229
|
+
readonly id: string
|
|
230
|
+
}
|
|
231
|
+
|
|
205
232
|
export interface ListProjectionRunsInput {
|
|
206
233
|
readonly projectId: string
|
|
207
234
|
readonly projectionId?: string
|
|
@@ -258,10 +285,23 @@ export interface ProjectionRunStorage {
|
|
|
258
285
|
recordMissingTarget(
|
|
259
286
|
input: RecordProjectionMissingTargetInput
|
|
260
287
|
): Promise<TelemetryProjectionRunRecord>
|
|
288
|
+
/**
|
|
289
|
+
* Records the failure of the current attempt as the `error` of a run that stays `running` to be
|
|
290
|
+
* retried. Fenced like every other write: a delivery that lost the run cannot overwrite the
|
|
291
|
+
* failure of the one that holds it now. A reclaim keeps it until the run ends.
|
|
292
|
+
*/
|
|
293
|
+
recordAttemptFailure(input: RecordProjectionAttemptFailureInput): Promise<ProjectionRunRecord>
|
|
261
294
|
/** Telemetry success also records the worker's EOF observation atomically. */
|
|
262
295
|
finish(input: FinishProjectionRunInput): Promise<ProjectionRunRecord>
|
|
296
|
+
/**
|
|
297
|
+
* The newest replacement run of the same projection that makes this one stale: pinned to a
|
|
298
|
+
* later dataset version, and queued, running, or succeeded. A failed or cancelled run replaces
|
|
299
|
+
* nothing, so it supersedes nothing either. Null for a telemetry run.
|
|
300
|
+
*/
|
|
301
|
+
findSupersedingRun(input: FindSupersedingProjectionRunInput): Promise<ProjectionRunRecord | null>
|
|
263
302
|
getById(params: { projectId: string; id: string }): Promise<ProjectionRunRecord | null>
|
|
264
303
|
list(input: ListProjectionRunsInput): Promise<ListProjectionRunsResult>
|
|
304
|
+
/** Superseded runs are skipped: the run that superseded them is the one that matters. */
|
|
265
305
|
listLatestByProjectionIds(
|
|
266
306
|
input: ListLatestProjectionRunsInput
|
|
267
307
|
): Promise<ListLatestProjectionRunsResult>
|