@sixb/core 0.1.12 → 0.1.14
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.d.ts +2 -2
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +28 -26
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/read-facade.d.ts +14 -16
- package/dist/actions/read-facade.d.ts.map +1 -1
- package/dist/actions/request.d.ts.map +1 -1
- package/dist/actions/run-dispatch.d.ts +2 -0
- package/dist/actions/run-dispatch.d.ts.map +1 -1
- package/dist/actions/types/context.d.ts +18 -31
- package/dist/actions/types/context.d.ts.map +1 -1
- package/dist/actions/types/params.d.ts +2 -1
- package/dist/actions/types/params.d.ts.map +1 -1
- package/dist/actions/worker.js +1 -1
- package/dist/agents/index.js +41 -39
- 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/assert-never.d.ts +6 -0
- package/dist/assert-never.d.ts.map +1 -0
- package/dist/auth/client-address.d.ts +3 -0
- package/dist/auth/client-address.d.ts.map +1 -0
- package/dist/auth/csrf.d.ts +5 -1
- package/dist/auth/csrf.d.ts.map +1 -1
- package/dist/auth/errors.d.ts +12 -0
- package/dist/auth/errors.d.ts.map +1 -1
- package/dist/auth/index.d.ts +4 -3
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +16 -8
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/runtime.d.ts +58 -41
- package/dist/auth/runtime.d.ts.map +1 -1
- package/dist/auth/session-cache.d.ts +10 -3
- package/dist/auth/session-cache.d.ts.map +1 -1
- package/dist/auth/sessions.d.ts +12 -0
- package/dist/auth/sessions.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 +16 -15
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/authorization/index.js +3 -3
- package/dist/bootstrap/index.d.ts +1 -1
- package/dist/bootstrap/index.d.ts.map +1 -1
- package/dist/bootstrap/index.js +45 -43
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/bootstrap/ontology-type-manifest.d.ts +8 -0
- package/dist/bootstrap/ontology-type-manifest.d.ts.map +1 -1
- package/dist/{chunk-m7cx05vp.js → chunk-00pfcqh4.js} +126 -59
- package/dist/{chunk-m7cx05vp.js.map → chunk-00pfcqh4.js.map} +13 -12
- package/dist/{chunk-nzsy3xrp.js → chunk-16jenmzw.js} +69 -44
- package/dist/{chunk-nzsy3xrp.js.map → chunk-16jenmzw.js.map} +7 -7
- package/dist/{chunk-y3ev53cq.js → chunk-2fv8sajb.js} +2 -2
- package/dist/{chunk-q5gz3g2j.js → chunk-2jntasmh.js} +13 -16
- package/dist/{chunk-q5gz3g2j.js.map → chunk-2jntasmh.js.map} +3 -3
- package/dist/chunk-3a338wrp.js +191 -0
- package/dist/chunk-3a338wrp.js.map +11 -0
- package/dist/{chunk-ybhz3j9g.js → chunk-3fpgxpsq.js} +104 -148
- package/dist/{chunk-ybhz3j9g.js.map → chunk-3fpgxpsq.js.map} +7 -8
- package/dist/{chunk-eyjzgav0.js → chunk-3nx8vj5a.js} +6 -4
- package/dist/chunk-3nx8vj5a.js.map +12 -0
- package/dist/{chunk-5tetw4hn.js → chunk-4tnrzqqh.js} +1 -1
- package/dist/{chunk-3ghw2t5q.js → chunk-4ypbe95r.js} +10 -16
- package/dist/chunk-4ypbe95r.js.map +10 -0
- package/dist/{chunk-2cxv584m.js → chunk-6rzb1g6h.js} +358 -248
- package/dist/chunk-6rzb1g6h.js.map +44 -0
- package/dist/{chunk-7zgecwy1.js → chunk-6x0pqh32.js} +12 -1
- package/dist/{chunk-7zgecwy1.js.map → chunk-6x0pqh32.js.map} +3 -3
- package/dist/{chunk-6ma8dvzc.js → chunk-728fp090.js} +49 -42
- package/dist/chunk-728fp090.js.map +15 -0
- package/dist/chunk-96yw3pwd.js.map +2 -2
- package/dist/{chunk-4k53sm9e.js → chunk-a0073121.js} +59 -59
- package/dist/{chunk-4k53sm9e.js.map → chunk-a0073121.js.map} +5 -5
- package/dist/{chunk-y1ahv8b7.js → chunk-bdhfn0ww.js} +1 -1
- package/dist/{chunk-kept9cdd.js → chunk-bxx3ms5t.js} +1 -1
- package/dist/{chunk-xtfryrfb.js → chunk-cbn96bve.js} +2 -2
- package/dist/{chunk-vsg0g7h9.js → chunk-d8yes9yx.js} +304 -45
- package/dist/chunk-d8yes9yx.js.map +20 -0
- package/dist/{chunk-vpxss818.js → chunk-drz59ve0.js} +9 -8
- package/dist/chunk-drz59ve0.js.map +10 -0
- package/dist/{chunk-7c2g3sz9.js → chunk-dsfw1bdr.js} +5 -5
- package/dist/{chunk-7c2g3sz9.js.map → chunk-dsfw1bdr.js.map} +1 -1
- package/dist/{chunk-qm535afa.js → chunk-dv4ct8mp.js} +66 -24
- package/dist/chunk-dv4ct8mp.js.map +15 -0
- package/dist/{chunk-t7dzd1tm.js → chunk-e2c5yxfe.js} +2 -2
- package/dist/{chunk-p6r1ex7t.js → chunk-ffwvdgk1.js} +5 -13
- package/dist/chunk-ffwvdgk1.js.map +10 -0
- package/dist/{chunk-tg4g4zh0.js → chunk-gct3m1da.js} +9 -9
- package/dist/{chunk-tg4g4zh0.js.map → chunk-gct3m1da.js.map} +3 -3
- package/dist/chunk-h89wz928.js +42 -0
- package/dist/chunk-h89wz928.js.map +10 -0
- package/dist/{chunk-b768c93y.js → chunk-hj0n3c2p.js} +83 -28
- package/dist/{chunk-b768c93y.js.map → chunk-hj0n3c2p.js.map} +5 -5
- package/dist/{chunk-hkw8rykk.js → chunk-ht4a7mjg.js} +74 -4
- package/dist/chunk-ht4a7mjg.js.map +15 -0
- package/dist/{chunk-7qnvhtcd.js → chunk-hxgj4kzd.js} +17 -17
- package/dist/{chunk-7qnvhtcd.js.map → chunk-hxgj4kzd.js.map} +5 -5
- package/dist/{chunk-bg2bs62d.js → chunk-jfdggg1p.js} +5 -5
- package/dist/{chunk-f06sf7rr.js → chunk-k4kkp58d.js} +18 -5
- package/dist/chunk-k4kkp58d.js.map +11 -0
- package/dist/{chunk-e1f1sqba.js → chunk-kxea54yg.js} +3 -3
- package/dist/{chunk-2h63nrde.js → chunk-ky7zpbtt.js} +5 -7
- package/dist/{chunk-2h63nrde.js.map → chunk-ky7zpbtt.js.map} +3 -4
- package/dist/chunk-m4ehq95f.js +9 -0
- package/dist/chunk-m4ehq95f.js.map +10 -0
- package/dist/{chunk-0mza4xb2.js → chunk-m8zkvep1.js} +2 -2
- package/dist/{chunk-xn686q2e.js → chunk-ma1mhh7w.js} +75 -57
- package/dist/{chunk-xn686q2e.js.map → chunk-ma1mhh7w.js.map} +3 -3
- package/dist/{chunk-yxb4c62x.js → chunk-mr60an99.js} +3 -2
- package/dist/{chunk-yxb4c62x.js.map → chunk-mr60an99.js.map} +3 -3
- package/dist/{chunk-g50nxqs5.js → chunk-pvgpckm1.js} +63 -20
- package/dist/chunk-pvgpckm1.js.map +20 -0
- package/dist/{chunk-jjwhy3rs.js → chunk-q2xghyft.js} +5 -5
- package/dist/chunk-rdghfsss.js.map +2 -2
- package/dist/{chunk-bbaa1fet.js → chunk-rzcjp5m2.js} +7 -3
- package/dist/chunk-rzcjp5m2.js.map +25 -0
- package/dist/{chunk-hzw7yv5g.js → chunk-rzkr70gr.js} +5 -1
- package/dist/{chunk-hzw7yv5g.js.map → chunk-rzkr70gr.js.map} +3 -3
- package/dist/{chunk-axndsymr.js → chunk-tw03bsmb.js} +2 -2
- package/dist/{chunk-axndsymr.js.map → chunk-tw03bsmb.js.map} +3 -3
- package/dist/{chunk-y0v18c2j.js → chunk-vef6qa14.js} +2 -2
- package/dist/{chunk-gzt6v1ja.js → chunk-vn3yh259.js} +1 -1
- package/dist/{chunk-sfypc7mk.js → chunk-wn7mznxc.js} +4 -4
- package/dist/{chunk-r5zythxp.js → chunk-wnxabtn4.js} +7 -7
- package/dist/{chunk-4ph94nhd.js → chunk-ww185kt6.js} +2 -2
- package/dist/{chunk-3h7ctayx.js → chunk-xgptywp0.js} +4 -3
- package/dist/chunk-xgptywp0.js.map +11 -0
- package/dist/{chunk-gswwr35f.js → chunk-y487ywrv.js} +4 -4
- package/dist/{chunk-bet1rb9h.js → chunk-y6vnvayj.js} +1 -1
- package/dist/{chunk-x9tmx3fc.js → chunk-ypj2wqtj.js} +3 -6
- package/dist/{chunk-x9tmx3fc.js.map → chunk-ypj2wqtj.js.map} +4 -4
- package/dist/{chunk-3bnt2wna.js → chunk-yvf2jqj8.js} +1 -1
- package/dist/{chunk-g2gezsg5.js → chunk-z9h698s8.js} +1 -1
- package/dist/{chunk-wjffn5m4.js → chunk-zdkcdshk.js} +3 -36
- package/dist/{chunk-wjffn5m4.js.map → chunk-zdkcdshk.js.map} +3 -4
- package/dist/{chunk-bfjv1adk.js → chunk-znw0zvy4.js} +1 -1
- package/dist/edits/types.d.ts +19 -19
- package/dist/edits/types.d.ts.map +1 -1
- 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/envelope.d.ts +0 -12
- package/dist/events/envelope.d.ts.map +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +3 -3
- package/dist/events/service.d.ts +1 -2
- package/dist/events/service.d.ts.map +1 -1
- package/dist/events/toStoredEvent.d.ts +1 -2
- package/dist/events/toStoredEvent.d.ts.map +1 -1
- package/dist/events/types/index.d.ts +2 -1
- package/dist/events/types/index.d.ts.map +1 -1
- package/dist/execution/agent.d.ts +1 -2
- package/dist/execution/agent.d.ts.map +1 -1
- package/dist/execution/agent.js +39 -37
- package/dist/execution/agent.js.map +1 -1
- package/dist/execution/authorized-object-reader.d.ts.map +1 -1
- package/dist/execution/primitive.d.ts +1 -2
- package/dist/execution/primitive.d.ts.map +1 -1
- package/dist/execution/primitive.js +38 -36
- package/dist/execution/primitive.js.map +3 -3
- package/dist/execution/request.d.ts +1 -2
- package/dist/execution/request.d.ts.map +1 -1
- package/dist/execution/request.js +39 -37
- package/dist/execution/request.js.map +3 -3
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -50
- package/dist/index.js.map +1 -1
- package/dist/maintenance/ontology-maintenance.d.ts +11 -1
- package/dist/maintenance/ontology-maintenance.d.ts.map +1 -1
- package/dist/materialization/errors.d.ts +3 -1
- package/dist/materialization/errors.d.ts.map +1 -1
- package/dist/materialization/events.d.ts +27 -2
- package/dist/materialization/events.d.ts.map +1 -1
- package/dist/materializer/edits/commit.d.ts.map +1 -1
- package/dist/materializer/edits/operations.d.ts +2 -1
- package/dist/materializer/edits/operations.d.ts.map +1 -1
- package/dist/materializer/edits/plan.d.ts +2 -2
- package/dist/materializer/edits/plan.d.ts.map +1 -1
- package/dist/materializer/edits/user-refs.d.ts +30 -0
- package/dist/materializer/edits/user-refs.d.ts.map +1 -0
- package/dist/materializer/effective/build-events.d.ts +2 -2
- package/dist/materializer/effective/build-events.d.ts.map +1 -1
- package/dist/materializer/execution/scope.d.ts +11 -3
- package/dist/materializer/execution/scope.d.ts.map +1 -1
- package/dist/materializer/index.js +23 -21
- package/dist/materializer/index.js.map +1 -1
- package/dist/materializer/projections/replacement-plan.d.ts +2 -0
- package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
- package/dist/materializer/telemetry/plan.d.ts +2 -2
- package/dist/materializer/telemetry/plan.d.ts.map +1 -1
- package/dist/models/execution/index.js +23 -21
- package/dist/models/execution/index.js.map +1 -1
- package/dist/models/index.js +1 -1
- package/dist/objects/execution.d.ts +21 -27
- package/dist/objects/execution.d.ts.map +1 -1
- package/dist/objects/index.js +28 -26
- package/dist/objects/index.js.map +1 -1
- package/dist/objects/query/executor.d.ts.map +1 -1
- package/dist/objects/query/index.js +27 -25
- package/dist/objects/query/index.js.map +1 -1
- package/dist/objects/query/ir.d.ts +8 -1
- package/dist/objects/query/ir.d.ts.map +1 -1
- package/dist/objects/query/scalar-values.d.ts.map +1 -1
- package/dist/objects/query/validate.d.ts.map +1 -1
- package/dist/objects/sdk/object-handle.d.ts +1 -2
- package/dist/objects/sdk/object-handle.d.ts.map +1 -1
- package/dist/objects/sdk/object-set.d.ts +2 -3
- package/dist/objects/sdk/object-set.d.ts.map +1 -1
- package/dist/objects/sdk/query-builder.d.ts +8 -10
- package/dist/objects/sdk/query-builder.d.ts.map +1 -1
- package/dist/objects/sdk/telemetry-channel.d.ts +1 -2
- package/dist/objects/sdk/telemetry-channel.d.ts.map +1 -1
- package/dist/objects/sdk/where.d.ts +2 -3
- package/dist/objects/sdk/where.d.ts.map +1 -1
- package/dist/ontology/builders.d.ts +11 -10
- package/dist/ontology/builders.d.ts.map +1 -1
- package/dist/ontology/index.d.ts +4 -2
- package/dist/ontology/index.d.ts.map +1 -1
- package/dist/ontology/index.js +6 -4
- package/dist/ontology/index.js.map +1 -1
- package/dist/ontology/inference/index.d.ts +34 -22
- package/dist/ontology/inference/index.d.ts.map +1 -1
- package/dist/ontology/internal.d.ts +1 -0
- package/dist/ontology/internal.d.ts.map +1 -1
- package/dist/ontology/internal.js +9 -7
- package/dist/ontology/internal.js.map +1 -1
- package/dist/ontology/primitives.d.ts +38 -0
- package/dist/ontology/primitives.d.ts.map +1 -0
- package/dist/ontology/query-capabilities.d.ts +38 -0
- package/dist/ontology/query-capabilities.d.ts.map +1 -0
- package/dist/ontology/refs.d.ts +23 -2
- package/dist/ontology/refs.d.ts.map +1 -1
- package/dist/ontology/registered.d.ts +16 -0
- package/dist/ontology/registered.d.ts.map +1 -0
- package/dist/ontology/registry.d.ts.map +1 -1
- package/dist/ontology/tokens.d.ts +35 -1
- package/dist/ontology/tokens.d.ts.map +1 -1
- package/dist/ontology/types.d.ts +18 -4
- package/dist/ontology/types.d.ts.map +1 -1
- package/dist/ontology/user-ref.d.ts +35 -0
- package/dist/ontology/user-ref.d.ts.map +1 -0
- package/dist/ontology/validation/definition.d.ts.map +1 -1
- package/dist/ontology/validation/index.d.ts +1 -1
- package/dist/ontology/validation/index.d.ts.map +1 -1
- package/dist/ontology/validation/normalize.d.ts.map +1 -1
- package/dist/ontology/validation/properties.d.ts +6 -1
- package/dist/ontology/validation/properties.d.ts.map +1 -1
- package/dist/ontology/validation/query.d.ts.map +1 -1
- package/dist/ontology/validation/schema.d.ts.map +1 -1
- package/dist/pipelines/index.js +26 -24
- package/dist/pipelines/index.js.map +1 -1
- package/dist/predicates/types.d.ts +53 -3
- package/dist/predicates/types.d.ts.map +1 -1
- package/dist/projections/builders.d.ts +19 -1
- package/dist/projections/builders.d.ts.map +1 -1
- package/dist/projections/internal.js +23 -21
- package/dist/projections/internal.js.map +1 -1
- package/dist/projections/validation.d.ts.map +1 -1
- package/dist/query.js +2 -2
- package/dist/queues/in-memory.d.ts +1 -1
- package/dist/queues/in-memory.d.ts.map +1 -1
- package/dist/runtime/create.d.ts +1 -1
- package/dist/runtime/create.d.ts.map +1 -1
- package/dist/runtime/host.d.ts +5 -5
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/internal.js +27 -25
- package/dist/runtime/internal.js.map +1 -1
- package/dist/runtime/sixb.d.ts +5 -5
- package/dist/runtime/sixb.d.ts.map +1 -1
- package/dist/runtime/types.d.ts +171 -188
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/sandboxes/index.js +5 -5
- package/dist/sandboxes/sandbox.d.ts +4 -1
- package/dist/sandboxes/sandbox.d.ts.map +1 -1
- package/dist/shared/params/types.d.ts +4 -3
- package/dist/shared/params/types.d.ts.map +1 -1
- package/dist/shared/params/user-refs.d.ts +19 -0
- package/dist/shared/params/user-refs.d.ts.map +1 -0
- package/dist/shares/compiler.d.ts.map +1 -1
- package/dist/shares/internal.js +24 -22
- package/dist/shares/internal.js.map +2 -2
- package/dist/storage/action-runs/failure.js +2 -2
- package/dist/storage/action-runs/types.d.ts +1 -1
- package/dist/storage/action-runs/types.d.ts.map +1 -1
- package/dist/storage/agents/provider.js +1 -1
- 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/access-tokens.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/in-memory/device-authorizations.d.ts.map +1 -1
- package/dist/storage/auth/in-memory/sessions.d.ts +8 -1
- package/dist/storage/auth/in-memory/sessions.d.ts.map +1 -1
- package/dist/storage/auth/in-memory/shared.d.ts.map +1 -1
- package/dist/storage/auth/index.d.ts +1 -1
- package/dist/storage/auth/index.d.ts.map +1 -1
- package/dist/storage/auth/types.d.ts +77 -20
- package/dist/storage/auth/types.d.ts.map +1 -1
- package/dist/storage/connector-connections/provider.js +1 -1
- package/dist/storage/executions/provider.js +1 -1
- package/dist/storage/file-upload-sessions/in-memory.d.ts +9 -18
- package/dist/storage/file-upload-sessions/in-memory.d.ts.map +1 -1
- package/dist/storage/file-upload-sessions/index.d.ts +1 -1
- package/dist/storage/file-upload-sessions/index.d.ts.map +1 -1
- package/dist/storage/file-upload-sessions/provider.d.ts +52 -0
- package/dist/storage/file-upload-sessions/provider.d.ts.map +1 -0
- package/dist/storage/file-upload-sessions/provider.js +24 -0
- package/dist/storage/file-upload-sessions/provider.js.map +9 -0
- package/dist/storage/file-upload-sessions/types.d.ts +19 -1
- package/dist/storage/file-upload-sessions/types.d.ts.map +1 -1
- package/dist/storage/file-upload-sessions/utils.d.ts +8 -2
- package/dist/storage/file-upload-sessions/utils.d.ts.map +1 -1
- package/dist/storage/index.d.ts +3 -3
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +29 -25
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/internal.js +11 -9
- package/dist/storage/internal.js.map +1 -1
- package/dist/storage/objects/in-memory/query.d.ts.map +1 -1
- package/dist/storage/ontology/commits.d.ts +6 -2
- package/dist/storage/ontology/commits.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/provider-work.d.ts.map +1 -1
- package/dist/storage/ontology/provider.d.ts +14 -1
- package/dist/storage/ontology/provider.d.ts.map +1 -1
- package/dist/storage/ontology/provider.js +8 -2
- package/dist/storage/ontology/provider.js.map +1 -1
- package/dist/storage/operation-scope.d.ts.map +1 -1
- package/dist/storage/operation-scope.js +1 -1
- package/dist/storage/projection-runs/provider.js +2 -2
- package/dist/storage/types.d.ts +1 -1
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/workflow-interventions/index.d.ts +1 -1
- package/dist/storage/workflow-interventions/index.d.ts.map +1 -1
- package/dist/storage/workflow-interventions/types.d.ts +5 -8
- package/dist/storage/workflow-interventions/types.d.ts.map +1 -1
- package/dist/storage/workflow-runs/provider.js +8 -8
- package/dist/syncs/index.js +27 -25
- package/dist/syncs/index.js.map +1 -1
- package/dist/testing/action-execution.d.ts +4 -0
- package/dist/testing/action-execution.d.ts.map +1 -1
- package/dist/testing/auth-storage-contract.d.ts.map +1 -1
- package/dist/testing/execution.d.ts +1 -2
- package/dist/testing/execution.d.ts.map +1 -1
- package/dist/testing/file-upload-session-storage-contract.d.ts +12 -0
- package/dist/testing/file-upload-session-storage-contract.d.ts.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2035 -1358
- package/dist/testing/index.js.map +15 -13
- package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
- package/dist/testing/object-query-contract.d.ts.map +1 -1
- package/dist/testing/ontology-contract-fixture.d.ts +8 -0
- package/dist/testing/ontology-contract-fixture.d.ts.map +1 -1
- package/dist/testing/ontology-storage-contract.d.ts.map +1 -1
- package/dist/testing/sandboxes-contract.d.ts.map +1 -1
- package/dist/testing/workflow-intervention-storage-contract.d.ts +8 -0
- package/dist/testing/workflow-intervention-storage-contract.d.ts.map +1 -0
- package/dist/webhooks/internal.js +24 -22
- package/dist/webhooks/internal.js.map +2 -2
- package/dist/webhooks/types.d.ts +2 -2
- package/dist/webhooks/types.d.ts.map +1 -1
- package/dist/workers/index.js +1 -1
- package/dist/workflows/index.js +42 -40
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/run-dispatch.d.ts.map +1 -1
- package/dist/workflows/types.d.ts +2 -2
- package/dist/workflows/types.d.ts.map +1 -1
- package/package.json +7 -1
- package/src/actions/index.ts +0 -3
- package/src/actions/read-facade.ts +102 -62
- package/src/actions/request.ts +13 -0
- package/src/actions/run-dispatch.ts +3 -0
- package/src/actions/types/context.ts +17 -65
- package/src/actions/types/params.ts +2 -1
- package/src/agents/authority.ts +1 -1
- package/src/assert-never.ts +7 -0
- package/src/auth/client-address.ts +12 -0
- package/src/auth/csrf.ts +14 -5
- package/src/auth/errors.ts +23 -0
- package/src/auth/index.ts +4 -3
- package/src/auth/runtime.ts +353 -297
- package/src/auth/session-cache.ts +18 -6
- package/src/auth/sessions.ts +30 -0
- package/src/auth/strategy.ts +2 -0
- package/src/auth/types.ts +15 -17
- package/src/bootstrap/index.ts +1 -0
- package/src/bootstrap/ontology-type-manifest.ts +112 -60
- package/src/edits/types.ts +47 -63
- package/src/errors/catalog.ts +4 -0
- package/src/events/envelope.ts +0 -13
- package/src/events/index.ts +1 -1
- package/src/events/service.ts +1 -11
- package/src/events/toStoredEvent.ts +1 -3
- package/src/events/types/index.ts +1 -1
- package/src/execution/agent.ts +1 -2
- package/src/execution/authorized-object-reader.ts +5 -7
- package/src/execution/primitive.ts +1 -2
- package/src/execution/request.ts +1 -2
- package/src/index.ts +8 -7
- package/src/maintenance/ontology-maintenance.ts +77 -1
- package/src/materialization/errors.ts +2 -0
- package/src/materialization/events.ts +27 -2
- package/src/materializer/README.md +2 -0
- package/src/materializer/edits/commit.ts +21 -12
- package/src/materializer/edits/operations.ts +32 -4
- package/src/materializer/edits/plan.ts +4 -5
- package/src/materializer/edits/user-refs.ts +115 -0
- package/src/materializer/effective/build-events.ts +4 -5
- package/src/materializer/execution/scope.ts +40 -7
- package/src/materializer/projections/replace.ts +2 -0
- package/src/materializer/projections/replacement-plan.ts +4 -0
- package/src/materializer/telemetry/append.ts +4 -12
- package/src/materializer/telemetry/plan.ts +4 -5
- package/src/objects/execution.ts +33 -62
- package/src/objects/query/executor.ts +12 -3
- package/src/objects/query/ir.ts +7 -0
- package/src/objects/query/planner.ts +1 -0
- package/src/objects/query/scalar-values.ts +19 -0
- package/src/objects/query/validate.ts +55 -44
- package/src/objects/sdk/object-handle.ts +8 -8
- package/src/objects/sdk/object-set.ts +8 -15
- package/src/objects/sdk/query-builder.ts +59 -71
- package/src/objects/sdk/telemetry-channel.ts +6 -7
- package/src/objects/sdk/where.ts +6 -13
- package/src/ontology/builders.ts +15 -11
- package/src/ontology/index.ts +4 -0
- package/src/ontology/inference/index.ts +56 -36
- package/src/ontology/internal.ts +1 -0
- package/src/ontology/json-schema.ts +12 -0
- package/src/ontology/primitives.ts +91 -0
- package/src/ontology/query-capabilities.ts +136 -0
- package/src/ontology/refs.ts +33 -6
- package/src/ontology/registered.ts +22 -0
- package/src/ontology/registry.ts +6 -3
- package/src/ontology/tokens.ts +41 -2
- package/src/ontology/types.ts +19 -3
- package/src/ontology/user-ref.ts +120 -0
- package/src/ontology/validation/definition.ts +2 -13
- package/src/ontology/validation/index.ts +1 -0
- package/src/ontology/validation/normalize.ts +39 -3
- package/src/ontology/validation/properties.ts +95 -19
- package/src/ontology/validation/query.ts +11 -42
- package/src/ontology/validation/schema.ts +16 -0
- package/src/predicates/types.ts +43 -33
- package/src/projections/builders.ts +24 -3
- package/src/projections/validation.ts +15 -1
- package/src/runtime/create.ts +2 -2
- package/src/runtime/host.ts +10 -12
- package/src/runtime/index.ts +3 -2
- package/src/runtime/sixb.ts +13 -23
- package/src/runtime/types.ts +277 -479
- package/src/sandboxes/sandbox.ts +4 -1
- package/src/shared/params/types.ts +4 -3
- package/src/shared/params/user-refs.ts +48 -0
- package/src/shares/compiler.ts +6 -16
- package/src/storage/action-runs/types.ts +1 -0
- package/src/storage/auth/errors.ts +0 -1
- package/src/storage/auth/in-memory/access-tokens.ts +5 -2
- package/src/storage/auth/in-memory/auth-storage.ts +49 -73
- package/src/storage/auth/in-memory/device-authorizations.ts +0 -2
- package/src/storage/auth/in-memory/sessions.ts +69 -1
- package/src/storage/auth/in-memory/shared.ts +13 -7
- package/src/storage/auth/index.ts +2 -1
- package/src/storage/auth/types.ts +72 -20
- package/src/storage/executions/validation.ts +1 -1
- package/src/storage/file-upload-sessions/in-memory.ts +64 -113
- package/src/storage/file-upload-sessions/index.ts +1 -0
- package/src/storage/file-upload-sessions/provider.ts +258 -0
- package/src/storage/file-upload-sessions/types.ts +20 -1
- package/src/storage/file-upload-sessions/utils.ts +25 -9
- package/src/storage/index.ts +3 -2
- package/src/storage/objects/in-memory/query.ts +13 -3
- package/src/storage/ontology/commits.ts +6 -2
- package/src/storage/ontology/in-memory/materializations.ts +6 -34
- package/src/storage/ontology/provider-header-validation.ts +57 -0
- package/src/storage/ontology/provider-work.ts +15 -3
- package/src/storage/ontology/provider.ts +59 -1
- package/src/storage/operation-scope.ts +1 -0
- package/src/storage/types.ts +0 -1
- package/src/storage/workflow-interventions/index.ts +0 -1
- package/src/storage/workflow-interventions/types.ts +5 -9
- package/src/testing/action-execution.ts +13 -3
- package/src/testing/auth-storage-contract.ts +253 -192
- package/src/testing/execution-storage-contract.ts +1 -2
- package/src/testing/execution.ts +4 -7
- package/src/testing/file-upload-session-storage-contract.ts +335 -0
- package/src/testing/index.ts +8 -0
- package/src/testing/materializer-storage-contract.ts +86 -4
- package/src/testing/object-query-contract.ts +121 -2
- package/src/testing/ontology-contract-fixture.ts +23 -3
- package/src/testing/ontology-storage-contract.ts +58 -0
- package/src/testing/sandboxes-contract.ts +27 -0
- package/src/testing/workflow-intervention-storage-contract.ts +203 -0
- package/src/webhooks/types.ts +2 -2
- package/src/workflows/run-dispatch.ts +12 -1
- package/src/workflows/snapshot.ts +16 -7
- package/src/workflows/types.ts +2 -2
- package/dist/chunk-2cxv584m.js.map +0 -43
- package/dist/chunk-3ghw2t5q.js.map +0 -10
- package/dist/chunk-3h7ctayx.js.map +0 -11
- package/dist/chunk-6ma8dvzc.js.map +0 -15
- package/dist/chunk-bbaa1fet.js.map +0 -25
- package/dist/chunk-eyjzgav0.js.map +0 -12
- package/dist/chunk-f06sf7rr.js.map +0 -11
- package/dist/chunk-g50nxqs5.js.map +0 -18
- package/dist/chunk-hkw8rykk.js.map +0 -15
- package/dist/chunk-p6r1ex7t.js.map +0 -10
- package/dist/chunk-qm535afa.js.map +0 -15
- package/dist/chunk-vpxss818.js.map +0 -10
- package/dist/chunk-vsg0g7h9.js.map +0 -17
- /package/dist/{chunk-y3ev53cq.js.map → chunk-2fv8sajb.js.map} +0 -0
- /package/dist/{chunk-5tetw4hn.js.map → chunk-4tnrzqqh.js.map} +0 -0
- /package/dist/{chunk-y1ahv8b7.js.map → chunk-bdhfn0ww.js.map} +0 -0
- /package/dist/{chunk-kept9cdd.js.map → chunk-bxx3ms5t.js.map} +0 -0
- /package/dist/{chunk-xtfryrfb.js.map → chunk-cbn96bve.js.map} +0 -0
- /package/dist/{chunk-t7dzd1tm.js.map → chunk-e2c5yxfe.js.map} +0 -0
- /package/dist/{chunk-bg2bs62d.js.map → chunk-jfdggg1p.js.map} +0 -0
- /package/dist/{chunk-e1f1sqba.js.map → chunk-kxea54yg.js.map} +0 -0
- /package/dist/{chunk-0mza4xb2.js.map → chunk-m8zkvep1.js.map} +0 -0
- /package/dist/{chunk-jjwhy3rs.js.map → chunk-q2xghyft.js.map} +0 -0
- /package/dist/{chunk-y0v18c2j.js.map → chunk-vef6qa14.js.map} +0 -0
- /package/dist/{chunk-gzt6v1ja.js.map → chunk-vn3yh259.js.map} +0 -0
- /package/dist/{chunk-sfypc7mk.js.map → chunk-wn7mznxc.js.map} +0 -0
- /package/dist/{chunk-r5zythxp.js.map → chunk-wnxabtn4.js.map} +0 -0
- /package/dist/{chunk-4ph94nhd.js.map → chunk-ww185kt6.js.map} +0 -0
- /package/dist/{chunk-gswwr35f.js.map → chunk-y487ywrv.js.map} +0 -0
- /package/dist/{chunk-bet1rb9h.js.map → chunk-y6vnvayj.js.map} +0 -0
- /package/dist/{chunk-3bnt2wna.js.map → chunk-yvf2jqj8.js.map} +0 -0
- /package/dist/{chunk-g2gezsg5.js.map → chunk-z9h698s8.js.map} +0 -0
- /package/dist/{chunk-bfjv1adk.js.map → chunk-znw0zvy4.js.map} +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { type Principal, principalsEqual } from "../../auth"
|
|
2
|
+
import type { FileRef, SignedBlobUploadPart } from "../../blob-storage"
|
|
3
|
+
import { FileUploadSessionError } from "./errors"
|
|
4
|
+
import type {
|
|
5
|
+
CreateFileUploadSessionInput,
|
|
6
|
+
FileUploadSession,
|
|
7
|
+
FileUploadSessionStore,
|
|
8
|
+
FileUploadStatus,
|
|
9
|
+
FileUploadStrategy,
|
|
10
|
+
ListAbandonedFileUploadSessionsInput,
|
|
11
|
+
} from "./types"
|
|
12
|
+
import {
|
|
13
|
+
createFileUploadId,
|
|
14
|
+
isFileUploadSessionExpired,
|
|
15
|
+
isTerminalFileUploadSessionExpired,
|
|
16
|
+
} from "./utils"
|
|
17
|
+
|
|
18
|
+
export { fileUploadSessionReapAt } from "./utils"
|
|
19
|
+
|
|
20
|
+
/** Database-specific row access used by the shared upload session state machine. */
|
|
21
|
+
export interface FileUploadSessionPersistence {
|
|
22
|
+
now(): Promise<Date>
|
|
23
|
+
/** Returns false when the id already exists. */
|
|
24
|
+
insert(session: FileUploadSession): Promise<boolean>
|
|
25
|
+
/** Inside `transaction`, must lock the row until the transaction ends. */
|
|
26
|
+
get(uploadId: string): Promise<FileUploadSession | null>
|
|
27
|
+
update(session: FileUploadSession): Promise<void>
|
|
28
|
+
/** The project's `pending` rows holding a provider upload, `expires_at <= now`, oldest first. */
|
|
29
|
+
listAbandoned(input: ListAbandonedFileUploadSessionsInput): Promise<readonly FileUploadSession[]>
|
|
30
|
+
/** Deletes rows whose persisted `fileUploadSessionReapAt` is `<= now`. */
|
|
31
|
+
deleteReapable(now: Date): Promise<number>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Transaction and lock boundary supplied by a concrete durable storage provider. */
|
|
35
|
+
export interface FileUploadSessionPersistenceBackend {
|
|
36
|
+
read<T>(run: (persistence: FileUploadSessionPersistence) => Promise<T>): Promise<T>
|
|
37
|
+
transaction<T>(run: (persistence: FileUploadSessionPersistence) => Promise<T>): Promise<T>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Shared durable implementation of the upload session lifecycle. Concrete providers own SQL,
|
|
42
|
+
* transactions and database time; every transition and retention rule lives here so SQLite,
|
|
43
|
+
* PostgreSQL and the in-memory reference cannot drift semantically.
|
|
44
|
+
*
|
|
45
|
+
* Every method is `async`: a storage's operation-scoped facade serializes only async methods, and
|
|
46
|
+
* a plain Promise-returning method would bypass it and join whatever SQLite transaction is open.
|
|
47
|
+
*/
|
|
48
|
+
export class DurableFileUploadSessions implements FileUploadSessionStore {
|
|
49
|
+
constructor(private readonly backend: FileUploadSessionPersistenceBackend) {}
|
|
50
|
+
|
|
51
|
+
async create(input: CreateFileUploadSessionInput): Promise<FileUploadSession> {
|
|
52
|
+
return this.backend.transaction(async (persistence) => {
|
|
53
|
+
const session: FileUploadSession = {
|
|
54
|
+
id: input.id ?? createFileUploadId(),
|
|
55
|
+
projectId: input.projectId,
|
|
56
|
+
principal: input.principal,
|
|
57
|
+
strategy: input.strategy,
|
|
58
|
+
status: "pending",
|
|
59
|
+
...(input.fileName === undefined ? {} : { fileName: input.fileName }),
|
|
60
|
+
...(input.mediaType === undefined ? {} : { mediaType: input.mediaType }),
|
|
61
|
+
...(input.logicalPath === undefined ? {} : { logicalPath: input.logicalPath }),
|
|
62
|
+
...(input.expectedSizeBytes === undefined
|
|
63
|
+
? {}
|
|
64
|
+
: { expectedSizeBytes: input.expectedSizeBytes }),
|
|
65
|
+
...(input.expectedDigest === undefined ? {} : { expectedDigest: input.expectedDigest }),
|
|
66
|
+
...(input.providerUpload === undefined ? {} : { providerUpload: input.providerUpload }),
|
|
67
|
+
signedParts: [],
|
|
68
|
+
createdAt: await persistence.now(),
|
|
69
|
+
expiresAt: input.expiresAt,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!(await persistence.insert(session))) {
|
|
73
|
+
throw new Error(`[Sixb] File upload session '${session.id}' already exists.`)
|
|
74
|
+
}
|
|
75
|
+
return session
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getForPrincipal(uploadId: string, principal: Principal): Promise<FileUploadSession> {
|
|
80
|
+
return this.backend.read(async (persistence) => {
|
|
81
|
+
const session = await persistence.get(uploadId)
|
|
82
|
+
if (!session || !principalsEqual(session.principal, principal)) {
|
|
83
|
+
throw new FileUploadSessionError("not_found", "File upload session not found.")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const nowMs = (await persistence.now()).getTime()
|
|
87
|
+
if (isFileUploadSessionExpired(session, nowMs)) {
|
|
88
|
+
throw new FileUploadSessionError("expired", "File upload session has expired.")
|
|
89
|
+
}
|
|
90
|
+
if (isTerminalFileUploadSessionExpired(session, nowMs)) {
|
|
91
|
+
throw new FileUploadSessionError("not_found", "File upload session not found.")
|
|
92
|
+
}
|
|
93
|
+
return session
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async markUploaded(uploadId: string, fileRef: FileRef): Promise<FileUploadSession> {
|
|
98
|
+
return this.transition(uploadId, (session) => ({ ...session, fileRef }))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async addSignedPart(uploadId: string, part: SignedBlobUploadPart): Promise<FileUploadSession> {
|
|
102
|
+
return this.transition(uploadId, (session) => ({
|
|
103
|
+
...session,
|
|
104
|
+
signedParts: [
|
|
105
|
+
...session.signedParts.filter((candidate) => candidate.partNumber !== part.partNumber),
|
|
106
|
+
part,
|
|
107
|
+
].sort((left, right) => left.partNumber - right.partNumber),
|
|
108
|
+
}))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async complete(uploadId: string, fileRef: FileRef): Promise<FileUploadSession> {
|
|
112
|
+
return this.transition(uploadId, (session, now) => ({
|
|
113
|
+
...session,
|
|
114
|
+
status: "completed",
|
|
115
|
+
fileRef,
|
|
116
|
+
completedAt: now,
|
|
117
|
+
}))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async abort(uploadId: string): Promise<FileUploadSession> {
|
|
121
|
+
return this.transition(uploadId, (session, now) => ({
|
|
122
|
+
...session,
|
|
123
|
+
status: "aborted",
|
|
124
|
+
abortedAt: now,
|
|
125
|
+
}))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async listAbandoned(
|
|
129
|
+
input: ListAbandonedFileUploadSessionsInput
|
|
130
|
+
): Promise<readonly FileUploadSession[]> {
|
|
131
|
+
if (input.projectId.trim().length === 0) {
|
|
132
|
+
throw new Error("[Sixb] File upload session listAbandoned projectId must not be blank.")
|
|
133
|
+
}
|
|
134
|
+
if (!Number.isSafeInteger(input.limit) || input.limit <= 0) {
|
|
135
|
+
throw new Error("[Sixb] File upload session listAbandoned limit must be a positive integer.")
|
|
136
|
+
}
|
|
137
|
+
return this.backend.read((persistence) => persistence.listAbandoned(input))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async cleanupExpired(now?: Date): Promise<number> {
|
|
141
|
+
return this.backend.transaction(async (persistence) =>
|
|
142
|
+
persistence.deleteReapable(now ?? (await persistence.now()))
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private transition(
|
|
147
|
+
uploadId: string,
|
|
148
|
+
next: (session: FileUploadSession, now: Date) => FileUploadSession
|
|
149
|
+
): Promise<FileUploadSession> {
|
|
150
|
+
return this.backend.transaction(async (persistence) => {
|
|
151
|
+
const session = await persistence.get(uploadId)
|
|
152
|
+
if (!session) {
|
|
153
|
+
throw new FileUploadSessionError("not_found", "File upload session not found.")
|
|
154
|
+
}
|
|
155
|
+
if (session.status !== "pending") {
|
|
156
|
+
throw new FileUploadSessionError(
|
|
157
|
+
session.status === "completed" ? "already_completed" : "already_aborted",
|
|
158
|
+
`File upload session is already ${session.status}.`
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const updated = next(session, await persistence.now())
|
|
163
|
+
await persistence.update(updated)
|
|
164
|
+
return updated
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const STRATEGIES: readonly FileUploadStrategy[] = ["server", "direct-put", "multipart"]
|
|
170
|
+
const STATUSES: readonly FileUploadStatus[] = ["pending", "completed", "aborted"]
|
|
171
|
+
const PRINCIPAL_TYPES: readonly Principal["type"][] = ["user", "serviceAccount", "system"]
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Rebuilds a session from a provider row. JSON columns may arrive parsed (jsonb) or as text
|
|
175
|
+
* (SQLite); nested `expiresAt` values are revived and every other nested field passes through,
|
|
176
|
+
* so blob providers can extend `providerUpload` without a migration. Fails closed on corruption.
|
|
177
|
+
*/
|
|
178
|
+
export function parseFileUploadSessionRow(row: {
|
|
179
|
+
readonly [column: string]: unknown
|
|
180
|
+
}): FileUploadSession {
|
|
181
|
+
const id = text(row.id, "id", String(row.id))
|
|
182
|
+
const strategy = text(row.strategy, "strategy", id) as FileUploadStrategy
|
|
183
|
+
const status = text(row.status, "status", id) as FileUploadStatus
|
|
184
|
+
if (!STRATEGIES.includes(strategy)) throw corrupt(id, `unknown strategy '${strategy}'`)
|
|
185
|
+
if (!STATUSES.includes(status)) throw corrupt(id, `unknown status '${status}'`)
|
|
186
|
+
const principalType = text(row.ownerPrincipalType, "ownerPrincipalType", id)
|
|
187
|
+
if (!PRINCIPAL_TYPES.includes(principalType as Principal["type"])) {
|
|
188
|
+
throw corrupt(id, `unknown owner principal type '${principalType}'`)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const providerUpload = json(row.providerUpload)
|
|
192
|
+
const fileRef = json(row.fileRef)
|
|
193
|
+
const signedParts = json(row.signedParts)
|
|
194
|
+
if (!Array.isArray(signedParts)) throw corrupt(id, "signedParts is not an array")
|
|
195
|
+
|
|
196
|
+
const optional = <T>(key: string, value: T | null | undefined) =>
|
|
197
|
+
value === null || value === undefined ? {} : { [key]: value }
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
id,
|
|
201
|
+
projectId: text(row.projectId, "projectId", id),
|
|
202
|
+
principal: {
|
|
203
|
+
type: principalType as Principal["type"],
|
|
204
|
+
id: text(row.ownerPrincipalId, "ownerPrincipalId", id),
|
|
205
|
+
},
|
|
206
|
+
strategy,
|
|
207
|
+
status,
|
|
208
|
+
...optional("fileName", row.fileName as string | null),
|
|
209
|
+
...optional("mediaType", row.mediaType as string | null),
|
|
210
|
+
...optional("logicalPath", row.logicalPath as string | null),
|
|
211
|
+
...optional(
|
|
212
|
+
"expectedSizeBytes",
|
|
213
|
+
row.expectedSizeBytes === null || row.expectedSizeBytes === undefined
|
|
214
|
+
? null
|
|
215
|
+
: Number(row.expectedSizeBytes)
|
|
216
|
+
),
|
|
217
|
+
...optional("expectedDigest", row.expectedDigest as string | null),
|
|
218
|
+
...optional(
|
|
219
|
+
"providerUpload",
|
|
220
|
+
providerUpload === null ? null : withExpiresAt(providerUpload, id)
|
|
221
|
+
),
|
|
222
|
+
signedParts: signedParts.map((part) => withExpiresAt(part, id)) as SignedBlobUploadPart[],
|
|
223
|
+
...optional("fileRef", fileRef as FileRef | null),
|
|
224
|
+
createdAt: date(row.createdAt, "createdAt", id),
|
|
225
|
+
expiresAt: date(row.expiresAt, "expiresAt", id),
|
|
226
|
+
...optional(
|
|
227
|
+
"completedAt",
|
|
228
|
+
row.completedAt == null ? null : date(row.completedAt, "completedAt", id)
|
|
229
|
+
),
|
|
230
|
+
...optional("abortedAt", row.abortedAt == null ? null : date(row.abortedAt, "abortedAt", id)),
|
|
231
|
+
} as FileUploadSession
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function json(value: unknown): unknown {
|
|
235
|
+
return typeof value === "string" ? JSON.parse(value) : (value ?? null)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function withExpiresAt<T>(value: unknown, id: string): T {
|
|
239
|
+
if (typeof value !== "object" || value === null)
|
|
240
|
+
throw corrupt(id, "nested record is not an object")
|
|
241
|
+
const record = value as Record<string, unknown>
|
|
242
|
+
return { ...record, expiresAt: date(record.expiresAt, "nested expiresAt", id) } as T
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function text(value: unknown, column: string, id: string): string {
|
|
246
|
+
if (typeof value !== "string" || value.length === 0) throw corrupt(id, `${column} is not text`)
|
|
247
|
+
return value
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function date(value: unknown, column: string, id: string): Date {
|
|
251
|
+
const parsed = value instanceof Date || typeof value === "string" ? new Date(value) : null
|
|
252
|
+
if (!parsed || !Number.isFinite(parsed.getTime())) throw corrupt(id, `${column} is not a date`)
|
|
253
|
+
return parsed
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function corrupt(id: string, reason: string): Error {
|
|
257
|
+
return new Error(`[Sixb] Stored file upload session '${id}' is invalid: ${reason}.`)
|
|
258
|
+
}
|
|
@@ -26,7 +26,7 @@ export interface CreateFileUploadSessionInput {
|
|
|
26
26
|
export interface FileUploadSession {
|
|
27
27
|
readonly id: string
|
|
28
28
|
readonly projectId: string
|
|
29
|
-
readonly
|
|
29
|
+
readonly principal: Principal
|
|
30
30
|
readonly strategy: FileUploadStrategy
|
|
31
31
|
readonly status: FileUploadStatus
|
|
32
32
|
readonly fileName?: string
|
|
@@ -43,19 +43,38 @@ export interface FileUploadSession {
|
|
|
43
43
|
readonly abortedAt?: Date
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
export interface ListAbandonedFileUploadSessionsInput {
|
|
47
|
+
readonly projectId: string
|
|
48
|
+
readonly now: Date
|
|
49
|
+
readonly limit: number
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
/**
|
|
47
53
|
* State machine for a staged/direct-put upload session. A session is created
|
|
48
54
|
* `pending`; `markUploaded` records the resolved {@link FileRef} but keeps the
|
|
49
55
|
* session `pending` (non-terminal), while `complete` and `abort` move it to a
|
|
50
56
|
* terminal `completed`/`aborted` state. Terminal sessions are retained briefly
|
|
51
57
|
* (for idempotent retries) then reaped by `cleanupExpired`.
|
|
58
|
+
*
|
|
59
|
+
* An expired `pending` session that still holds a `providerUpload` is abandoned:
|
|
60
|
+
* the provider may be billing for parts only `abortUpload` can release. The store
|
|
61
|
+
* never deletes one. A sweep lists them with `listAbandoned`, aborts the provider
|
|
62
|
+
* upload, then calls `abort` so the row becomes terminal and is reaped normally.
|
|
52
63
|
*/
|
|
53
64
|
export interface FileUploadSessionStore {
|
|
54
65
|
create(input: CreateFileUploadSessionInput): Promise<FileUploadSession>
|
|
66
|
+
/**
|
|
67
|
+
* The expiry gate: throws `expired` or `not_found`, and never deletes. Callers check expiry
|
|
68
|
+
* here when a request starts; the transitions below do not re-check it, because a request
|
|
69
|
+
* that passed the gate may finish slow blob I/O after `expiresAt`.
|
|
70
|
+
*/
|
|
55
71
|
getForPrincipal(uploadId: string, principal: Principal): Promise<FileUploadSession>
|
|
56
72
|
markUploaded(uploadId: string, fileRef: FileRef): Promise<FileUploadSession>
|
|
57
73
|
addSignedPart(uploadId: string, part: SignedBlobUploadPart): Promise<FileUploadSession>
|
|
58
74
|
complete(uploadId: string, fileRef: FileRef): Promise<FileUploadSession>
|
|
59
75
|
abort(uploadId: string): Promise<FileUploadSession>
|
|
76
|
+
/** One project's abandoned sessions expired at or before `now`, oldest expiry first. */
|
|
77
|
+
listAbandoned(input: ListAbandonedFileUploadSessionsInput): Promise<readonly FileUploadSession[]>
|
|
78
|
+
/** Deletes reapable sessions and returns the count. Never deletes an abandoned session. */
|
|
60
79
|
cleanupExpired(now?: Date): Promise<number>
|
|
61
80
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto"
|
|
2
|
-
import type { Principal } from "../../auth"
|
|
3
2
|
import type { FileUploadSession } from "./types"
|
|
4
3
|
|
|
5
4
|
export const DEFAULT_FILE_UPLOAD_SESSION_TTL_MS = 60 * 60 * 1000
|
|
@@ -13,10 +12,6 @@ export function createFileUploadId(): string {
|
|
|
13
12
|
return `upload_${randomUUID().replaceAll("-", "")}`
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
export function principalKey(principal: Principal): string {
|
|
17
|
-
return `${principal.type}:${principal.id}`
|
|
18
|
-
}
|
|
19
|
-
|
|
20
15
|
export function isFileUploadSessionExpired(
|
|
21
16
|
session: FileUploadSession,
|
|
22
17
|
nowMs = Date.now()
|
|
@@ -24,12 +19,33 @@ export function isFileUploadSessionExpired(
|
|
|
24
19
|
return session.status === "pending" && session.expiresAt.getTime() <= nowMs
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
/** Expired, still `pending`, and holding a provider upload only `abortUpload` can release. */
|
|
23
|
+
export function isAbandonedFileUploadSession(
|
|
24
|
+
session: FileUploadSession,
|
|
25
|
+
nowMs = Date.now()
|
|
26
|
+
): boolean {
|
|
27
|
+
return session.providerUpload !== undefined && isFileUploadSessionExpired(session, nowMs)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* When a session may be deleted, or null when only a state change can make it deletable.
|
|
32
|
+
* This is the single retention rule: durable providers persist it as `reap_at` and delete
|
|
33
|
+
* `reap_at <= now`, so SQL never restates it.
|
|
34
|
+
*/
|
|
35
|
+
export function fileUploadSessionReapAt(session: FileUploadSession): Date | null {
|
|
36
|
+
if (session.status === "pending") {
|
|
37
|
+
return session.providerUpload === undefined ? session.expiresAt : null
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
|
|
40
|
+
const terminalAt = session.completedAt ?? session.abortedAt
|
|
41
|
+
return terminalAt
|
|
42
|
+
? new Date(terminalAt.getTime() + DEFAULT_FILE_UPLOAD_TERMINAL_SESSION_TTL_MS)
|
|
43
|
+
: null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function shouldDeleteFileUploadSession(session: FileUploadSession, nowMs: number): boolean {
|
|
47
|
+
const reapAt = fileUploadSessionReapAt(session)
|
|
48
|
+
return reapAt !== null && reapAt.getTime() <= nowMs
|
|
33
49
|
}
|
|
34
50
|
|
|
35
51
|
export function isTerminalFileUploadSessionExpired(
|
package/src/storage/index.ts
CHANGED
|
@@ -199,7 +199,6 @@ export type {
|
|
|
199
199
|
export { AiUsageStorageError, aggregateAiModelCallUsage, InMemoryAiUsageStorage } from "./ai-usage"
|
|
200
200
|
export type {
|
|
201
201
|
AccessTokenRecord,
|
|
202
|
-
AccessTokenSubjectType,
|
|
203
202
|
AuthAccessTokenStore,
|
|
204
203
|
AuthDeviceAuthorizationStore,
|
|
205
204
|
AuthGroupMembershipStore,
|
|
@@ -213,6 +212,7 @@ export type {
|
|
|
213
212
|
AuthStorageErrorCode,
|
|
214
213
|
AuthUserIdentityStore,
|
|
215
214
|
AuthUserStore,
|
|
215
|
+
BearerSessionState,
|
|
216
216
|
CompleteAuthSessionInput,
|
|
217
217
|
CompleteDeviceAuthorizationInput,
|
|
218
218
|
CompleteDeviceAuthorizationResult,
|
|
@@ -244,6 +244,7 @@ export type {
|
|
|
244
244
|
MagicLinkRecord,
|
|
245
245
|
OidcAuthorizationAttemptRecord,
|
|
246
246
|
ReconcileAuthServiceAccountGroupMembershipsInput,
|
|
247
|
+
RotateSessionRefreshTokenResult,
|
|
247
248
|
ServiceAccountGroupMembershipRecord,
|
|
248
249
|
ServiceAccountRecord,
|
|
249
250
|
ServiceAccountStatus,
|
|
@@ -357,6 +358,7 @@ export type {
|
|
|
357
358
|
FileUploadSessionStore,
|
|
358
359
|
FileUploadStatus,
|
|
359
360
|
FileUploadStrategy,
|
|
361
|
+
ListAbandonedFileUploadSessionsInput,
|
|
360
362
|
} from "./file-upload-sessions"
|
|
361
363
|
export {
|
|
362
364
|
DEFAULT_FILE_UPLOAD_SESSION_TTL_MS,
|
|
@@ -710,7 +712,6 @@ export type {
|
|
|
710
712
|
ListWorkflowInterventionsInput,
|
|
711
713
|
ListWorkflowInterventionsResult,
|
|
712
714
|
SubmitWorkflowInterventionInput,
|
|
713
|
-
WorkflowInterventionActor,
|
|
714
715
|
WorkflowInterventionRecord,
|
|
715
716
|
WorkflowInterventionStatus,
|
|
716
717
|
WorkflowInterventionStorage,
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
ObjectQuery,
|
|
3
3
|
ObjectQueryPredicate,
|
|
4
4
|
ObjectQuerySortField,
|
|
5
|
+
QueryScalarKind,
|
|
5
6
|
} from "../../../objects/query"
|
|
6
7
|
import {
|
|
7
8
|
compareQueryScalarValues,
|
|
@@ -82,6 +83,7 @@ export const IN_MEMORY_OBJECT_QUERY_CAPABILITIES: ObjectQueryCapabilities = {
|
|
|
82
83
|
decimal: { equality: true, ordering: true },
|
|
83
84
|
date: { equality: true, ordering: true },
|
|
84
85
|
timestamp: { equality: true, ordering: true },
|
|
86
|
+
userRef: { equality: true },
|
|
85
87
|
},
|
|
86
88
|
limits: {
|
|
87
89
|
totalCount: true,
|
|
@@ -423,17 +425,25 @@ function matchesPredicate(row: ObjectRow, predicate: ObjectQueryPredicate): bool
|
|
|
423
425
|
return predicate.value ? exists : !exists
|
|
424
426
|
}
|
|
425
427
|
case "contains":
|
|
426
|
-
return containsValue(
|
|
428
|
+
return containsValue(
|
|
429
|
+
row.properties[predicate.propertyId],
|
|
430
|
+
predicate.value,
|
|
431
|
+
predicate.scalarKind
|
|
432
|
+
)
|
|
427
433
|
}
|
|
428
434
|
}
|
|
429
435
|
|
|
430
|
-
function containsValue(
|
|
436
|
+
function containsValue(
|
|
437
|
+
actual: unknown,
|
|
438
|
+
expected: unknown,
|
|
439
|
+
itemScalarKind: QueryScalarKind | undefined
|
|
440
|
+
): boolean {
|
|
431
441
|
if (typeof actual === "string" && typeof expected === "string") {
|
|
432
442
|
return actual.includes(expected)
|
|
433
443
|
}
|
|
434
444
|
|
|
435
445
|
if (Array.isArray(actual)) {
|
|
436
|
-
return actual.some((item) => queryScalarValuesEqual(item, expected))
|
|
446
|
+
return actual.some((item) => queryScalarValuesEqual(item, expected, itemScalarKind))
|
|
437
447
|
}
|
|
438
448
|
|
|
439
449
|
if (isPlainObject(actual) && typeof expected === "string") {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AuthorizablePrincipal } from "../../execution/types"
|
|
2
|
+
import type { EventExecutor } from "../../materialization/events"
|
|
2
3
|
import type {
|
|
3
4
|
EditCommitResult,
|
|
4
5
|
OntologyMaterializationOrigin,
|
|
@@ -57,7 +58,10 @@ interface OntologyCommitFields {
|
|
|
57
58
|
readonly requestHash: string
|
|
58
59
|
readonly executionId: string
|
|
59
60
|
readonly origin: OntologyMaterializationOrigin
|
|
60
|
-
|
|
61
|
+
/** Principal on whose behalf the execution ran, copied from `ExecutionRecord.requestedBy`. */
|
|
62
|
+
readonly requestedBy?: AuthorizablePrincipal
|
|
63
|
+
/** Workload that wrote the commit, copied from its execution. */
|
|
64
|
+
readonly executor: EventExecutor
|
|
61
65
|
readonly ontologyRevision: string
|
|
62
66
|
readonly projectionRevision?: string
|
|
63
67
|
readonly ownershipHash?: string
|
|
@@ -64,6 +64,9 @@ import type {
|
|
|
64
64
|
import type { OntologyMaterializationEvent } from "../outbox"
|
|
65
65
|
import {
|
|
66
66
|
appendScopeSnapshot,
|
|
67
|
+
assertExpectedLinkRevision,
|
|
68
|
+
assertExpectedLinkScopeRevision,
|
|
69
|
+
assertExpectedObjectRevision,
|
|
67
70
|
assertMaterializationHeader,
|
|
68
71
|
finishScopeAccumulator,
|
|
69
72
|
type ProviderMaterializationTransactionLifecycle,
|
|
@@ -217,12 +220,7 @@ export class InMemoryOntologyMaterializationStorage implements OntologyMateriali
|
|
|
217
220
|
expectedScopeRevisions.get(key) ??
|
|
218
221
|
this.computeEffectiveLinkScope(input.commit.projectId, expected.source, expected.linkId)
|
|
219
222
|
expectedScopeRevisions.set(key, current)
|
|
220
|
-
|
|
221
|
-
throw new MaterializationConflictError(
|
|
222
|
-
"effective-state",
|
|
223
|
-
`Expected link scope changed for ${expected.source.objectTypeId}:${expected.source.primaryId}.${expected.linkId}.`
|
|
224
|
-
)
|
|
225
|
-
}
|
|
223
|
+
assertExpectedLinkScopeRevision(current.fingerprint, expected)
|
|
226
224
|
}
|
|
227
225
|
for (const expected of input.expected.points) this.assertPoint(expected, input.commit.projectId)
|
|
228
226
|
|
|
@@ -1039,20 +1037,7 @@ export class InMemoryOntologyMaterializationStorage implements OntologyMateriali
|
|
|
1039
1037
|
expected.ref.objectTypeId,
|
|
1040
1038
|
expected.ref.primaryId
|
|
1041
1039
|
)
|
|
1042
|
-
|
|
1043
|
-
if (row)
|
|
1044
|
-
throw new MaterializationConflictError(
|
|
1045
|
-
"effective-state",
|
|
1046
|
-
`Expected object ${objectRefKey(expected.ref)} to be absent.`
|
|
1047
|
-
)
|
|
1048
|
-
return
|
|
1049
|
-
}
|
|
1050
|
-
if (!row || row.version !== expected.version || row.lastCommitId !== expected.lastCommitId) {
|
|
1051
|
-
throw new MaterializationConflictError(
|
|
1052
|
-
"effective-state",
|
|
1053
|
-
`Expected object ${objectRefKey(expected.ref)} changed.`
|
|
1054
|
-
)
|
|
1055
|
-
}
|
|
1040
|
+
assertExpectedObjectRevision(row ?? null, expected)
|
|
1056
1041
|
}
|
|
1057
1042
|
|
|
1058
1043
|
private async assertLink(expected: ExpectedLinkRevision, projectId: string): Promise<void> {
|
|
@@ -1067,20 +1052,7 @@ export class InMemoryOntologyMaterializationStorage implements OntologyMateriali
|
|
|
1067
1052
|
targetTypeId: expected.ref.target.objectTypeId,
|
|
1068
1053
|
targetId: expected.ref.target.primaryId,
|
|
1069
1054
|
})
|
|
1070
|
-
|
|
1071
|
-
if (row)
|
|
1072
|
-
throw new MaterializationConflictError(
|
|
1073
|
-
"effective-state",
|
|
1074
|
-
`Expected link ${linkRefKey(expected.ref)} to be absent.`
|
|
1075
|
-
)
|
|
1076
|
-
return
|
|
1077
|
-
}
|
|
1078
|
-
if (!row || row.lastCommitId !== expected.lastCommitId) {
|
|
1079
|
-
throw new MaterializationConflictError(
|
|
1080
|
-
"effective-state",
|
|
1081
|
-
`Expected link ${linkRefKey(expected.ref)} changed.`
|
|
1082
|
-
)
|
|
1083
|
-
}
|
|
1055
|
+
assertExpectedLinkRevision(row?.lastCommitId, expected)
|
|
1084
1056
|
}
|
|
1085
1057
|
|
|
1086
1058
|
private assertPoint(expected: ExpectedTimeseriesPointRevision, projectId: string): void {
|
|
@@ -38,6 +38,55 @@ function assertCommitEnvelope(commit: OntologyCommitWrite): void {
|
|
|
38
38
|
assertNonblank(commit.executionId, "Materialization execution id")
|
|
39
39
|
assertNonblank(commit.ontologyRevision, "Materialization ontology revision")
|
|
40
40
|
assertTimestamp(commit.committedAt, "Materialization commit time")
|
|
41
|
+
assertCommitAttribution(commit)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Shape only: the Materializer copies both values from the execution it has already verified. */
|
|
45
|
+
function assertCommitAttribution(commit: OntologyCommitWrite): void {
|
|
46
|
+
const { requestedBy, executor } = commit
|
|
47
|
+
if (requestedBy !== undefined) {
|
|
48
|
+
if (requestedBy.type !== "user" && requestedBy.type !== "serviceAccount") {
|
|
49
|
+
invalidCorrelation("Materialization requester must be a user or service account.")
|
|
50
|
+
}
|
|
51
|
+
assertNonblank(requestedBy.id, "Materialization requester id")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
switch (executor?.type) {
|
|
55
|
+
case "request":
|
|
56
|
+
assertNonblank(executor.requestId, "Materialization executor request id")
|
|
57
|
+
return
|
|
58
|
+
case "primitive":
|
|
59
|
+
assertNonblank(executor.kind, "Materialization executor primitive kind")
|
|
60
|
+
assertNonblank(executor.id, "Materialization executor primitive id")
|
|
61
|
+
assertNonblank(executor.runId, "Materialization executor run id")
|
|
62
|
+
return
|
|
63
|
+
case "agent":
|
|
64
|
+
assertNonblank(executor.runId, "Materialization executor Agent run id")
|
|
65
|
+
return
|
|
66
|
+
case "kernel":
|
|
67
|
+
assertNonblank(executor.operation?.type, "Materialization executor kernel operation")
|
|
68
|
+
return
|
|
69
|
+
default:
|
|
70
|
+
invalidCorrelation("Materialization executor is invalid.")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** A governed or projected write is attributed to exactly the primitive run that owns it. */
|
|
75
|
+
function assertPrimitiveExecutor(
|
|
76
|
+
commit: OntologyCommitWrite,
|
|
77
|
+
kind: "action" | "projection",
|
|
78
|
+
id: string,
|
|
79
|
+
runId: string
|
|
80
|
+
): void {
|
|
81
|
+
const { executor } = commit
|
|
82
|
+
if (
|
|
83
|
+
executor.type !== "primitive" ||
|
|
84
|
+
executor.kind !== kind ||
|
|
85
|
+
executor.id !== id ||
|
|
86
|
+
executor.runId !== runId
|
|
87
|
+
) {
|
|
88
|
+
invalidCorrelation(`Commit ${kind} origin does not match its executor.`)
|
|
89
|
+
}
|
|
41
90
|
}
|
|
42
91
|
|
|
43
92
|
function assertEditCommit(commit: OntologyCommitWrite, intent: EditOntologyCommitIntent): void {
|
|
@@ -47,6 +96,7 @@ function assertEditCommit(commit: OntologyCommitWrite, intent: EditOntologyCommi
|
|
|
47
96
|
case "action":
|
|
48
97
|
assertNonblank(commit.origin.actionId, "Action origin action id")
|
|
49
98
|
assertNonblank(commit.origin.runId, "Action origin run id")
|
|
99
|
+
assertPrimitiveExecutor(commit, "action", commit.origin.actionId, commit.origin.runId)
|
|
50
100
|
return
|
|
51
101
|
case "runtime":
|
|
52
102
|
assertNonblank(commit.origin.requestId, "Runtime origin request id")
|
|
@@ -77,6 +127,12 @@ function assertProjectionCommit(
|
|
|
77
127
|
) {
|
|
78
128
|
invalidCorrelation("Projection commit origin does not match its dataset version.")
|
|
79
129
|
}
|
|
130
|
+
assertPrimitiveExecutor(
|
|
131
|
+
commit,
|
|
132
|
+
"projection",
|
|
133
|
+
commit.origin.projectionId,
|
|
134
|
+
commit.origin.projectionRunId
|
|
135
|
+
)
|
|
80
136
|
}
|
|
81
137
|
|
|
82
138
|
function assertTelemetryCommit(
|
|
@@ -142,6 +198,7 @@ function assertProjectionTelemetryCommit(
|
|
|
142
198
|
if (origin.batchOrdinal !== source.batchOrdinal) {
|
|
143
199
|
invalidCorrelation("Projection telemetry origin does not match its batch ordinal.")
|
|
144
200
|
}
|
|
201
|
+
assertPrimitiveExecutor(commit, "projection", origin.projectionId, origin.projectionRunId)
|
|
145
202
|
}
|
|
146
203
|
|
|
147
204
|
function assertProjectionTelemetryBatch(
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
objectRefKey,
|
|
10
10
|
telemetryPointKey,
|
|
11
11
|
} from "../../materialization/refs"
|
|
12
|
+
import type { OntologyCommitWrite } from "./commits"
|
|
12
13
|
import {
|
|
13
14
|
type ExactTimeseriesPointWrite,
|
|
14
15
|
type MaterializationCardinalityOccupantWorkRecord,
|
|
@@ -107,8 +108,7 @@ export function assertWorkRecord(
|
|
|
107
108
|
record.draft.commitId !== header.commit.id ||
|
|
108
109
|
record.draft.occurredAt !== header.commit.committedAt ||
|
|
109
110
|
stableJsonStringify(record.draft.origin) !== stableJsonStringify(header.commit.origin) ||
|
|
110
|
-
|
|
111
|
-
stableJsonStringify(header.commit.actor ?? null)
|
|
111
|
+
!sameAttribution(record.draft, header.commit)
|
|
112
112
|
) {
|
|
113
113
|
throw new MaterializationValidationError("Materialization event work is invalid.")
|
|
114
114
|
}
|
|
@@ -312,7 +312,7 @@ function assertOutboxCorrelation(
|
|
|
312
312
|
value.availableAt !== commit.committedAt ||
|
|
313
313
|
value.createdAt !== commit.committedAt ||
|
|
314
314
|
stableJsonStringify(envelope.origin) !== stableJsonStringify(commit.origin) ||
|
|
315
|
-
|
|
315
|
+
!sameAttribution(envelope, commit) ||
|
|
316
316
|
!Number.isSafeInteger(envelope.commitOrdinal) ||
|
|
317
317
|
envelope.commitOrdinal < 0 ||
|
|
318
318
|
envelope.id !== createEventId(commit.projectId, commit.id, envelope.commitOrdinal)
|
|
@@ -347,3 +347,15 @@ function assertLinkRefEqual(left: OntologyLinkRef, right: OntologyLinkRef, label
|
|
|
347
347
|
invalidCorrelation(`${label} row and expected references differ.`)
|
|
348
348
|
}
|
|
349
349
|
}
|
|
350
|
+
|
|
351
|
+
/** Events carry exactly the attribution of the commit that produced them. */
|
|
352
|
+
function sameAttribution(
|
|
353
|
+
event: Pick<OntologyCommitWrite, "requestedBy" | "executor">,
|
|
354
|
+
commit: Pick<OntologyCommitWrite, "requestedBy" | "executor">
|
|
355
|
+
): boolean {
|
|
356
|
+
return (
|
|
357
|
+
stableJsonStringify(event.requestedBy ?? null) ===
|
|
358
|
+
stableJsonStringify(commit.requestedBy ?? null) &&
|
|
359
|
+
stableJsonStringify(event.executor) === stableJsonStringify(commit.executor)
|
|
360
|
+
)
|
|
361
|
+
}
|