@sixb/core 0.1.14 → 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 +21 -21
- package/dist/agents/index.js +33 -33
- 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/index.js +3 -3
- package/dist/authorization/index.js +2 -2
- package/dist/bootstrap/index.js +36 -36
- package/dist/{chunk-dv4ct8mp.js → chunk-1jvq82rp.js} +3 -3
- package/dist/{chunk-16jenmzw.js → chunk-2tz5vnvz.js} +28 -28
- package/dist/{chunk-16jenmzw.js.map → chunk-2tz5vnvz.js.map} +1 -1
- package/dist/{chunk-728fp090.js → chunk-3c90jvfj.js} +2 -2
- package/dist/{chunk-vn3yh259.js → chunk-4gmng3vf.js} +1 -1
- package/dist/{chunk-hxgj4kzd.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-wn7mznxc.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-4ypbe95r.js → chunk-adbve9zt.js} +1 -1
- package/dist/{chunk-hj0n3c2p.js → chunk-dqkd3kdj.js} +40 -22
- package/dist/{chunk-hj0n3c2p.js.map → chunk-dqkd3kdj.js.map} +3 -3
- package/dist/{chunk-wnxabtn4.js → chunk-ex8s8wsk.js} +6 -6
- package/dist/{chunk-4tnrzqqh.js → chunk-fj1dvp37.js} +1 -1
- package/dist/{chunk-3fpgxpsq.js → chunk-fjw417jf.js} +127 -69
- package/dist/{chunk-3fpgxpsq.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-ww185kt6.js → chunk-mmac1mp6.js} +2 -2
- package/dist/{chunk-jfdggg1p.js → chunk-n5t4mq6z.js} +5 -5
- package/dist/{chunk-3a338wrp.js → chunk-p0nbkys4.js} +1 -1
- package/dist/{chunk-kxea54yg.js → chunk-py2dw8cw.js} +3 -3
- package/dist/{chunk-e2c5yxfe.js → chunk-q3grgzp1.js} +2 -2
- package/dist/{chunk-6rzb1g6h.js → chunk-qne45xqq.js} +1 -1
- package/dist/{chunk-cbn96bve.js → chunk-r5sc1d2b.js} +2 -2
- package/dist/{chunk-y6vnvayj.js → chunk-vjcd8d27.js} +1 -1
- package/dist/{chunk-ma1mhh7w.js → chunk-wd34wnsy.js} +6 -6
- package/dist/{chunk-pvgpckm1.js → chunk-wem5vqjw.js} +7 -7
- package/dist/{chunk-gct3m1da.js → chunk-xr7y35yj.js} +3 -3
- package/dist/{chunk-q2xghyft.js → chunk-y0zmae99.js} +5 -5
- package/dist/{chunk-xgptywp0.js → chunk-y2aq6ag9.js} +1 -1
- package/dist/{chunk-yvf2jqj8.js → chunk-yfppyaty.js} +1 -1
- package/dist/{chunk-00pfcqh4.js → chunk-z708gemf.js} +129 -70
- package/dist/{chunk-00pfcqh4.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 +32 -32
- package/dist/execution/primitive.js +28 -28
- package/dist/execution/request.js +30 -30
- package/dist/execution/request.js.map +1 -1
- package/dist/index.js +48 -48
- 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 +17 -17
- 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 +13 -13
- package/dist/objects/index.js +20 -20
- package/dist/objects/query/index.js +14 -14
- package/dist/pipelines/index.js +18 -18
- package/dist/projections/internal.js +15 -15
- 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 +18 -18
- package/dist/shares/internal.js +13 -13
- 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/connector-connections/provider.js +1 -1
- package/dist/storage/file-upload-sessions/provider.js +4 -4
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +28 -28
- 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 +4 -4
- package/dist/syncs/index.js +19 -19
- package/dist/testing/index.js +296 -54
- package/dist/testing/index.js.map +4 -4
- 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 +14 -14
- package/dist/webhooks/internal.js.map +1 -1
- package/dist/workers/index.js +1 -1
- package/dist/workflows/index.js +33 -33
- package/package.json +13 -1
- 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/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/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-dv4ct8mp.js.map → chunk-1jvq82rp.js.map} +0 -0
- /package/dist/{chunk-728fp090.js.map → chunk-3c90jvfj.js.map} +0 -0
- /package/dist/{chunk-vn3yh259.js.map → chunk-4gmng3vf.js.map} +0 -0
- /package/dist/{chunk-hxgj4kzd.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-wn7mznxc.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-4ypbe95r.js.map → chunk-adbve9zt.js.map} +0 -0
- /package/dist/{chunk-wnxabtn4.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-ww185kt6.js.map → chunk-mmac1mp6.js.map} +0 -0
- /package/dist/{chunk-jfdggg1p.js.map → chunk-n5t4mq6z.js.map} +0 -0
- /package/dist/{chunk-3a338wrp.js.map → chunk-p0nbkys4.js.map} +0 -0
- /package/dist/{chunk-kxea54yg.js.map → chunk-py2dw8cw.js.map} +0 -0
- /package/dist/{chunk-e2c5yxfe.js.map → chunk-q3grgzp1.js.map} +0 -0
- /package/dist/{chunk-6rzb1g6h.js.map → chunk-qne45xqq.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-ma1mhh7w.js.map → chunk-wd34wnsy.js.map} +0 -0
- /package/dist/{chunk-pvgpckm1.js.map → chunk-wem5vqjw.js.map} +0 -0
- /package/dist/{chunk-gct3m1da.js.map → chunk-xr7y35yj.js.map} +0 -0
- /package/dist/{chunk-q2xghyft.js.map → chunk-y0zmae99.js.map} +0 -0
- /package/dist/{chunk-xgptywp0.js.map → chunk-y2aq6ag9.js.map} +0 -0
- /package/dist/{chunk-yvf2jqj8.js.map → chunk-yfppyaty.js.map} +0 -0
|
@@ -2,16 +2,20 @@ import { MaterializationConflictError } from "./errors"
|
|
|
2
2
|
import type { PinnedDatasetVersion } from "./model"
|
|
3
3
|
|
|
4
4
|
export type PinnedDatasetWatermarkConflict =
|
|
5
|
-
| "dataset-mismatch"
|
|
6
5
|
| "version-metadata-mismatch"
|
|
7
6
|
| "older-version"
|
|
8
7
|
| "ambiguous-version"
|
|
9
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Orders versions of one dataset. A projection rebound to a different dataset starts a new
|
|
11
|
+
* watermark: versions of two datasets have no order, and whether a run may read that dataset is
|
|
12
|
+
* decided by the registered definition, which rejects runs pinned to any other dataset.
|
|
13
|
+
*/
|
|
10
14
|
export function comparePinnedDatasetWatermarks(
|
|
11
15
|
active: PinnedDatasetVersion,
|
|
12
16
|
next: PinnedDatasetVersion
|
|
13
17
|
): PinnedDatasetWatermarkConflict | null {
|
|
14
|
-
if (active.datasetId !== next.datasetId) return
|
|
18
|
+
if (active.datasetId !== next.datasetId) return null
|
|
15
19
|
if (active.versionId === next.versionId && active.createdAt !== next.createdAt) {
|
|
16
20
|
return "version-metadata-mismatch"
|
|
17
21
|
}
|
|
@@ -40,8 +44,6 @@ function pinnedDatasetWatermarkConflictMessage(
|
|
|
40
44
|
subject: string
|
|
41
45
|
): string {
|
|
42
46
|
switch (conflict) {
|
|
43
|
-
case "dataset-mismatch":
|
|
44
|
-
return `${subject} dataset does not match the active source dataset.`
|
|
45
47
|
case "version-metadata-mismatch":
|
|
46
48
|
return `${subject} reused an immutable dataset version id with different metadata.`
|
|
47
49
|
case "older-version":
|
|
@@ -217,6 +217,13 @@ export type ProjectionRunTerminalDecision =
|
|
|
217
217
|
readonly error?: SixbFailure<ProjectionRunFailureCode>
|
|
218
218
|
readonly inputExhausted?: never
|
|
219
219
|
}
|
|
220
|
+
| {
|
|
221
|
+
readonly protocol: "replacement"
|
|
222
|
+
/** A run of the same projection pinned to a later dataset version makes this one stale. */
|
|
223
|
+
readonly status: "superseded"
|
|
224
|
+
readonly error?: never
|
|
225
|
+
readonly inputExhausted?: never
|
|
226
|
+
}
|
|
220
227
|
|
|
221
228
|
/**
|
|
222
229
|
* Queue-agnostic terminal decision for one fenced projection execution.
|
|
@@ -70,13 +70,33 @@ dataset entries
|
|
|
70
70
|
-> atomically activate candidate and finalize commit
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Source ingress is sealed before commit time is assigned.
|
|
74
|
-
|
|
75
|
-
projection run stores no separate commit pointer.
|
|
73
|
+
Source ingress is sealed before commit time is assigned. Activation and ontology commit
|
|
74
|
+
finalization are atomic; the projection run stores no separate commit pointer.
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
A candidate belongs to its run, not to the delivery that staged it:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
delivery fails transiently -> candidate stays with the run
|
|
80
|
+
next delivery -> adopts it: ready is published as is, staging resumes at its last root
|
|
81
|
+
run ends without success -> finishRun abandons it in the same transaction
|
|
82
|
+
maintenance -> deletes abandoned candidates whole, without retention
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
An adopted candidate staged against another delta base is abandoned and replaced, since its roots
|
|
86
|
+
describe a different change. Staging resumes by reading the entries again from the start, which is
|
|
87
|
+
sound because they are deterministic for the pinned dataset version and definition.
|
|
88
|
+
|
|
89
|
+
Projection runs finish only through `projections.finishRun(...)`, including a failure found before
|
|
90
|
+
materialization began. Its serializable transaction reads the authoritative ontology commit before
|
|
91
|
+
replacement success, rejects failure after commit, releases the run's candidate, and then applies
|
|
92
|
+
the fenced run transition. Success must match the deployed definition; failure only has to hold
|
|
93
|
+
the run's execution token, so a run pinned to a definition a deploy has since replaced can still
|
|
94
|
+
end.
|
|
95
|
+
|
|
96
|
+
A replacement run ends `superseded`, without materializing, when a run of the same projection
|
|
97
|
+
pinned to a later dataset version is queued, running, or succeeded. The worker checks this on every
|
|
98
|
+
delivery after its claim; `finishRun` checks it again under its transaction, since a newer run that
|
|
99
|
+
failed in between replaces nothing, and releases the candidate like any other end without success.
|
|
80
100
|
|
|
81
101
|
## Managed edits and Actions
|
|
82
102
|
|
|
@@ -12,7 +12,10 @@ import type { ProjectionDefinition, ResolvedProjection } from "../../projections
|
|
|
12
12
|
import type { OntologyCommitRecord } from "../../storage/ontology"
|
|
13
13
|
import type { MaterializerContext, MaterializerStorage } from "../context"
|
|
14
14
|
import { withSerializationRetry } from "../execution/commit-lifecycle"
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
type LockedProjectionExecution,
|
|
17
|
+
lockProjectionRunForMaterialization,
|
|
18
|
+
} from "../execution/run-correlation"
|
|
16
19
|
import {
|
|
17
20
|
assertMaterializerRunExecution,
|
|
18
21
|
assertTrustedPrimitiveMutationExecution,
|
|
@@ -31,12 +34,21 @@ import { createProjectionRunMaterializationIdentity } from "../shared/projection
|
|
|
31
34
|
interface PreparedProjectionRunFinish {
|
|
32
35
|
readonly projectId: string
|
|
33
36
|
readonly input: ProjectionRunFinishInput
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The deployed definition a success must match. A failure needs none: it only has to hold the
|
|
39
|
+
* run's execution token, and it must stay possible after a deploy changed or removed the
|
|
40
|
+
* projection, or the run and its candidate could never end.
|
|
41
|
+
*/
|
|
42
|
+
readonly deployed: DeployedProjectionIdentity | null
|
|
36
43
|
readonly finishedAt: Date
|
|
37
44
|
readonly execution: MaterializerExecution
|
|
38
45
|
}
|
|
39
46
|
|
|
47
|
+
interface DeployedProjectionIdentity {
|
|
48
|
+
readonly identity: ProjectionMaterializationIdentity
|
|
49
|
+
readonly resolved: ResolvedProjection<ProjectionDefinition>
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
export async function finishProjectionRun(
|
|
41
53
|
context: MaterializerContext,
|
|
42
54
|
raw: MaterializerCommand<ProjectionRunFinishInput>
|
|
@@ -57,28 +69,35 @@ function prepareProjectionRunFinish(
|
|
|
57
69
|
const source = normalizeProjectionSourceRef(raw.input.source)
|
|
58
70
|
const datasetVersion = normalizePinnedDatasetVersion(raw.input.datasetVersion)
|
|
59
71
|
const projectionExecution = normalizeProjectionExecution(raw.input.execution)
|
|
72
|
+
const input = { ...raw.input, source, datasetVersion, execution: projectionExecution }
|
|
73
|
+
return {
|
|
74
|
+
projectId: context.projectId,
|
|
75
|
+
input,
|
|
76
|
+
deployed: input.status === "succeeded" ? resolveDeployedProjection(context, input) : null,
|
|
77
|
+
finishedAt: new Date(raw.input.finishedAt ?? context.clock()),
|
|
78
|
+
execution: prepareMaterializerExecution(context.projectId, raw.scope),
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveDeployedProjection(
|
|
83
|
+
context: Pick<MaterializerContext, "projectionRegistry">,
|
|
84
|
+
input: ProjectionRunFinishInput
|
|
85
|
+
): DeployedProjectionIdentity {
|
|
60
86
|
const resolved =
|
|
61
|
-
|
|
62
|
-
? context.projectionRegistry.resolveSource(source.projectionId)
|
|
63
|
-
: context.projectionRegistry.resolveTelemetry(source.projectionId)
|
|
64
|
-
if (resolved.datasetId !== datasetVersion.datasetId) {
|
|
87
|
+
input.protocol === "replacement"
|
|
88
|
+
? context.projectionRegistry.resolveSource(input.source.projectionId)
|
|
89
|
+
: context.projectionRegistry.resolveTelemetry(input.source.projectionId)
|
|
90
|
+
if (resolved.datasetId !== input.datasetVersion.datasetId) {
|
|
65
91
|
throw new MaterializationValidationError(
|
|
66
92
|
`Projection '${resolved.projectionId}' requires dataset '${resolved.datasetId}'.`
|
|
67
93
|
)
|
|
68
94
|
}
|
|
69
95
|
const identity = createProjectionRunMaterializationIdentity({
|
|
70
96
|
resolved,
|
|
71
|
-
datasetVersion,
|
|
97
|
+
datasetVersion: input.datasetVersion,
|
|
72
98
|
ontologyRevision: context.projectionRegistry.ontologyRevision,
|
|
73
99
|
})
|
|
74
|
-
return {
|
|
75
|
-
projectId: context.projectId,
|
|
76
|
-
input: { ...raw.input, source, datasetVersion, execution: projectionExecution },
|
|
77
|
-
identity,
|
|
78
|
-
resolved,
|
|
79
|
-
finishedAt: new Date(raw.input.finishedAt ?? context.clock()),
|
|
80
|
-
execution: prepareMaterializerExecution(context.projectId, raw.scope),
|
|
81
|
-
}
|
|
100
|
+
return { identity, resolved }
|
|
82
101
|
}
|
|
83
102
|
|
|
84
103
|
async function finishProjectionRunTransaction(
|
|
@@ -91,36 +110,115 @@ async function finishProjectionRunTransaction(
|
|
|
91
110
|
id: command.input.source.projectionId,
|
|
92
111
|
runId: command.input.execution.projectionRunId,
|
|
93
112
|
})
|
|
94
|
-
const { projectionRuns, run } =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
const { projectionRuns, run } = command.deployed
|
|
114
|
+
? await lockProjectionRunForMaterialization(storage, {
|
|
115
|
+
projectId: command.projectId,
|
|
116
|
+
projectionRunId: command.input.execution.projectionRunId,
|
|
117
|
+
executionToken: command.input.execution.executionToken,
|
|
118
|
+
identity: command.deployed.identity,
|
|
119
|
+
resolved: command.deployed.resolved,
|
|
120
|
+
})
|
|
121
|
+
: await lockProjectionRunAsStored(storage, command)
|
|
101
122
|
assertMaterializerRunExecution(command.execution, run.executionId, `Projection run '${run.id}'`)
|
|
102
123
|
|
|
103
124
|
if (command.input.protocol === "replacement") {
|
|
104
125
|
await assertReplacementTerminalDecision(storage, command)
|
|
126
|
+
if (command.input.status === "superseded") {
|
|
127
|
+
await assertRunSuperseded(projectionRuns, command)
|
|
128
|
+
}
|
|
129
|
+
if (command.input.status !== "succeeded") {
|
|
130
|
+
// The candidate belongs to the run: once the run ends, nothing may adopt or activate it.
|
|
131
|
+
await storage.ontology.sources.abandon({
|
|
132
|
+
kind: "run",
|
|
133
|
+
projectId: command.projectId,
|
|
134
|
+
source: command.input.source,
|
|
135
|
+
execution: command.input.execution,
|
|
136
|
+
abandonedAt: command.finishedAt.toISOString(),
|
|
137
|
+
})
|
|
138
|
+
}
|
|
105
139
|
}
|
|
106
140
|
|
|
107
141
|
await projectionRuns.finish({
|
|
108
142
|
id: command.input.execution.projectionRunId,
|
|
109
143
|
projectId: command.projectId,
|
|
110
144
|
executionToken: command.input.execution.executionToken,
|
|
111
|
-
identity:
|
|
145
|
+
identity: run.identity,
|
|
112
146
|
...terminalDecision(command.input),
|
|
113
147
|
finishedAt: command.finishedAt,
|
|
114
148
|
})
|
|
115
149
|
}
|
|
116
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Checked again here, under the finish transaction, rather than trusted from the caller's earlier
|
|
153
|
+
* read: the newer run may have failed since, and a run superseded by a failure would leave the
|
|
154
|
+
* projection with neither version.
|
|
155
|
+
*/
|
|
156
|
+
async function assertRunSuperseded(
|
|
157
|
+
projectionRuns: LockedProjectionExecution["projectionRuns"],
|
|
158
|
+
command: PreparedProjectionRunFinish
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
const newer = await projectionRuns.findSupersedingRun({
|
|
161
|
+
projectId: command.projectId,
|
|
162
|
+
id: command.input.execution.projectionRunId,
|
|
163
|
+
})
|
|
164
|
+
if (newer) return
|
|
165
|
+
throw new MaterializationConflictError(
|
|
166
|
+
"run-correlation",
|
|
167
|
+
`Projection run '${command.input.execution.projectionRunId}' cannot be superseded: no run of a later dataset version stands to replace it.`
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Locks a run by the identity it was pinned with, for a decision that needs no definition. */
|
|
172
|
+
async function lockProjectionRunAsStored(
|
|
173
|
+
storage: MaterializerStorage,
|
|
174
|
+
command: PreparedProjectionRunFinish
|
|
175
|
+
): Promise<LockedProjectionExecution> {
|
|
176
|
+
const projectionRuns = storage.projectionRuns
|
|
177
|
+
if (!projectionRuns) {
|
|
178
|
+
throw new MaterializationValidationError(
|
|
179
|
+
"Storage transaction does not provide projection run capabilities."
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
const { input } = command
|
|
183
|
+
const stored = await projectionRuns.getById({
|
|
184
|
+
projectId: command.projectId,
|
|
185
|
+
id: input.execution.projectionRunId,
|
|
186
|
+
})
|
|
187
|
+
if (
|
|
188
|
+
!stored ||
|
|
189
|
+
stored.identity.projectionId !== input.source.projectionId ||
|
|
190
|
+
stored.identity.protocol !== input.protocol ||
|
|
191
|
+
!datasetVersionsEqual(stored.identity.datasetVersion, input.datasetVersion)
|
|
192
|
+
) {
|
|
193
|
+
throw new MaterializationConflictError(
|
|
194
|
+
"run-correlation",
|
|
195
|
+
`Projection run '${input.execution.projectionRunId}' does not match its finish decision.`
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
const run = await projectionRuns.lockForMaterialization({
|
|
199
|
+
id: stored.id,
|
|
200
|
+
projectId: command.projectId,
|
|
201
|
+
executionToken: input.execution.executionToken,
|
|
202
|
+
identity: stored.identity,
|
|
203
|
+
})
|
|
204
|
+
return { projectionRuns, run }
|
|
205
|
+
}
|
|
206
|
+
|
|
117
207
|
function assertValidTerminalDecision(input: ProjectionRunFinishInput): void {
|
|
118
208
|
if (input.protocol !== "replacement" && input.protocol !== "telemetry") {
|
|
119
209
|
throw new MaterializationValidationError("Projection finish protocol is invalid.")
|
|
120
210
|
}
|
|
121
|
-
if (
|
|
211
|
+
if (
|
|
212
|
+
input.status !== "succeeded" &&
|
|
213
|
+
input.status !== "failed" &&
|
|
214
|
+
input.status !== "cancelled" &&
|
|
215
|
+
input.status !== "superseded"
|
|
216
|
+
) {
|
|
122
217
|
throw new MaterializationValidationError("Projection finish status must be terminal.")
|
|
123
218
|
}
|
|
219
|
+
if (input.status === "superseded" && input.protocol !== "replacement") {
|
|
220
|
+
throw new MaterializationValidationError("Only a replacement projection run can be superseded.")
|
|
221
|
+
}
|
|
124
222
|
const inputExhausted = "inputExhausted" in input ? input.inputExhausted : undefined
|
|
125
223
|
if (input.status === "succeeded" && input.protocol === "telemetry") {
|
|
126
224
|
if (inputExhausted === true) return
|
|
@@ -136,6 +234,9 @@ function assertValidTerminalDecision(input: ProjectionRunFinishInput): void {
|
|
|
136
234
|
}
|
|
137
235
|
|
|
138
236
|
function terminalDecision(input: ProjectionRunFinishInput): ProjectionRunTerminalDecision {
|
|
237
|
+
if (input.status === "superseded") {
|
|
238
|
+
return { protocol: "replacement", status: "superseded" }
|
|
239
|
+
}
|
|
139
240
|
if (input.status !== "succeeded") {
|
|
140
241
|
return {
|
|
141
242
|
protocol: input.protocol,
|
|
@@ -182,8 +283,10 @@ function assertReplacementCommitCorrelation(
|
|
|
182
283
|
commit: OntologyCommitRecord,
|
|
183
284
|
command: PreparedProjectionRunFinish
|
|
184
285
|
): void {
|
|
185
|
-
const { input
|
|
286
|
+
const { input } = command
|
|
287
|
+
const identity = command.deployed?.identity
|
|
186
288
|
if (
|
|
289
|
+
!identity ||
|
|
187
290
|
commit.origin.kind !== "projection" ||
|
|
188
291
|
commit.executionId !== command.execution.executionId ||
|
|
189
292
|
commit.intent.kind !== "projection" ||
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { assertPinnedDatasetWatermark } from "../../materialization/dataset-watermark"
|
|
2
2
|
import {
|
|
3
|
-
MaterializationCancellationError,
|
|
4
3
|
MaterializationConflictError,
|
|
5
4
|
MaterializationValidationError,
|
|
6
5
|
} from "../../materialization/errors"
|
|
@@ -18,6 +17,7 @@ import type {
|
|
|
18
17
|
} from "../../materialization/model"
|
|
19
18
|
import type { ProjectionRegistry } from "../../projections/registry"
|
|
20
19
|
import type {
|
|
20
|
+
AdoptedSourceMaterialization,
|
|
21
21
|
OntologyCommitRecord,
|
|
22
22
|
OntologyCommitWrite,
|
|
23
23
|
OntologyMaterializationStorage,
|
|
@@ -76,6 +76,8 @@ interface PreparedProjectionReplacement {
|
|
|
76
76
|
interface ProjectionCandidate {
|
|
77
77
|
readonly materializationId: string
|
|
78
78
|
readonly createdAt: string
|
|
79
|
+
/** Set when a redelivery adopted the candidate a previous execution of this run staged. */
|
|
80
|
+
readonly adopted?: AdoptedSourceMaterialization
|
|
79
81
|
readonly expectedSource: {
|
|
80
82
|
readonly source: ProjectionSourceRef
|
|
81
83
|
readonly activeMaterializationId: string | null
|
|
@@ -96,14 +98,11 @@ export async function replaceProjection(
|
|
|
96
98
|
const replay = await admitProjectionExecution(context, command)
|
|
97
99
|
if (replay) return replay
|
|
98
100
|
|
|
101
|
+
// A failed attempt leaves its candidate to the run: a redelivery adopts it, and the run's
|
|
102
|
+
// terminal transition (`finishRun`) abandons it.
|
|
99
103
|
const candidate = await prepareProjectionCandidate(context, command)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return await commitProjectionCandidate(context, command, ready)
|
|
103
|
-
} catch (error) {
|
|
104
|
-
await abandonFailedCandidate(context, command, candidate, error)
|
|
105
|
-
throw error
|
|
106
|
-
}
|
|
104
|
+
const ready = await stageProjectionCandidate(context, command, candidate)
|
|
105
|
+
return commitProjectionCandidate(context, command, ready)
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
function prepareProjectionReplacement(
|
|
@@ -230,12 +229,11 @@ async function prepareProjectionCandidate(
|
|
|
230
229
|
context: MaterializerContext,
|
|
231
230
|
command: PreparedProjectionReplacement
|
|
232
231
|
): Promise<ProjectionCandidate> {
|
|
233
|
-
await context.storage.ontology.sources.
|
|
234
|
-
kind: "reclaim",
|
|
232
|
+
const adopted = await context.storage.ontology.sources.adopt({
|
|
235
233
|
projectId: context.projectId,
|
|
236
234
|
source: command.source,
|
|
237
235
|
execution: command.execution,
|
|
238
|
-
|
|
236
|
+
adoptedAt: context.clock().toISOString(),
|
|
239
237
|
})
|
|
240
238
|
const active = await context.storage.ontology.sources.getActive({
|
|
241
239
|
projectId: context.projectId,
|
|
@@ -243,14 +241,35 @@ async function prepareProjectionCandidate(
|
|
|
243
241
|
})
|
|
244
242
|
validateProjectionWatermark(active, command.datasetVersion)
|
|
245
243
|
assertDeltaBase(active, command)
|
|
244
|
+
const expectedSource = {
|
|
245
|
+
source: command.source,
|
|
246
|
+
activeMaterializationId: active?.materializationId ?? null,
|
|
247
|
+
lastCommitId: active?.lastCommitId ?? null,
|
|
248
|
+
}
|
|
249
|
+
if (adopted && sameSourceBase(adopted.record.base, command.base)) {
|
|
250
|
+
return {
|
|
251
|
+
materializationId: adopted.record.materializationId,
|
|
252
|
+
createdAt: adopted.record.createdAt,
|
|
253
|
+
adopted,
|
|
254
|
+
expectedSource,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (adopted) {
|
|
258
|
+
// Staged against another delta base (the active source moved, or this attempt reads the
|
|
259
|
+
// whole version): its roots answer a different question, so it cannot be completed.
|
|
260
|
+
await context.storage.ontology.sources.abandon({
|
|
261
|
+
kind: "candidate",
|
|
262
|
+
projectId: context.projectId,
|
|
263
|
+
source: command.source,
|
|
264
|
+
materializationId: adopted.record.materializationId,
|
|
265
|
+
execution: command.execution,
|
|
266
|
+
abandonedAt: context.clock().toISOString(),
|
|
267
|
+
})
|
|
268
|
+
}
|
|
246
269
|
return {
|
|
247
270
|
materializationId: context.materializationId(),
|
|
248
271
|
createdAt: context.clock().toISOString(),
|
|
249
|
-
expectedSource
|
|
250
|
-
source: command.source,
|
|
251
|
-
activeMaterializationId: active?.materializationId ?? null,
|
|
252
|
-
lastCommitId: active?.lastCommitId ?? null,
|
|
253
|
-
},
|
|
272
|
+
expectedSource,
|
|
254
273
|
}
|
|
255
274
|
}
|
|
256
275
|
|
|
@@ -259,6 +278,26 @@ async function stageProjectionCandidate(
|
|
|
259
278
|
command: PreparedProjectionReplacement,
|
|
260
279
|
candidate: ProjectionCandidate
|
|
261
280
|
): Promise<ReadyProjectionReplacement> {
|
|
281
|
+
const staged = await stageOrReuseCandidate(context, command, candidate)
|
|
282
|
+
return {
|
|
283
|
+
...candidate,
|
|
284
|
+
staged,
|
|
285
|
+
// Commit time starts only after the source candidate is sealed ready.
|
|
286
|
+
identity: timestampCommitIdentity(command.identity, context.clock()),
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async function stageOrReuseCandidate(
|
|
291
|
+
context: MaterializerContext,
|
|
292
|
+
command: PreparedProjectionReplacement,
|
|
293
|
+
candidate: ProjectionCandidate
|
|
294
|
+
): Promise<StagedProjectionMaterialization> {
|
|
295
|
+
const adopted = candidate.adopted?.record
|
|
296
|
+
if (adopted?.status === "ready" && adopted.rootCount !== null) {
|
|
297
|
+
// The entries are left unread: the pinned version and definition that produced this candidate
|
|
298
|
+
// are the ones this run is bound to.
|
|
299
|
+
return { rootCount: adopted.rootCount, assertionCount: adopted.assertionCount ?? 0 }
|
|
300
|
+
}
|
|
262
301
|
const input = {
|
|
263
302
|
source: command.source,
|
|
264
303
|
materializationId: candidate.materializationId,
|
|
@@ -270,15 +309,10 @@ async function stageProjectionCandidate(
|
|
|
270
309
|
createdAt: candidate.createdAt,
|
|
271
310
|
entries: command.entries,
|
|
272
311
|
...(command.base ? { base: command.base } : {}),
|
|
312
|
+
resumeStagingOrdinal: candidate.adopted?.resumeStagingOrdinal ?? 0,
|
|
273
313
|
validateEntry: createProjectionEntryValidator(context.ontology, command.resolved),
|
|
274
314
|
}
|
|
275
|
-
|
|
276
|
-
return {
|
|
277
|
-
...candidate,
|
|
278
|
-
staged,
|
|
279
|
-
// Commit time starts only after the source candidate is sealed ready.
|
|
280
|
-
identity: timestampCommitIdentity(command.identity, context.clock()),
|
|
281
|
-
}
|
|
315
|
+
return stageCandidateEntries(context, input, command.signal)
|
|
282
316
|
}
|
|
283
317
|
|
|
284
318
|
async function stageCandidateEntries(
|
|
@@ -462,32 +496,6 @@ function projectionActivation(
|
|
|
462
496
|
}
|
|
463
497
|
}
|
|
464
498
|
|
|
465
|
-
async function abandonFailedCandidate(
|
|
466
|
-
context: MaterializerContext,
|
|
467
|
-
command: PreparedProjectionReplacement,
|
|
468
|
-
candidate: ProjectionCandidate,
|
|
469
|
-
error: unknown
|
|
470
|
-
): Promise<void> {
|
|
471
|
-
if (!shouldAbandonCandidate(error)) return
|
|
472
|
-
await context.storage.ontology.sources.abandon({
|
|
473
|
-
kind: "candidate",
|
|
474
|
-
projectId: context.projectId,
|
|
475
|
-
source: command.source,
|
|
476
|
-
materializationId: candidate.materializationId,
|
|
477
|
-
execution: command.execution,
|
|
478
|
-
abandonedAt: context.clock().toISOString(),
|
|
479
|
-
})
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
function shouldAbandonCandidate(error: unknown): boolean {
|
|
483
|
-
if (error instanceof MaterializationValidationError) return true
|
|
484
|
-
if (error instanceof MaterializationCancellationError) return true
|
|
485
|
-
return (
|
|
486
|
-
error instanceof MaterializationConflictError &&
|
|
487
|
-
(error.kind === "run-correlation" || error.kind === "idempotency")
|
|
488
|
-
)
|
|
489
|
-
}
|
|
490
|
-
|
|
491
499
|
function validateProjectionWatermark(
|
|
492
500
|
active: Awaited<ReturnType<OntologyStorage["sources"]["getActive"]>>,
|
|
493
501
|
next: PinnedDatasetVersion
|
|
@@ -496,6 +504,16 @@ function validateProjectionWatermark(
|
|
|
496
504
|
assertPinnedDatasetWatermark(active.datasetVersion, next, "Projection replacement")
|
|
497
505
|
}
|
|
498
506
|
|
|
507
|
+
function sameSourceBase(
|
|
508
|
+
left: ProjectionSourceBase | undefined,
|
|
509
|
+
right: ProjectionSourceBase | undefined
|
|
510
|
+
): boolean {
|
|
511
|
+
return (
|
|
512
|
+
left?.materializationId === right?.materializationId &&
|
|
513
|
+
left?.lastCommitId === right?.lastCommitId
|
|
514
|
+
)
|
|
515
|
+
}
|
|
516
|
+
|
|
499
517
|
function assertDeltaBase(
|
|
500
518
|
active: OntologySourceRecord | null,
|
|
501
519
|
command: PreparedProjectionReplacement
|
|
@@ -23,8 +23,10 @@ export interface StagedProjectionMaterialization {
|
|
|
23
23
|
/**
|
|
24
24
|
* Persist and seal one explicit source-materialization candidate.
|
|
25
25
|
*
|
|
26
|
-
* A candidate is deliberately left staging/ready when execution is interrupted. The next
|
|
27
|
-
*
|
|
26
|
+
* A candidate is deliberately left staging/ready when execution is interrupted. The next delivery
|
|
27
|
+
* of the same run adopts it and resumes at `resumeStagingOrdinal`: the entries are read again from
|
|
28
|
+
* the start, since they are deterministic for the pinned version, but only the roots from that
|
|
29
|
+
* ordinal on are written. Age is never used to infer abandonment; the run's end is.
|
|
28
30
|
*/
|
|
29
31
|
export async function stageProjectionMaterialization(
|
|
30
32
|
context: Pick<
|
|
@@ -42,6 +44,8 @@ export async function stageProjectionMaterialization(
|
|
|
42
44
|
readonly createdAt: string
|
|
43
45
|
readonly entries: AsyncIterable<ProjectionSourceEntry | ProjectionSourceDeletion>
|
|
44
46
|
readonly base?: ProjectionSourceBase
|
|
47
|
+
/** First root ordinal to write; earlier ones are already staged. */
|
|
48
|
+
readonly resumeStagingOrdinal: number
|
|
45
49
|
readonly validateEntry: ProjectionEntryValidator
|
|
46
50
|
readonly signal?: AbortSignal
|
|
47
51
|
}
|
|
@@ -77,16 +81,17 @@ export async function stageProjectionMaterialization(
|
|
|
77
81
|
context.projectionRegistry.resolveSource(input.source.projectionId),
|
|
78
82
|
root
|
|
79
83
|
)
|
|
80
|
-
|
|
84
|
+
const stagingOrdinal = rootCount++
|
|
85
|
+
if (stagingOrdinal >= input.resumeStagingOrdinal) yield { root, stagingOrdinal }
|
|
81
86
|
continue
|
|
82
87
|
}
|
|
83
88
|
const entry = input.validateEntry(normalizeProjectionSourceEntry(rawEntry))
|
|
84
|
-
const stagingOrdinal = rootCount
|
|
89
|
+
const stagingOrdinal = rootCount++
|
|
90
|
+
assertionCount += entry.assertions.length
|
|
91
|
+
if (stagingOrdinal < input.resumeStagingOrdinal) continue
|
|
85
92
|
for (const assertion of entry.assertions) {
|
|
86
|
-
assertionCount += 1
|
|
87
93
|
yield { root: entry.root, assertion, stagingOrdinal }
|
|
88
94
|
}
|
|
89
|
-
rootCount += 1
|
|
90
95
|
}
|
|
91
96
|
throwIfAborted(input.signal)
|
|
92
97
|
}
|
package/src/projections/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export const PROJECTION_RUN_FAILURE_CODES = [
|
|
|
6
6
|
"runtime.cancelled",
|
|
7
7
|
"queue.enqueue_failed",
|
|
8
8
|
"projection.execution_failed",
|
|
9
|
+
"storage.unavailable",
|
|
9
10
|
] as const satisfies readonly [SixbErrorCode, ...SixbErrorCode[]]
|
|
10
11
|
|
|
11
12
|
export type ProjectionRunFailureCode = (typeof PROJECTION_RUN_FAILURE_CODES)[number]
|
package/src/storage/index.ts
CHANGED
|
@@ -449,8 +449,11 @@ export {
|
|
|
449
449
|
snapshotObjectReadExecutionLimits,
|
|
450
450
|
} from "./objects"
|
|
451
451
|
export type {
|
|
452
|
+
AbandonRunSourceMaterializationInput,
|
|
452
453
|
AbandonSourceMaterializationCandidateInput,
|
|
453
454
|
AbandonSourceMaterializationInput,
|
|
455
|
+
AdoptedSourceMaterialization,
|
|
456
|
+
AdoptSourceMaterializationInput,
|
|
454
457
|
ApplyMaterializationChunkInput,
|
|
455
458
|
ApplyMaterializationResult,
|
|
456
459
|
AssertSourceMaterializationExecution,
|
|
@@ -530,9 +533,9 @@ export type {
|
|
|
530
533
|
OntologyStorage,
|
|
531
534
|
OntologyVectorStorage,
|
|
532
535
|
ProjectionOntologyCommitIntent,
|
|
536
|
+
PurgeAbandonedSourceMaterializationsInput,
|
|
533
537
|
PurgePublishedOntologyOutboxInput,
|
|
534
538
|
ReadMaterializationObjectExistenceInput,
|
|
535
|
-
ReclaimSourceMaterializationInput,
|
|
536
539
|
RescheduleOntologyOutboxLeaseInput,
|
|
537
540
|
SourceActivationWrite,
|
|
538
541
|
SourceReplacementLinkState,
|
|
@@ -595,6 +598,7 @@ export {
|
|
|
595
598
|
export type {
|
|
596
599
|
AdvanceProjectionTelemetryCheckpointInput,
|
|
597
600
|
FailProjectionRunEnqueueInput,
|
|
601
|
+
FindSupersedingProjectionRunInput,
|
|
598
602
|
FinishProjectionRunInput,
|
|
599
603
|
LinkProjectionRunRecord,
|
|
600
604
|
LinkProjectionTarget,
|
|
@@ -616,6 +620,7 @@ export type {
|
|
|
616
620
|
ProjectionTarget,
|
|
617
621
|
ProjectionTelemetryCheckpoint,
|
|
618
622
|
QueueProjectionRunInput,
|
|
623
|
+
RecordProjectionAttemptFailureInput,
|
|
619
624
|
RecordProjectionMissingTargetInput,
|
|
620
625
|
StartOrReclaimProjectionRunInput,
|
|
621
626
|
TelemetryProjectionRunRecord,
|