@sixb/core 0.1.16 → 0.1.17
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 +25 -25
- package/dist/actions/types/context.d.ts +2 -2
- package/dist/actions/types/context.d.ts.map +1 -1
- package/dist/actions/worker.js +1 -1
- package/dist/agents/index.js +41 -40
- package/dist/agents/index.js.map +1 -1
- package/dist/auth/index.js +5 -5
- package/dist/authorization/index.js +2 -2
- package/dist/blob-storage/download-urls.d.ts +41 -0
- package/dist/blob-storage/download-urls.d.ts.map +1 -0
- package/dist/blob-storage/execution.d.ts +9 -1
- package/dist/blob-storage/execution.d.ts.map +1 -1
- package/dist/blob-storage/index.js +5 -3
- package/dist/blob-storage/index.js.map +1 -1
- package/dist/blob-storage/internal.d.ts +2 -0
- package/dist/blob-storage/internal.d.ts.map +1 -0
- package/dist/blob-storage/internal.js +11 -0
- package/dist/blob-storage/internal.js.map +9 -0
- package/dist/bootstrap/index.js +45 -44
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/{chunk-8x74221e.js → chunk-10styjgk.js} +18 -13
- package/dist/{chunk-8x74221e.js.map → chunk-10styjgk.js.map} +3 -3
- package/dist/{chunk-hgqpcmyr.js → chunk-1hqwggsn.js} +47 -19
- package/dist/chunk-1hqwggsn.js.map +12 -0
- package/dist/{chunk-zb47r1c8.js → chunk-23xs4qp9.js} +2 -2
- package/dist/{chunk-gmdvns8f.js → chunk-2am3db31.js} +2 -2
- package/dist/{chunk-fj1dvp37.js → chunk-2vhg6ysa.js} +1 -1
- package/dist/{chunk-dp7yk20b.js → chunk-33saed7g.js} +1 -1
- package/dist/{chunk-mdnw7nj8.js → chunk-3rrezgyc.js} +33 -8
- package/dist/chunk-3rrezgyc.js.map +15 -0
- package/dist/{chunk-jgwb25gc.js → chunk-4as3wt1c.js} +13 -5
- package/dist/chunk-4as3wt1c.js.map +12 -0
- package/dist/chunk-4ra628t7.js +88 -0
- package/dist/chunk-4ra628t7.js.map +10 -0
- package/dist/{chunk-chdg6eqq.js → chunk-52c5zb0z.js} +2 -2
- package/dist/{chunk-69kt9q43.js → chunk-5be2ath4.js} +1 -1
- package/dist/{chunk-qnd7ehe5.js → chunk-5thzcb8g.js} +2 -2
- package/dist/{chunk-6z1q7j19.js → chunk-5yd8cchh.js} +1126 -780
- package/dist/chunk-5yd8cchh.js.map +66 -0
- package/dist/{chunk-3q7z9hd4.js → chunk-6wbm6ymz.js} +234 -40
- package/dist/{chunk-3q7z9hd4.js.map → chunk-6wbm6ymz.js.map} +8 -6
- package/dist/{chunk-kvysp909.js → chunk-7ecp4v7a.js} +26 -19
- package/dist/chunk-7ecp4v7a.js.map +17 -0
- package/dist/{chunk-f85hpqnm.js → chunk-99nd4rc1.js} +3 -3
- package/dist/{chunk-f85hpqnm.js.map → chunk-99nd4rc1.js.map} +3 -3
- package/dist/{chunk-dsv8kdgk.js → chunk-9g6jz9kk.js} +5 -5
- package/dist/{chunk-39tqv9hz.js → chunk-9se093qz.js} +5 -6
- package/dist/{chunk-39tqv9hz.js.map → chunk-9se093qz.js.map} +3 -4
- package/dist/{chunk-7g2gjvah.js → chunk-a7er86jd.js} +1 -1
- package/dist/{chunk-zdkcdshk.js → chunk-aq39q04r.js} +41 -3
- package/dist/{chunk-zdkcdshk.js.map → chunk-aq39q04r.js.map} +4 -3
- package/dist/chunk-b9affek3.js +261 -0
- package/dist/chunk-b9affek3.js.map +12 -0
- package/dist/{chunk-b9y8hcm2.js → chunk-c2rga5cx.js} +1 -1
- package/dist/{chunk-f72rbvsb.js → chunk-cnb5kv05.js} +2 -2
- package/dist/chunk-d62kjtbg.js.map +2 -2
- package/dist/{chunk-vjqt7q3a.js → chunk-dam456ve.js} +233 -34
- package/dist/{chunk-vjqt7q3a.js.map → chunk-dam456ve.js.map} +7 -5
- package/dist/{chunk-sbcm1b92.js → chunk-e67ynxcr.js} +3 -3
- package/dist/{chunk-xnx96gfy.js → chunk-ere85b8y.js} +17 -8
- package/dist/chunk-ere85b8y.js.map +15 -0
- package/dist/{chunk-k4kkp58d.js → chunk-ewqa58h9.js} +12 -2
- package/dist/chunk-ewqa58h9.js.map +11 -0
- package/dist/{chunk-cq44v1a6.js → chunk-f1xh7a32.js} +3 -3
- package/dist/{chunk-h4138ww2.js → chunk-fggq3d9k.js} +450 -799
- package/dist/chunk-fggq3d9k.js.map +49 -0
- package/dist/{chunk-kttr5ftm.js → chunk-gf7yht60.js} +3 -3
- package/dist/chunk-h8teetr0.js +9 -0
- package/dist/chunk-h8teetr0.js.map +10 -0
- package/dist/chunk-hn2r7z41.js.map +1 -1
- package/dist/{chunk-nj0020ay.js → chunk-jjrn5v0p.js} +1 -1
- package/dist/{chunk-nvymebc1.js → chunk-jnfxmr3f.js} +1 -1
- package/dist/{chunk-nkbev3tr.js → chunk-k4g51s47.js} +3 -3
- package/dist/{chunk-a0073121.js → chunk-kpx7jrmn.js} +3 -1
- package/dist/chunk-kpx7jrmn.js.map +12 -0
- package/dist/{chunk-h044jb97.js → chunk-pja9jfz6.js} +172 -10
- package/dist/chunk-pja9jfz6.js.map +19 -0
- package/dist/chunk-pqajwytd.js.map +1 -1
- package/dist/{chunk-mr60an99.js → chunk-qczk96d9.js} +22 -2
- package/dist/{chunk-mr60an99.js.map → chunk-qczk96d9.js.map} +3 -3
- package/dist/{chunk-s3csryxe.js → chunk-rj69qcrd.js} +8 -2
- package/dist/chunk-rj69qcrd.js.map +11 -0
- package/dist/{chunk-swxzncrv.js → chunk-rpxz486p.js} +32 -5
- package/dist/{chunk-swxzncrv.js.map → chunk-rpxz486p.js.map} +4 -4
- package/dist/{chunk-tkdbge6v.js → chunk-rx7h5fdx.js} +1 -1
- package/dist/{chunk-tnvafr7g.js → chunk-s7ftxrdr.js} +105 -7
- package/dist/chunk-s7ftxrdr.js.map +22 -0
- package/dist/{chunk-h866d223.js → chunk-sk0hcjsz.js} +1 -1
- package/dist/{chunk-2xvgy3x5.js → chunk-svabwqdq.js} +2 -2
- package/dist/{chunk-667x4drs.js → chunk-t9shqx3w.js} +2 -2
- package/dist/{chunk-40qb8wpe.js → chunk-tjjgy3z4.js} +26 -23
- package/dist/{chunk-40qb8wpe.js.map → chunk-tjjgy3z4.js.map} +3 -3
- package/dist/{chunk-gkxsenvp.js → chunk-vp3z1ckh.js} +31 -7
- package/dist/{chunk-gkxsenvp.js.map → chunk-vp3z1ckh.js.map} +5 -4
- package/dist/{chunk-cxj8y8t0.js → chunk-vre348sb.js} +2 -2
- package/dist/{chunk-vsvrv7n8.js → chunk-w9yycd3t.js} +1 -1
- package/dist/{chunk-g4rbm4a6.js → chunk-wt4szfec.js} +379 -331
- package/dist/chunk-wt4szfec.js.map +14 -0
- package/dist/{chunk-a7ne02hk.js → chunk-xcy5ddha.js} +6 -6
- package/dist/{chunk-zvmr2hqk.js → chunk-xyvy73tj.js} +4 -3
- package/dist/{chunk-zvmr2hqk.js.map → chunk-xyvy73tj.js.map} +3 -3
- package/dist/datasets/write.js +1 -1
- package/dist/execution/agent.js +38 -37
- package/dist/execution/agent.js.map +1 -1
- package/dist/execution/authorized-object-reader.d.ts +3 -1
- package/dist/execution/authorized-object-reader.d.ts.map +1 -1
- package/dist/execution/primitive.js +36 -35
- package/dist/execution/primitive.js.map +2 -2
- package/dist/execution/request.js +37 -36
- package/dist/execution/request.js.map +2 -2
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62 -59
- package/dist/index.js.map +1 -1
- package/dist/lake-storage/in-memory.d.ts +5 -1
- package/dist/lake-storage/in-memory.d.ts.map +1 -1
- package/dist/lake-storage/index.d.ts +1 -1
- package/dist/lake-storage/index.d.ts.map +1 -1
- package/dist/lake-storage/index.js +2 -2
- package/dist/lake-storage/types.d.ts +26 -0
- package/dist/lake-storage/types.d.ts.map +1 -1
- package/dist/maintenance/ontology-maintenance.d.ts +5 -1
- package/dist/maintenance/ontology-maintenance.d.ts.map +1 -1
- package/dist/maintenance/types.d.ts +1 -4
- package/dist/maintenance/types.d.ts.map +1 -1
- package/dist/materialization/event-envelopes.d.ts +20 -0
- package/dist/materialization/event-envelopes.d.ts.map +1 -0
- package/dist/materialization/events.d.ts +29 -3
- package/dist/materialization/events.d.ts.map +1 -1
- package/dist/materialization/index.d.ts +4 -1
- package/dist/materialization/index.d.ts.map +1 -1
- package/dist/materialization/index.js +9 -3
- package/dist/materialization/index.js.map +1 -1
- package/dist/materializer/edits/plan.d.ts +2 -10
- package/dist/materializer/edits/plan.d.ts.map +1 -1
- package/dist/materializer/effective/build-events.d.ts +5 -21
- package/dist/materializer/effective/build-events.d.ts.map +1 -1
- package/dist/materializer/effective/vector-indexing.d.ts +2 -3
- package/dist/materializer/effective/vector-indexing.d.ts.map +1 -1
- package/dist/materializer/effective/vectors.d.ts +2 -3
- package/dist/materializer/effective/vectors.d.ts.map +1 -1
- package/dist/materializer/execution/scope.d.ts +1 -11
- package/dist/materializer/execution/scope.d.ts.map +1 -1
- package/dist/materializer/execution/work-executor.d.ts +5 -7
- package/dist/materializer/execution/work-executor.d.ts.map +1 -1
- package/dist/materializer/execution/work-records.d.ts +1 -3
- package/dist/materializer/execution/work-records.d.ts.map +1 -1
- package/dist/materializer/index.js +31 -32
- package/dist/materializer/index.js.map +1 -1
- package/dist/materializer/projections/replace.d.ts.map +1 -1
- package/dist/materializer/projections/replacement-plan.d.ts +8 -11
- package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
- package/dist/materializer/shared/batching.d.ts +5 -0
- package/dist/materializer/shared/batching.d.ts.map +1 -1
- package/dist/materializer/telemetry/plan.d.ts +2 -8
- package/dist/materializer/telemetry/plan.d.ts.map +1 -1
- package/dist/models/audio/catalog.d.ts +20 -0
- package/dist/models/audio/catalog.d.ts.map +1 -0
- package/dist/models/audio/errors.d.ts +8 -0
- package/dist/models/audio/errors.d.ts.map +1 -0
- package/dist/models/audio/file.d.ts +9 -0
- package/dist/models/audio/file.d.ts.map +1 -0
- package/dist/models/audio/runtime.d.ts +8 -0
- package/dist/models/audio/runtime.d.ts.map +1 -0
- package/dist/models/audio/types.d.ts +60 -0
- package/dist/models/audio/types.d.ts.map +1 -0
- package/dist/models/catalog.d.ts +23 -1
- package/dist/models/catalog.d.ts.map +1 -1
- package/dist/models/definitions.d.ts +1 -1
- package/dist/models/definitions.d.ts.map +1 -1
- package/dist/models/events.d.ts +3 -0
- package/dist/models/events.d.ts.map +1 -1
- package/dist/models/execution/index.js +22 -22
- package/dist/models/execution/model-call-admission.d.ts +6 -1
- package/dist/models/execution/model-call-admission.d.ts.map +1 -1
- package/dist/models/execution/model-call-limits.d.ts.map +1 -1
- package/dist/models/execution/model-call-recorder.d.ts.map +1 -1
- package/dist/models/execution/reranking.d.ts +4 -0
- package/dist/models/execution/reranking.d.ts.map +1 -0
- package/dist/models/execution/usage.d.ts.map +1 -1
- package/dist/models/execution.d.ts +2 -1
- package/dist/models/execution.d.ts.map +1 -1
- package/dist/models/generation-types.d.ts +2 -0
- package/dist/models/generation-types.d.ts.map +1 -1
- package/dist/models/index.d.ts +7 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +6 -2
- package/dist/models/index.js.map +1 -1
- package/dist/models/pricing.d.ts +2 -2
- package/dist/models/pricing.d.ts.map +1 -1
- package/dist/models/reranking-model.d.ts +49 -0
- package/dist/models/reranking-model.d.ts.map +1 -0
- package/dist/objects/index.js +25 -25
- package/dist/objects/query/executor.d.ts +2 -1
- package/dist/objects/query/executor.d.ts.map +1 -1
- package/dist/objects/query/index.d.ts +1 -1
- package/dist/objects/query/index.d.ts.map +1 -1
- package/dist/objects/query/index.js +22 -22
- package/dist/objects/query/ir.d.ts +8 -1
- package/dist/objects/query/ir.d.ts.map +1 -1
- package/dist/objects/query/normalize.d.ts.map +1 -1
- package/dist/objects/query/planner.d.ts +1 -1
- package/dist/objects/query/planner.d.ts.map +1 -1
- package/dist/objects/query/primary-id.d.ts +7 -0
- package/dist/objects/query/primary-id.d.ts.map +1 -0
- package/dist/objects/query/reranking-executor.d.ts +13 -0
- package/dist/objects/query/reranking-executor.d.ts.map +1 -0
- package/dist/objects/query/reranking-limits.d.ts +3 -0
- package/dist/objects/query/reranking-limits.d.ts.map +1 -0
- package/dist/objects/query/reranking-query.d.ts +4 -0
- package/dist/objects/query/reranking-query.d.ts.map +1 -0
- package/dist/objects/query/validate.d.ts.map +1 -1
- package/dist/objects/sdk/query-builder.d.ts +8 -0
- package/dist/objects/sdk/query-builder.d.ts.map +1 -1
- package/dist/objects/sdk/query-executor.d.ts +2 -2
- package/dist/objects/sdk/query-executor.d.ts.map +1 -1
- package/dist/objects/sdk/runtime-query-executor.d.ts.map +1 -1
- package/dist/objects/vectors/indexing-dispatch.d.ts +21 -0
- package/dist/objects/vectors/indexing-dispatch.d.ts.map +1 -0
- package/dist/objects/vectors/query.d.ts.map +1 -1
- package/dist/ontology/builders.d.ts.map +1 -1
- package/dist/ontology/index.d.ts +1 -1
- package/dist/ontology/index.d.ts.map +1 -1
- package/dist/ontology/index.js +3 -3
- package/dist/ontology/internal.js +2 -2
- package/dist/ontology/query-capabilities.d.ts +1 -0
- package/dist/ontology/query-capabilities.d.ts.map +1 -1
- package/dist/ontology/types.d.ts +20 -0
- package/dist/ontology/types.d.ts.map +1 -1
- package/dist/ontology/validation/query.d.ts.map +1 -1
- package/dist/pipelines/index.js +23 -23
- package/dist/projections/internal.js +22 -22
- package/dist/query.d.ts +4 -2
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +2 -2
- package/dist/queues/in-memory.d.ts +3 -0
- package/dist/queues/in-memory.d.ts.map +1 -1
- package/dist/queues/index.js +1 -1
- package/dist/queues/types.d.ts +4 -0
- package/dist/queues/types.d.ts.map +1 -1
- package/dist/runtime/host.d.ts +1 -0
- 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.d.ts +1 -0
- package/dist/runtime/internal.d.ts.map +1 -1
- package/dist/runtime/internal.js +28 -26
- package/dist/runtime/internal.js.map +1 -1
- package/dist/runtime/public-origin.d.ts +10 -0
- package/dist/runtime/public-origin.d.ts.map +1 -0
- package/dist/runtime/sixb.d.ts +1 -0
- package/dist/runtime/sixb.d.ts.map +1 -1
- package/dist/runtime/types.d.ts +12 -2
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/sandboxes/index.js +5 -5
- package/dist/shares/internal.js +19 -19
- package/dist/storage/agents/provider.js +2 -2
- package/dist/storage/ai-cost/analytics.d.ts +1 -0
- package/dist/storage/ai-cost/analytics.d.ts.map +1 -1
- package/dist/storage/ai-cost/provider.js +3 -3
- package/dist/storage/ai-cost/types.d.ts +1 -1
- package/dist/storage/ai-cost/types.d.ts.map +1 -1
- package/dist/storage/ai-cost/validation.d.ts.map +1 -1
- package/dist/storage/ai-limits/enforcement.js +2 -2
- package/dist/storage/ai-limits/in-memory.d.ts.map +1 -1
- package/dist/storage/ai-limits/provider.d.ts +7 -2
- package/dist/storage/ai-limits/provider.d.ts.map +1 -1
- package/dist/storage/ai-limits/provider.js +4 -2
- package/dist/storage/ai-limits/provider.js.map +1 -1
- package/dist/storage/ai-limits/types.d.ts +3 -0
- package/dist/storage/ai-limits/types.d.ts.map +1 -1
- package/dist/storage/ai-usage/record.d.ts.map +1 -1
- package/dist/storage/ai-usage/types.d.ts +8 -4
- package/dist/storage/ai-usage/types.d.ts.map +1 -1
- package/dist/storage/ai-usage/usage.d.ts.map +1 -1
- package/dist/storage/file-download-grants/in-memory.d.ts +11 -0
- package/dist/storage/file-download-grants/in-memory.d.ts.map +1 -0
- package/dist/storage/file-download-grants/index.d.ts +3 -0
- package/dist/storage/file-download-grants/index.d.ts.map +1 -0
- package/dist/storage/file-download-grants/record.d.ts +11 -0
- package/dist/storage/file-download-grants/record.d.ts.map +1 -0
- package/dist/storage/file-download-grants/types.d.ts +44 -0
- package/dist/storage/file-download-grants/types.d.ts.map +1 -0
- package/dist/storage/file-upload-sessions/provider.js +6 -6
- package/dist/storage/in-memory/index.d.ts +4 -0
- package/dist/storage/in-memory/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +5 -3
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +30 -30
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/internal.d.ts +1 -0
- package/dist/storage/internal.d.ts.map +1 -1
- package/dist/storage/internal.js +8 -4
- package/dist/storage/internal.js.map +1 -1
- package/dist/storage/migrations/index.d.ts +1 -1
- package/dist/storage/migrations/index.d.ts.map +1 -1
- package/dist/storage/migrations/migrate-storage.d.ts +3 -3
- package/dist/storage/migrations/migrate-storage.d.ts.map +1 -1
- package/dist/storage/migrations/types.d.ts +7 -0
- package/dist/storage/migrations/types.d.ts.map +1 -1
- package/dist/storage/objects/in-memory/query.d.ts.map +1 -1
- package/dist/storage/objects/in-memory/selected-reader.d.ts.map +1 -1
- package/dist/storage/objects/in-memory/storage.d.ts.map +1 -1
- package/dist/storage/objects/query-preparation.d.ts +39 -0
- package/dist/storage/objects/query-preparation.d.ts.map +1 -0
- package/dist/storage/objects/types.d.ts +2 -0
- package/dist/storage/objects/types.d.ts.map +1 -1
- package/dist/storage/ontology/commits.d.ts +1 -6
- package/dist/storage/ontology/commits.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/index.d.ts +4 -2
- package/dist/storage/ontology/in-memory/index.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/materializations-state.d.ts +0 -2
- package/dist/storage/ontology/in-memory/materializations-state.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/materializations-work.d.ts +1 -3
- package/dist/storage/ontology/in-memory/materializations-work.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/materializations.d.ts +23 -57
- package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/outbox.d.ts +3 -2
- package/dist/storage/ontology/in-memory/outbox.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/replacement-plans.d.ts +104 -0
- package/dist/storage/ontology/in-memory/replacement-plans.d.ts.map +1 -0
- package/dist/storage/ontology/in-memory/shared-state.d.ts +17 -2
- package/dist/storage/ontology/in-memory/shared-state.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/source-roots.d.ts +3 -1
- package/dist/storage/ontology/in-memory/source-roots.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/sources.d.ts +1 -2
- package/dist/storage/ontology/in-memory/sources.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/state-reader.d.ts +25 -0
- package/dist/storage/ontology/in-memory/state-reader.d.ts.map +1 -0
- package/dist/storage/ontology/index.d.ts +6 -3
- package/dist/storage/ontology/index.d.ts.map +1 -1
- package/dist/storage/ontology/materializations.d.ts +40 -59
- package/dist/storage/ontology/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/outbox.d.ts +4 -6
- package/dist/storage/ontology/outbox.d.ts.map +1 -1
- package/dist/storage/ontology/provider-work.d.ts +114 -3
- package/dist/storage/ontology/provider-work.d.ts.map +1 -1
- package/dist/storage/ontology/provider.d.ts +14 -39
- package/dist/storage/ontology/provider.d.ts.map +1 -1
- package/dist/storage/ontology/provider.js +26 -12
- package/dist/storage/ontology/provider.js.map +1 -1
- package/dist/storage/ontology/replacement-plans.d.ts +103 -0
- package/dist/storage/ontology/replacement-plans.d.ts.map +1 -0
- package/dist/storage/ontology/sources.d.ts +0 -8
- package/dist/storage/ontology/sources.d.ts.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/in-memory.d.ts.map +1 -1
- package/dist/storage/projection-runs/types.d.ts +2 -0
- package/dist/storage/projection-runs/types.d.ts.map +1 -1
- package/dist/storage/types.d.ts +2 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/workflow-runs/provider.js +6 -6
- package/dist/syncs/index.js +24 -24
- package/dist/testing/ai-cost-storage-contract.d.ts.map +1 -1
- package/dist/testing/ai-limit-storage-contract.d.ts.map +1 -1
- package/dist/testing/ai-usage-storage-contract.d.ts.map +1 -1
- package/dist/testing/file-download-grant-storage-contract.d.ts +9 -0
- package/dist/testing/file-download-grant-storage-contract.d.ts.map +1 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2549 -1490
- package/dist/testing/index.js.map +14 -13
- package/dist/testing/lake-storage-contract.d.ts.map +1 -1
- package/dist/testing/materializer-storage-contract.d.ts +14 -0
- package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
- package/dist/testing/object-read-scope-contract.d.ts.map +1 -1
- package/dist/testing/ontology-contract-fixture.d.ts +5 -1
- 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/projection-run-storage-contract.d.ts.map +1 -1
- package/dist/testing/queues-contract.d.ts.map +1 -1
- package/dist/webhooks/internal.js +20 -20
- package/dist/workers/index.js +15 -17
- package/dist/workers/index.js.map +3 -3
- package/dist/workers/queue-worker.d.ts +3 -2
- package/dist/workers/queue-worker.d.ts.map +1 -1
- package/dist/workflows/index.js +42 -41
- package/dist/workflows/index.js.map +1 -1
- package/package.json +7 -1
- package/src/actions/types/context.ts +5 -2
- package/src/blob-storage/download-urls.ts +138 -0
- package/src/blob-storage/execution.ts +32 -1
- package/src/blob-storage/internal.ts +1 -0
- package/src/execution/authorized-object-reader.ts +8 -1
- package/src/index.ts +25 -0
- package/src/lake-storage/in-memory.ts +38 -9
- package/src/lake-storage/index.ts +2 -0
- package/src/lake-storage/types.ts +30 -0
- package/src/maintenance/ontology-maintenance.ts +50 -23
- package/src/maintenance/types.ts +1 -4
- package/src/materialization/event-envelopes.ts +168 -0
- package/src/materialization/events.ts +40 -4
- package/src/materialization/index.ts +9 -1
- package/src/materializer/README.md +55 -10
- package/src/materializer/edits/commit.ts +3 -19
- package/src/materializer/edits/plan.ts +20 -71
- package/src/materializer/effective/build-events.ts +42 -136
- package/src/materializer/effective/vector-indexing.ts +2 -3
- package/src/materializer/effective/vectors.ts +2 -3
- package/src/materializer/execution/scope.ts +1 -38
- package/src/materializer/execution/work-executor.ts +21 -115
- package/src/materializer/execution/work-records.ts +0 -15
- package/src/materializer/projections/replace.ts +106 -63
- package/src/materializer/projections/replacement-plan.ts +73 -218
- package/src/materializer/shared/batching.ts +7 -0
- package/src/materializer/telemetry/append.ts +2 -14
- package/src/materializer/telemetry/plan.ts +6 -43
- package/src/models/audio/catalog.ts +90 -0
- package/src/models/audio/errors.ts +19 -0
- package/src/models/audio/file.ts +78 -0
- package/src/models/audio/runtime.ts +182 -0
- package/src/models/audio/types.ts +69 -0
- package/src/models/catalog.ts +52 -5
- package/src/models/definitions.ts +8 -1
- package/src/models/events.ts +3 -0
- package/src/models/execution/README.md +20 -1
- package/src/models/execution/model-call-admission.ts +6 -1
- package/src/models/execution/model-call-limits.ts +21 -11
- package/src/models/execution/model-call-recorder.ts +1 -0
- package/src/models/execution/model-call-recovery.ts +1 -0
- package/src/models/execution/reranking.ts +137 -0
- package/src/models/execution/usage.ts +1 -0
- package/src/models/execution.ts +5 -1
- package/src/models/generation-types.ts +2 -0
- package/src/models/index.ts +32 -0
- package/src/models/pricing.ts +2 -1
- package/src/models/reranking-model.ts +114 -0
- package/src/objects/query/executor.ts +42 -2
- package/src/objects/query/explain.ts +8 -0
- package/src/objects/query/index.ts +1 -0
- package/src/objects/query/ir.ts +10 -0
- package/src/objects/query/normalize.ts +2 -0
- package/src/objects/query/planner.ts +12 -1
- package/src/objects/query/primary-id.ts +56 -0
- package/src/objects/query/reranking-executor.ts +91 -0
- package/src/objects/query/reranking-limits.ts +3 -0
- package/src/objects/query/reranking-query.ts +8 -0
- package/src/objects/query/validate.ts +33 -1
- package/src/objects/sdk/query-builder.ts +15 -2
- package/src/objects/sdk/query-executor.ts +2 -2
- package/src/objects/sdk/runtime-query-executor.ts +7 -4
- package/src/objects/vectors/README.md +6 -2
- package/src/objects/vectors/indexing-dispatch.ts +83 -0
- package/src/objects/vectors/query.ts +3 -0
- package/src/ontology/builders.ts +1 -0
- package/src/ontology/index.ts +2 -0
- package/src/ontology/query-capabilities.ts +1 -1
- package/src/ontology/types.ts +21 -0
- package/src/ontology/validation/query.ts +57 -0
- package/src/query.ts +4 -0
- package/src/queues/in-memory.ts +54 -19
- package/src/queues/types.ts +4 -0
- package/src/runtime/host.ts +28 -1
- package/src/runtime/index.ts +1 -0
- package/src/runtime/internal.ts +1 -0
- package/src/runtime/public-origin.ts +33 -0
- package/src/runtime/sixb.ts +13 -2
- package/src/runtime/types.ts +12 -2
- package/src/storage/ai-cost/analytics.ts +2 -0
- package/src/storage/ai-cost/codec.ts +2 -1
- package/src/storage/ai-cost/types.ts +1 -0
- package/src/storage/ai-cost/validation.ts +21 -8
- package/src/storage/ai-limits/in-memory.ts +10 -2
- package/src/storage/ai-limits/provider.ts +29 -2
- package/src/storage/ai-limits/types.ts +3 -0
- package/src/storage/ai-usage/record.ts +9 -0
- package/src/storage/ai-usage/types.ts +8 -4
- package/src/storage/ai-usage/usage.ts +2 -0
- package/src/storage/file-download-grants/in-memory.ts +73 -0
- package/src/storage/file-download-grants/index.ts +8 -0
- package/src/storage/file-download-grants/record.ts +47 -0
- package/src/storage/file-download-grants/types.ts +48 -0
- package/src/storage/in-memory/index.ts +13 -2
- package/src/storage/index.ts +31 -13
- package/src/storage/internal.ts +1 -0
- package/src/storage/migrations/index.ts +1 -0
- package/src/storage/migrations/migrate-storage.ts +36 -12
- package/src/storage/migrations/types.ts +8 -0
- package/src/storage/objects/in-memory/query.ts +2 -0
- package/src/storage/objects/in-memory/selected-reader.ts +1 -0
- package/src/storage/objects/in-memory/storage.ts +1 -0
- package/src/storage/objects/query-preparation.ts +77 -0
- package/src/storage/objects/types.ts +2 -0
- package/src/storage/ontology/commits.ts +1 -6
- package/src/storage/ontology/in-memory/index.ts +28 -9
- package/src/storage/ontology/in-memory/materializations-finalization.ts +35 -68
- package/src/storage/ontology/in-memory/materializations-state.ts +0 -22
- package/src/storage/ontology/in-memory/materializations-work.ts +0 -45
- package/src/storage/ontology/in-memory/materializations.ts +172 -653
- package/src/storage/ontology/in-memory/outbox.ts +37 -29
- package/src/storage/ontology/in-memory/replacement-plans.ts +697 -0
- package/src/storage/ontology/in-memory/shared-state.ts +24 -2
- package/src/storage/ontology/in-memory/source-roots.ts +7 -2
- package/src/storage/ontology/in-memory/sources.ts +7 -33
- package/src/storage/ontology/in-memory/state-reader.ts +245 -0
- package/src/storage/ontology/index.ts +19 -13
- package/src/storage/ontology/materializations.ts +45 -74
- package/src/storage/ontology/outbox.ts +4 -7
- package/src/storage/ontology/provider-header-validation.ts +0 -57
- package/src/storage/ontology/provider-work.ts +381 -90
- package/src/storage/ontology/provider.ts +74 -171
- package/src/storage/ontology/replacement-plans.ts +117 -0
- package/src/storage/ontology/sources.ts +0 -12
- package/src/storage/operation-scope.ts +33 -1
- package/src/storage/projection-runs/in-memory.ts +7 -1
- package/src/storage/projection-runs/types.ts +2 -0
- package/src/storage/types.ts +2 -0
- package/src/testing/ai-cost-storage-contract.ts +1 -0
- package/src/testing/ai-limit-storage-contract.ts +62 -0
- package/src/testing/ai-usage-storage-contract.ts +31 -0
- package/src/testing/file-download-grant-storage-contract.ts +139 -0
- package/src/testing/index.ts +4 -0
- package/src/testing/lake-storage-contract.ts +87 -1
- package/src/testing/materializer-storage-contract.ts +1008 -1
- package/src/testing/object-read-scope-contract.ts +1 -0
- package/src/testing/ontology-contract-fixture.ts +11 -87
- package/src/testing/ontology-storage-contract.ts +70 -39
- package/src/testing/projection-run-storage-contract.ts +14 -0
- package/src/testing/queues-contract.ts +59 -0
- package/src/workers/queue-worker.ts +19 -16
- package/dist/chunk-6z1q7j19.js.map +0 -62
- package/dist/chunk-7ytf06d3.js +0 -113
- package/dist/chunk-7ytf06d3.js.map +0 -10
- package/dist/chunk-a0073121.js.map +0 -12
- package/dist/chunk-g4rbm4a6.js.map +0 -15
- package/dist/chunk-h044jb97.js.map +0 -15
- package/dist/chunk-h4138ww2.js.map +0 -50
- package/dist/chunk-hgqpcmyr.js.map +0 -12
- package/dist/chunk-jgwb25gc.js.map +0 -12
- package/dist/chunk-k4kkp58d.js.map +0 -11
- package/dist/chunk-kvysp909.js.map +0 -17
- package/dist/chunk-mdnw7nj8.js.map +0 -15
- package/dist/chunk-s3csryxe.js.map +0 -11
- package/dist/chunk-tnvafr7g.js.map +0 -19
- package/dist/chunk-xnx96gfy.js.map +0 -15
- package/dist/materializer/execution/plan-stream.d.ts +0 -8
- package/dist/materializer/execution/plan-stream.d.ts.map +0 -1
- package/src/materializer/execution/plan-stream.ts +0 -121
- /package/dist/{chunk-zb47r1c8.js.map → chunk-23xs4qp9.js.map} +0 -0
- /package/dist/{chunk-gmdvns8f.js.map → chunk-2am3db31.js.map} +0 -0
- /package/dist/{chunk-fj1dvp37.js.map → chunk-2vhg6ysa.js.map} +0 -0
- /package/dist/{chunk-dp7yk20b.js.map → chunk-33saed7g.js.map} +0 -0
- /package/dist/{chunk-chdg6eqq.js.map → chunk-52c5zb0z.js.map} +0 -0
- /package/dist/{chunk-69kt9q43.js.map → chunk-5be2ath4.js.map} +0 -0
- /package/dist/{chunk-qnd7ehe5.js.map → chunk-5thzcb8g.js.map} +0 -0
- /package/dist/{chunk-dsv8kdgk.js.map → chunk-9g6jz9kk.js.map} +0 -0
- /package/dist/{chunk-7g2gjvah.js.map → chunk-a7er86jd.js.map} +0 -0
- /package/dist/{chunk-b9y8hcm2.js.map → chunk-c2rga5cx.js.map} +0 -0
- /package/dist/{chunk-f72rbvsb.js.map → chunk-cnb5kv05.js.map} +0 -0
- /package/dist/{chunk-sbcm1b92.js.map → chunk-e67ynxcr.js.map} +0 -0
- /package/dist/{chunk-cq44v1a6.js.map → chunk-f1xh7a32.js.map} +0 -0
- /package/dist/{chunk-kttr5ftm.js.map → chunk-gf7yht60.js.map} +0 -0
- /package/dist/{chunk-nj0020ay.js.map → chunk-jjrn5v0p.js.map} +0 -0
- /package/dist/{chunk-nvymebc1.js.map → chunk-jnfxmr3f.js.map} +0 -0
- /package/dist/{chunk-nkbev3tr.js.map → chunk-k4g51s47.js.map} +0 -0
- /package/dist/{chunk-tkdbge6v.js.map → chunk-rx7h5fdx.js.map} +0 -0
- /package/dist/{chunk-h866d223.js.map → chunk-sk0hcjsz.js.map} +0 -0
- /package/dist/{chunk-2xvgy3x5.js.map → chunk-svabwqdq.js.map} +0 -0
- /package/dist/{chunk-667x4drs.js.map → chunk-t9shqx3w.js.map} +0 -0
- /package/dist/{chunk-cxj8y8t0.js.map → chunk-vre348sb.js.map} +0 -0
- /package/dist/{chunk-vsvrv7n8.js.map → chunk-w9yycd3t.js.map} +0 -0
- /package/dist/{chunk-a7ne02hk.js.map → chunk-xcy5ddha.js.map} +0 -0
|
@@ -16,6 +16,7 @@ import { createTestingScope } from "../execution/scopes"
|
|
|
16
16
|
import type {
|
|
17
17
|
ExpectedLinkRevision,
|
|
18
18
|
ExpectedObjectRevision,
|
|
19
|
+
OntologyLinkRef,
|
|
19
20
|
OntologyMaterializer,
|
|
20
21
|
} from "../materializer"
|
|
21
22
|
import {
|
|
@@ -27,13 +28,34 @@ import {
|
|
|
27
28
|
type ProjectionSourceDeletion,
|
|
28
29
|
type ProjectionSourceEntry,
|
|
29
30
|
} from "../materializer"
|
|
30
|
-
import type {
|
|
31
|
+
import type {
|
|
32
|
+
ActionRunStorage,
|
|
33
|
+
OntologyCommitWrite,
|
|
34
|
+
OntologyReplacementPlanStorage,
|
|
35
|
+
PlannedReplacementIdentity,
|
|
36
|
+
ProjectionExecution,
|
|
37
|
+
ProjectionRunStorage,
|
|
38
|
+
} from "../storage"
|
|
31
39
|
import { createTestActionExecution, queueTestActionRun } from "./action-execution"
|
|
32
40
|
import { createTestProjectionExecution, startTestProjectionRun } from "./projection-execution"
|
|
33
41
|
|
|
34
42
|
export interface MaterializerStorageContractProvider<TStorage extends Storage> {
|
|
35
43
|
readonly createStorage: () => TStorage | Promise<TStorage>
|
|
36
44
|
readonly cleanup?: (storage: TStorage) => void | Promise<void>
|
|
45
|
+
/** Write transactions run side by side instead of one after another. */
|
|
46
|
+
readonly concurrentTransactions?: boolean
|
|
47
|
+
/**
|
|
48
|
+
* Moves the transaction ids that commits and plans recorded far ahead of the store's own, as a
|
|
49
|
+
* logical restore from a cluster further along leaves them.
|
|
50
|
+
*/
|
|
51
|
+
readonly restoreFromClusterAhead?: (storage: TStorage) => Promise<void>
|
|
52
|
+
/** How many entity touches of commits the store still records. */
|
|
53
|
+
readonly countCommitTouches: (storage: TStorage) => Promise<number>
|
|
54
|
+
/**
|
|
55
|
+
* Deletes every commit touch as a purge that has not seen a plan opening yet would, leaving the
|
|
56
|
+
* record that they are gone. Only a store whose purge can race a plan's opening provides it.
|
|
57
|
+
*/
|
|
58
|
+
readonly losePlanTouchesToPurge?: (storage: TStorage) => Promise<void>
|
|
37
59
|
}
|
|
38
60
|
|
|
39
61
|
type ContractStorage = Storage & {
|
|
@@ -982,6 +1004,758 @@ export function runMaterializerStorageContractSuite<TStorage extends Storage>(
|
|
|
982
1004
|
await provider.cleanup?.(createdStorage)
|
|
983
1005
|
}
|
|
984
1006
|
})
|
|
1007
|
+
|
|
1008
|
+
// Removal proof: make every provider's `refresh` answer fresh; the edited object's planned
|
|
1009
|
+
// upsert then fails its revision check and the publication rejects. Drop the round inside the
|
|
1010
|
+
// commit transaction from `refreshProjectionPlan`: a is then planned again outside it.
|
|
1011
|
+
test(`${name} plans again only the identity an edit changed while it planned`, async () => {
|
|
1012
|
+
const createdStorage = await provider.createStorage()
|
|
1013
|
+
const storage = requireContractStorage(createdStorage)
|
|
1014
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1015
|
+
let armed = false
|
|
1016
|
+
let edited = false
|
|
1017
|
+
const staged: string[] = []
|
|
1018
|
+
const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
|
|
1019
|
+
if (!armed) return
|
|
1020
|
+
staged.push(...planned.map((value) => `${plannedId(value)}${inTransaction ? "@commit" : ""}`))
|
|
1021
|
+
if (edited || !planned.some((value) => plannedId(value) === "a")) return
|
|
1022
|
+
edited = true
|
|
1023
|
+
await runtime.edits.commit({
|
|
1024
|
+
mode: "atomic",
|
|
1025
|
+
source: { kind: "runtime", requestId: "edit-while-planned" },
|
|
1026
|
+
operations: [
|
|
1027
|
+
{
|
|
1028
|
+
id: "rename",
|
|
1029
|
+
kind: "object.patch",
|
|
1030
|
+
ref: deviceRef("a"),
|
|
1031
|
+
set: { name: "edited" },
|
|
1032
|
+
unset: [],
|
|
1033
|
+
reset: [],
|
|
1034
|
+
},
|
|
1035
|
+
],
|
|
1036
|
+
expectedObjects: [],
|
|
1037
|
+
expectedLinks: [],
|
|
1038
|
+
expectedLinkScopes: [],
|
|
1039
|
+
})
|
|
1040
|
+
})
|
|
1041
|
+
const materializer = contractMaterializer(observed)
|
|
1042
|
+
try {
|
|
1043
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1044
|
+
armed = true
|
|
1045
|
+
await publishDevices(materializer, storage, 2, [
|
|
1046
|
+
sourceEntry("a", "A2"),
|
|
1047
|
+
sourceEntry("b", "B2"),
|
|
1048
|
+
])
|
|
1049
|
+
// The commit plans the one identity the edit made stale itself.
|
|
1050
|
+
expect(staged.filter((id) => id.startsWith("a"))).toEqual(["a", "a@commit"])
|
|
1051
|
+
expect(staged.filter((id) => id.startsWith("b"))).toEqual(["b"])
|
|
1052
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
|
|
1053
|
+
expect(await device(storage, "b")).toMatchObject({ properties: { name: "B2" } })
|
|
1054
|
+
} finally {
|
|
1055
|
+
await provider.cleanup?.(createdStorage)
|
|
1056
|
+
}
|
|
1057
|
+
})
|
|
1058
|
+
|
|
1059
|
+
// Removal proof: drop the link expansion from every provider's `refresh`; the link the edit
|
|
1060
|
+
// added keeps pointing at the object the publication deleted.
|
|
1061
|
+
test(`${name} plans the links an edit adds to an object the projection deletes`, async () => {
|
|
1062
|
+
const createdStorage = await provider.createStorage()
|
|
1063
|
+
const storage = requireContractStorage(createdStorage)
|
|
1064
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1065
|
+
let armed = false
|
|
1066
|
+
const observed = observePlanning(storage, async (planned) => {
|
|
1067
|
+
if (!armed || !planned.some(({ identity }) => identity.kind === "link")) return
|
|
1068
|
+
armed = false
|
|
1069
|
+
await runtime.edits.commit({
|
|
1070
|
+
mode: "atomic",
|
|
1071
|
+
source: { kind: "runtime", requestId: "link-while-planned" },
|
|
1072
|
+
operations: [
|
|
1073
|
+
{
|
|
1074
|
+
id: "peer",
|
|
1075
|
+
kind: "link.upsert",
|
|
1076
|
+
ref: { source: deviceRef("c"), linkId: "peers", target: deviceRef("a") },
|
|
1077
|
+
},
|
|
1078
|
+
],
|
|
1079
|
+
expectedObjects: [],
|
|
1080
|
+
expectedLinks: [],
|
|
1081
|
+
expectedLinkScopes: [],
|
|
1082
|
+
})
|
|
1083
|
+
})
|
|
1084
|
+
const materializer = contractMaterializer(observed)
|
|
1085
|
+
try {
|
|
1086
|
+
await publishDevices(materializer, storage, 1, [
|
|
1087
|
+
sourceEntry("a", "A"),
|
|
1088
|
+
sourceEntry("b", "B", "a"),
|
|
1089
|
+
sourceEntry("c", "C"),
|
|
1090
|
+
])
|
|
1091
|
+
armed = true
|
|
1092
|
+
await publishDevices(materializer, storage, 2, [sourceEntry("b", "B"), sourceEntry("c", "C")])
|
|
1093
|
+
expect(await device(storage, "a")).toBeNull()
|
|
1094
|
+
for (const id of ["b", "c"]) {
|
|
1095
|
+
expect(
|
|
1096
|
+
await storage.objects.listLinks({
|
|
1097
|
+
projectId: CONTRACT_PROJECT,
|
|
1098
|
+
objectTypeId: Device.id,
|
|
1099
|
+
objectId: id,
|
|
1100
|
+
})
|
|
1101
|
+
).toEqual([])
|
|
1102
|
+
}
|
|
1103
|
+
} finally {
|
|
1104
|
+
await provider.cleanup?.(createdStorage)
|
|
1105
|
+
}
|
|
1106
|
+
})
|
|
1107
|
+
|
|
1108
|
+
// Removal proof: compare a link's edge override by an unqualified `identity_key` in the SQLite
|
|
1109
|
+
// revision; it then reads another link's override, and the untouched link is planned again.
|
|
1110
|
+
// Drop the touches of slot overrides from every provider: b is then not planned again.
|
|
1111
|
+
test(`${name} plans again only the link whose override an edit changed while it planned`, async () => {
|
|
1112
|
+
const createdStorage = await provider.createStorage()
|
|
1113
|
+
const storage = requireContractStorage(createdStorage)
|
|
1114
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1115
|
+
let armed = false
|
|
1116
|
+
let edited = false
|
|
1117
|
+
const staged: string[] = []
|
|
1118
|
+
const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
|
|
1119
|
+
if (!armed) return
|
|
1120
|
+
const links = planned.flatMap(({ identity }) =>
|
|
1121
|
+
identity.kind === "link" ? [identity.ref.source.primaryId] : []
|
|
1122
|
+
)
|
|
1123
|
+
staged.push(...links.map((id) => `${id}${inTransaction ? "@commit" : ""}`))
|
|
1124
|
+
if (edited || !links.includes("c")) return
|
|
1125
|
+
edited = true
|
|
1126
|
+
// Once both links are planned, keeps the one of b the publication retracts; its effective
|
|
1127
|
+
// row stays as it was.
|
|
1128
|
+
await runtime.edits.commit({
|
|
1129
|
+
mode: "atomic",
|
|
1130
|
+
source: { kind: "runtime", requestId: "override-while-planned" },
|
|
1131
|
+
operations: [
|
|
1132
|
+
{
|
|
1133
|
+
id: "keep",
|
|
1134
|
+
kind: "link.upsert",
|
|
1135
|
+
ref: { source: deviceRef("b"), linkId: "parent", target: deviceRef("a") },
|
|
1136
|
+
},
|
|
1137
|
+
],
|
|
1138
|
+
expectedObjects: [],
|
|
1139
|
+
expectedLinks: [],
|
|
1140
|
+
expectedLinkScopes: [],
|
|
1141
|
+
})
|
|
1142
|
+
})
|
|
1143
|
+
const materializer = contractMaterializer(observed)
|
|
1144
|
+
const parent = (id: string) =>
|
|
1145
|
+
storage.objects.listLinks({
|
|
1146
|
+
projectId: CONTRACT_PROJECT,
|
|
1147
|
+
objectTypeId: Device.id,
|
|
1148
|
+
objectId: id,
|
|
1149
|
+
})
|
|
1150
|
+
try {
|
|
1151
|
+
await publishDevices(materializer, storage, 1, [
|
|
1152
|
+
sourceEntry("a", "A"),
|
|
1153
|
+
sourceEntry("b", "B", "a"),
|
|
1154
|
+
sourceEntry("c", "C", "a"),
|
|
1155
|
+
])
|
|
1156
|
+
armed = true
|
|
1157
|
+
await publishDevices(materializer, storage, 2, [
|
|
1158
|
+
sourceEntry("a", "A"),
|
|
1159
|
+
sourceEntry("b", "B"),
|
|
1160
|
+
sourceEntry("c", "C"),
|
|
1161
|
+
])
|
|
1162
|
+
expect(staged.filter((id) => id.startsWith("b"))).toEqual(["b", "b@commit"])
|
|
1163
|
+
expect(staged.filter((id) => id.startsWith("c"))).toEqual(["c"])
|
|
1164
|
+
expect(await parent("b")).toHaveLength(1)
|
|
1165
|
+
expect(await parent("c")).toEqual([])
|
|
1166
|
+
} finally {
|
|
1167
|
+
await provider.cleanup?.(createdStorage)
|
|
1168
|
+
}
|
|
1169
|
+
})
|
|
1170
|
+
|
|
1171
|
+
// Removal proof: drop the touches source activation records from every provider; the
|
|
1172
|
+
// publication then creates the link from the assertion the other source retracted.
|
|
1173
|
+
test(`${name} plans again a link whose live assertion another source retracts`, async () => {
|
|
1174
|
+
const createdStorage = await provider.createStorage()
|
|
1175
|
+
const storage = requireContractStorage(createdStorage)
|
|
1176
|
+
const peer = { source: deviceRef("b"), linkId: "peers", target: deviceRef("a") }
|
|
1177
|
+
let armed = false
|
|
1178
|
+
const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
|
|
1179
|
+
if (!armed || inTransaction || !planned.some(({ identity }) => identity.kind === "link")) {
|
|
1180
|
+
return
|
|
1181
|
+
}
|
|
1182
|
+
armed = false
|
|
1183
|
+
// a is still missing: retracting the assertion changes no effective link.
|
|
1184
|
+
await publishPeers(contractMaterializer(storage), storage, 2, [])
|
|
1185
|
+
})
|
|
1186
|
+
const materializer = contractMaterializer(observed)
|
|
1187
|
+
try {
|
|
1188
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("b", "B")])
|
|
1189
|
+
await publishPeers(materializer, storage, 1, [peer])
|
|
1190
|
+
armed = true
|
|
1191
|
+
// Creating a brings in the link the peers source asserts towards it.
|
|
1192
|
+
await publishDevices(materializer, storage, 2, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1193
|
+
expect(armed).toBe(false)
|
|
1194
|
+
expect(
|
|
1195
|
+
await storage.objects.listLinks({
|
|
1196
|
+
projectId: CONTRACT_PROJECT,
|
|
1197
|
+
objectTypeId: Device.id,
|
|
1198
|
+
objectId: "b",
|
|
1199
|
+
linkId: "peers",
|
|
1200
|
+
})
|
|
1201
|
+
).toEqual([])
|
|
1202
|
+
} finally {
|
|
1203
|
+
await provider.cleanup?.(createdStorage)
|
|
1204
|
+
}
|
|
1205
|
+
})
|
|
1206
|
+
|
|
1207
|
+
// Removal proof: drop the lookup of links by `target_key` from the PostgreSQL and SQLite refresh,
|
|
1208
|
+
// or the target from the in-memory `touchesIdentity`; the link then stays planned as dangling.
|
|
1209
|
+
test(`${name} plans again a link whose missing target an edit creates meanwhile`, async () => {
|
|
1210
|
+
const createdStorage = await provider.createStorage()
|
|
1211
|
+
const storage = requireContractStorage(createdStorage)
|
|
1212
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1213
|
+
let armed = false
|
|
1214
|
+
const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
|
|
1215
|
+
if (!armed || inTransaction || !planned.some(({ identity }) => identity.kind === "link")) {
|
|
1216
|
+
return
|
|
1217
|
+
}
|
|
1218
|
+
armed = false
|
|
1219
|
+
await runtime.edits.commit({
|
|
1220
|
+
mode: "atomic",
|
|
1221
|
+
source: { kind: "runtime", requestId: "target-while-planned" },
|
|
1222
|
+
operations: [
|
|
1223
|
+
{ id: "create", kind: "object.create", ref: deviceRef("x"), properties: { name: "X" } },
|
|
1224
|
+
],
|
|
1225
|
+
expectedObjects: [],
|
|
1226
|
+
expectedLinks: [],
|
|
1227
|
+
expectedLinkScopes: [],
|
|
1228
|
+
})
|
|
1229
|
+
})
|
|
1230
|
+
const materializer = contractMaterializer(observed)
|
|
1231
|
+
try {
|
|
1232
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("b", "B")])
|
|
1233
|
+
armed = true
|
|
1234
|
+
await publishDevices(materializer, storage, 2, [sourceEntry("b", "B", "x")])
|
|
1235
|
+
expect(armed).toBe(false)
|
|
1236
|
+
expect(
|
|
1237
|
+
await storage.objects.listLinks({
|
|
1238
|
+
projectId: CONTRACT_PROJECT,
|
|
1239
|
+
objectTypeId: Device.id,
|
|
1240
|
+
objectId: "b",
|
|
1241
|
+
linkId: "parent",
|
|
1242
|
+
})
|
|
1243
|
+
).toMatchObject([{ targetId: "x" }])
|
|
1244
|
+
} finally {
|
|
1245
|
+
await provider.cleanup?.(createdStorage)
|
|
1246
|
+
}
|
|
1247
|
+
})
|
|
1248
|
+
|
|
1249
|
+
// Removal proof: drop the lookup of the links a touched object starts from the PostgreSQL and
|
|
1250
|
+
// SQLite refresh, or the source from the in-memory `touchesIdentity`; the publication then
|
|
1251
|
+
// plans the link from an object that no longer exists.
|
|
1252
|
+
test(`${name} plans again a link whose source an edit deletes meanwhile`, async () => {
|
|
1253
|
+
const createdStorage = await provider.createStorage()
|
|
1254
|
+
const storage = requireContractStorage(createdStorage)
|
|
1255
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1256
|
+
const edit = (requestId: string, operation: OntologyEditOperation) =>
|
|
1257
|
+
runtime.edits.commit({
|
|
1258
|
+
mode: "atomic",
|
|
1259
|
+
source: { kind: "runtime", requestId },
|
|
1260
|
+
operations: [operation],
|
|
1261
|
+
expectedObjects: [],
|
|
1262
|
+
expectedLinks: [],
|
|
1263
|
+
expectedLinkScopes: [],
|
|
1264
|
+
})
|
|
1265
|
+
let armed = false
|
|
1266
|
+
const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
|
|
1267
|
+
if (!armed || inTransaction || !planned.some(({ identity }) => identity.kind === "link")) {
|
|
1268
|
+
return
|
|
1269
|
+
}
|
|
1270
|
+
armed = false
|
|
1271
|
+
await edit("source-while-planned", {
|
|
1272
|
+
id: "delete",
|
|
1273
|
+
kind: "object.delete",
|
|
1274
|
+
ref: deviceRef("c"),
|
|
1275
|
+
})
|
|
1276
|
+
})
|
|
1277
|
+
const materializer = contractMaterializer(observed)
|
|
1278
|
+
try {
|
|
1279
|
+
await edit("create-source", {
|
|
1280
|
+
id: "create",
|
|
1281
|
+
kind: "object.create",
|
|
1282
|
+
ref: deviceRef("c"),
|
|
1283
|
+
properties: { name: "C" },
|
|
1284
|
+
})
|
|
1285
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("b", "B")])
|
|
1286
|
+
await publishPeers(materializer, storage, 1, [
|
|
1287
|
+
{ source: deviceRef("c"), linkId: "peers", target: deviceRef("a") },
|
|
1288
|
+
])
|
|
1289
|
+
armed = true
|
|
1290
|
+
// Creating a brings in the link from c the peers source asserts towards it.
|
|
1291
|
+
await publishDevices(materializer, storage, 2, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1292
|
+
expect(armed).toBe(false)
|
|
1293
|
+
expect(await device(storage, "c")).toBeNull()
|
|
1294
|
+
expect(
|
|
1295
|
+
await storage.objects.listLinks({
|
|
1296
|
+
projectId: CONTRACT_PROJECT,
|
|
1297
|
+
objectTypeId: Device.id,
|
|
1298
|
+
objectId: "c",
|
|
1299
|
+
linkId: "peers",
|
|
1300
|
+
})
|
|
1301
|
+
).toEqual([])
|
|
1302
|
+
} finally {
|
|
1303
|
+
await provider.cleanup?.(createdStorage)
|
|
1304
|
+
}
|
|
1305
|
+
})
|
|
1306
|
+
|
|
1307
|
+
// Removal proof: make SQLite's plan-bound session compare its watermark with the last commit of
|
|
1308
|
+
// any project; the commit then rejects the plan its refresh just found fresh.
|
|
1309
|
+
test(`${name} commits a plan another project committed beside`, async () => {
|
|
1310
|
+
const createdStorage = await provider.createStorage()
|
|
1311
|
+
const storage = requireContractStorage(createdStorage)
|
|
1312
|
+
const other = createOntologyMaterializer({
|
|
1313
|
+
projectId: "other-project",
|
|
1314
|
+
ontology,
|
|
1315
|
+
projections,
|
|
1316
|
+
storage,
|
|
1317
|
+
}).withScope(
|
|
1318
|
+
createTestingScope({
|
|
1319
|
+
projectId: "other-project",
|
|
1320
|
+
executionId: "other-project-runtime-execution",
|
|
1321
|
+
requestId: "other-project-runtime-request",
|
|
1322
|
+
correlationId: "other-project-runtime-correlation",
|
|
1323
|
+
})
|
|
1324
|
+
)
|
|
1325
|
+
let armed = false
|
|
1326
|
+
let staged = 0
|
|
1327
|
+
const observed = observePlanning(storage, async (planned) => {
|
|
1328
|
+
if (!armed) return
|
|
1329
|
+
staged += planned.length
|
|
1330
|
+
if (staged !== 1) return
|
|
1331
|
+
await other.edits.commit({
|
|
1332
|
+
mode: "atomic",
|
|
1333
|
+
source: { kind: "runtime", requestId: "other-project-edit" },
|
|
1334
|
+
operations: [
|
|
1335
|
+
{ id: "create", kind: "object.create", ref: deviceRef("x"), properties: { name: "X" } },
|
|
1336
|
+
],
|
|
1337
|
+
expectedObjects: [],
|
|
1338
|
+
expectedLinks: [],
|
|
1339
|
+
expectedLinkScopes: [],
|
|
1340
|
+
})
|
|
1341
|
+
})
|
|
1342
|
+
const materializer = contractMaterializer(observed)
|
|
1343
|
+
try {
|
|
1344
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
|
|
1345
|
+
armed = true
|
|
1346
|
+
await publishDevices(materializer, storage, 2, [
|
|
1347
|
+
sourceEntry("a", "A2"),
|
|
1348
|
+
sourceEntry("b", "B"),
|
|
1349
|
+
])
|
|
1350
|
+
expect(staged).toBe(2)
|
|
1351
|
+
expect(await device(storage, "b")).toMatchObject({ properties: { name: "B" } })
|
|
1352
|
+
} finally {
|
|
1353
|
+
await provider.cleanup?.(createdStorage)
|
|
1354
|
+
}
|
|
1355
|
+
})
|
|
1356
|
+
|
|
1357
|
+
// Removal proof: in PostgreSQL's `committedSince`, count only commits at or past the
|
|
1358
|
+
// watermark's xmax; the edit, in flight when the plan opened, is then taken as seen.
|
|
1359
|
+
if (provider.concurrentTransactions) {
|
|
1360
|
+
test(`${name} plans again what a commit in flight when the plan opened changed`, async () => {
|
|
1361
|
+
const createdStorage = await provider.createStorage()
|
|
1362
|
+
const storage = requireContractStorage(createdStorage)
|
|
1363
|
+
const paused = pauseBeforeFinalize(storage)
|
|
1364
|
+
const runtime = contractMaterializer(paused.storage).withScope(runtimeScope())
|
|
1365
|
+
let edit: Promise<unknown> | undefined
|
|
1366
|
+
let armed = false
|
|
1367
|
+
let staged = 0
|
|
1368
|
+
const observed = observePlanning(storage, async (planned) => {
|
|
1369
|
+
if (!armed) return
|
|
1370
|
+
staged += planned.length
|
|
1371
|
+
if (staged !== 1) return
|
|
1372
|
+
// The page read the object before the edit committed.
|
|
1373
|
+
paused.release()
|
|
1374
|
+
await edit
|
|
1375
|
+
})
|
|
1376
|
+
const materializer = contractMaterializer(observed)
|
|
1377
|
+
try {
|
|
1378
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
|
|
1379
|
+
edit = runtime.edits.commit({
|
|
1380
|
+
mode: "atomic",
|
|
1381
|
+
source: { kind: "runtime", requestId: "edit-in-flight" },
|
|
1382
|
+
operations: [
|
|
1383
|
+
{
|
|
1384
|
+
id: "rename",
|
|
1385
|
+
kind: "object.patch",
|
|
1386
|
+
ref: deviceRef("a"),
|
|
1387
|
+
set: { name: "edited" },
|
|
1388
|
+
unset: [],
|
|
1389
|
+
reset: [],
|
|
1390
|
+
},
|
|
1391
|
+
],
|
|
1392
|
+
expectedObjects: [],
|
|
1393
|
+
expectedLinks: [],
|
|
1394
|
+
expectedLinkScopes: [],
|
|
1395
|
+
})
|
|
1396
|
+
// It has written the object and holds its transaction open.
|
|
1397
|
+
await paused.reached
|
|
1398
|
+
armed = true
|
|
1399
|
+
await publishDevices(materializer, storage, 2, [sourceEntry("a", "A2")])
|
|
1400
|
+
await edit
|
|
1401
|
+
expect(staged).toBe(2)
|
|
1402
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
|
|
1403
|
+
} finally {
|
|
1404
|
+
paused.release()
|
|
1405
|
+
await provider.cleanup?.(createdStorage)
|
|
1406
|
+
}
|
|
1407
|
+
})
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// Removal proof: let the in-memory `streamState` keep the identities it listed instead of
|
|
1411
|
+
// looking each page's up again; the rollback restores the plan as copies, and the next page
|
|
1412
|
+
// marks as read identities the plan no longer holds.
|
|
1413
|
+
test(`${name} keeps planning across a transaction that rolls back meanwhile`, async () => {
|
|
1414
|
+
const createdStorage = await provider.createStorage()
|
|
1415
|
+
const storage = requireContractStorage(createdStorage)
|
|
1416
|
+
let staged = 0
|
|
1417
|
+
const observed = observePlanning(storage, async (planned) => {
|
|
1418
|
+
staged += planned.length
|
|
1419
|
+
if (staged !== 1) return
|
|
1420
|
+
await expect(
|
|
1421
|
+
storage.transaction(async () => {
|
|
1422
|
+
throw new Error("rolled back")
|
|
1423
|
+
})
|
|
1424
|
+
).rejects.toThrow("rolled back")
|
|
1425
|
+
})
|
|
1426
|
+
const materializer = contractMaterializer(observed)
|
|
1427
|
+
try {
|
|
1428
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1429
|
+
expect(staged).toBe(2)
|
|
1430
|
+
expect(await device(storage, "b")).toMatchObject({ properties: { name: "B" } })
|
|
1431
|
+
} finally {
|
|
1432
|
+
await provider.cleanup?.(createdStorage)
|
|
1433
|
+
}
|
|
1434
|
+
})
|
|
1435
|
+
|
|
1436
|
+
// Removal proof: in PostgreSQL's `committedSince`, drop the check of a watermark from beyond
|
|
1437
|
+
// this snapshot (the stale plan applies and conflicts with the edit), or the filter on commits
|
|
1438
|
+
// this snapshot sees (no plan reads as just refreshed again).
|
|
1439
|
+
const restoreFromClusterAhead = provider.restoreFromClusterAhead
|
|
1440
|
+
if (restoreFromClusterAhead) {
|
|
1441
|
+
test(`${name} plans again after a restore from a cluster further along`, async () => {
|
|
1442
|
+
const createdStorage = await provider.createStorage()
|
|
1443
|
+
const storage = requireContractStorage(createdStorage)
|
|
1444
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1445
|
+
let failNextCommit = false
|
|
1446
|
+
let staged = 0
|
|
1447
|
+
const observed = observePlanning(
|
|
1448
|
+
storage,
|
|
1449
|
+
async (planned) => {
|
|
1450
|
+
staged += planned.length
|
|
1451
|
+
},
|
|
1452
|
+
async () => {
|
|
1453
|
+
if (!failNextCommit || staged === 0) return
|
|
1454
|
+
failNextCommit = false
|
|
1455
|
+
throw new Error("commit lost")
|
|
1456
|
+
}
|
|
1457
|
+
)
|
|
1458
|
+
const materializer = contractMaterializer(observed)
|
|
1459
|
+
try {
|
|
1460
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
|
|
1461
|
+
const execution = await claimDevices(storage, 2)
|
|
1462
|
+
failNextCommit = true
|
|
1463
|
+
staged = 0
|
|
1464
|
+
await expect(
|
|
1465
|
+
publishDevices(materializer, storage, 2, [sourceEntry("a", "A2")], execution)
|
|
1466
|
+
).rejects.toThrow("commit lost")
|
|
1467
|
+
await runtime.edits.commit({
|
|
1468
|
+
mode: "atomic",
|
|
1469
|
+
source: { kind: "runtime", requestId: "edit-before-restore" },
|
|
1470
|
+
operations: [
|
|
1471
|
+
{
|
|
1472
|
+
id: "rename",
|
|
1473
|
+
kind: "object.patch",
|
|
1474
|
+
ref: deviceRef("a"),
|
|
1475
|
+
set: { name: "edited" },
|
|
1476
|
+
unset: [],
|
|
1477
|
+
reset: [],
|
|
1478
|
+
},
|
|
1479
|
+
],
|
|
1480
|
+
expectedObjects: [],
|
|
1481
|
+
expectedLinks: [],
|
|
1482
|
+
expectedLinkScopes: [],
|
|
1483
|
+
})
|
|
1484
|
+
await restoreFromClusterAhead(createdStorage)
|
|
1485
|
+
await publishDevices(materializer, storage, 2, [sourceEntry("a", "A2")], execution)
|
|
1486
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
|
|
1487
|
+
} finally {
|
|
1488
|
+
await provider.cleanup?.(createdStorage)
|
|
1489
|
+
}
|
|
1490
|
+
})
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// Removal proof: let `open` reset an existing plan; the redelivery stages all three identities
|
|
1494
|
+
// again. Let it keep the plan but answer the time it was given: the redelivery cannot commit.
|
|
1495
|
+
test(`${name} resumes the plan a failed commit left to the next delivery`, async () => {
|
|
1496
|
+
const createdStorage = await provider.createStorage()
|
|
1497
|
+
const storage = requireContractStorage(createdStorage)
|
|
1498
|
+
let failNextCommit = true
|
|
1499
|
+
let stagedIdentities = 0
|
|
1500
|
+
let plannedAt: string | undefined
|
|
1501
|
+
const observed = observePlanning(
|
|
1502
|
+
storage,
|
|
1503
|
+
async (planned, commit) => {
|
|
1504
|
+
stagedIdentities += planned.length
|
|
1505
|
+
plannedAt ??= commit.committedAt
|
|
1506
|
+
},
|
|
1507
|
+
async () => {
|
|
1508
|
+
// Admission opens a transaction before anything is planned: fail the commit's.
|
|
1509
|
+
if (!failNextCommit || stagedIdentities === 0) return
|
|
1510
|
+
failNextCommit = false
|
|
1511
|
+
throw new Error("commit lost")
|
|
1512
|
+
}
|
|
1513
|
+
)
|
|
1514
|
+
const materializer = contractMaterializer(observed)
|
|
1515
|
+
try {
|
|
1516
|
+
const execution = await claimDevices(storage, 1)
|
|
1517
|
+
const values = [sourceEntry("a", "A"), sourceEntry("b", "B", "a")]
|
|
1518
|
+
await expect(publishDevices(materializer, storage, 1, values, execution)).rejects.toThrow(
|
|
1519
|
+
"commit lost"
|
|
1520
|
+
)
|
|
1521
|
+
expect(stagedIdentities).toBe(3)
|
|
1522
|
+
// The redelivery's clock has moved on; its commit keeps the time its events were planned at.
|
|
1523
|
+
await new Promise((resolve) => setTimeout(resolve, 5))
|
|
1524
|
+
const result = await publishDevices(materializer, storage, 1, values, execution)
|
|
1525
|
+
expect(stagedIdentities).toBe(3)
|
|
1526
|
+
expect(result.committedAt).toBe(plannedAt!)
|
|
1527
|
+
expect(await device(storage, "b")).toMatchObject({ properties: { name: "B" } })
|
|
1528
|
+
} finally {
|
|
1529
|
+
await provider.cleanup?.(createdStorage)
|
|
1530
|
+
}
|
|
1531
|
+
})
|
|
1532
|
+
|
|
1533
|
+
// Removal proof: let `open` resume a plan whatever source it replaces; the redelivery then
|
|
1534
|
+
// keeps an entity only the newer active source asserted, or rejects its own activation.
|
|
1535
|
+
test(`${name} plans again from scratch when the source a plan replaces moved`, async () => {
|
|
1536
|
+
const createdStorage = await provider.createStorage()
|
|
1537
|
+
const storage = requireContractStorage(createdStorage)
|
|
1538
|
+
let failNextCommit = false
|
|
1539
|
+
let staged = 0
|
|
1540
|
+
const observed = observePlanning(
|
|
1541
|
+
storage,
|
|
1542
|
+
async (planned) => {
|
|
1543
|
+
staged += planned.length
|
|
1544
|
+
},
|
|
1545
|
+
async () => {
|
|
1546
|
+
if (!failNextCommit || staged === 0) return
|
|
1547
|
+
failNextCommit = false
|
|
1548
|
+
throw new Error("commit lost")
|
|
1549
|
+
}
|
|
1550
|
+
)
|
|
1551
|
+
const materializer = contractMaterializer(observed)
|
|
1552
|
+
try {
|
|
1553
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
|
|
1554
|
+
const execution = await claimDevices(storage, 3)
|
|
1555
|
+
failNextCommit = true
|
|
1556
|
+
staged = 0
|
|
1557
|
+
await expect(
|
|
1558
|
+
publishDevices(materializer, storage, 3, [sourceEntry("a", "A3")], execution)
|
|
1559
|
+
).rejects.toThrow("commit lost")
|
|
1560
|
+
await publishDevices(materializer, storage, 2, [
|
|
1561
|
+
sourceEntry("a", "A2"),
|
|
1562
|
+
sourceEntry("z", "Z"),
|
|
1563
|
+
])
|
|
1564
|
+
staged = 0
|
|
1565
|
+
await publishDevices(materializer, storage, 3, [sourceEntry("a", "A3")], execution)
|
|
1566
|
+
expect(staged).toBe(2)
|
|
1567
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "A3" } })
|
|
1568
|
+
expect(await device(storage, "z")).toBeNull()
|
|
1569
|
+
} finally {
|
|
1570
|
+
await provider.cleanup?.(createdStorage)
|
|
1571
|
+
}
|
|
1572
|
+
})
|
|
1573
|
+
|
|
1574
|
+
// Removal proof: drop the round bound in `commitProjectionCandidate`; the delivery plans again
|
|
1575
|
+
// after every edit and never returns. Drop the `transactionReplanRows` bound from
|
|
1576
|
+
// `refreshProjectionPlan`: the commit then plans both edits itself and the publication lands.
|
|
1577
|
+
test(`${name} gives the delivery back when identities keep changing while planned`, async () => {
|
|
1578
|
+
const createdStorage = await provider.createStorage()
|
|
1579
|
+
const storage = requireContractStorage(createdStorage)
|
|
1580
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1581
|
+
let armed = false
|
|
1582
|
+
let edits = 0
|
|
1583
|
+
const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
|
|
1584
|
+
// Once both are read: each round finds them both stale.
|
|
1585
|
+
if (!armed || inTransaction || !planned.some((value) => plannedId(value) === "b")) return
|
|
1586
|
+
edits += 1
|
|
1587
|
+
await runtime.edits.commit({
|
|
1588
|
+
mode: "atomic",
|
|
1589
|
+
source: { kind: "runtime", requestId: `keeps-changing-${edits}` },
|
|
1590
|
+
operations: ["a", "b"].map((id) => ({
|
|
1591
|
+
id: `rename-${id}`,
|
|
1592
|
+
kind: "object.patch" as const,
|
|
1593
|
+
ref: deviceRef(id),
|
|
1594
|
+
set: { name: `${id}${edits}` },
|
|
1595
|
+
unset: [],
|
|
1596
|
+
reset: [],
|
|
1597
|
+
})),
|
|
1598
|
+
expectedObjects: [],
|
|
1599
|
+
expectedLinks: [],
|
|
1600
|
+
expectedLinkScopes: [],
|
|
1601
|
+
})
|
|
1602
|
+
})
|
|
1603
|
+
// Two stale identities are more than its commit plans itself.
|
|
1604
|
+
const materializer = contractMaterializer(observed, { transactionReplanRows: 1 })
|
|
1605
|
+
try {
|
|
1606
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1607
|
+
armed = true
|
|
1608
|
+
await expect(
|
|
1609
|
+
publishDevices(materializer, storage, 2, [sourceEntry("a", "A2"), sourceEntry("b", "B2")])
|
|
1610
|
+
).rejects.toMatchObject({
|
|
1611
|
+
kind: "effective-state",
|
|
1612
|
+
message: expect.stringContaining("(2 changed during the last of 3 rounds)"),
|
|
1613
|
+
})
|
|
1614
|
+
expect(edits).toBe(3)
|
|
1615
|
+
} finally {
|
|
1616
|
+
await provider.cleanup?.(createdStorage)
|
|
1617
|
+
}
|
|
1618
|
+
})
|
|
1619
|
+
|
|
1620
|
+
// Removal proof: drop the purge of touches from every provider's `purge`; touches outlive
|
|
1621
|
+
// every plan. Let it ignore the watermark of ready plans: it then keeps none of the touches the
|
|
1622
|
+
// resumed plan needs.
|
|
1623
|
+
test(`${name} purges only the touches no ready plan still needs`, async () => {
|
|
1624
|
+
const createdStorage = await provider.createStorage()
|
|
1625
|
+
const storage = requireContractStorage(createdStorage)
|
|
1626
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1627
|
+
let failNextCommit = false
|
|
1628
|
+
let staged = 0
|
|
1629
|
+
const observed = observePlanning(
|
|
1630
|
+
storage,
|
|
1631
|
+
async (planned) => {
|
|
1632
|
+
staged += planned.length
|
|
1633
|
+
},
|
|
1634
|
+
async () => {
|
|
1635
|
+
if (!failNextCommit || staged === 0) return
|
|
1636
|
+
failNextCommit = false
|
|
1637
|
+
throw new Error("commit lost")
|
|
1638
|
+
}
|
|
1639
|
+
)
|
|
1640
|
+
const materializer = contractMaterializer(observed)
|
|
1641
|
+
try {
|
|
1642
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1643
|
+
const execution = await claimDevices(storage, 2)
|
|
1644
|
+
failNextCommit = true
|
|
1645
|
+
staged = 0
|
|
1646
|
+
const values = [sourceEntry("a", "A2"), sourceEntry("b", "B2")]
|
|
1647
|
+
await expect(publishDevices(materializer, storage, 2, values, execution)).rejects.toThrow(
|
|
1648
|
+
"commit lost"
|
|
1649
|
+
)
|
|
1650
|
+
await renameDevice(runtime, "a", "edited")
|
|
1651
|
+
const recorded = await provider.countCommitTouches(createdStorage)
|
|
1652
|
+
await purgeEverything(storage)
|
|
1653
|
+
// The edit committed after the plan last read a: the plan still needs what it touched.
|
|
1654
|
+
const kept = await provider.countCommitTouches(createdStorage)
|
|
1655
|
+
expect(kept).toBeGreaterThan(0)
|
|
1656
|
+
expect(kept).toBeLessThan(recorded)
|
|
1657
|
+
|
|
1658
|
+
await publishDevices(materializer, storage, 2, values, execution)
|
|
1659
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
|
|
1660
|
+
await purgeEverything(storage)
|
|
1661
|
+
expect(await provider.countCommitTouches(createdStorage)).toBe(0)
|
|
1662
|
+
} finally {
|
|
1663
|
+
await provider.cleanup?.(createdStorage)
|
|
1664
|
+
}
|
|
1665
|
+
})
|
|
1666
|
+
|
|
1667
|
+
// Removal proof: drop the horizon from PostgreSQL's `touchesIncomplete`; the refresh then finds
|
|
1668
|
+
// no touch for the edit, and the stale upsert of a conflicts with it.
|
|
1669
|
+
const losePlanTouchesToPurge = provider.losePlanTouchesToPurge
|
|
1670
|
+
if (losePlanTouchesToPurge) {
|
|
1671
|
+
test(`${name} checks every identity of a plan whose touches a racing purge took`, async () => {
|
|
1672
|
+
const createdStorage = await provider.createStorage()
|
|
1673
|
+
const storage = requireContractStorage(createdStorage)
|
|
1674
|
+
const runtime = contractMaterializer(storage).withScope(runtimeScope())
|
|
1675
|
+
let failNextCommit = false
|
|
1676
|
+
let staged = 0
|
|
1677
|
+
const observed = observePlanning(
|
|
1678
|
+
storage,
|
|
1679
|
+
async (planned) => {
|
|
1680
|
+
staged += planned.length
|
|
1681
|
+
},
|
|
1682
|
+
async () => {
|
|
1683
|
+
if (!failNextCommit || staged === 0) return
|
|
1684
|
+
failNextCommit = false
|
|
1685
|
+
throw new Error("commit lost")
|
|
1686
|
+
}
|
|
1687
|
+
)
|
|
1688
|
+
const materializer = contractMaterializer(observed)
|
|
1689
|
+
try {
|
|
1690
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
|
|
1691
|
+
const execution = await claimDevices(storage, 2)
|
|
1692
|
+
failNextCommit = true
|
|
1693
|
+
staged = 0
|
|
1694
|
+
const values = [sourceEntry("a", "A2")]
|
|
1695
|
+
await expect(publishDevices(materializer, storage, 2, values, execution)).rejects.toThrow(
|
|
1696
|
+
"commit lost"
|
|
1697
|
+
)
|
|
1698
|
+
await renameDevice(runtime, "a", "edited")
|
|
1699
|
+
await losePlanTouchesToPurge(createdStorage)
|
|
1700
|
+
await publishDevices(materializer, storage, 2, values, execution)
|
|
1701
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
|
|
1702
|
+
} finally {
|
|
1703
|
+
await provider.cleanup?.(createdStorage)
|
|
1704
|
+
}
|
|
1705
|
+
})
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// Removal proof: let `purge` take plans whose candidate is still ready; the second delivery
|
|
1709
|
+
// then plans every identity again instead of resuming. Let it stop after one plan: a second
|
|
1710
|
+
// call still finds the other.
|
|
1711
|
+
test(`${name} purges only the plans of candidates that moved on`, async () => {
|
|
1712
|
+
const createdStorage = await provider.createStorage()
|
|
1713
|
+
const storage = requireContractStorage(createdStorage)
|
|
1714
|
+
let interrupt = false
|
|
1715
|
+
let staged = 0
|
|
1716
|
+
const observed = observePlanning(storage, async (planned) => {
|
|
1717
|
+
staged += planned.length
|
|
1718
|
+
if (interrupt && staged === 1) throw new Error("delivery lost")
|
|
1719
|
+
})
|
|
1720
|
+
const materializer = contractMaterializer(observed)
|
|
1721
|
+
const purgeAll = async () => {
|
|
1722
|
+
let rounds = 0
|
|
1723
|
+
while (
|
|
1724
|
+
(await storage.ontology.replacementPlans.purge({ projectId: CONTRACT_PROJECT, limit: 2 })) >
|
|
1725
|
+
0
|
|
1726
|
+
) {
|
|
1727
|
+
rounds += 1
|
|
1728
|
+
if (rounds > 100) throw new Error("Plan purge never ran out.")
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
try {
|
|
1732
|
+
await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
|
|
1733
|
+
await purgeAll()
|
|
1734
|
+
const execution = await claimDevices(storage, 2)
|
|
1735
|
+
const values = [sourceEntry("a", "A2"), sourceEntry("c", "C")]
|
|
1736
|
+
interrupt = true
|
|
1737
|
+
staged = 0
|
|
1738
|
+
await expect(publishDevices(materializer, storage, 2, values, execution)).rejects.toThrow(
|
|
1739
|
+
"delivery lost"
|
|
1740
|
+
)
|
|
1741
|
+
interrupt = false
|
|
1742
|
+
await purgeAll()
|
|
1743
|
+
staged = 0
|
|
1744
|
+
await publishDevices(materializer, storage, 2, values, execution)
|
|
1745
|
+
expect(staged).toBe(2)
|
|
1746
|
+
// Two spent plans: one call within its budget purges both.
|
|
1747
|
+
await publishDevices(materializer, storage, 3, values)
|
|
1748
|
+
await storage.ontology.replacementPlans.purge({ projectId: CONTRACT_PROJECT, limit: 1_000 })
|
|
1749
|
+
expect(
|
|
1750
|
+
await storage.ontology.replacementPlans.purge({ projectId: CONTRACT_PROJECT, limit: 1_000 })
|
|
1751
|
+
).toBe(0)
|
|
1752
|
+
expect(await device(storage, "a")).toMatchObject({ properties: { name: "A2" } })
|
|
1753
|
+
expect(await device(storage, "b")).toBeNull()
|
|
1754
|
+
expect(await device(storage, "c")).toMatchObject({ properties: { name: "C" } })
|
|
1755
|
+
} finally {
|
|
1756
|
+
await provider.cleanup?.(createdStorage)
|
|
1757
|
+
}
|
|
1758
|
+
})
|
|
985
1759
|
}
|
|
986
1760
|
|
|
987
1761
|
function runtimeScope() {
|
|
@@ -1128,3 +1902,236 @@ async function claim(
|
|
|
1128
1902
|
})
|
|
1129
1903
|
return claim.execution
|
|
1130
1904
|
}
|
|
1905
|
+
|
|
1906
|
+
const CONTRACT_PROJECT = "materializer-storage-contract"
|
|
1907
|
+
|
|
1908
|
+
function contractMaterializer(
|
|
1909
|
+
storage: Storage,
|
|
1910
|
+
batching: { readonly transactionReplanRows?: number } = {}
|
|
1911
|
+
): OntologyMaterializer {
|
|
1912
|
+
return createOntologyMaterializer({
|
|
1913
|
+
projectId: CONTRACT_PROJECT,
|
|
1914
|
+
ontology,
|
|
1915
|
+
projections,
|
|
1916
|
+
storage,
|
|
1917
|
+
dependencies: {
|
|
1918
|
+
batching: { sourceStageRows: 1, statePageRows: 1, planChunkRows: 1, ...batching },
|
|
1919
|
+
},
|
|
1920
|
+
})
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
function deviceRef(primaryId: string) {
|
|
1924
|
+
return { objectTypeId: Device.id, primaryId }
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
function device(storage: ContractStorage, primaryId: string) {
|
|
1928
|
+
return storage.objects.getByPrimaryId({ projectId: CONTRACT_PROJECT, ...deviceRef(primaryId) })
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
function plannedId({ identity }: PlannedReplacementIdentity): string {
|
|
1932
|
+
return identity.kind === "object" ? identity.ref.primaryId : "link"
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
/**
|
|
1936
|
+
* The same storage, whose plan staging runs `afterStage` once a page is staged, inside or outside a
|
|
1937
|
+
* commit transaction, and whose transactions run `beforeTransaction` first: a way to interleave
|
|
1938
|
+
* writes with a projection's plan. A write from `afterStage` must stay outside the transaction.
|
|
1939
|
+
*/
|
|
1940
|
+
function observePlanning(
|
|
1941
|
+
storage: ContractStorage,
|
|
1942
|
+
afterStage: (
|
|
1943
|
+
planned: readonly PlannedReplacementIdentity[],
|
|
1944
|
+
commit: OntologyCommitWrite,
|
|
1945
|
+
inTransaction: boolean
|
|
1946
|
+
) => Promise<void>,
|
|
1947
|
+
beforeTransaction?: () => Promise<void>
|
|
1948
|
+
): ContractStorage {
|
|
1949
|
+
const observe = <T extends Storage>(scoped: T, inTransaction: boolean): T => {
|
|
1950
|
+
const plans = scoped.ontology.replacementPlans
|
|
1951
|
+
const observed: OntologyReplacementPlanStorage = {
|
|
1952
|
+
open: (input) => plans.open(input),
|
|
1953
|
+
streamState: (input) => plans.streamState(input),
|
|
1954
|
+
async stage(input) {
|
|
1955
|
+
await plans.stage(input)
|
|
1956
|
+
await afterStage(input.planned, input.commit, inTransaction)
|
|
1957
|
+
},
|
|
1958
|
+
refresh: (input) => plans.refresh(input),
|
|
1959
|
+
purge: (input) => plans.purge(input),
|
|
1960
|
+
}
|
|
1961
|
+
const ontologyFacade = new Proxy(scoped.ontology, {
|
|
1962
|
+
get(target, property) {
|
|
1963
|
+
if (property === "replacementPlans") return observed
|
|
1964
|
+
const value = Reflect.get(target, property, target)
|
|
1965
|
+
return typeof value === "function" ? value.bind(target) : value
|
|
1966
|
+
},
|
|
1967
|
+
})
|
|
1968
|
+
return new Proxy(scoped, {
|
|
1969
|
+
get(target, property) {
|
|
1970
|
+
if (property === "ontology") return ontologyFacade
|
|
1971
|
+
if (property === "transaction") {
|
|
1972
|
+
return async (
|
|
1973
|
+
run: (tx: Storage) => unknown,
|
|
1974
|
+
options?: Parameters<Storage["transaction"]>[1]
|
|
1975
|
+
) => {
|
|
1976
|
+
await beforeTransaction?.()
|
|
1977
|
+
return target.transaction((tx) => run(observe(tx, true)), options)
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
const value = Reflect.get(target, property, target)
|
|
1981
|
+
return typeof value === "function" ? value.bind(target) : value
|
|
1982
|
+
},
|
|
1983
|
+
})
|
|
1984
|
+
}
|
|
1985
|
+
return observe(storage, false)
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
/** The same storage, whose transactions wait before they finalize until `release` is called. */
|
|
1989
|
+
function pauseBeforeFinalize(storage: ContractStorage) {
|
|
1990
|
+
let reach!: () => void
|
|
1991
|
+
const reached = new Promise<void>((resolve) => {
|
|
1992
|
+
reach = resolve
|
|
1993
|
+
})
|
|
1994
|
+
let release!: () => void
|
|
1995
|
+
const released = new Promise<void>((resolve) => {
|
|
1996
|
+
release = resolve
|
|
1997
|
+
})
|
|
1998
|
+
const paused = new Proxy(storage, {
|
|
1999
|
+
get(target, property) {
|
|
2000
|
+
if (property !== "transaction") {
|
|
2001
|
+
const value = Reflect.get(target, property, target)
|
|
2002
|
+
return typeof value === "function" ? value.bind(target) : value
|
|
2003
|
+
}
|
|
2004
|
+
return (run: (tx: Storage) => unknown, options?: Parameters<Storage["transaction"]>[1]) =>
|
|
2005
|
+
target.transaction((tx) => {
|
|
2006
|
+
const materializations = new Proxy(tx.ontology.materializations, {
|
|
2007
|
+
get(store, key) {
|
|
2008
|
+
const value = Reflect.get(store, key, store)
|
|
2009
|
+
if (key !== "finalize") return typeof value === "function" ? value.bind(store) : value
|
|
2010
|
+
return async (...args: Parameters<typeof store.finalize>) => {
|
|
2011
|
+
reach()
|
|
2012
|
+
await released
|
|
2013
|
+
return store.finalize(...args)
|
|
2014
|
+
}
|
|
2015
|
+
},
|
|
2016
|
+
})
|
|
2017
|
+
const ontology = new Proxy(tx.ontology, {
|
|
2018
|
+
get: (store, key) =>
|
|
2019
|
+
key === "materializations" ? materializations : Reflect.get(store, key, store),
|
|
2020
|
+
})
|
|
2021
|
+
return run(
|
|
2022
|
+
new Proxy(tx, {
|
|
2023
|
+
get: (store, key) => (key === "ontology" ? ontology : Reflect.get(store, key, store)),
|
|
2024
|
+
})
|
|
2025
|
+
)
|
|
2026
|
+
}, options)
|
|
2027
|
+
},
|
|
2028
|
+
})
|
|
2029
|
+
return { storage: paused, reached, release }
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
function deviceVersion(version: number) {
|
|
2033
|
+
return {
|
|
2034
|
+
datasetId: devices.id,
|
|
2035
|
+
versionId: `plan-v${version}`,
|
|
2036
|
+
createdAt: `2026-02-${String(version).padStart(2, "0")}T00:00:00.000Z`,
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
function claimDevices(storage: ContractStorage, version: number): Promise<ProjectionExecution> {
|
|
2041
|
+
return claim(storage, {
|
|
2042
|
+
runId: `plan-run-${version}`,
|
|
2043
|
+
projectionId: devices.id,
|
|
2044
|
+
protocol: "replacement",
|
|
2045
|
+
datasetVersion: deviceVersion(version),
|
|
2046
|
+
})
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
function renameDevice(
|
|
2050
|
+
runtime: ReturnType<OntologyMaterializer["withScope"]>,
|
|
2051
|
+
primaryId: string,
|
|
2052
|
+
name: string
|
|
2053
|
+
) {
|
|
2054
|
+
return runtime.edits.commit({
|
|
2055
|
+
mode: "atomic",
|
|
2056
|
+
source: { kind: "runtime", requestId: `rename-${primaryId}-${name}` },
|
|
2057
|
+
operations: [
|
|
2058
|
+
{
|
|
2059
|
+
id: "rename",
|
|
2060
|
+
kind: "object.patch",
|
|
2061
|
+
ref: deviceRef(primaryId),
|
|
2062
|
+
set: { name },
|
|
2063
|
+
unset: [],
|
|
2064
|
+
reset: [],
|
|
2065
|
+
},
|
|
2066
|
+
],
|
|
2067
|
+
expectedObjects: [],
|
|
2068
|
+
expectedLinks: [],
|
|
2069
|
+
expectedLinkScopes: [],
|
|
2070
|
+
})
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
async function purgeEverything(storage: ContractStorage): Promise<void> {
|
|
2074
|
+
for (let rounds = 0; ; rounds += 1) {
|
|
2075
|
+
if (rounds > 100) throw new Error("Plan purge never ran out.")
|
|
2076
|
+
const deleted = await storage.ontology.replacementPlans.purge({
|
|
2077
|
+
projectId: CONTRACT_PROJECT,
|
|
2078
|
+
limit: 2,
|
|
2079
|
+
})
|
|
2080
|
+
if (deleted === 0) return
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
async function publishPeers(
|
|
2085
|
+
materializer: OntologyMaterializer,
|
|
2086
|
+
storage: ContractStorage,
|
|
2087
|
+
version: number,
|
|
2088
|
+
refs: readonly OntologyLinkRef[]
|
|
2089
|
+
) {
|
|
2090
|
+
const datasetVersion = {
|
|
2091
|
+
datasetId: devicePeers.id,
|
|
2092
|
+
versionId: `peers-v${version}`,
|
|
2093
|
+
createdAt: `2026-02-${String(version).padStart(2, "0")}T00:00:00.000Z`,
|
|
2094
|
+
}
|
|
2095
|
+
const execution = await claim(storage, {
|
|
2096
|
+
runId: `peers-run-${version}`,
|
|
2097
|
+
projectionId: devicePeersProjection.id,
|
|
2098
|
+
protocol: "replacement",
|
|
2099
|
+
datasetVersion,
|
|
2100
|
+
})
|
|
2101
|
+
const bound = await projectionMaterializer(
|
|
2102
|
+
materializer,
|
|
2103
|
+
storage,
|
|
2104
|
+
devicePeersProjection.id,
|
|
2105
|
+
execution.projectionRunId
|
|
2106
|
+
)
|
|
2107
|
+
return bound.projections.replace({
|
|
2108
|
+
source: { projectionId: devicePeersProjection.id },
|
|
2109
|
+
datasetVersion,
|
|
2110
|
+
execution,
|
|
2111
|
+
entries: entries(
|
|
2112
|
+
refs.map((ref) => ({ root: { kind: "link", ref }, assertions: [{ kind: "link", ref }] }))
|
|
2113
|
+
),
|
|
2114
|
+
})
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
async function publishDevices(
|
|
2118
|
+
materializer: OntologyMaterializer,
|
|
2119
|
+
storage: ContractStorage,
|
|
2120
|
+
version: number,
|
|
2121
|
+
values: readonly ProjectionSourceEntry[],
|
|
2122
|
+
execution?: ProjectionExecution
|
|
2123
|
+
) {
|
|
2124
|
+
const claimed = execution ?? (await claimDevices(storage, version))
|
|
2125
|
+
const bound = await projectionMaterializer(
|
|
2126
|
+
materializer,
|
|
2127
|
+
storage,
|
|
2128
|
+
devices.id,
|
|
2129
|
+
claimed.projectionRunId
|
|
2130
|
+
)
|
|
2131
|
+
return bound.projections.replace({
|
|
2132
|
+
source: { projectionId: devices.id },
|
|
2133
|
+
datasetVersion: deviceVersion(version),
|
|
2134
|
+
execution: claimed,
|
|
2135
|
+
entries: entries(values),
|
|
2136
|
+
})
|
|
2137
|
+
}
|