@sixb/core 0.1.9 → 0.1.11
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 +9 -9
- package/dist/agents/index.js +17 -16
- package/dist/agents/index.js.map +1 -1
- package/dist/blob-storage/types.d.ts +4 -1
- package/dist/blob-storage/types.d.ts.map +1 -1
- package/dist/bootstrap/index.js +21 -20
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/broker/in-memory.d.ts +8 -2
- package/dist/broker/in-memory.d.ts.map +1 -1
- package/dist/broker/index.d.ts +4 -2
- package/dist/broker/index.d.ts.map +1 -1
- package/dist/broker/index.js +7 -3
- package/dist/broker/index.js.map +1 -1
- package/dist/broker/retention.d.ts +4 -0
- package/dist/broker/retention.d.ts.map +1 -0
- package/dist/broker/subscriber.d.ts +10 -0
- package/dist/broker/subscriber.d.ts.map +1 -0
- package/dist/broker/types.d.ts +14 -1
- package/dist/broker/types.d.ts.map +1 -1
- package/dist/{chunk-ypbtykv6.js → chunk-01kj2pbh.js} +1 -1
- package/dist/{chunk-k3cqkkn2.js → chunk-1824gssz.js} +30 -65
- package/dist/chunk-1824gssz.js.map +12 -0
- package/dist/{chunk-xyr8kppc.js → chunk-1yefycb1.js} +1 -1
- package/dist/chunk-2c4j899j.js.map +1 -1
- package/dist/{chunk-ppytyr6w.js → chunk-358caqf5.js} +4 -4
- package/dist/chunk-358caqf5.js.map +12 -0
- package/dist/{chunk-m3z3x9v0.js → chunk-3ckk0xfj.js} +2 -2
- package/dist/{chunk-kxwa347f.js → chunk-3qms4nax.js} +2 -2
- package/dist/{chunk-kxwa347f.js.map → chunk-3qms4nax.js.map} +3 -3
- package/dist/{chunk-52hbv0ak.js → chunk-4zhmdsx6.js} +141 -55
- package/dist/chunk-4zhmdsx6.js.map +36 -0
- package/dist/{chunk-zcnq6105.js → chunk-85cd7e8c.js} +2 -1
- package/dist/chunk-85cd7e8c.js.map +10 -0
- package/dist/{chunk-3f7veca0.js → chunk-9x8dybsb.js} +3 -3
- package/dist/chunk-9x8dybsb.js.map +10 -0
- package/dist/{chunk-0w35wavj.js → chunk-a0e6x5hd.js} +1 -1
- package/dist/{chunk-r29fxdhn.js → chunk-aa6z4a19.js} +160 -44
- package/dist/chunk-aa6z4a19.js.map +12 -0
- package/dist/{chunk-emyyk7dx.js → chunk-cfvakeax.js} +22 -145
- package/dist/chunk-cfvakeax.js.map +12 -0
- package/dist/chunk-d62kjtbg.js.map +1 -1
- package/dist/{chunk-h1gfhhbh.js → chunk-d63nnr5b.js} +2 -2
- package/dist/{chunk-r4tfx1sf.js → chunk-fh8kgex1.js} +5 -5
- package/dist/{chunk-an5tt9y0.js → chunk-ftv470j8.js} +42 -4
- package/dist/{chunk-an5tt9y0.js.map → chunk-ftv470j8.js.map} +7 -7
- package/dist/{chunk-jjy0fhrn.js → chunk-g91qxjj0.js} +20 -3
- package/dist/chunk-g91qxjj0.js.map +12 -0
- package/dist/{chunk-hpr1r6av.js → chunk-gq8vhakp.js} +51 -40
- package/dist/{chunk-hpr1r6av.js.map → chunk-gq8vhakp.js.map} +6 -6
- package/dist/{chunk-x57ycxq0.js → chunk-gqh45d2n.js} +42 -3
- package/dist/{chunk-x57ycxq0.js.map → chunk-gqh45d2n.js.map} +3 -3
- package/dist/{chunk-mjbk2djy.js → chunk-gqm76kse.js} +231 -125
- package/dist/{chunk-mjbk2djy.js.map → chunk-gqm76kse.js.map} +9 -8
- package/dist/{chunk-e0d1rzef.js → chunk-jsy70480.js} +16 -3
- package/dist/chunk-jsy70480.js.map +15 -0
- package/dist/{chunk-0rdrecsb.js → chunk-kfee1h52.js} +116 -32
- package/dist/chunk-kfee1h52.js.map +13 -0
- package/dist/{chunk-3frsnm7x.js → chunk-qma80ych.js} +4 -6
- package/dist/chunk-qma80ych.js.map +11 -0
- package/dist/{chunk-vf691g1r.js → chunk-sepyxgpc.js} +3 -3
- package/dist/chunk-v2vcg0w6.js +151 -0
- package/dist/chunk-v2vcg0w6.js.map +11 -0
- package/dist/{chunk-3tgwrcyh.js → chunk-wf88w4kp.js} +17 -23
- package/dist/chunk-wf88w4kp.js.map +14 -0
- package/dist/{chunk-xfbydgzy.js → chunk-x9m9x2eq.js} +7 -8
- package/dist/{chunk-xfbydgzy.js.map → chunk-x9m9x2eq.js.map} +3 -3
- package/dist/{chunk-qhcpj9wc.js → chunk-z0271qkp.js} +98 -2
- package/dist/chunk-z0271qkp.js.map +15 -0
- package/dist/{chunk-1enhpacz.js → chunk-z0s4axeh.js} +6 -6
- package/dist/connectors/connections/authorizations.d.ts.map +1 -1
- package/dist/connectors/connections/command-context.d.ts +2 -0
- package/dist/connectors/connections/command-context.d.ts.map +1 -1
- package/dist/connectors/connections/contracts.d.ts +4 -1
- package/dist/connectors/connections/contracts.d.ts.map +1 -1
- package/dist/connectors/connections/execution.d.ts +1 -0
- package/dist/connectors/connections/execution.d.ts.map +1 -1
- package/dist/connectors/connections/internal.js +1 -1
- package/dist/connectors/connections/request.d.ts +3 -1
- package/dist/connectors/connections/request.d.ts.map +1 -1
- package/dist/connectors/connections/runs.d.ts +1 -0
- package/dist/connectors/connections/runs.d.ts.map +1 -1
- package/dist/connectors/connections/service.d.ts +2 -0
- package/dist/connectors/connections/service.d.ts.map +1 -1
- package/dist/connectors/connections/tokens.d.ts.map +1 -1
- package/dist/connectors/connections/validation.d.ts +5 -1
- package/dist/connectors/connections/validation.d.ts.map +1 -1
- package/dist/connectors/types.d.ts +19 -4
- package/dist/connectors/types.d.ts.map +1 -1
- package/dist/events/execution.d.ts +1 -1
- package/dist/events/execution.d.ts.map +1 -1
- package/dist/events/index.js +1 -1
- package/dist/events/outbox-dispatcher.d.ts +2 -2
- package/dist/events/outbox-dispatcher.d.ts.map +1 -1
- package/dist/events/service.d.ts +2 -2
- package/dist/events/service.d.ts.map +1 -1
- package/dist/execution/agent.js +17 -16
- package/dist/execution/agent.js.map +1 -1
- package/dist/execution/primitive.js +17 -16
- package/dist/execution/primitive.js.map +2 -2
- package/dist/execution/request.js +17 -16
- package/dist/execution/request.js.map +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -29
- package/dist/index.js.map +1 -1
- package/dist/lake-storage/changes.d.ts +5 -0
- package/dist/lake-storage/changes.d.ts.map +1 -0
- package/dist/lake-storage/in-memory.d.ts +2 -1
- package/dist/lake-storage/in-memory.d.ts.map +1 -1
- package/dist/lake-storage/index.d.ts +2 -1
- package/dist/lake-storage/index.d.ts.map +1 -1
- package/dist/lake-storage/index.js +4 -2
- package/dist/lake-storage/index.js.map +1 -1
- package/dist/lake-storage/types.d.ts +38 -0
- package/dist/lake-storage/types.d.ts.map +1 -1
- package/dist/logging/internal.js +1 -1
- package/dist/maintenance/ontology-maintenance.d.ts.map +1 -1
- package/dist/maintenance/types.d.ts +1 -1
- package/dist/maintenance/types.d.ts.map +1 -1
- package/dist/materialization/index.d.ts +1 -1
- package/dist/materialization/index.d.ts.map +1 -1
- package/dist/materialization/model.d.ts +12 -1
- package/dist/materialization/model.d.ts.map +1 -1
- package/dist/materializer/index.d.ts +1 -1
- package/dist/materializer/index.d.ts.map +1 -1
- package/dist/materializer/index.js +6 -6
- package/dist/materializer/materializer.d.ts +5 -1
- package/dist/materializer/materializer.d.ts.map +1 -1
- package/dist/materializer/projections/entry-validator.d.ts +2 -1
- package/dist/materializer/projections/entry-validator.d.ts.map +1 -1
- package/dist/materializer/projections/replace.d.ts.map +1 -1
- package/dist/materializer/projections/source-materialization.d.ts +4 -3
- package/dist/materializer/projections/source-materialization.d.ts.map +1 -1
- package/dist/materializer/shared/normalize.d.ts +2 -1
- package/dist/materializer/shared/normalize.d.ts.map +1 -1
- package/dist/models/definitions.d.ts +7 -0
- package/dist/models/definitions.d.ts.map +1 -1
- package/dist/models/execution/index.js +6 -6
- package/dist/models/index.js +1 -1
- package/dist/objects/index.js +10 -10
- package/dist/objects/query/index.js +6 -6
- package/dist/pipelines/index.js +7 -7
- package/dist/pipelines/run-dispatch.d.ts.map +1 -1
- package/dist/projections/internal.js +7 -9
- package/dist/projections/internal.js.map +1 -1
- package/dist/projections/run-dispatch.d.ts.map +1 -1
- package/dist/queues/in-memory.d.ts +7 -3
- package/dist/queues/in-memory.d.ts.map +1 -1
- package/dist/queues/index.js +1 -1
- package/dist/queues/indexed-heap.d.ts +15 -0
- package/dist/queues/indexed-heap.d.ts.map +1 -0
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/internal.js +1 -1
- package/dist/runtime/ontology-mutations.d.ts +3 -1
- package/dist/runtime/ontology-mutations.d.ts.map +1 -1
- package/dist/shares/internal.js +5 -5
- package/dist/storage/agents/provider.js +1 -1
- package/dist/storage/connector-connections/in-memory.d.ts +1 -0
- package/dist/storage/connector-connections/in-memory.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider/connections.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider/runs.d.ts +1 -0
- package/dist/storage/connector-connections/provider/runs.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider/shared.d.ts +1 -0
- package/dist/storage/connector-connections/provider/shared.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider.d.ts +1 -0
- package/dist/storage/connector-connections/provider.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider.js +11 -17
- package/dist/storage/connector-connections/provider.js.map +6 -6
- package/dist/storage/connector-connections/types.d.ts +6 -3
- package/dist/storage/connector-connections/types.d.ts.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +5 -5
- package/dist/storage/internal.js +1 -1
- package/dist/storage/ontology/in-memory/materializations-state.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/materializations.d.ts +1 -1
- package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/shared-state.d.ts +15 -2
- package/dist/storage/ontology/in-memory/shared-state.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/source-roots.d.ts +6 -0
- package/dist/storage/ontology/in-memory/source-roots.d.ts.map +1 -0
- 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/outbox.d.ts +1 -0
- package/dist/storage/ontology/outbox.d.ts.map +1 -1
- package/dist/storage/ontology/provider.d.ts +16 -0
- package/dist/storage/ontology/provider.d.ts.map +1 -1
- package/dist/storage/ontology/provider.js +4 -2
- package/dist/storage/ontology/provider.js.map +1 -1
- package/dist/storage/ontology/sources.d.ts +13 -4
- package/dist/storage/ontology/sources.d.ts.map +1 -1
- package/dist/storage/projection-runs/lifecycle.d.ts.map +1 -1
- package/dist/storage/projection-runs/provider.js +2 -2
- package/dist/storage/projection-runs/types.d.ts +2 -0
- package/dist/storage/projection-runs/types.d.ts.map +1 -1
- package/dist/syncs/index.js +9 -8
- package/dist/syncs/index.js.map +1 -1
- package/dist/syncs/run-dispatch.d.ts.map +1 -1
- package/dist/testing/broker-contract.d.ts.map +1 -1
- package/dist/testing/connector-connection-storage-contract.d.ts.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1499 -963
- package/dist/testing/index.js.map +10 -9
- package/dist/testing/lake-changes-contract.d.ts +6 -0
- package/dist/testing/lake-changes-contract.d.ts.map +1 -0
- package/dist/testing/lake-storage-contract.d.ts.map +1 -1
- package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
- 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/connections.d.ts +6 -0
- package/dist/webhooks/connections.d.ts.map +1 -0
- package/dist/webhooks/index.d.ts +1 -1
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/internal.d.ts +2 -0
- package/dist/webhooks/internal.d.ts.map +1 -1
- package/dist/webhooks/internal.js +55 -10
- package/dist/webhooks/internal.js.map +4 -3
- package/dist/webhooks/registry.d.ts +1 -1
- package/dist/webhooks/registry.d.ts.map +1 -1
- package/dist/webhooks/types.d.ts +15 -4
- package/dist/webhooks/types.d.ts.map +1 -1
- package/dist/workflows/index.js +18 -17
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/run-dispatch.d.ts +3 -1
- package/dist/workflows/run-dispatch.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agents/model-loop.ts +7 -0
- package/src/blob-storage/types.ts +4 -1
- package/src/broker/in-memory.ts +104 -39
- package/src/broker/index.ts +4 -1
- package/src/broker/retention.ts +28 -0
- package/src/broker/subscriber.ts +21 -0
- package/src/broker/types.ts +15 -1
- package/src/connectors/builders.ts +0 -6
- package/src/connectors/connections/authorizations.ts +11 -5
- package/src/connectors/connections/command-context.ts +21 -4
- package/src/connectors/connections/contracts.ts +7 -1
- package/src/connectors/connections/execution.ts +3 -0
- package/src/connectors/connections/request.ts +56 -22
- package/src/connectors/connections/runs.ts +39 -1
- package/src/connectors/connections/service.ts +6 -0
- package/src/connectors/connections/tokens.ts +4 -0
- package/src/connectors/connections/validation.ts +91 -5
- package/src/connectors/types.ts +19 -4
- package/src/events/execution.ts +2 -2
- package/src/events/outbox-dispatcher.ts +20 -26
- package/src/events/service.ts +3 -3
- package/src/index.ts +10 -2
- package/src/lake-storage/changes.ts +43 -0
- package/src/lake-storage/in-memory.ts +75 -0
- package/src/lake-storage/index.ts +4 -0
- package/src/lake-storage/types.ts +42 -0
- package/src/logging/service.ts +1 -1
- package/src/maintenance/ontology-maintenance.ts +6 -2
- package/src/maintenance/types.ts +1 -1
- package/src/materialization/index.ts +2 -0
- package/src/materialization/model.ts +14 -1
- package/src/materializer/README.md +1 -1
- package/src/materializer/index.ts +2 -0
- package/src/materializer/materializer.ts +10 -0
- package/src/materializer/projections/entry-validator.ts +19 -1
- package/src/materializer/projections/replace.ts +36 -1
- package/src/materializer/projections/source-materialization.ts +26 -6
- package/src/materializer/shared/normalize.ts +1 -1
- package/src/models/definitions.ts +19 -0
- package/src/models/pricing.ts +6 -2
- package/src/pipelines/run-dispatch.ts +21 -1
- package/src/projections/run-dispatch.ts +30 -68
- package/src/queues/in-memory.ts +105 -62
- package/src/queues/indexed-heap.ts +74 -0
- package/src/runtime/host.ts +0 -14
- package/src/runtime/ontology-mutations.ts +4 -0
- package/src/storage/connector-connections/in-memory.ts +19 -19
- package/src/storage/connector-connections/provider/connections.ts +1 -15
- package/src/storage/connector-connections/provider/runs.ts +9 -1
- package/src/storage/connector-connections/provider/shared.ts +2 -3
- package/src/storage/connector-connections/provider.ts +6 -0
- package/src/storage/connector-connections/types.ts +8 -3
- package/src/storage/index.ts +1 -0
- package/src/storage/ontology/in-memory/materializations-state.ts +5 -18
- package/src/storage/ontology/in-memory/materializations.ts +73 -92
- package/src/storage/ontology/in-memory/shared-state.ts +36 -4
- package/src/storage/ontology/in-memory/source-roots.ts +123 -0
- package/src/storage/ontology/in-memory/sources.ts +78 -23
- package/src/storage/ontology/index.ts +1 -0
- package/src/storage/ontology/outbox.ts +1 -0
- package/src/storage/ontology/provider.ts +70 -0
- package/src/storage/ontology/sources.ts +14 -3
- package/src/storage/projection-runs/lifecycle.ts +5 -2
- package/src/storage/projection-runs/types.ts +4 -3
- package/src/syncs/run-dispatch.ts +19 -1
- package/src/testing/broker-contract.ts +95 -0
- package/src/testing/connector-connection-storage-contract.ts +29 -12
- package/src/testing/index.ts +1 -0
- package/src/testing/lake-changes-contract.ts +240 -0
- package/src/testing/lake-storage-contract.ts +29 -0
- package/src/testing/materializer-storage-contract.ts +172 -1
- package/src/testing/ontology-storage-contract.ts +15 -3
- package/src/testing/projection-run-storage-contract.ts +34 -0
- package/src/webhooks/connections.ts +56 -0
- package/src/webhooks/index.ts +2 -0
- package/src/webhooks/internal.ts +2 -0
- package/src/webhooks/registry.ts +3 -4
- package/src/webhooks/types.ts +17 -4
- package/src/workflows/run-dispatch.ts +42 -29
- package/dist/chunk-0rdrecsb.js.map +0 -11
- package/dist/chunk-3f7veca0.js.map +0 -10
- package/dist/chunk-3frsnm7x.js.map +0 -11
- package/dist/chunk-3tgwrcyh.js.map +0 -14
- package/dist/chunk-52hbv0ak.js.map +0 -36
- package/dist/chunk-e0d1rzef.js.map +0 -15
- package/dist/chunk-emyyk7dx.js.map +0 -14
- package/dist/chunk-jjy0fhrn.js.map +0 -12
- package/dist/chunk-k3cqkkn2.js.map +0 -12
- package/dist/chunk-ppytyr6w.js.map +0 -12
- package/dist/chunk-qhcpj9wc.js.map +0 -14
- package/dist/chunk-r29fxdhn.js.map +0 -11
- package/dist/chunk-zcnq6105.js.map +0 -10
- /package/dist/{chunk-ypbtykv6.js.map → chunk-01kj2pbh.js.map} +0 -0
- /package/dist/{chunk-xyr8kppc.js.map → chunk-1yefycb1.js.map} +0 -0
- /package/dist/{chunk-m3z3x9v0.js.map → chunk-3ckk0xfj.js.map} +0 -0
- /package/dist/{chunk-0w35wavj.js.map → chunk-a0e6x5hd.js.map} +0 -0
- /package/dist/{chunk-h1gfhhbh.js.map → chunk-d63nnr5b.js.map} +0 -0
- /package/dist/{chunk-r4tfx1sf.js.map → chunk-fh8kgex1.js.map} +0 -0
- /package/dist/{chunk-vf691g1r.js.map → chunk-sepyxgpc.js.map} +0 -0
- /package/dist/{chunk-1enhpacz.js.map → chunk-z0s4axeh.js.map} +0 -0
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto"
|
|
2
|
-
import { reportRunFailure } from "../error-reporting/capability"
|
|
3
|
-
import { createSixbError, toSixbFailure } from "../errors/internal"
|
|
4
|
-
import type { SixbFailure } from "../errors/types"
|
|
5
2
|
import type { RunDispatcher } from "../execution/dispatch"
|
|
6
3
|
import { createPrimitiveExecutionRecord } from "../execution/durable"
|
|
7
4
|
import type { DatasetProducer, LakeStorage } from "../lake-storage"
|
|
@@ -17,11 +14,7 @@ import {
|
|
|
17
14
|
import { getProjectionRegistry } from "./capability"
|
|
18
15
|
import { ProjectionValidationError } from "./errors"
|
|
19
16
|
import { createProjectionRunId } from "./run-id"
|
|
20
|
-
import {
|
|
21
|
-
PROJECTION_RUN_FAILURE_CODES,
|
|
22
|
-
type ProjectionDefinition,
|
|
23
|
-
type ProjectionRunFailureCode,
|
|
24
|
-
} from "./types"
|
|
17
|
+
import type { ProjectionDefinition } from "./types"
|
|
25
18
|
|
|
26
19
|
/** Target maximum mapped points per telemetry commit; a single-property projection reads 500 rows. */
|
|
27
20
|
export const PROJECTION_TELEMETRY_BATCH_SIZE = 500
|
|
@@ -106,7 +99,7 @@ export class ProjectionRunDispatcher implements ProjectionRunDispatchPort {
|
|
|
106
99
|
const runId = createProjectionRunId(this.dependencies.id, identity)
|
|
107
100
|
const projectionRuns = requireProjectionRunStorage(this.dependencies.storage)
|
|
108
101
|
const existing = await projectionRuns.getById({ projectId: this.dependencies.id, id: runId })
|
|
109
|
-
|
|
102
|
+
let persisted = existing
|
|
110
103
|
? await reuseProjectionRun(this.dependencies, existing, identity)
|
|
111
104
|
: await persistProjectionRun({
|
|
112
105
|
dependencies: this.dependencies,
|
|
@@ -120,6 +113,9 @@ export class ProjectionRunDispatcher implements ProjectionRunDispatchPort {
|
|
|
120
113
|
),
|
|
121
114
|
})
|
|
122
115
|
|
|
116
|
+
if (!persisted.publish && persisted.run.status === "queued") {
|
|
117
|
+
persisted = await reuseProjectionRun(this.dependencies, persisted.run, identity)
|
|
118
|
+
}
|
|
123
119
|
if (!persisted.publish) return existingResult(persisted.run)
|
|
124
120
|
return publishProjectionRun(this.dependencies, input.metadata, persisted)
|
|
125
121
|
}
|
|
@@ -195,6 +191,9 @@ async function reuseProjectionRun(
|
|
|
195
191
|
identity: ProjectionRunRecord["identity"]
|
|
196
192
|
): Promise<PersistedProjectionRun> {
|
|
197
193
|
await assertExistingRun(dependencies.storage, existing, identity)
|
|
194
|
+
if (existing.status === "queued") {
|
|
195
|
+
return { publish: true, run: existing, queuedAt: existing.queuedAt, created: false }
|
|
196
|
+
}
|
|
198
197
|
if (
|
|
199
198
|
existing.status !== "failed" ||
|
|
200
199
|
existing.error?.code !== "queue.enqueue_failed" ||
|
|
@@ -228,45 +227,29 @@ async function publishProjectionRun(
|
|
|
228
227
|
metadata: Readonly<Record<string, string>> | undefined,
|
|
229
228
|
persisted: Extract<PersistedProjectionRun, { readonly publish: true }>
|
|
230
229
|
): Promise<ProjectionRunDispatchResult> {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
})
|
|
243
|
-
return {
|
|
244
|
-
projectionId: persisted.run.identity.projectionId,
|
|
245
|
-
runId: persisted.run.id,
|
|
246
|
-
queuedAt: persisted.queuedAt.toISOString(),
|
|
247
|
-
...(job?.id ? { jobId: job.id } : {}),
|
|
248
|
-
created: persisted.created,
|
|
249
|
-
}
|
|
250
|
-
} catch (error) {
|
|
251
|
-
const failedAt = new Date()
|
|
252
|
-
const failure = toEnqueueFailure(error, persisted.run, failedAt)
|
|
253
|
-
const failed = await requireProjectionRunStorage(dependencies.storage).failEnqueue({
|
|
254
|
-
projectId: dependencies.id,
|
|
255
|
-
id: persisted.run.id,
|
|
256
|
-
finishedAt: failedAt,
|
|
257
|
-
error: failure,
|
|
258
|
-
})
|
|
259
|
-
reportRunFailure(dependencies, error, {
|
|
260
|
-
projectId: dependencies.id,
|
|
261
|
-
runKind: "projection",
|
|
262
|
-
run: {
|
|
263
|
-
runId: failed.id,
|
|
264
|
-
projectionId: failed.identity.projectionId,
|
|
265
|
-
projectionKind: failed.identity.projectionKind,
|
|
230
|
+
// Keep the run queued on uncertain publication; the caller retries the same identity.
|
|
231
|
+
const [job] = await dependencies.queues.projections.enqueue({
|
|
232
|
+
projectId: dependencies.id,
|
|
233
|
+
jobs: [
|
|
234
|
+
{
|
|
235
|
+
id: persisted.run.id,
|
|
236
|
+
type: "projection.run.requested",
|
|
237
|
+
payload: { runId: persisted.run.id },
|
|
238
|
+
...(metadata === undefined ? {} : { metadata }),
|
|
266
239
|
},
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
240
|
+
],
|
|
241
|
+
})
|
|
242
|
+
if (!job || job.id !== persisted.run.id) {
|
|
243
|
+
throw new ProjectionRunError(
|
|
244
|
+
`[Sixb] Queue did not acknowledge Projection run '${persisted.run.id}'.`
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
projectionId: persisted.run.identity.projectionId,
|
|
249
|
+
runId: persisted.run.id,
|
|
250
|
+
queuedAt: persisted.queuedAt.toISOString(),
|
|
251
|
+
...(job?.id ? { jobId: job.id } : {}),
|
|
252
|
+
created: persisted.created,
|
|
270
253
|
}
|
|
271
254
|
}
|
|
272
255
|
|
|
@@ -478,24 +461,3 @@ function assertDispatchInput(input: ProjectionRunDispatchInput): void {
|
|
|
478
461
|
throw new ProjectionValidationError("[Sixb] Projection dataset version timestamp is invalid.")
|
|
479
462
|
}
|
|
480
463
|
}
|
|
481
|
-
|
|
482
|
-
function toEnqueueFailure(
|
|
483
|
-
error: unknown,
|
|
484
|
-
run: ProjectionRunRecord,
|
|
485
|
-
at: Date
|
|
486
|
-
): SixbFailure<ProjectionRunFailureCode> {
|
|
487
|
-
const enqueueError = createSixbError(
|
|
488
|
-
"queue.enqueue_failed",
|
|
489
|
-
`[Sixb] Could not enqueue Projection run '${run.id}'.`,
|
|
490
|
-
{
|
|
491
|
-
cause: error,
|
|
492
|
-
details: {
|
|
493
|
-
projectionId: run.identity.projectionId,
|
|
494
|
-
projectionKind: run.identity.projectionKind,
|
|
495
|
-
runId: run.id,
|
|
496
|
-
phase: "enqueue",
|
|
497
|
-
},
|
|
498
|
-
}
|
|
499
|
-
)
|
|
500
|
-
return toSixbFailure(enqueueError, { allowedCodes: PROJECTION_RUN_FAILURE_CODES, at })
|
|
501
|
-
}
|
package/src/queues/in-memory.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto"
|
|
2
2
|
import type { SixbErrorCode } from "../errors/types"
|
|
3
3
|
import { QueueError } from "./errors"
|
|
4
|
+
import { IndexedHeap } from "./indexed-heap"
|
|
4
5
|
import type {
|
|
5
6
|
ActionQueueJobFailureCode,
|
|
6
7
|
ActionRunRequestedQueueJob,
|
|
@@ -29,6 +30,9 @@ interface QueueRecord<TQueueJob extends QueueJob = QueueJob> {
|
|
|
29
30
|
readonly sequence: number
|
|
30
31
|
readonly queueId: string
|
|
31
32
|
job: TQueueJob
|
|
33
|
+
availableAtMs: number
|
|
34
|
+
readonly createdAtMs: number
|
|
35
|
+
leaseExpiryMs: number | null
|
|
32
36
|
// A leased job stays "queued" until a worker completes or fails it.
|
|
33
37
|
state: QueueRecordState
|
|
34
38
|
failure: QueueJobFailure | null
|
|
@@ -63,25 +67,15 @@ function clearLease(record: QueueRecord): void {
|
|
|
63
67
|
record.leaseId = null
|
|
64
68
|
record.claimedAt = null
|
|
65
69
|
record.leaseExpiresAt = null
|
|
70
|
+
record.leaseExpiryMs = null
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
// Best-effort ordering is part of the contract; this keeps the in-memory provider deterministic.
|
|
69
74
|
function compareQueueRecords(left: QueueRecord, right: QueueRecord): number {
|
|
70
|
-
const availableDifference =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (availableDifference !== 0) {
|
|
75
|
-
return availableDifference
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const createdDifference =
|
|
79
|
-
parseTimestamp(left.job.createdAt, "job.createdAt") -
|
|
80
|
-
parseTimestamp(right.job.createdAt, "job.createdAt")
|
|
81
|
-
|
|
82
|
-
if (createdDifference !== 0) {
|
|
83
|
-
return createdDifference
|
|
84
|
-
}
|
|
75
|
+
const availableDifference = left.availableAtMs - right.availableAtMs
|
|
76
|
+
if (availableDifference !== 0) return availableDifference
|
|
77
|
+
const createdDifference = left.createdAtMs - right.createdAtMs
|
|
78
|
+
if (createdDifference !== 0) return createdDifference
|
|
85
79
|
|
|
86
80
|
return left.sequence - right.sequence
|
|
87
81
|
}
|
|
@@ -107,11 +101,18 @@ function createQueueJob<TQueueJob extends QueueJob>(
|
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
function leaseExpiresAtMs(record: QueueRecord): number | null {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
104
|
+
return record.leaseExpiryMs
|
|
105
|
+
}
|
|
113
106
|
|
|
114
|
-
|
|
107
|
+
function eligibleAt(record: QueueRecord): number {
|
|
108
|
+
return Math.max(record.availableAtMs, record.leaseExpiryMs ?? -Infinity)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface QueueLane {
|
|
112
|
+
// Terminal records remain here for caller-id deduplication, never in the delivery indexes.
|
|
113
|
+
readonly records: Map<string, QueueRecord>
|
|
114
|
+
readonly ready: IndexedHeap<QueueRecord>
|
|
115
|
+
readonly waiting: IndexedHeap<QueueRecord>
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
function toClaimedQueueJob<TQueueJob extends QueueJob>(
|
|
@@ -130,27 +131,26 @@ function toClaimedQueueJob<TQueueJob extends QueueJob>(
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
class InMemoryQueueStore {
|
|
133
|
-
private readonly
|
|
134
|
+
private readonly projects = new Map<string, Map<string, QueueLane>>()
|
|
134
135
|
private nextSequence = 1
|
|
135
136
|
|
|
136
137
|
add<TQueueJob extends QueueJob>(projectId: string, queueId: string, job: TQueueJob): void {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
sequence: this.nextSequence
|
|
138
|
+
const lane = this.lane(projectId, queueId)
|
|
139
|
+
const record: QueueRecord = {
|
|
140
|
+
sequence: this.nextSequence++,
|
|
140
141
|
queueId,
|
|
141
142
|
job,
|
|
143
|
+
availableAtMs: parseTimestamp(job.availableAt, "job.availableAt"),
|
|
144
|
+
createdAtMs: parseTimestamp(job.createdAt, "job.createdAt"),
|
|
145
|
+
leaseExpiryMs: null,
|
|
142
146
|
state: "queued",
|
|
143
147
|
failure: null,
|
|
144
148
|
leaseId: null,
|
|
145
149
|
claimedAt: null,
|
|
146
150
|
leaseExpiresAt: null,
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
list<TQueueJob extends QueueJob>(projectId: string, queueId: string): QueueRecord<TQueueJob>[] {
|
|
152
|
-
const records = this.recordsByProject.get(projectId) ?? []
|
|
153
|
-
return records.filter((record) => record.queueId === queueId) as QueueRecord<TQueueJob>[]
|
|
151
|
+
}
|
|
152
|
+
lane.records.set(job.id, record)
|
|
153
|
+
this.schedule(projectId, record, Date.now())
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
find<TQueueJob extends QueueJob>(
|
|
@@ -158,20 +158,67 @@ class InMemoryQueueStore {
|
|
|
158
158
|
queueId: string,
|
|
159
159
|
jobId: string
|
|
160
160
|
): QueueRecord<TQueueJob> | null {
|
|
161
|
-
return (
|
|
162
|
-
|
|
163
|
-
)
|
|
161
|
+
return (this.projects.get(projectId)?.get(queueId)?.records.get(jobId) ??
|
|
162
|
+
null) as QueueRecord<TQueueJob> | null
|
|
164
163
|
}
|
|
165
164
|
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
if (
|
|
169
|
-
|
|
165
|
+
schedule(projectId: string, record: QueueRecord, now: number): void {
|
|
166
|
+
const lane = this.lane(projectId, record.queueId)
|
|
167
|
+
if (record.state !== "queued") {
|
|
168
|
+
lane.ready.delete(record)
|
|
169
|
+
lane.waiting.delete(record)
|
|
170
|
+
} else if (eligibleAt(record) <= now) {
|
|
171
|
+
lane.waiting.delete(record)
|
|
172
|
+
lane.ready.set(record)
|
|
173
|
+
} else {
|
|
174
|
+
lane.ready.delete(record)
|
|
175
|
+
lane.waiting.set(record)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
takeReady<TQueueJob extends QueueJob>(
|
|
180
|
+
projectId: string,
|
|
181
|
+
queueId: string,
|
|
182
|
+
now: number,
|
|
183
|
+
limit: number
|
|
184
|
+
): QueueRecord<TQueueJob>[] {
|
|
185
|
+
const lane = this.projects.get(projectId)?.get(queueId)
|
|
186
|
+
if (!lane) return []
|
|
187
|
+
// Wake delayed jobs and expired leases, then order all ready jobs by the original contract.
|
|
188
|
+
// A lease expiry controls eligibility, not the priority of a redelivered job.
|
|
189
|
+
while (lane.waiting.peek() && eligibleAt(lane.waiting.peek()!) <= now) {
|
|
190
|
+
lane.ready.set(lane.waiting.pop()!)
|
|
170
191
|
}
|
|
192
|
+
const selected: QueueRecord[] = []
|
|
193
|
+
while (selected.length < limit) {
|
|
194
|
+
const record = lane.ready.peek()
|
|
195
|
+
if (!record || record.availableAtMs > now) break
|
|
196
|
+
lane.ready.pop()
|
|
197
|
+
// A backwards wall-clock adjustment can make a previously expired lease live again.
|
|
198
|
+
if (eligibleAt(record) > now) lane.waiting.set(record)
|
|
199
|
+
else selected.push(record)
|
|
200
|
+
}
|
|
201
|
+
return selected as QueueRecord<TQueueJob>[]
|
|
202
|
+
}
|
|
171
203
|
|
|
172
|
-
|
|
173
|
-
this.
|
|
174
|
-
|
|
204
|
+
private lane(projectId: string, queueId: string): QueueLane {
|
|
205
|
+
let queues = this.projects.get(projectId)
|
|
206
|
+
if (!queues) {
|
|
207
|
+
queues = new Map()
|
|
208
|
+
this.projects.set(projectId, queues)
|
|
209
|
+
}
|
|
210
|
+
let lane = queues.get(queueId)
|
|
211
|
+
if (!lane) {
|
|
212
|
+
lane = {
|
|
213
|
+
records: new Map(),
|
|
214
|
+
ready: new IndexedHeap(compareQueueRecords),
|
|
215
|
+
waiting: new IndexedHeap(
|
|
216
|
+
(left, right) => eligibleAt(left) - eligibleAt(right) || left.sequence - right.sequence
|
|
217
|
+
),
|
|
218
|
+
}
|
|
219
|
+
queues.set(queueId, lane)
|
|
220
|
+
}
|
|
221
|
+
return lane
|
|
175
222
|
}
|
|
176
223
|
}
|
|
177
224
|
|
|
@@ -219,8 +266,8 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
219
266
|
assertNonEmpty(params.projectId, "projectId")
|
|
220
267
|
assertNonEmpty(params.workerId, "workerId")
|
|
221
268
|
|
|
222
|
-
const limit = params.limit ?? 1
|
|
223
|
-
if (limit
|
|
269
|
+
const limit = Math.trunc(params.limit ?? 1)
|
|
270
|
+
if (!(limit > 0)) {
|
|
224
271
|
return []
|
|
225
272
|
}
|
|
226
273
|
|
|
@@ -228,24 +275,11 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
228
275
|
assertPositiveNumber(leaseMs, "leaseMs")
|
|
229
276
|
|
|
230
277
|
const now = Date.now()
|
|
231
|
-
const claimable = this.store
|
|
232
|
-
.list<TQueueJob>(params.projectId, this.queueId)
|
|
233
|
-
.filter((record) => {
|
|
234
|
-
if (record.state !== "queued") {
|
|
235
|
-
return false
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (parseTimestamp(record.job.availableAt, "job.availableAt") > now) {
|
|
239
|
-
return false
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const expiresAt = leaseExpiresAtMs(record)
|
|
243
|
-
return expiresAt === null || expiresAt <= now
|
|
244
|
-
})
|
|
245
|
-
.sort(compareQueueRecords)
|
|
246
|
-
.slice(0, limit)
|
|
247
|
-
|
|
248
278
|
const claimedAt = new Date(now).toISOString()
|
|
279
|
+
// Validate before removing candidates, and cache the same millisecond precision we return.
|
|
280
|
+
const leaseExpiry = new Date(now + leaseMs)
|
|
281
|
+
const leaseExpiresAt = leaseExpiry.toISOString()
|
|
282
|
+
const claimable = this.store.takeReady<TQueueJob>(params.projectId, this.queueId, now, limit)
|
|
249
283
|
|
|
250
284
|
return claimable.map((record) => {
|
|
251
285
|
// Attempts count claims so redelivery after lease expiry or retry is visible to workers.
|
|
@@ -255,7 +289,9 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
255
289
|
}
|
|
256
290
|
record.leaseId = randomUUID()
|
|
257
291
|
record.claimedAt = claimedAt
|
|
258
|
-
record.leaseExpiresAt =
|
|
292
|
+
record.leaseExpiresAt = leaseExpiresAt
|
|
293
|
+
record.leaseExpiryMs = leaseExpiry.getTime()
|
|
294
|
+
this.store.schedule(params.projectId, record, now)
|
|
259
295
|
|
|
260
296
|
return toClaimedQueueJob(record)
|
|
261
297
|
})
|
|
@@ -265,6 +301,7 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
265
301
|
const record = this.requireActiveLease(params)
|
|
266
302
|
record.state = "completed"
|
|
267
303
|
clearLease(record)
|
|
304
|
+
this.store.schedule(params.projectId, record, Date.now())
|
|
268
305
|
}
|
|
269
306
|
|
|
270
307
|
async retry(params: {
|
|
@@ -275,13 +312,15 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
275
312
|
}): Promise<void> {
|
|
276
313
|
const record = this.requireActiveLease(params)
|
|
277
314
|
const availableAt = params.availableAt ?? new Date().toISOString()
|
|
278
|
-
parseTimestamp(availableAt, "availableAt")
|
|
315
|
+
const availableAtMs = parseTimestamp(availableAt, "availableAt")
|
|
279
316
|
|
|
317
|
+
record.availableAtMs = availableAtMs
|
|
280
318
|
record.job = {
|
|
281
319
|
...record.job,
|
|
282
320
|
availableAt,
|
|
283
321
|
}
|
|
284
322
|
clearLease(record)
|
|
323
|
+
this.store.schedule(params.projectId, record, Date.now())
|
|
285
324
|
}
|
|
286
325
|
|
|
287
326
|
async fail(params: {
|
|
@@ -294,6 +333,7 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
294
333
|
record.state = "failed"
|
|
295
334
|
record.failure = structuredClone(params.failure)
|
|
296
335
|
clearLease(record)
|
|
336
|
+
this.store.schedule(params.projectId, record, Date.now())
|
|
297
337
|
}
|
|
298
338
|
|
|
299
339
|
async renewLease(params: {
|
|
@@ -319,7 +359,10 @@ class InMemoryQueue<TQueueJob extends QueueJob, TFailureCode extends SixbErrorCo
|
|
|
319
359
|
return null
|
|
320
360
|
}
|
|
321
361
|
|
|
322
|
-
|
|
362
|
+
const leaseExpiry = new Date(now + params.leaseMs)
|
|
363
|
+
record.leaseExpiresAt = leaseExpiry.toISOString()
|
|
364
|
+
record.leaseExpiryMs = leaseExpiry.getTime()
|
|
365
|
+
this.store.schedule(params.projectId, record, now)
|
|
323
366
|
return toClaimedQueueJob(record)
|
|
324
367
|
}
|
|
325
368
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Internal mutable priority index. Updating or removing an entry never leaves stale copies. */
|
|
2
|
+
export class IndexedHeap<T> {
|
|
3
|
+
private readonly items: T[] = []
|
|
4
|
+
private readonly positions = new Map<T, number>()
|
|
5
|
+
|
|
6
|
+
constructor(private readonly compare: (left: T, right: T) => number) {}
|
|
7
|
+
|
|
8
|
+
peek(): T | undefined {
|
|
9
|
+
return this.items[0]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
pop(): T | undefined {
|
|
13
|
+
const first = this.peek()
|
|
14
|
+
if (first !== undefined) this.delete(first)
|
|
15
|
+
return first
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
set(item: T): void {
|
|
19
|
+
const index = this.positions.get(item)
|
|
20
|
+
if (index === undefined) {
|
|
21
|
+
this.positions.set(item, this.items.length)
|
|
22
|
+
this.items.push(item)
|
|
23
|
+
this.up(this.items.length - 1)
|
|
24
|
+
} else {
|
|
25
|
+
this.down(this.up(index))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
delete(item: T): void {
|
|
30
|
+
const index = this.positions.get(item)
|
|
31
|
+
if (index === undefined) return
|
|
32
|
+
const last = this.items.pop()!
|
|
33
|
+
this.positions.delete(item)
|
|
34
|
+
if (index === this.items.length) return
|
|
35
|
+
this.items[index] = last
|
|
36
|
+
this.positions.set(last, index)
|
|
37
|
+
this.down(this.up(index))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private up(start: number): number {
|
|
41
|
+
let index = start
|
|
42
|
+
while (index > 0) {
|
|
43
|
+
const parent = Math.floor((index - 1) / 2)
|
|
44
|
+
if (this.compare(this.items[parent]!, this.items[index]!) <= 0) break
|
|
45
|
+
this.swap(parent, index)
|
|
46
|
+
index = parent
|
|
47
|
+
}
|
|
48
|
+
return index
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private down(start: number): void {
|
|
52
|
+
let index = start
|
|
53
|
+
while (index * 2 + 1 < this.items.length) {
|
|
54
|
+
const left = index * 2 + 1
|
|
55
|
+
const right = left + 1
|
|
56
|
+
const child =
|
|
57
|
+
right < this.items.length && this.compare(this.items[right]!, this.items[left]!) < 0
|
|
58
|
+
? right
|
|
59
|
+
: left
|
|
60
|
+
if (this.compare(this.items[index]!, this.items[child]!) <= 0) break
|
|
61
|
+
this.swap(index, child)
|
|
62
|
+
index = child
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private swap(left: number, right: number): void {
|
|
67
|
+
const a = this.items[left]!
|
|
68
|
+
const b = this.items[right]!
|
|
69
|
+
this.items[left] = b
|
|
70
|
+
this.items[right] = a
|
|
71
|
+
this.positions.set(a, right)
|
|
72
|
+
this.positions.set(b, left)
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/runtime/host.ts
CHANGED
|
@@ -19,7 +19,6 @@ import type { BlobStorage } from "../blob-storage"
|
|
|
19
19
|
import type { Broker } from "../broker"
|
|
20
20
|
import { registerConnectorConnectionCallbackProcess } from "../connectors/connections/capability"
|
|
21
21
|
import { createConnectorCredentialProtectorFromKey } from "../connectors/credentials"
|
|
22
|
-
import { createConnectorCodedError } from "../connectors/errors"
|
|
23
22
|
import { ConnectorService } from "../connectors/service"
|
|
24
23
|
import {
|
|
25
24
|
type ConnectorConnectionOptions,
|
|
@@ -185,7 +184,6 @@ export class SixbHost<
|
|
|
185
184
|
})
|
|
186
185
|
validateAuthStrategySecurityReferences(this.auth.getStrategy(), definitions.security)
|
|
187
186
|
const connectors = definitions.connectors.list()
|
|
188
|
-
assertConnectorConnectionSurfaces(connectors)
|
|
189
187
|
const hasOAuthConnectors = connectors.some(isOAuthConnectorDefinition)
|
|
190
188
|
const credentialProtector =
|
|
191
189
|
hasOAuthConnectors && options.connectorConnections?.encryptionKey !== undefined
|
|
@@ -386,15 +384,3 @@ function assertWebhookRunStorage(
|
|
|
386
384
|
}
|
|
387
385
|
}
|
|
388
386
|
}
|
|
389
|
-
|
|
390
|
-
function assertConnectorConnectionSurfaces(connectors: readonly ConnectorDefinition[]): void {
|
|
391
|
-
for (const connector of connectors) {
|
|
392
|
-
if (!isOAuthConnectorDefinition(connector)) continue
|
|
393
|
-
if (connector.adapter.webhooks !== undefined) {
|
|
394
|
-
throw createConnectorCodedError(
|
|
395
|
-
"connector.configuration_invalid",
|
|
396
|
-
`OAuth connector '${connector.id}' cannot register webhooks until connection routing is defined.`
|
|
397
|
-
)
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
@@ -3,13 +3,16 @@ import type {
|
|
|
3
3
|
OntologyEditCommit,
|
|
4
4
|
ProjectionCommitResult,
|
|
5
5
|
ProjectionRunFinishInput,
|
|
6
|
+
ProjectionSourceRef,
|
|
6
7
|
ProjectionSourceReplacement,
|
|
7
8
|
TelemetryAppend,
|
|
8
9
|
TelemetryCommitResult,
|
|
9
10
|
} from "../materialization/model"
|
|
10
11
|
import type { BoundOntologyMaterializer } from "../materializer"
|
|
12
|
+
import type { OntologySourceRecord } from "../storage/ontology"
|
|
11
13
|
|
|
12
14
|
export interface OntologyMutationRuntime {
|
|
15
|
+
getProjectionSource?(source: ProjectionSourceRef): Promise<OntologySourceRecord | null>
|
|
13
16
|
commitEdits(input: OntologyEditCommit): Promise<EditCommitResult>
|
|
14
17
|
replaceProjection(input: ProjectionSourceReplacement): Promise<ProjectionCommitResult>
|
|
15
18
|
finishProjection(input: ProjectionRunFinishInput): Promise<void>
|
|
@@ -55,6 +58,7 @@ export function createOntologyMutationRuntime(input: {
|
|
|
55
58
|
readonly notifyCommittedFacts: () => void
|
|
56
59
|
}): OntologyMutationRuntime {
|
|
57
60
|
const runtime: OntologyMutationRuntime = {
|
|
61
|
+
getProjectionSource: (source) => input.materializer.projections.getActive(source),
|
|
58
62
|
commitEdits: (command) =>
|
|
59
63
|
commitAndNotify(() => input.materializer.edits.commit(command), input.notifyCommittedFacts),
|
|
60
64
|
replaceProjection: (command) =>
|
|
@@ -147,7 +147,9 @@ export class InMemoryConnectorConnectionStorage implements ConnectorConnectionSt
|
|
|
147
147
|
slot: input.slot,
|
|
148
148
|
initiatedByExecutionId: input.initiatedByExecutionId,
|
|
149
149
|
stateHash: input.stateHash,
|
|
150
|
-
|
|
150
|
+
...(input.codeVerifier === undefined
|
|
151
|
+
? {}
|
|
152
|
+
: { codeVerifier: structuredClone(input.codeVerifier) }),
|
|
151
153
|
redirectUri: input.redirectUri,
|
|
152
154
|
...(input.connectionRunId === undefined ? {} : { connectionRunId: input.connectionRunId }),
|
|
153
155
|
...(input.returnTo === undefined ? {} : { returnTo: input.returnTo }),
|
|
@@ -411,6 +413,20 @@ export class InMemoryConnectorConnectionStorage implements ConnectorConnectionSt
|
|
|
411
413
|
return structuredClone(finished)
|
|
412
414
|
}
|
|
413
415
|
|
|
416
|
+
async listPendingConnectionRuns(
|
|
417
|
+
input: Parameters<ConnectorConnectionStorage["listPendingConnectionRuns"]>[0]
|
|
418
|
+
): Promise<readonly ConnectorConnectionRunRecord[]> {
|
|
419
|
+
return [...this.connectionRuns.values()]
|
|
420
|
+
.filter(
|
|
421
|
+
(run) =>
|
|
422
|
+
run.projectId === input.projectId &&
|
|
423
|
+
run.connectorId === input.connectorId &&
|
|
424
|
+
(run.status === "running" ||
|
|
425
|
+
(run.status === "waiting" && run.waitingFor === "account_selection"))
|
|
426
|
+
)
|
|
427
|
+
.map((run) => structuredClone(run))
|
|
428
|
+
}
|
|
429
|
+
|
|
414
430
|
async getConnectionRun(
|
|
415
431
|
input: GetConnectorConnectionRunInput
|
|
416
432
|
): Promise<ConnectorConnectionRunRecord | null> {
|
|
@@ -853,7 +869,7 @@ export class InMemoryConnectorConnectionStorage implements ConnectorConnectionSt
|
|
|
853
869
|
input: PutConnectorConnectionInput,
|
|
854
870
|
now: Date
|
|
855
871
|
): PutConnectorConnectionResult {
|
|
856
|
-
|
|
872
|
+
const authorization = this.authorizations.get(input.authorizationId)
|
|
857
873
|
if (
|
|
858
874
|
!sameAuthorizationScope(authorization, input) ||
|
|
859
875
|
!isSelectable(authorization.status) ||
|
|
@@ -861,20 +877,6 @@ export class InMemoryConnectorConnectionStorage implements ConnectorConnectionSt
|
|
|
861
877
|
) {
|
|
862
878
|
throw authorizationConflict()
|
|
863
879
|
}
|
|
864
|
-
if (
|
|
865
|
-
authorization.status === "pending_selection" &&
|
|
866
|
-
authorization.selectionExpiresAt!.getTime() <= now.getTime()
|
|
867
|
-
) {
|
|
868
|
-
authorization = {
|
|
869
|
-
...authorization,
|
|
870
|
-
status: "revocation_pending",
|
|
871
|
-
selectionExpiresAt: undefined,
|
|
872
|
-
revision: authorization.revision + 1,
|
|
873
|
-
updatedAt: now,
|
|
874
|
-
}
|
|
875
|
-
this.authorizations.set(authorization.id, authorization)
|
|
876
|
-
throw authorizationConflict()
|
|
877
|
-
}
|
|
878
880
|
const account = authorization.accounts.find((candidate) => candidate.id === input.account.id)
|
|
879
881
|
if (!account) {
|
|
880
882
|
throw new ConnectorConnectionStorageError(
|
|
@@ -1076,6 +1078,7 @@ export class InMemoryConnectorConnectionStorage implements ConnectorConnectionSt
|
|
|
1076
1078
|
const run = this.connectionRuns.get(runId)
|
|
1077
1079
|
if (!run || (run.status !== "waiting" && run.status !== "running")) return run
|
|
1078
1080
|
|
|
1081
|
+
if (run.status === "waiting" && run.waitingFor === "account_selection") return run
|
|
1079
1082
|
const now = this.now()
|
|
1080
1083
|
if (run.expiresAt.getTime() > now.getTime()) return run
|
|
1081
1084
|
|
|
@@ -1084,9 +1087,6 @@ export class InMemoryConnectorConnectionStorage implements ConnectorConnectionSt
|
|
|
1084
1087
|
if (attempt) this.attempts.delete(attempt.id)
|
|
1085
1088
|
}
|
|
1086
1089
|
if (run.status === "waiting") {
|
|
1087
|
-
if (run.kind === "connect" && run.waitingFor === "account_selection") {
|
|
1088
|
-
this.markPendingAuthorizationForCleanup(run.connectorId, run.authorizationId, now)
|
|
1089
|
-
}
|
|
1090
1090
|
const expired = expireConnectionRun(run, now)
|
|
1091
1091
|
this.connectionRuns.set(run.id, expired)
|
|
1092
1092
|
return expired
|
|
@@ -165,7 +165,7 @@ export class DurableConnectorConnections extends ConnectorConnectionOperations {
|
|
|
165
165
|
input: PutConnectorConnectionInput,
|
|
166
166
|
now: Date
|
|
167
167
|
): Promise<PutConnectorConnectionResult | CommittedConnectorConnectionError> {
|
|
168
|
-
|
|
168
|
+
const authorization = await persistence.getAuthorization(input.authorizationId)
|
|
169
169
|
if (
|
|
170
170
|
!authorization ||
|
|
171
171
|
!isSelectable(authorization.status) ||
|
|
@@ -173,20 +173,6 @@ export class DurableConnectorConnections extends ConnectorConnectionOperations {
|
|
|
173
173
|
) {
|
|
174
174
|
throw authorizationConflict()
|
|
175
175
|
}
|
|
176
|
-
if (
|
|
177
|
-
authorization.status === "pending_selection" &&
|
|
178
|
-
authorization.selectionExpiresAt!.getTime() <= now.getTime()
|
|
179
|
-
) {
|
|
180
|
-
authorization = {
|
|
181
|
-
...authorization,
|
|
182
|
-
status: "revocation_pending",
|
|
183
|
-
selectionExpiresAt: undefined,
|
|
184
|
-
revision: authorization.revision + 1,
|
|
185
|
-
updatedAt: now,
|
|
186
|
-
}
|
|
187
|
-
await persistence.updateAuthorization(authorization)
|
|
188
|
-
return { error: authorizationConflict() }
|
|
189
|
-
}
|
|
190
176
|
const account = authorization.accounts.find((candidate) => candidate.id === input.account.id)
|
|
191
177
|
if (!account) {
|
|
192
178
|
throw new ConnectorConnectionStorageError(
|
|
@@ -63,7 +63,9 @@ export class DurableConnectorConnectionRuns extends ConnectorConnectionOperation
|
|
|
63
63
|
slot: input.slot,
|
|
64
64
|
initiatedByExecutionId: input.initiatedByExecutionId,
|
|
65
65
|
stateHash: input.stateHash,
|
|
66
|
-
|
|
66
|
+
...(input.codeVerifier === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { codeVerifier: structuredClone(input.codeVerifier) }),
|
|
67
69
|
redirectUri: input.redirectUri,
|
|
68
70
|
...(input.connectionRunId === undefined ? {} : { connectionRunId: input.connectionRunId }),
|
|
69
71
|
...(input.returnTo === undefined ? {} : { returnTo: input.returnTo }),
|
|
@@ -358,6 +360,12 @@ export class DurableConnectorConnectionRuns extends ConnectorConnectionOperation
|
|
|
358
360
|
})
|
|
359
361
|
}
|
|
360
362
|
|
|
363
|
+
listPendingConnectionRuns(
|
|
364
|
+
input: Parameters<ConnectorConnectionStorage["listPendingConnectionRuns"]>[0]
|
|
365
|
+
) {
|
|
366
|
+
return this.read(input, (persistence) => persistence.listPendingConnectionRuns())
|
|
367
|
+
}
|
|
368
|
+
|
|
361
369
|
getConnectionRun(
|
|
362
370
|
input: GetConnectorConnectionRunInput
|
|
363
371
|
): Promise<ConnectorConnectionRunRecord | null> {
|