@sixb/core 0.1.2 → 0.1.4
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 +19 -17
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/worker.js +4 -4
- package/dist/actions/worker.js.map +1 -1
- package/dist/agents/adapters.d.ts +11 -1
- package/dist/agents/adapters.d.ts.map +1 -1
- package/dist/agents/context-compaction.d.ts +40 -0
- package/dist/agents/context-compaction.d.ts.map +1 -0
- package/dist/agents/context.js +1 -1
- package/dist/agents/errors.d.ts +1 -1
- package/dist/agents/errors.d.ts.map +1 -1
- package/dist/agents/execution.d.ts +3 -0
- package/dist/agents/execution.d.ts.map +1 -1
- package/dist/agents/ids.d.ts +2 -0
- package/dist/agents/ids.d.ts.map +1 -1
- package/dist/agents/index.d.ts +10 -6
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +51 -35
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/request.d.ts.map +1 -1
- package/dist/agents/streams.d.ts +17 -1
- package/dist/agents/streams.d.ts.map +1 -1
- package/dist/agents/streams.js +5 -3
- package/dist/agents/streams.js.map +1 -1
- package/dist/agents/thread-context-projection.d.ts +19 -0
- package/dist/agents/thread-context-projection.d.ts.map +1 -0
- package/dist/agents/tool-definition.d.ts.map +1 -1
- package/dist/agents/tool-result.d.ts +6 -0
- package/dist/agents/tool-result.d.ts.map +1 -0
- package/dist/agents/types.d.ts +46 -1
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/validation.d.ts +2 -2
- package/dist/agents/validation.d.ts.map +1 -1
- package/dist/auth/index.js +11 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/authorization/index.js +6 -2
- package/dist/authorization/index.js.map +1 -1
- package/dist/bootstrap/index.js +33 -31
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/{chunk-ys1nse2v.js → chunk-1wk20wn3.js} +438 -246
- package/dist/{chunk-ys1nse2v.js.map → chunk-1wk20wn3.js.map} +11 -11
- package/dist/{chunk-sa4340y1.js → chunk-1yz3x65y.js} +7 -7
- package/dist/{chunk-gqdd7508.js → chunk-4rh2m6zg.js} +1 -1
- package/dist/{chunk-fmx1sz2h.js → chunk-72q2y8hn.js} +3 -3
- package/dist/{chunk-fmx1sz2h.js.map → chunk-72q2y8hn.js.map} +4 -4
- package/dist/{chunk-nnyp53zt.js → chunk-7gw7mepb.js} +259 -9
- package/dist/chunk-7gw7mepb.js.map +14 -0
- package/dist/{chunk-nten49ta.js → chunk-819wnjz8.js} +11 -5
- package/dist/chunk-819wnjz8.js.map +12 -0
- package/dist/chunk-96swp2wd.js +47 -0
- package/dist/chunk-96swp2wd.js.map +10 -0
- package/dist/{chunk-4x43bkbp.js → chunk-a09jx26t.js} +1 -1
- package/dist/{chunk-st4xgxey.js → chunk-afjpa2hs.js} +205 -48
- package/dist/chunk-afjpa2hs.js.map +45 -0
- package/dist/{chunk-0mbx247x.js → chunk-c43qr6s0.js} +427 -99
- package/dist/chunk-c43qr6s0.js.map +46 -0
- package/dist/{chunk-zg9yryhz.js → chunk-cbkm2vam.js} +3 -3
- package/dist/{chunk-57zpb99z.js → chunk-dm72y8wt.js} +26 -3
- package/dist/chunk-dm72y8wt.js.map +10 -0
- package/dist/chunk-drjqm1aa.js +913 -0
- package/dist/chunk-drjqm1aa.js.map +15 -0
- package/dist/chunk-dysw7nsm.js.map +1 -1
- package/dist/{chunk-8ryen3p3.js → chunk-f6erf2vv.js} +1 -1
- package/dist/{chunk-34bqh420.js → chunk-f83ka50g.js} +188 -44
- package/dist/chunk-f83ka50g.js.map +23 -0
- package/dist/{chunk-bct7hmfc.js → chunk-g13869yf.js} +3 -3
- package/dist/{chunk-0k4avqr2.js → chunk-hbeh8j9w.js} +2 -2
- package/dist/{chunk-qvybnnpe.js → chunk-nzw7sm3b.js} +2 -2
- package/dist/{chunk-k9pts48t.js → chunk-pn8n8sba.js} +16 -15
- package/dist/{chunk-k9pts48t.js.map → chunk-pn8n8sba.js.map} +3 -3
- package/dist/{chunk-63te770v.js → chunk-qewtks41.js} +8 -8
- package/dist/{chunk-63te770v.js.map → chunk-qewtks41.js.map} +2 -2
- package/dist/{chunk-85j5ybfj.js → chunk-rdeagz6b.js} +2 -2
- package/dist/{chunk-85j5ybfj.js.map → chunk-rdeagz6b.js.map} +3 -3
- package/dist/chunk-rhrbz7d4.js +36 -0
- package/dist/chunk-rhrbz7d4.js.map +10 -0
- package/dist/{chunk-bh6k3nc6.js → chunk-rs1wbvy6.js} +1 -1
- package/dist/{chunk-88ppkr54.js → chunk-rte5sm3z.js} +26 -2
- package/dist/chunk-rte5sm3z.js.map +12 -0
- package/dist/{chunk-n8herkry.js → chunk-s31d0qmq.js} +57 -20
- package/dist/{chunk-n8herkry.js.map → chunk-s31d0qmq.js.map} +8 -7
- package/dist/{chunk-7pc8b818.js → chunk-sxwk41qa.js} +1 -1
- package/dist/{chunk-663csy96.js → chunk-t0jjkep3.js} +2 -1
- package/dist/chunk-t0jjkep3.js.map +10 -0
- package/dist/{chunk-c6qd89g5.js → chunk-tek1qwgm.js} +6 -6
- package/dist/{chunk-c6qd89g5.js.map → chunk-tek1qwgm.js.map} +1 -1
- package/dist/{chunk-jaj13078.js → chunk-tkdscva6.js} +3 -33
- package/dist/{chunk-jaj13078.js.map → chunk-tkdscva6.js.map} +3 -4
- package/dist/{chunk-5egfka8j.js → chunk-tycbzedm.js} +2 -2
- package/dist/{chunk-g9t3kdtx.js → chunk-x2yw73hy.js} +1 -1
- package/dist/{chunk-57r1cpxx.js → chunk-xc7hq65b.js} +3 -2
- package/dist/{chunk-57r1cpxx.js.map → chunk-xc7hq65b.js.map} +3 -3
- package/dist/chunk-xdf9yswn.js +133 -0
- package/dist/chunk-xdf9yswn.js.map +11 -0
- package/dist/execution/agent.js +29 -27
- package/dist/execution/agent.js.map +1 -1
- package/dist/execution/primitive.js +29 -27
- package/dist/execution/primitive.js.map +2 -2
- package/dist/execution/request.js +30 -28
- package/dist/execution/request.js.map +2 -2
- package/dist/http/index.js +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +60 -58
- package/dist/index.js.map +1 -1
- package/dist/lake-storage/types.d.ts +2 -1
- package/dist/lake-storage/types.d.ts.map +1 -1
- package/dist/materialization/model.d.ts +4 -0
- package/dist/materialization/model.d.ts.map +1 -1
- package/dist/materializer/edits/apply.d.ts +6 -1
- package/dist/materializer/edits/apply.d.ts.map +1 -1
- package/dist/materializer/edits/working-state.d.ts +2 -0
- package/dist/materializer/edits/working-state.d.ts.map +1 -1
- package/dist/materializer/effective/resolve.d.ts +3 -1
- package/dist/materializer/effective/resolve.d.ts.map +1 -1
- package/dist/materializer/execution/work-records.d.ts.map +1 -1
- package/dist/materializer/index.js +19 -17
- package/dist/materializer/index.js.map +1 -1
- package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
- package/dist/materializer/shared/normalize.d.ts.map +1 -1
- package/dist/models/index.d.ts +40 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/objects/execution.d.ts +6 -1
- package/dist/objects/execution.d.ts.map +1 -1
- package/dist/objects/index.js +21 -19
- package/dist/objects/index.js.map +1 -1
- package/dist/objects/link/endpoints.d.ts.map +1 -1
- package/dist/objects/query/executor.d.ts +1 -0
- package/dist/objects/query/executor.d.ts.map +1 -1
- package/dist/objects/query/explain.d.ts +1 -0
- package/dist/objects/query/explain.d.ts.map +1 -1
- package/dist/objects/query/index.d.ts +3 -1
- package/dist/objects/query/index.d.ts.map +1 -1
- package/dist/objects/query/index.js +30 -5
- package/dist/objects/query/index.js.map +1 -1
- package/dist/objects/query/ir.d.ts +14 -1
- package/dist/objects/query/ir.d.ts.map +1 -1
- package/dist/objects/query/links.d.ts +25 -0
- package/dist/objects/query/links.d.ts.map +1 -0
- package/dist/objects/query/normalize.d.ts.map +1 -1
- package/dist/objects/query/planner.d.ts.map +1 -1
- package/dist/objects/query/validate.d.ts +1 -0
- package/dist/objects/query/validate.d.ts.map +1 -1
- package/dist/pipelines/index.js +16 -15
- package/dist/pipelines/index.js.map +1 -1
- package/dist/projections/builders.d.ts +52 -10
- package/dist/projections/builders.d.ts.map +1 -1
- package/dist/projections/index.d.ts +2 -1
- package/dist/projections/index.d.ts.map +1 -1
- package/dist/projections/internal.d.ts +4 -1
- package/dist/projections/internal.d.ts.map +1 -1
- package/dist/projections/internal.js +22 -17
- package/dist/projections/internal.js.map +1 -1
- package/dist/projections/run-dispatch.d.ts +1 -0
- package/dist/projections/run-dispatch.d.ts.map +1 -1
- package/dist/projections/timestamp.d.ts +3 -0
- package/dist/projections/timestamp.d.ts.map +1 -0
- package/dist/projections/types.d.ts +21 -9
- package/dist/projections/types.d.ts.map +1 -1
- package/dist/projections/validation.d.ts +6 -5
- package/dist/projections/validation.d.ts.map +1 -1
- package/dist/query.d.ts +2 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +2 -2
- package/dist/queues/index.d.ts +1 -1
- package/dist/queues/index.d.ts.map +1 -1
- package/dist/queues/types.d.ts +7 -0
- package/dist/queues/types.d.ts.map +1 -1
- package/dist/runtime/ai-cost.d.ts +8 -0
- package/dist/runtime/ai-cost.d.ts.map +1 -0
- package/dist/runtime/create.d.ts +3 -0
- package/dist/runtime/create.d.ts.map +1 -1
- package/dist/runtime/definitions.d.ts +3 -0
- package/dist/runtime/definitions.d.ts.map +1 -1
- package/dist/runtime/host.d.ts +2 -0
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/resolve-definitions.d.ts +2 -0
- package/dist/runtime/resolve-definitions.d.ts.map +1 -1
- package/dist/storage/agents/in-memory.d.ts +22 -4
- package/dist/storage/agents/in-memory.d.ts.map +1 -1
- package/dist/storage/agents/index.d.ts +1 -1
- package/dist/storage/agents/index.d.ts.map +1 -1
- package/dist/storage/agents/provider.d.ts +31 -0
- package/dist/storage/agents/provider.d.ts.map +1 -1
- package/dist/storage/agents/provider.js +22 -7
- package/dist/storage/agents/provider.js.map +1 -1
- package/dist/storage/agents/types.d.ts +75 -4
- package/dist/storage/agents/types.d.ts.map +1 -1
- package/dist/storage/ai-cost/analytics.d.ts +61 -0
- package/dist/storage/ai-cost/analytics.d.ts.map +1 -0
- package/dist/storage/ai-cost/codec.d.ts +14 -0
- package/dist/storage/ai-cost/codec.d.ts.map +1 -0
- package/dist/storage/ai-cost/errors.d.ts +7 -0
- package/dist/storage/ai-cost/errors.d.ts.map +1 -0
- package/dist/storage/ai-cost/in-memory.d.ts +32 -0
- package/dist/storage/ai-cost/in-memory.d.ts.map +1 -0
- package/dist/storage/ai-cost/index.d.ts +6 -0
- package/dist/storage/ai-cost/index.d.ts.map +1 -0
- package/dist/storage/ai-cost/provider.d.ts +7 -0
- package/dist/storage/ai-cost/provider.d.ts.map +1 -0
- package/dist/storage/ai-cost/provider.js +132 -0
- package/dist/storage/ai-cost/provider.js.map +10 -0
- package/dist/storage/ai-cost/types.d.ts +154 -0
- package/dist/storage/ai-cost/types.d.ts.map +1 -0
- package/dist/storage/ai-cost/validation.d.ts +7 -0
- package/dist/storage/ai-cost/validation.d.ts.map +1 -0
- package/dist/storage/ai-usage/in-memory.d.ts +2 -1
- package/dist/storage/ai-usage/in-memory.d.ts.map +1 -1
- package/dist/storage/ai-usage/index.d.ts +1 -1
- package/dist/storage/ai-usage/index.d.ts.map +1 -1
- package/dist/storage/ai-usage/types.d.ts +6 -0
- package/dist/storage/ai-usage/types.d.ts.map +1 -1
- package/dist/storage/in-memory/index.d.ts +5 -0
- package/dist/storage/in-memory/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +6 -3
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +33 -21
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/objects/in-memory.d.ts +6 -3
- package/dist/storage/objects/in-memory.d.ts.map +1 -1
- package/dist/storage/objects/index.d.ts +3 -1
- package/dist/storage/objects/index.d.ts.map +1 -1
- package/dist/storage/objects/keys.d.ts +16 -0
- package/dist/storage/objects/keys.d.ts.map +1 -0
- package/dist/storage/objects/types.d.ts +33 -6
- package/dist/storage/objects/types.d.ts.map +1 -1
- package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/materializations.d.ts +3 -0
- package/dist/storage/ontology/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/provider.js +1 -1
- package/dist/storage/operation-scope.d.ts.map +1 -1
- package/dist/storage/operation-scope.js +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 +10 -5
- package/dist/storage/workflow-runs/provider.js.map +1 -1
- package/dist/syncs/index.js +16 -15
- package/dist/syncs/index.js.map +1 -1
- package/dist/testing/agent-storage-contract.d.ts +3 -2
- package/dist/testing/agent-storage-contract.d.ts.map +1 -1
- package/dist/testing/ai-cost-storage-contract.d.ts +12 -0
- package/dist/testing/ai-cost-storage-contract.d.ts.map +1 -0
- package/dist/testing/ai-usage-storage-contract.d.ts.map +1 -1
- package/dist/testing/effective-storage-contract.d.ts +1 -1
- package/dist/testing/effective-storage-contract.d.ts.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2525 -1480
- package/dist/testing/index.js.map +10 -9
- package/dist/testing/lake-storage-contract.d.ts.map +1 -1
- package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
- package/dist/testing/object-query-contract.d.ts +1 -1
- package/dist/testing/object-query-contract.d.ts.map +1 -1
- package/dist/webhooks/internal.js +14 -13
- package/dist/webhooks/internal.js.map +2 -2
- package/dist/workers/index.js +12 -2
- package/dist/workers/index.js.map +3 -3
- package/dist/workers/queue-worker.d.ts +2 -0
- package/dist/workers/queue-worker.d.ts.map +1 -1
- package/dist/workflows/execution.d.ts +3 -0
- package/dist/workflows/execution.d.ts.map +1 -1
- package/dist/workflows/index.js +30 -28
- package/dist/workflows/index.js.map +1 -1
- package/package.json +7 -1
- package/src/agents/adapters.ts +64 -23
- package/src/agents/builders.ts +3 -3
- package/src/agents/context-compaction.ts +261 -0
- package/src/agents/errors.ts +2 -2
- package/src/agents/execution.ts +14 -2
- package/src/agents/ids.ts +5 -0
- package/src/agents/index.ts +32 -6
- package/src/agents/request.ts +5 -0
- package/src/agents/streams.ts +56 -0
- package/src/agents/thread-context-projection.ts +93 -0
- package/src/agents/tool-definition.ts +17 -2
- package/src/agents/tool-result.ts +61 -0
- package/src/agents/types.ts +57 -1
- package/src/agents/validation.ts +36 -6
- package/src/http/api-routes.ts +7 -7
- package/src/index.ts +27 -0
- package/src/lake-storage/types.ts +2 -1
- package/src/materialization/model.ts +4 -0
- package/src/materializer/edits/apply.ts +55 -2
- package/src/materializer/edits/operations.ts +8 -1
- package/src/materializer/edits/working-state.ts +7 -0
- package/src/materializer/effective/resolve.ts +78 -9
- package/src/materializer/execution/work-records.ts +3 -1
- package/src/materializer/projections/entry-validator.ts +23 -1
- package/src/materializer/projections/replacement-plan.ts +2 -0
- package/src/materializer/shared/normalize.ts +16 -0
- package/src/materializer/telemetry/append.ts +33 -16
- package/src/models/index.ts +71 -0
- package/src/objects/execution.ts +20 -0
- package/src/objects/link/endpoints.ts +2 -1
- package/src/objects/query/executor.ts +42 -11
- package/src/objects/query/explain.ts +11 -0
- package/src/objects/query/index.ts +6 -0
- package/src/objects/query/ir.ts +16 -0
- package/src/objects/query/links.ts +308 -0
- package/src/objects/query/normalize.ts +40 -1
- package/src/objects/query/planner.ts +5 -0
- package/src/objects/query/validate.ts +58 -2
- package/src/projections/builders.ts +320 -50
- package/src/projections/index.ts +7 -0
- package/src/projections/internal.ts +4 -1
- package/src/projections/ownership.ts +5 -5
- package/src/projections/registry.ts +16 -3
- package/src/projections/revision.ts +35 -5
- package/src/projections/run-dispatch.ts +10 -1
- package/src/projections/timestamp.ts +66 -0
- package/src/projections/types.ts +20 -9
- package/src/projections/validation.ts +85 -19
- package/src/query.ts +2 -0
- package/src/queues/index.ts +1 -0
- package/src/queues/types.ts +8 -0
- package/src/runtime/ai-cost.ts +15 -0
- package/src/runtime/create.ts +4 -0
- package/src/runtime/definitions.ts +3 -0
- package/src/runtime/host.ts +2 -0
- package/src/runtime/resolve-definitions.ts +28 -0
- package/src/storage/agents/in-memory.ts +186 -4
- package/src/storage/agents/index.ts +5 -0
- package/src/storage/agents/provider.ts +225 -0
- package/src/storage/agents/types.ts +82 -3
- package/src/storage/ai-cost/analytics.ts +602 -0
- package/src/storage/ai-cost/codec.ts +136 -0
- package/src/storage/ai-cost/errors.ts +12 -0
- package/src/storage/ai-cost/in-memory.ts +164 -0
- package/src/storage/ai-cost/index.ts +35 -0
- package/src/storage/ai-cost/provider.ts +20 -0
- package/src/storage/ai-cost/types.ts +193 -0
- package/src/storage/ai-cost/validation.ts +337 -0
- package/src/storage/ai-usage/in-memory.ts +23 -0
- package/src/storage/ai-usage/index.ts +1 -0
- package/src/storage/ai-usage/types.ts +10 -0
- package/src/storage/in-memory/index.ts +50 -0
- package/src/storage/index.ts +48 -0
- package/src/storage/objects/in-memory.ts +103 -16
- package/src/storage/objects/index.ts +9 -0
- package/src/storage/objects/keys.ts +36 -0
- package/src/storage/objects/types.ts +34 -6
- package/src/storage/ontology/in-memory/materializations.ts +1 -0
- package/src/storage/ontology/materializations.ts +3 -0
- package/src/storage/ontology/provider-header-validation.ts +2 -2
- package/src/storage/operation-scope.ts +1 -0
- package/src/storage/types.ts +2 -0
- package/src/testing/agent-storage-contract.ts +353 -2
- package/src/testing/ai-cost-storage-contract.ts +320 -0
- package/src/testing/ai-usage-storage-contract.ts +35 -0
- package/src/testing/effective-storage-contract.ts +194 -4
- package/src/testing/index.ts +5 -0
- package/src/testing/lake-storage-contract.ts +56 -0
- package/src/testing/materializer-storage-contract.ts +120 -2
- package/src/testing/object-query-contract.ts +208 -1
- package/src/workers/queue-worker.ts +14 -1
- package/src/workflows/execution.ts +31 -10
- package/dist/agents/prompt.d.ts +0 -15
- package/dist/agents/prompt.d.ts.map +0 -1
- package/dist/chunk-0mbx247x.js.map +0 -43
- package/dist/chunk-34bqh420.js.map +0 -23
- package/dist/chunk-57zpb99z.js.map +0 -10
- package/dist/chunk-663csy96.js.map +0 -10
- package/dist/chunk-6wetht33.js +0 -89
- package/dist/chunk-6wetht33.js.map +0 -10
- package/dist/chunk-88ppkr54.js.map +0 -12
- package/dist/chunk-nnyp53zt.js.map +0 -13
- package/dist/chunk-nten49ta.js.map +0 -12
- package/dist/chunk-st4xgxey.js.map +0 -45
- package/dist/chunk-vp1vc6ee.js +0 -35
- package/dist/chunk-vp1vc6ee.js.map +0 -11
- package/src/agents/prompt.ts +0 -57
- /package/dist/{chunk-sa4340y1.js.map → chunk-1yz3x65y.js.map} +0 -0
- /package/dist/{chunk-gqdd7508.js.map → chunk-4rh2m6zg.js.map} +0 -0
- /package/dist/{chunk-4x43bkbp.js.map → chunk-a09jx26t.js.map} +0 -0
- /package/dist/{chunk-zg9yryhz.js.map → chunk-cbkm2vam.js.map} +0 -0
- /package/dist/{chunk-8ryen3p3.js.map → chunk-f6erf2vv.js.map} +0 -0
- /package/dist/{chunk-bct7hmfc.js.map → chunk-g13869yf.js.map} +0 -0
- /package/dist/{chunk-0k4avqr2.js.map → chunk-hbeh8j9w.js.map} +0 -0
- /package/dist/{chunk-qvybnnpe.js.map → chunk-nzw7sm3b.js.map} +0 -0
- /package/dist/{chunk-bh6k3nc6.js.map → chunk-rs1wbvy6.js.map} +0 -0
- /package/dist/{chunk-7pc8b818.js.map → chunk-sxwk41qa.js.map} +0 -0
- /package/dist/{chunk-5egfka8j.js.map → chunk-tycbzedm.js.map} +0 -0
- /package/dist/{chunk-g9t3kdtx.js.map → chunk-x2yw73hy.js.map} +0 -0
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ExpandedLinkValue,
|
|
8
8
|
ExpandedObjectRow,
|
|
9
9
|
FacetObjectsResult,
|
|
10
|
+
ObjectBatchKey,
|
|
10
11
|
ObjectFacetRequest,
|
|
11
12
|
ObjectFacetResult,
|
|
12
13
|
ObjectLinkRow,
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
ObjectStorage,
|
|
17
18
|
QueryObjectsResult,
|
|
18
19
|
} from "../../storage"
|
|
20
|
+
import { linkBatchKey, objectBatchKey } from "../../storage"
|
|
19
21
|
import {
|
|
20
22
|
ObjectQueryExecutionError,
|
|
21
23
|
ObjectQueryPlanningError,
|
|
@@ -52,6 +54,7 @@ export interface QueryExecutorOptions
|
|
|
52
54
|
storage: ObjectStorage
|
|
53
55
|
maxLimit?: number
|
|
54
56
|
maxPageSize?: number
|
|
57
|
+
maxRefs?: number
|
|
55
58
|
maxFacetLimit?: number
|
|
56
59
|
/**
|
|
57
60
|
* Per-parent cap on how many links a single `expand` hydrates, applied as a
|
|
@@ -132,6 +135,7 @@ export async function executeObjectQuery(
|
|
|
132
135
|
ontology: options.ontology,
|
|
133
136
|
maxLimit: options.maxLimit,
|
|
134
137
|
maxPageSize: options.maxPageSize,
|
|
138
|
+
maxRefs: options.maxRefs,
|
|
135
139
|
normalize: false,
|
|
136
140
|
})
|
|
137
141
|
assertQueryViewable(validated, options)
|
|
@@ -199,6 +203,7 @@ export async function countObjects(
|
|
|
199
203
|
ontology: options.ontology,
|
|
200
204
|
maxLimit: options.maxLimit,
|
|
201
205
|
maxPageSize: options.maxPageSize,
|
|
206
|
+
maxRefs: options.maxRefs,
|
|
202
207
|
normalize: false,
|
|
203
208
|
})
|
|
204
209
|
assertQueryViewable(validated, options)
|
|
@@ -259,6 +264,7 @@ export async function existsObjects(
|
|
|
259
264
|
ontology: options.ontology,
|
|
260
265
|
maxLimit: options.maxLimit,
|
|
261
266
|
maxPageSize: options.maxPageSize,
|
|
267
|
+
maxRefs: options.maxRefs,
|
|
262
268
|
normalize: false,
|
|
263
269
|
})
|
|
264
270
|
assertQueryViewable(validated, options)
|
|
@@ -319,6 +325,7 @@ export async function facetObjects(
|
|
|
319
325
|
ontology: options.ontology,
|
|
320
326
|
maxLimit: options.maxLimit,
|
|
321
327
|
maxPageSize: options.maxPageSize,
|
|
328
|
+
maxRefs: options.maxRefs,
|
|
322
329
|
normalize: false,
|
|
323
330
|
})
|
|
324
331
|
assertQueryViewable(validated, options)
|
|
@@ -435,6 +442,7 @@ function resolveExpansions(query: ObjectQuery, ctx: ExpansionResolutionContext):
|
|
|
435
442
|
}
|
|
436
443
|
}
|
|
437
444
|
case "start":
|
|
445
|
+
case "refs":
|
|
438
446
|
return query
|
|
439
447
|
case "set":
|
|
440
448
|
return {
|
|
@@ -555,6 +563,8 @@ function expandIncludeSubtypes(query: ObjectQuery, ontology: OntologyRegistry):
|
|
|
555
563
|
inputs: objectTypeIds.map((objectTypeId) => ({ kind: "start", objectTypeId })),
|
|
556
564
|
}
|
|
557
565
|
}
|
|
566
|
+
case "refs":
|
|
567
|
+
return query
|
|
558
568
|
case "filter":
|
|
559
569
|
case "text":
|
|
560
570
|
case "vector":
|
|
@@ -598,6 +608,8 @@ async function evaluateFallbackQuery(
|
|
|
598
608
|
switch (query.kind) {
|
|
599
609
|
case "start":
|
|
600
610
|
return evaluateFallbackStart(projectId, query, options, maxRows)
|
|
611
|
+
case "refs":
|
|
612
|
+
return evaluateFallbackRefs(projectId, query, options)
|
|
601
613
|
case "filter": {
|
|
602
614
|
const input = await evaluateFallbackQuery(projectId, query.input, options, maxRows)
|
|
603
615
|
return completeFallbackEvaluation(
|
|
@@ -672,6 +684,23 @@ async function evaluateFallbackQuery(
|
|
|
672
684
|
}
|
|
673
685
|
}
|
|
674
686
|
|
|
687
|
+
async function evaluateFallbackRefs(
|
|
688
|
+
projectId: string,
|
|
689
|
+
query: Extract<ObjectQuery, { kind: "refs" }>,
|
|
690
|
+
options: QueryExecutorOptions
|
|
691
|
+
): Promise<FallbackEvaluation> {
|
|
692
|
+
const rows = await options.storage.getByPrimaryIdBatch({
|
|
693
|
+
projectId,
|
|
694
|
+
items: query.refs,
|
|
695
|
+
})
|
|
696
|
+
return completeFallbackEvaluation(
|
|
697
|
+
query.refs.flatMap((ref, order) => {
|
|
698
|
+
const row = rows.get(objectBatchKey(ref.objectTypeId, ref.primaryId))
|
|
699
|
+
return row ? [{ row, order }] : []
|
|
700
|
+
})
|
|
701
|
+
)
|
|
702
|
+
}
|
|
703
|
+
|
|
675
704
|
/**
|
|
676
705
|
* A candidate neighbour for one parent under a single expansion: the object to
|
|
677
706
|
* hydrate plus the metadata carried on the link edge. For outgoing expansions
|
|
@@ -769,7 +798,9 @@ async function collectOutgoingEdges(
|
|
|
769
798
|
})
|
|
770
799
|
|
|
771
800
|
return parents.map((parent) => {
|
|
772
|
-
const links = linksByKey.get(
|
|
801
|
+
const links = linksByKey.get(
|
|
802
|
+
linkBatchKey(parent.objectTypeId, parent.primaryId, expansion.linkId)
|
|
803
|
+
)
|
|
773
804
|
if (!links) return []
|
|
774
805
|
return links.map((link) => ({
|
|
775
806
|
neighborTypeId: link.targetTypeId,
|
|
@@ -821,8 +852,8 @@ async function fetchExpansionTargets(
|
|
|
821
852
|
projectId: string,
|
|
822
853
|
edgesByParent: readonly ExpansionEdge[][],
|
|
823
854
|
options: QueryExecutorOptions
|
|
824
|
-
): Promise<
|
|
825
|
-
const seen = new Set<
|
|
855
|
+
): Promise<ReadonlyMap<ObjectBatchKey, ObjectRow>> {
|
|
856
|
+
const seen = new Set<ObjectBatchKey>()
|
|
826
857
|
const items: { objectTypeId: string; primaryId: string }[] = []
|
|
827
858
|
for (const edges of edgesByParent) {
|
|
828
859
|
for (const edge of edges) {
|
|
@@ -841,10 +872,10 @@ async function fetchExpansionTargets(
|
|
|
841
872
|
async function enrichExpansionTargets(
|
|
842
873
|
projectId: string,
|
|
843
874
|
trimmedByParent: readonly ExpansionEdge[][],
|
|
844
|
-
baseTargets:
|
|
875
|
+
baseTargets: ReadonlyMap<ObjectBatchKey, ObjectRow>,
|
|
845
876
|
expansion: ObjectExpansion,
|
|
846
877
|
options: QueryExecutorOptions
|
|
847
|
-
): Promise<
|
|
878
|
+
): Promise<ReadonlyMap<ObjectBatchKey, ObjectRow>> {
|
|
848
879
|
if (!expansion.expand || expansion.expand.length === 0) {
|
|
849
880
|
return baseTargets
|
|
850
881
|
}
|
|
@@ -862,7 +893,7 @@ async function enrichExpansionTargets(
|
|
|
862
893
|
}
|
|
863
894
|
|
|
864
895
|
const enriched = await hydrateExpansions(projectId, uniqueTargets, expansion.expand, options)
|
|
865
|
-
const enrichedByKey = new Map<
|
|
896
|
+
const enrichedByKey = new Map<ObjectBatchKey, ObjectRow>()
|
|
866
897
|
for (const row of enriched) {
|
|
867
898
|
enrichedByKey.set(targetKey(row.objectTypeId, row.primaryId), row)
|
|
868
899
|
}
|
|
@@ -872,7 +903,7 @@ async function enrichExpansionTargets(
|
|
|
872
903
|
function trimExpansionEdges(
|
|
873
904
|
edges: readonly ExpansionEdge[],
|
|
874
905
|
expansion: ObjectExpansion,
|
|
875
|
-
baseTargets:
|
|
906
|
+
baseTargets: ReadonlyMap<ObjectBatchKey, ObjectRow>,
|
|
876
907
|
options: QueryExecutorOptions
|
|
877
908
|
): ExpansionEdge[] {
|
|
878
909
|
let ordered = edges
|
|
@@ -899,7 +930,7 @@ function compareExpansionEdges(
|
|
|
899
930
|
left: ExpansionEdge,
|
|
900
931
|
right: ExpansionEdge,
|
|
901
932
|
fields: readonly ObjectQuerySortField[],
|
|
902
|
-
baseTargets:
|
|
933
|
+
baseTargets: ReadonlyMap<ObjectBatchKey, ObjectRow>
|
|
903
934
|
): number {
|
|
904
935
|
const leftRow = baseTargets.get(targetKey(left.neighborTypeId, left.neighborId))
|
|
905
936
|
const rightRow = baseTargets.get(targetKey(right.neighborTypeId, right.neighborId))
|
|
@@ -954,8 +985,8 @@ function toLinkValue(
|
|
|
954
985
|
return rows
|
|
955
986
|
}
|
|
956
987
|
|
|
957
|
-
function targetKey(objectTypeId: string, id: string):
|
|
958
|
-
return
|
|
988
|
+
function targetKey(objectTypeId: string, id: string): ObjectBatchKey {
|
|
989
|
+
return objectBatchKey(objectTypeId, id)
|
|
959
990
|
}
|
|
960
991
|
|
|
961
992
|
async function evaluateFallbackStart(
|
|
@@ -1300,7 +1331,7 @@ function facetValueSortKey(value: unknown): string {
|
|
|
1300
1331
|
}
|
|
1301
1332
|
|
|
1302
1333
|
function rowIdentityKey(row: ObjectRow): string {
|
|
1303
|
-
return
|
|
1334
|
+
return objectBatchKey(row.objectTypeId, row.primaryId)
|
|
1304
1335
|
}
|
|
1305
1336
|
|
|
1306
1337
|
function encodePageOffset(offset: number): string {
|
|
@@ -18,6 +18,7 @@ export interface ObjectQueryExplainOptions {
|
|
|
18
18
|
normalize?: boolean
|
|
19
19
|
maxLimit?: number
|
|
20
20
|
maxPageSize?: number
|
|
21
|
+
maxRefs?: number
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export interface ObjectQueryExplanation {
|
|
@@ -47,6 +48,7 @@ export function explainObjectQuery(
|
|
|
47
48
|
ontology: options.ontology,
|
|
48
49
|
maxLimit: options.maxLimit,
|
|
49
50
|
maxPageSize: options.maxPageSize,
|
|
51
|
+
maxRefs: options.maxRefs,
|
|
50
52
|
normalize: false,
|
|
51
53
|
})
|
|
52
54
|
: []
|
|
@@ -57,6 +59,7 @@ export function explainObjectQuery(
|
|
|
57
59
|
ontology: options.ontology,
|
|
58
60
|
maxLimit: options.maxLimit,
|
|
59
61
|
maxPageSize: options.maxPageSize,
|
|
62
|
+
maxRefs: options.maxRefs,
|
|
60
63
|
normalize: false,
|
|
61
64
|
}).result
|
|
62
65
|
: undefined
|
|
@@ -84,6 +87,14 @@ function buildExplainNode(query: ObjectQuery, path: string): ObjectQueryExplainN
|
|
|
84
87
|
},
|
|
85
88
|
children: [],
|
|
86
89
|
}
|
|
90
|
+
case "refs":
|
|
91
|
+
return {
|
|
92
|
+
path,
|
|
93
|
+
kind: query.kind,
|
|
94
|
+
summary: `refs ${query.refs.length}`,
|
|
95
|
+
details: { refs: query.refs },
|
|
96
|
+
children: [],
|
|
97
|
+
}
|
|
87
98
|
case "filter":
|
|
88
99
|
return {
|
|
89
100
|
path,
|
|
@@ -44,6 +44,7 @@ export type {
|
|
|
44
44
|
ObjectQueryPredicateIn,
|
|
45
45
|
ObjectQueryPredicateNot,
|
|
46
46
|
ObjectQueryProject,
|
|
47
|
+
ObjectQueryRefs,
|
|
47
48
|
ObjectQueryResultShape,
|
|
48
49
|
ObjectQuerySet,
|
|
49
50
|
ObjectQuerySetOperation,
|
|
@@ -56,6 +57,11 @@ export type {
|
|
|
56
57
|
ObjectQueryVector,
|
|
57
58
|
QueryScalarKind,
|
|
58
59
|
} from "./ir"
|
|
60
|
+
export type {
|
|
61
|
+
ExecuteObjectQueryLinksInput,
|
|
62
|
+
ExecuteObjectQueryLinksResult,
|
|
63
|
+
} from "./links"
|
|
64
|
+
export { executeObjectQueryLinks } from "./links"
|
|
59
65
|
export { normalizeObjectQuery, normalizeObjectQueryPredicate } from "./normalize"
|
|
60
66
|
export type {
|
|
61
67
|
ObjectQueryPlan,
|
package/src/objects/query/ir.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* storage backend. Providers can push down the subset they support, while the
|
|
6
6
|
* core planner decides whether a bounded fallback is acceptable.
|
|
7
7
|
*/
|
|
8
|
+
import type { ObjectRef } from "../../ontology/refs"
|
|
9
|
+
|
|
8
10
|
export type ObjectQueryDirection = "outgoing" | "incoming"
|
|
9
11
|
export type ObjectQuerySetOperation = "union" | "intersect" | "subtract"
|
|
10
12
|
export type ObjectQuerySortDirection = "asc" | "desc"
|
|
@@ -21,6 +23,7 @@ export type QueryScalarKind =
|
|
|
21
23
|
|
|
22
24
|
export type ObjectQuery =
|
|
23
25
|
| ObjectQueryStart
|
|
26
|
+
| ObjectQueryRefs
|
|
24
27
|
| ObjectQueryFilter
|
|
25
28
|
| ObjectQueryText
|
|
26
29
|
| ObjectQueryVector
|
|
@@ -38,6 +41,19 @@ export interface ObjectQueryStart {
|
|
|
38
41
|
includeSubtypes?: boolean
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Starts a query from an explicit, heterogeneous set of object identities.
|
|
46
|
+
*
|
|
47
|
+
* Unlike `start`, this source is intrinsically bounded. Providers can compile
|
|
48
|
+
* it natively for composition with the rest of the IR; core resolves it through
|
|
49
|
+
* `getByPrimaryIdBatch` when pushdown is unavailable. Normalization removes
|
|
50
|
+
* duplicate identities and orders the set canonically by type and primary id.
|
|
51
|
+
*/
|
|
52
|
+
export interface ObjectQueryRefs {
|
|
53
|
+
kind: "refs"
|
|
54
|
+
refs: readonly ObjectRef[]
|
|
55
|
+
}
|
|
56
|
+
|
|
41
57
|
export interface ObjectQueryFilter {
|
|
42
58
|
kind: "filter"
|
|
43
59
|
input: ObjectQuery
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { createHash } from "node:crypto"
|
|
2
|
+
import { isAllowed } from "../../authorization"
|
|
3
|
+
import { stableJsonStringify } from "../../json"
|
|
4
|
+
import {
|
|
5
|
+
type LinkDirection,
|
|
6
|
+
type ObjectBatchKey,
|
|
7
|
+
type ObjectLinkCursor,
|
|
8
|
+
type ObjectLinkRow,
|
|
9
|
+
type ObjectRow,
|
|
10
|
+
type ObjectStorage,
|
|
11
|
+
objectBatchKey,
|
|
12
|
+
objectLinkCursor,
|
|
13
|
+
} from "../../storage"
|
|
14
|
+
import { ObjectQueryExecutionError } from "./errors"
|
|
15
|
+
import { executeObjectQuery, type QueryExecutorOptions } from "./executor"
|
|
16
|
+
import type { ObjectQuery } from "./ir"
|
|
17
|
+
import { normalizeObjectQuery } from "./normalize"
|
|
18
|
+
import { validateObjectQuery } from "./validate"
|
|
19
|
+
|
|
20
|
+
export interface ExecuteObjectQueryLinksInput {
|
|
21
|
+
projectId: string
|
|
22
|
+
query: ObjectQuery
|
|
23
|
+
direction?: LinkDirection
|
|
24
|
+
linkId?: string
|
|
25
|
+
includeObjects?: boolean
|
|
26
|
+
pageSize?: number
|
|
27
|
+
pageToken?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ExecuteObjectQueryLinksResult {
|
|
31
|
+
objects: readonly ObjectRow[]
|
|
32
|
+
links: readonly ObjectLinkRow[]
|
|
33
|
+
hasMore: boolean
|
|
34
|
+
nextPageToken?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const MAX_LINK_QUERY_OBJECTS = 1_000
|
|
38
|
+
const MAX_LINK_PAGE_SIZE = 1_000
|
|
39
|
+
const DEFAULT_LINK_PAGE_SIZE = 100
|
|
40
|
+
const LINK_PAGE_TOKEN_PREFIX = "link:v1:"
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Select a bounded object set with the query IR, then return physical links
|
|
44
|
+
* incident to that set. This is a separate terminal because edge rows and edge
|
|
45
|
+
* pagination are a different response contract from object-set queries.
|
|
46
|
+
*/
|
|
47
|
+
export async function executeObjectQueryLinks(
|
|
48
|
+
input: ExecuteObjectQueryLinksInput,
|
|
49
|
+
options: QueryExecutorOptions
|
|
50
|
+
): Promise<ExecuteObjectQueryLinksResult> {
|
|
51
|
+
const direction = input.direction ?? "both"
|
|
52
|
+
if (direction !== "outgoing" && direction !== "incoming" && direction !== "both") {
|
|
53
|
+
throw new ObjectQueryExecutionError(
|
|
54
|
+
"invalid_link_direction",
|
|
55
|
+
"direction must be 'outgoing', 'incoming', or 'both'",
|
|
56
|
+
"$.direction"
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
if (input.linkId !== undefined && input.linkId.length === 0) {
|
|
60
|
+
throw new ObjectQueryExecutionError("invalid_link_id", "linkId must not be empty", "$.linkId")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const pageSize = input.pageSize ?? DEFAULT_LINK_PAGE_SIZE
|
|
64
|
+
if (!Number.isInteger(pageSize) || pageSize <= 0 || pageSize > MAX_LINK_PAGE_SIZE) {
|
|
65
|
+
throw new ObjectQueryExecutionError(
|
|
66
|
+
"invalid_link_page_size",
|
|
67
|
+
`pageSize must be an integer between 1 and ${MAX_LINK_PAGE_SIZE}`,
|
|
68
|
+
"$.pageSize"
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
const validated = validateObjectQuery(normalizeObjectQuery(input.query), {
|
|
72
|
+
ontology: options.ontology,
|
|
73
|
+
maxLimit: options.maxLimit,
|
|
74
|
+
maxPageSize: options.maxPageSize,
|
|
75
|
+
maxRefs: options.maxRefs,
|
|
76
|
+
normalize: false,
|
|
77
|
+
})
|
|
78
|
+
assertLinkSelectorShape(validated.query)
|
|
79
|
+
const selectorQuery = validated.query
|
|
80
|
+
const pageScope = linkPageScope(input.projectId, selectorQuery, direction, input.linkId)
|
|
81
|
+
const cursor = decodeLinkPageToken(input.pageToken, pageScope)
|
|
82
|
+
|
|
83
|
+
// A root page already has an explicit result bound and must execute directly: nesting it under a
|
|
84
|
+
// probe limit would expose the provider's internal pageSize+1 row. All other selector shapes are
|
|
85
|
+
// capped here before the provider receives the selected identities.
|
|
86
|
+
const boundedSelector =
|
|
87
|
+
selectorQuery.kind === "page"
|
|
88
|
+
? selectorQuery
|
|
89
|
+
: { kind: "limit" as const, limit: MAX_LINK_QUERY_OBJECTS + 1, input: selectorQuery }
|
|
90
|
+
const selection = await executeObjectQuery(
|
|
91
|
+
{
|
|
92
|
+
projectId: input.projectId,
|
|
93
|
+
query: boundedSelector,
|
|
94
|
+
includeTotal: false,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
...options,
|
|
98
|
+
maxLimit: Math.max(options.maxLimit ?? 1_000, MAX_LINK_QUERY_OBJECTS + 1),
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
if (selection.objects.length > MAX_LINK_QUERY_OBJECTS) {
|
|
102
|
+
throw new ObjectQueryExecutionError(
|
|
103
|
+
"link_query_object_limit_exceeded",
|
|
104
|
+
`Link query selected more than ${MAX_LINK_QUERY_OBJECTS} objects; add a limit or page node`,
|
|
105
|
+
"$.query"
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const selected = selection.objects
|
|
110
|
+
if (selected.length === 0) {
|
|
111
|
+
return { objects: [], links: [], hasMore: false }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const endpointObjectTypeIds = visibleEndpointTypeIds(options)
|
|
115
|
+
const page = await options.storage.queryLinks({
|
|
116
|
+
projectId: input.projectId,
|
|
117
|
+
objectRefs: selected.map((row) => ({
|
|
118
|
+
objectTypeId: row.objectTypeId,
|
|
119
|
+
primaryId: row.primaryId,
|
|
120
|
+
})),
|
|
121
|
+
direction,
|
|
122
|
+
...(input.linkId === undefined ? {} : { linkId: input.linkId }),
|
|
123
|
+
...(endpointObjectTypeIds === undefined ? {} : { endpointObjectTypeIds }),
|
|
124
|
+
...(cursor === undefined ? {} : { after: cursor }),
|
|
125
|
+
limit: pageSize,
|
|
126
|
+
})
|
|
127
|
+
const lastLink = page.links.at(-1)
|
|
128
|
+
let nextPageToken: string | undefined
|
|
129
|
+
if (page.hasMore) {
|
|
130
|
+
if (!lastLink) {
|
|
131
|
+
throw new Error("[Sixb] Object storage returned hasMore for an empty link page.")
|
|
132
|
+
}
|
|
133
|
+
nextPageToken = encodeLinkPageToken(objectLinkCursor(lastLink), pageScope)
|
|
134
|
+
}
|
|
135
|
+
const objects = input.includeObjects
|
|
136
|
+
? await hydrateLinkQueryObjects(input.projectId, selected, page.links, options.storage)
|
|
137
|
+
: []
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
objects,
|
|
141
|
+
links: page.links,
|
|
142
|
+
hasMore: page.hasMore,
|
|
143
|
+
...(nextPageToken ? { nextPageToken } : {}),
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface EncodedLinkPageToken {
|
|
148
|
+
version: 1
|
|
149
|
+
scope: string
|
|
150
|
+
cursor: ObjectLinkCursor
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function assertLinkSelectorShape(query: ObjectQuery, path = "$.query", root = true): void {
|
|
154
|
+
switch (query.kind) {
|
|
155
|
+
case "project":
|
|
156
|
+
case "expand":
|
|
157
|
+
throw new ObjectQueryExecutionError(
|
|
158
|
+
"link_selector_output_shape_not_supported",
|
|
159
|
+
`Link selectors do not support '${query.kind}' nodes; remove output shaping from the selector`,
|
|
160
|
+
path
|
|
161
|
+
)
|
|
162
|
+
case "page":
|
|
163
|
+
if (!root) {
|
|
164
|
+
throw new ObjectQueryExecutionError(
|
|
165
|
+
"link_selector_page_must_be_root",
|
|
166
|
+
"A page node in a link selector must be the outermost node",
|
|
167
|
+
path
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
assertLinkSelectorShape(query.input, `${path}.input`, false)
|
|
171
|
+
return
|
|
172
|
+
case "start":
|
|
173
|
+
case "refs":
|
|
174
|
+
return
|
|
175
|
+
case "set": {
|
|
176
|
+
for (const [index, input] of query.inputs.entries()) {
|
|
177
|
+
assertLinkSelectorShape(input, `${path}.inputs[${index}]`, false)
|
|
178
|
+
}
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
case "filter":
|
|
182
|
+
case "text":
|
|
183
|
+
case "vector":
|
|
184
|
+
case "traverse":
|
|
185
|
+
case "sort":
|
|
186
|
+
case "limit":
|
|
187
|
+
assertLinkSelectorShape(query.input, `${path}.input`, false)
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function visibleEndpointTypeIds(options: QueryExecutorOptions): readonly string[] | undefined {
|
|
193
|
+
if (!options.authorization) return undefined
|
|
194
|
+
return options.ontology
|
|
195
|
+
.listObjectTypes()
|
|
196
|
+
.filter((objectType) =>
|
|
197
|
+
isAllowed(options.authorization, { kind: "object.view", objectTypeId: objectType.id })
|
|
198
|
+
)
|
|
199
|
+
.map((objectType) => objectType.id)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function objectIdentity(objectTypeId: string, primaryId: string): ObjectBatchKey {
|
|
203
|
+
return objectBatchKey(objectTypeId, primaryId)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function linkPageScope(
|
|
207
|
+
projectId: string,
|
|
208
|
+
query: ObjectQuery,
|
|
209
|
+
direction: LinkDirection,
|
|
210
|
+
linkId: string | undefined
|
|
211
|
+
): string {
|
|
212
|
+
return createHash("sha256")
|
|
213
|
+
.update(
|
|
214
|
+
stableJsonStringify({
|
|
215
|
+
projectId,
|
|
216
|
+
query,
|
|
217
|
+
direction,
|
|
218
|
+
linkId: linkId ?? null,
|
|
219
|
+
})
|
|
220
|
+
)
|
|
221
|
+
.digest("base64url")
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function encodeLinkPageToken(cursor: ObjectLinkCursor, scope: string): string {
|
|
225
|
+
const payload: EncodedLinkPageToken = { version: 1, scope, cursor }
|
|
226
|
+
return `${LINK_PAGE_TOKEN_PREFIX}${Buffer.from(JSON.stringify(payload)).toString("base64url")}`
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function decodeLinkPageToken(
|
|
230
|
+
token: string | undefined,
|
|
231
|
+
expectedScope: string
|
|
232
|
+
): ObjectLinkCursor | undefined {
|
|
233
|
+
if (token === undefined) return undefined
|
|
234
|
+
try {
|
|
235
|
+
if (!token.startsWith(LINK_PAGE_TOKEN_PREFIX)) throw new Error("invalid prefix")
|
|
236
|
+
const value = JSON.parse(
|
|
237
|
+
Buffer.from(token.slice(LINK_PAGE_TOKEN_PREFIX.length), "base64url").toString("utf8")
|
|
238
|
+
) as unknown
|
|
239
|
+
if (
|
|
240
|
+
!isPlainObject(value) ||
|
|
241
|
+
value.version !== 1 ||
|
|
242
|
+
typeof value.scope !== "string" ||
|
|
243
|
+
!isObjectLinkCursor(value.cursor)
|
|
244
|
+
) {
|
|
245
|
+
throw new Error("invalid cursor")
|
|
246
|
+
}
|
|
247
|
+
if (value.scope !== expectedScope) {
|
|
248
|
+
throw new Error("cursor scope mismatch")
|
|
249
|
+
}
|
|
250
|
+
return value.cursor
|
|
251
|
+
} catch {
|
|
252
|
+
throw new ObjectQueryExecutionError(
|
|
253
|
+
"invalid_link_page_token",
|
|
254
|
+
"pageToken is not a valid object-links cursor",
|
|
255
|
+
"$.pageToken"
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function isObjectLinkCursor(value: unknown): value is ObjectLinkCursor {
|
|
261
|
+
return (
|
|
262
|
+
Array.isArray(value) && value.length === 5 && value.every((part) => typeof part === "string")
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
267
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function hydrateLinkQueryObjects(
|
|
271
|
+
projectId: string,
|
|
272
|
+
selected: readonly ObjectRow[],
|
|
273
|
+
links: readonly ObjectLinkRow[],
|
|
274
|
+
storage: ObjectStorage
|
|
275
|
+
): Promise<ObjectRow[]> {
|
|
276
|
+
const byIdentity = new Map(
|
|
277
|
+
selected.map((row) => [objectIdentity(row.objectTypeId, row.primaryId), row])
|
|
278
|
+
)
|
|
279
|
+
const orderedIdentities = selected.map((row) => objectIdentity(row.objectTypeId, row.primaryId))
|
|
280
|
+
const seenIdentities = new Set(orderedIdentities)
|
|
281
|
+
const missingRefs: { objectTypeId: string; primaryId: string }[] = []
|
|
282
|
+
|
|
283
|
+
for (const link of links) {
|
|
284
|
+
for (const ref of [
|
|
285
|
+
{ objectTypeId: link.sourceTypeId, primaryId: link.sourceId },
|
|
286
|
+
{ objectTypeId: link.targetTypeId, primaryId: link.targetId },
|
|
287
|
+
]) {
|
|
288
|
+
const identity = objectIdentity(ref.objectTypeId, ref.primaryId)
|
|
289
|
+
if (seenIdentities.has(identity)) continue
|
|
290
|
+
seenIdentities.add(identity)
|
|
291
|
+
orderedIdentities.push(identity)
|
|
292
|
+
missingRefs.push(ref)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (missingRefs.length > 0) {
|
|
297
|
+
const hydrated = await storage.getByPrimaryIdBatch({ projectId, items: missingRefs })
|
|
298
|
+
for (const ref of missingRefs) {
|
|
299
|
+
const row = hydrated.get(objectBatchKey(ref.objectTypeId, ref.primaryId))
|
|
300
|
+
if (row) byIdentity.set(objectIdentity(ref.objectTypeId, ref.primaryId), row)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return orderedIdentities.flatMap((identity) => {
|
|
305
|
+
const row = byIdentity.get(identity)
|
|
306
|
+
return row ? [row] : []
|
|
307
|
+
})
|
|
308
|
+
}
|
|
@@ -22,6 +22,11 @@ function normalizeNode(query: ObjectQuery): ObjectQuery {
|
|
|
22
22
|
switch (query.kind) {
|
|
23
23
|
case "start":
|
|
24
24
|
return { ...query }
|
|
25
|
+
case "refs":
|
|
26
|
+
return {
|
|
27
|
+
kind: "refs",
|
|
28
|
+
refs: uniqueRefs(query.refs),
|
|
29
|
+
}
|
|
25
30
|
case "filter":
|
|
26
31
|
return normalizeFilter(query.input, query.predicate)
|
|
27
32
|
case "text":
|
|
@@ -63,7 +68,14 @@ function normalizeNode(query: ObjectQuery): ObjectQuery {
|
|
|
63
68
|
* lands above another `expand` is merged into one.
|
|
64
69
|
*/
|
|
65
70
|
function hoistExpand(query: ObjectQuery): ObjectQuery {
|
|
66
|
-
if (
|
|
71
|
+
if (
|
|
72
|
+
query.kind === "start" ||
|
|
73
|
+
query.kind === "refs" ||
|
|
74
|
+
query.kind === "set" ||
|
|
75
|
+
query.kind === "expand"
|
|
76
|
+
) {
|
|
77
|
+
return query
|
|
78
|
+
}
|
|
67
79
|
if (query.input.kind !== "expand") return query
|
|
68
80
|
|
|
69
81
|
const inner = query.input
|
|
@@ -236,6 +248,33 @@ function uniqueStrings(values: readonly string[]): string[] {
|
|
|
236
248
|
return [...new Set(values)]
|
|
237
249
|
}
|
|
238
250
|
|
|
251
|
+
function uniqueRefs(
|
|
252
|
+
refs: readonly { objectTypeId: string; primaryId: string }[]
|
|
253
|
+
): { objectTypeId: string; primaryId: string }[] {
|
|
254
|
+
const seen = new Set<string>()
|
|
255
|
+
const unique = refs.flatMap((ref) => {
|
|
256
|
+
const key = JSON.stringify([ref.objectTypeId, ref.primaryId])
|
|
257
|
+
if (seen.has(key)) return []
|
|
258
|
+
seen.add(key)
|
|
259
|
+
return [{ ...ref }]
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// `refs` is an object-set source, not a positional batch response. Canonical
|
|
263
|
+
// identity order makes equivalent sets normalize identically and matches the
|
|
264
|
+
// default ordering used by provider query sources.
|
|
265
|
+
return unique.sort(
|
|
266
|
+
(left, right) =>
|
|
267
|
+
compareStrings(left.objectTypeId, right.objectTypeId) ||
|
|
268
|
+
compareStrings(left.primaryId, right.primaryId)
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function compareStrings(left: string, right: string): number {
|
|
273
|
+
if (left < right) return -1
|
|
274
|
+
if (left > right) return 1
|
|
275
|
+
return 0
|
|
276
|
+
}
|
|
277
|
+
|
|
239
278
|
function uniqueStringRecord(
|
|
240
279
|
record: Readonly<Record<string, readonly string[]>>
|
|
241
280
|
): Record<string, string[]> {
|
|
@@ -40,6 +40,7 @@ const DEFAULT_MAX_FALLBACK_ROWS = 1_000
|
|
|
40
40
|
// accidental full scans.
|
|
41
41
|
const fallbackNodeKinds = new Set<ObjectQuery["kind"]>([
|
|
42
42
|
"start",
|
|
43
|
+
"refs",
|
|
43
44
|
"filter",
|
|
44
45
|
"sort",
|
|
45
46
|
"limit",
|
|
@@ -195,6 +196,8 @@ function collectNodeProviderIssues(
|
|
|
195
196
|
)
|
|
196
197
|
}
|
|
197
198
|
return
|
|
199
|
+
case "refs":
|
|
200
|
+
return
|
|
198
201
|
case "filter":
|
|
199
202
|
collectPredicateProviderIssues(query.predicate, `${path}.predicate`, capabilities, issues)
|
|
200
203
|
collectNodeProviderIssues(query.input, `${path}.input`, capabilities, issues)
|
|
@@ -474,6 +477,7 @@ function collectFallbackNodeIssues(
|
|
|
474
477
|
|
|
475
478
|
switch (query.kind) {
|
|
476
479
|
case "start":
|
|
480
|
+
case "refs":
|
|
477
481
|
return
|
|
478
482
|
case "filter":
|
|
479
483
|
case "limit":
|
|
@@ -512,6 +516,7 @@ function hasExplicitResultBound(query: ObjectQuery): boolean {
|
|
|
512
516
|
switch (query.kind) {
|
|
513
517
|
case "limit":
|
|
514
518
|
case "page":
|
|
519
|
+
case "refs":
|
|
515
520
|
return true
|
|
516
521
|
case "start":
|
|
517
522
|
return false
|