@sixb/core 0.1.14 → 0.1.16
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 +26 -26
- package/dist/actions/worker.js +1 -1
- package/dist/agents/index.js +41 -41
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/streams/index.js +2 -2
- package/dist/agents/streams/internal.js +2 -2
- package/dist/auth/index.js +6 -6
- package/dist/authorization/index.js +3 -3
- package/dist/bootstrap/index.js +44 -44
- package/dist/{chunk-6rzb1g6h.js → chunk-2xvgy3x5.js} +2 -2
- package/dist/{chunk-16jenmzw.js → chunk-3q7z9hd4.js} +33 -33
- package/dist/{chunk-16jenmzw.js.map → chunk-3q7z9hd4.js.map} +1 -1
- package/dist/{chunk-hxgj4kzd.js → chunk-40qb8wpe.js} +11 -11
- package/dist/{chunk-hxgj4kzd.js.map → chunk-40qb8wpe.js.map} +3 -3
- package/dist/{chunk-vn3yh259.js → chunk-4gmng3vf.js} +1 -1
- package/dist/{chunk-znw0zvy4.js → chunk-4wn7bxxa.js} +25 -7
- package/dist/chunk-4wn7bxxa.js.map +12 -0
- package/dist/{chunk-gct3m1da.js → chunk-667x4drs.js} +3 -3
- package/dist/{chunk-rzcjp5m2.js → chunk-69kt9q43.js} +2 -2
- package/dist/{chunk-3qpcrcj8.js → chunk-6aawea28.js} +2 -4
- package/dist/chunk-6aawea28.js.map +10 -0
- package/dist/{chunk-rzkr70gr.js → chunk-6fsr7y93.js} +5 -1
- package/dist/{chunk-rzkr70gr.js.map → chunk-6fsr7y93.js.map} +3 -3
- package/dist/{chunk-3fpgxpsq.js → chunk-6z1q7j19.js} +144 -73
- package/dist/{chunk-3fpgxpsq.js.map → chunk-6z1q7j19.js.map} +6 -6
- package/dist/{chunk-ypj2wqtj.js → chunk-70jmg2zx.js} +2 -2
- package/dist/{chunk-m8zkvep1.js → chunk-7g2gjvah.js} +1 -1
- package/dist/{chunk-pvgpckm1.js → chunk-8x74221e.js} +10 -10
- package/dist/{chunk-ma1mhh7w.js → chunk-a7ne02hk.js} +6 -6
- package/dist/{chunk-bxx3ms5t.js → chunk-b9y8hcm2.js} +2 -2
- package/dist/{chunk-ww185kt6.js → chunk-chdg6eqq.js} +2 -2
- package/dist/{chunk-y487ywrv.js → chunk-cq44v1a6.js} +4 -4
- package/dist/{chunk-4ypbe95r.js → chunk-cxj8y8t0.js} +2 -2
- package/dist/{chunk-3a338wrp.js → chunk-dp7yk20b.js} +1 -1
- package/dist/{chunk-dv4ct8mp.js → chunk-dsv8kdgk.js} +4 -4
- package/dist/{chunk-dsfw1bdr.js → chunk-f72rbvsb.js} +2 -2
- package/dist/{chunk-4tnrzqqh.js → chunk-fj1dvp37.js} +1 -1
- package/dist/{chunk-ht4a7mjg.js → chunk-g4rbm4a6.js} +42 -8
- package/dist/{chunk-ht4a7mjg.js.map → chunk-g4rbm4a6.js.map} +3 -3
- package/dist/{chunk-wnxabtn4.js → chunk-gkxsenvp.js} +19 -11
- package/dist/{chunk-wnxabtn4.js.map → chunk-gkxsenvp.js.map} +4 -4
- package/dist/{chunk-vef6qa14.js → chunk-gmdvns8f.js} +2 -2
- package/dist/{chunk-728fp090.js → chunk-h044jb97.js} +1072 -1075
- package/dist/chunk-h044jb97.js.map +15 -0
- package/dist/{chunk-00pfcqh4.js → chunk-h4138ww2.js} +130 -71
- package/dist/{chunk-00pfcqh4.js.map → chunk-h4138ww2.js.map} +5 -5
- package/dist/{chunk-yvf2jqj8.js → chunk-h866d223.js} +1 -1
- package/dist/{chunk-qma80ych.js → chunk-hn2r7z41.js} +3 -2
- package/dist/chunk-hn2r7z41.js.map +11 -0
- package/dist/{chunk-bdhfn0ww.js → chunk-kkqwzy6h.js} +1 -1
- package/dist/{chunk-wn7mznxc.js → chunk-kttr5ftm.js} +5 -5
- package/dist/{chunk-kxea54yg.js → chunk-kvysp909.js} +3 -3
- package/dist/{chunk-p1683c0v.js → chunk-kyjcwqz6.js} +5 -2
- package/dist/{chunk-p1683c0v.js.map → chunk-kyjcwqz6.js.map} +3 -3
- package/dist/{chunk-ffwvdgk1.js → chunk-nj0020ay.js} +1 -1
- package/dist/{chunk-q2xghyft.js → chunk-nkbev3tr.js} +5 -5
- package/dist/{chunk-cbn96bve.js → chunk-nvymebc1.js} +2 -2
- package/dist/{chunk-2fv8sajb.js → chunk-qnd7ehe5.js} +2 -2
- package/dist/{chunk-jfdggg1p.js → chunk-sbcm1b92.js} +5 -5
- package/dist/{chunk-d8yes9yx.js → chunk-swxzncrv.js} +1 -1
- package/dist/{chunk-drz59ve0.js → chunk-tkdbge6v.js} +1 -1
- package/dist/{chunk-ky7zpbtt.js → chunk-tnvafr7g.js} +1 -1
- package/dist/{chunk-y6vnvayj.js → chunk-vjcd8d27.js} +1 -1
- package/dist/{chunk-hj0n3c2p.js → chunk-vjqt7q3a.js} +45 -27
- package/dist/{chunk-hj0n3c2p.js.map → chunk-vjqt7q3a.js.map} +3 -3
- package/dist/{chunk-z9h698s8.js → chunk-vsvrv7n8.js} +1 -1
- package/dist/{chunk-xgptywp0.js → chunk-y2aq6ag9.js} +1 -1
- package/dist/{chunk-e2c5yxfe.js → chunk-zb47r1c8.js} +2 -2
- package/dist/{chunk-3nx8vj5a.js → chunk-zvmr2hqk.js} +3 -2
- package/dist/chunk-zvmr2hqk.js.map +12 -0
- package/dist/deploy/define.d.ts +4 -0
- package/dist/deploy/define.d.ts.map +1 -0
- package/dist/deploy/index.d.ts +3 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js +10 -0
- package/dist/deploy/index.js.map +10 -0
- package/dist/deploy/internal.d.ts +3 -0
- package/dist/deploy/internal.d.ts.map +1 -0
- package/dist/deploy/internal.js +244 -0
- package/dist/deploy/internal.js.map +11 -0
- package/dist/deploy/services.d.ts +8 -0
- package/dist/deploy/services.d.ts.map +1 -0
- package/dist/deploy/types.d.ts +309 -0
- package/dist/deploy/types.d.ts.map +1 -0
- package/dist/deploy/validation.d.ts +7 -0
- package/dist/deploy/validation.d.ts.map +1 -0
- package/dist/error-reporting/internal.js +3 -3
- package/dist/errors/catalog.d.ts +4 -0
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/internal.js +1 -1
- package/dist/events/index.js +3 -3
- package/dist/execution/agent.js +38 -38
- package/dist/execution/primitive.js +34 -34
- package/dist/execution/request.js +36 -36
- package/dist/execution/request.js.map +1 -1
- package/dist/index.js +56 -56
- package/dist/index.js.map +1 -1
- package/dist/maintenance/ontology-maintenance.d.ts +2 -0
- package/dist/maintenance/ontology-maintenance.d.ts.map +1 -1
- package/dist/maintenance/types.d.ts +8 -2
- package/dist/maintenance/types.d.ts.map +1 -1
- package/dist/materialization/dataset-watermark.d.ts +6 -1
- package/dist/materialization/dataset-watermark.d.ts.map +1 -1
- package/dist/materialization/index.js +1 -1
- package/dist/materialization/model.d.ts +6 -0
- package/dist/materialization/model.d.ts.map +1 -1
- package/dist/materializer/index.js +22 -22
- package/dist/materializer/index.js.map +1 -1
- package/dist/materializer/projections/finish-run.d.ts.map +1 -1
- package/dist/materializer/projections/replace.d.ts.map +1 -1
- package/dist/materializer/projections/source-materialization.d.ts +6 -2
- package/dist/materializer/projections/source-materialization.d.ts.map +1 -1
- package/dist/models/embedding-model.d.ts +4 -0
- package/dist/models/embedding-model.d.ts.map +1 -1
- package/dist/models/execution/index.js +19 -19
- package/dist/models/index.js +2 -2
- package/dist/objects/index.js +25 -25
- package/dist/objects/query/index.js +21 -21
- package/dist/objects/query/index.js.map +1 -1
- package/dist/objects/vectors/indexing-generate.d.ts.map +1 -1
- package/dist/objects/vectors/profile.d.ts.map +1 -1
- package/dist/objects/vectors/query.d.ts +1 -1
- package/dist/objects/vectors/query.d.ts.map +1 -1
- package/dist/objects/vectors/resolve-query.d.ts.map +1 -1
- package/dist/objects/vectors/types.d.ts +1 -1
- package/dist/objects/vectors/types.d.ts.map +1 -1
- package/dist/ontology/builders.d.ts +13 -4
- package/dist/ontology/builders.d.ts.map +1 -1
- package/dist/ontology/index.js +3 -3
- package/dist/ontology/internal.js +2 -2
- package/dist/ontology/vector-profiles.d.ts.map +1 -1
- package/dist/pipelines/index.js +23 -23
- package/dist/projections/internal.js +20 -20
- package/dist/projections/types.d.ts +1 -1
- package/dist/projections/types.d.ts.map +1 -1
- package/dist/queues/in-memory.d.ts +1 -1
- package/dist/queues/in-memory.d.ts.map +1 -1
- package/dist/runtime/internal.js +23 -23
- package/dist/sandboxes/index.js +5 -5
- package/dist/shares/internal.js +18 -18
- package/dist/shares/internal.js.map +1 -1
- package/dist/storage/action-runs/failure.js +2 -2
- package/dist/storage/agents/provider.js +1 -1
- package/dist/storage/ai-limits/enforcement.js +2 -2
- package/dist/storage/connector-connections/provider.js +1 -1
- package/dist/storage/file-upload-sessions/provider.js +7 -7
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +33 -33
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/internal.js +1 -1
- package/dist/storage/ontology/in-memory/sources.d.ts +6 -3
- package/dist/storage/ontology/in-memory/sources.d.ts.map +1 -1
- package/dist/storage/ontology/index.d.ts +1 -1
- package/dist/storage/ontology/index.d.ts.map +1 -1
- package/dist/storage/ontology/provider.d.ts +16 -3
- package/dist/storage/ontology/provider.d.ts.map +1 -1
- package/dist/storage/ontology/provider.js +8 -4
- package/dist/storage/ontology/provider.js.map +1 -1
- package/dist/storage/ontology/sources.d.ts +36 -8
- package/dist/storage/ontology/sources.d.ts.map +1 -1
- package/dist/storage/projection-runs/in-memory.d.ts +3 -1
- package/dist/storage/projection-runs/in-memory.d.ts.map +1 -1
- package/dist/storage/projection-runs/index.d.ts +1 -1
- package/dist/storage/projection-runs/index.d.ts.map +1 -1
- package/dist/storage/projection-runs/lifecycle.d.ts +12 -0
- package/dist/storage/projection-runs/lifecycle.d.ts.map +1 -1
- package/dist/storage/projection-runs/provider.js +10 -4
- package/dist/storage/projection-runs/provider.js.map +1 -1
- package/dist/storage/projection-runs/types.d.ts +32 -1
- package/dist/storage/projection-runs/types.d.ts.map +1 -1
- package/dist/storage/workflow-runs/provider.js +7 -7
- package/dist/syncs/index.js +24 -24
- package/dist/testing/index.js +306 -64
- package/dist/testing/index.js.map +4 -4
- package/dist/testing/ontology-storage-contract.d.ts.map +1 -1
- package/dist/testing/projection-run-storage-contract.d.ts.map +1 -1
- package/dist/webhooks/internal.js +19 -19
- package/dist/webhooks/internal.js.map +1 -1
- package/dist/workers/index.js +1 -1
- package/dist/workflows/index.js +41 -41
- package/package.json +13 -1
- package/src/deploy/define.ts +6 -0
- package/src/deploy/index.ts +41 -0
- package/src/deploy/internal.ts +7 -0
- package/src/deploy/services.ts +51 -0
- package/src/deploy/types.ts +338 -0
- package/src/deploy/validation.ts +261 -0
- package/src/errors/catalog.ts +4 -0
- package/src/maintenance/ontology-maintenance.ts +32 -2
- package/src/maintenance/types.ts +8 -2
- package/src/materialization/dataset-watermark.ts +6 -4
- package/src/materialization/model.ts +7 -0
- package/src/materializer/README.md +26 -6
- package/src/materializer/projections/finish-run.ts +129 -26
- package/src/materializer/projections/replace.ts +67 -49
- package/src/materializer/projections/source-materialization.ts +11 -6
- package/src/models/embedding-model.ts +12 -0
- package/src/models/execution/embedding.ts +5 -1
- package/src/objects/query/validate.ts +1 -10
- package/src/objects/vectors/README.md +8 -0
- package/src/objects/vectors/handle.ts +1 -1
- package/src/objects/vectors/indexing-generate.ts +5 -1
- package/src/objects/vectors/profile.ts +2 -0
- package/src/objects/vectors/query.ts +18 -4
- package/src/objects/vectors/resolve-query.ts +9 -5
- package/src/objects/vectors/types.ts +3 -1
- package/src/ontology/builders.ts +21 -7
- package/src/ontology/vector-profiles.ts +1 -0
- package/src/projections/types.ts +1 -0
- package/src/storage/index.ts +6 -1
- package/src/storage/ontology/in-memory/sources.ts +119 -55
- package/src/storage/ontology/index.ts +4 -1
- package/src/storage/ontology/provider.ts +64 -7
- package/src/storage/ontology/sources.ts +42 -8
- package/src/storage/projection-runs/in-memory.ts +41 -2
- package/src/storage/projection-runs/index.ts +2 -0
- package/src/storage/projection-runs/lifecycle.ts +61 -4
- package/src/storage/projection-runs/types.ts +41 -1
- package/src/testing/ontology-storage-contract.ts +141 -15
- package/src/testing/projection-run-storage-contract.ts +174 -1
- package/dist/chunk-3nx8vj5a.js.map +0 -12
- package/dist/chunk-3qpcrcj8.js.map +0 -10
- package/dist/chunk-728fp090.js.map +0 -15
- package/dist/chunk-qma80ych.js.map +0 -11
- package/dist/chunk-znw0zvy4.js.map +0 -12
- /package/dist/{chunk-6rzb1g6h.js.map → chunk-2xvgy3x5.js.map} +0 -0
- /package/dist/{chunk-vn3yh259.js.map → chunk-4gmng3vf.js.map} +0 -0
- /package/dist/{chunk-gct3m1da.js.map → chunk-667x4drs.js.map} +0 -0
- /package/dist/{chunk-rzcjp5m2.js.map → chunk-69kt9q43.js.map} +0 -0
- /package/dist/{chunk-ypj2wqtj.js.map → chunk-70jmg2zx.js.map} +0 -0
- /package/dist/{chunk-m8zkvep1.js.map → chunk-7g2gjvah.js.map} +0 -0
- /package/dist/{chunk-pvgpckm1.js.map → chunk-8x74221e.js.map} +0 -0
- /package/dist/{chunk-ma1mhh7w.js.map → chunk-a7ne02hk.js.map} +0 -0
- /package/dist/{chunk-bxx3ms5t.js.map → chunk-b9y8hcm2.js.map} +0 -0
- /package/dist/{chunk-ww185kt6.js.map → chunk-chdg6eqq.js.map} +0 -0
- /package/dist/{chunk-y487ywrv.js.map → chunk-cq44v1a6.js.map} +0 -0
- /package/dist/{chunk-4ypbe95r.js.map → chunk-cxj8y8t0.js.map} +0 -0
- /package/dist/{chunk-3a338wrp.js.map → chunk-dp7yk20b.js.map} +0 -0
- /package/dist/{chunk-dv4ct8mp.js.map → chunk-dsv8kdgk.js.map} +0 -0
- /package/dist/{chunk-dsfw1bdr.js.map → chunk-f72rbvsb.js.map} +0 -0
- /package/dist/{chunk-4tnrzqqh.js.map → chunk-fj1dvp37.js.map} +0 -0
- /package/dist/{chunk-vef6qa14.js.map → chunk-gmdvns8f.js.map} +0 -0
- /package/dist/{chunk-yvf2jqj8.js.map → chunk-h866d223.js.map} +0 -0
- /package/dist/{chunk-bdhfn0ww.js.map → chunk-kkqwzy6h.js.map} +0 -0
- /package/dist/{chunk-wn7mznxc.js.map → chunk-kttr5ftm.js.map} +0 -0
- /package/dist/{chunk-kxea54yg.js.map → chunk-kvysp909.js.map} +0 -0
- /package/dist/{chunk-ffwvdgk1.js.map → chunk-nj0020ay.js.map} +0 -0
- /package/dist/{chunk-q2xghyft.js.map → chunk-nkbev3tr.js.map} +0 -0
- /package/dist/{chunk-cbn96bve.js.map → chunk-nvymebc1.js.map} +0 -0
- /package/dist/{chunk-2fv8sajb.js.map → chunk-qnd7ehe5.js.map} +0 -0
- /package/dist/{chunk-jfdggg1p.js.map → chunk-sbcm1b92.js.map} +0 -0
- /package/dist/{chunk-d8yes9yx.js.map → chunk-swxzncrv.js.map} +0 -0
- /package/dist/{chunk-drz59ve0.js.map → chunk-tkdbge6v.js.map} +0 -0
- /package/dist/{chunk-ky7zpbtt.js.map → chunk-tnvafr7g.js.map} +0 -0
- /package/dist/{chunk-y6vnvayj.js.map → chunk-vjcd8d27.js.map} +0 -0
- /package/dist/{chunk-z9h698s8.js.map → chunk-vsvrv7n8.js.map} +0 -0
- /package/dist/{chunk-xgptywp0.js.map → chunk-y2aq6ag9.js.map} +0 -0
- /package/dist/{chunk-e2c5yxfe.js.map → chunk-zb47r1c8.js.map} +0 -0
|
@@ -63,7 +63,11 @@ export async function generateVectors(
|
|
|
63
63
|
)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const result = await model.embed({
|
|
66
|
+
const result = await model.embed({
|
|
67
|
+
texts: entries.map((entry) => entry.input.text),
|
|
68
|
+
purpose: "document",
|
|
69
|
+
signal,
|
|
70
|
+
})
|
|
67
71
|
const values = normalizeEmbeddingResult(
|
|
68
72
|
result,
|
|
69
73
|
entries.length,
|
|
@@ -13,6 +13,8 @@ export function vectorConfiguration(profile: ObjectVectorSearchProfile): string
|
|
|
13
13
|
model: profile.model.modelId,
|
|
14
14
|
representation: profile.model.definition.representation ?? { name: profile.model.modelId },
|
|
15
15
|
dimensions: profile.model.definition.dimensions,
|
|
16
|
+
// Include retrieval preparation without changing existing symmetric identities.
|
|
17
|
+
...(profile.model.definition.inputMode === "asymmetric" ? { inputMode: "asymmetric" } : {}),
|
|
16
18
|
metric: "cosine",
|
|
17
19
|
precision: "float32",
|
|
18
20
|
normalization: "l2-v1",
|
|
@@ -6,11 +6,25 @@ export function hasVectorProfile(query: ObjectQuery): boolean {
|
|
|
6
6
|
return "input" in query && hasVectorProfile(query.input)
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/** Rank one eligible object set; validation resolves its type and admits every traversed edge. */
|
|
10
10
|
export function isVectorProfileQuery(query: ObjectQuery): boolean {
|
|
11
11
|
if (query.kind === "limit" || query.kind === "project") return isVectorProfileQuery(query.input)
|
|
12
12
|
if (query.kind !== "vector" || !query.profile) return false
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
return isVectorCandidateQuery(query.input)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isVectorCandidateQuery(query: ObjectQuery): boolean {
|
|
17
|
+
switch (query.kind) {
|
|
18
|
+
case "start":
|
|
19
|
+
return !query.includeSubtypes
|
|
20
|
+
case "refs":
|
|
21
|
+
return true
|
|
22
|
+
case "filter":
|
|
23
|
+
case "traverse":
|
|
24
|
+
return isVectorCandidateQuery(query.input)
|
|
25
|
+
case "set":
|
|
26
|
+
return query.inputs.every(isVectorCandidateQuery)
|
|
27
|
+
default:
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
16
30
|
}
|
|
@@ -3,6 +3,7 @@ import { type EmbeddingModel, sameEmbeddingModel } from "../../models/embedding-
|
|
|
3
3
|
import type { OntologyRegistry } from "../../ontology"
|
|
4
4
|
import { ObjectQueryExecutionError } from "../query/errors"
|
|
5
5
|
import type { ObjectQuery, ObjectQueryVector } from "../query/ir"
|
|
6
|
+
import { resolveObjectQueryResultShape } from "../query/validate"
|
|
6
7
|
import { normalizeVector } from "./profile"
|
|
7
8
|
|
|
8
9
|
const QUERY_EMBEDDING_TIMEOUT_MS = 30_000
|
|
@@ -30,16 +31,19 @@ function resolveProfileEmbeddingModel(
|
|
|
30
31
|
ontology: OntologyRegistry,
|
|
31
32
|
models: EmbeddingModelCatalog | undefined
|
|
32
33
|
): EmbeddingModel {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const { objectTypeIds } = resolveObjectQueryResultShape(query.input, {
|
|
35
|
+
ontology,
|
|
36
|
+
normalize: false,
|
|
37
|
+
})
|
|
38
|
+
const objectTypeId = objectTypeIds.length === 1 ? objectTypeIds[0] : undefined
|
|
39
|
+
if (!objectTypeId || !query.profile) {
|
|
36
40
|
throw new ObjectQueryExecutionError(
|
|
37
41
|
"embedding_model_unavailable",
|
|
38
42
|
"Vector search requires the embedding model registered for its profile."
|
|
39
43
|
)
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
const profile = ontology.resolveObjectType(
|
|
46
|
+
const profile = ontology.resolveObjectType(objectTypeId).search?.vectors?.[query.profile]
|
|
43
47
|
if (!profile) {
|
|
44
48
|
throw new ObjectQueryExecutionError(
|
|
45
49
|
"embedding_model_unavailable",
|
|
@@ -69,7 +73,7 @@ async function embedSearchText(
|
|
|
69
73
|
const timeout = AbortSignal.timeout(QUERY_EMBEDDING_TIMEOUT_MS)
|
|
70
74
|
const requestSignal = signal ? AbortSignal.any([signal, timeout]) : timeout
|
|
71
75
|
requestSignal.throwIfAborted()
|
|
72
|
-
const result = await model.embed({ texts: [text], signal: requestSignal })
|
|
76
|
+
const result = await model.embed({ texts: [text], purpose: "query", signal: requestSignal })
|
|
73
77
|
requestSignal.throwIfAborted()
|
|
74
78
|
|
|
75
79
|
if (!Array.isArray(result?.vectors) || result.vectors.length !== 1) {
|
|
@@ -2,7 +2,9 @@ import type { ObjectType } from "../../ontology"
|
|
|
2
2
|
|
|
3
3
|
export type VectorProfileName<T extends ObjectType> = T extends { search: { vectors: infer P } }
|
|
4
4
|
? Extract<keyof P, string>
|
|
5
|
-
:
|
|
5
|
+
: string extends T["id"]
|
|
6
|
+
? string
|
|
7
|
+
: never
|
|
6
8
|
|
|
7
9
|
export interface ObjectVectorHandle {
|
|
8
10
|
/** Generate and atomically store this profile using its configured model. Conflicts are not retried. */
|
package/src/ontology/builders.ts
CHANGED
|
@@ -35,6 +35,7 @@ import type {
|
|
|
35
35
|
ObjectLink,
|
|
36
36
|
ObjectLinkTargetMetadata,
|
|
37
37
|
ObjectType,
|
|
38
|
+
ObjectVectorSearchProfile,
|
|
38
39
|
Ontology,
|
|
39
40
|
Property,
|
|
40
41
|
PropertyMode,
|
|
@@ -446,19 +447,32 @@ export type DirectLinkResult<
|
|
|
446
447
|
> = LinkResult<TId, TTargetObjectTypeId, TOptions> & ObjectLinkTargetMetadata<TTarget>
|
|
447
448
|
|
|
448
449
|
type ObjectTypeIdArray<TTargets extends readonly ObjectType[]> = Array<TTargets[number]["id"]>
|
|
450
|
+
/** Keep profile names without carrying provider types through every linked declaration. */
|
|
449
451
|
export type DirectLinkTarget<
|
|
450
452
|
TId extends string,
|
|
451
453
|
TName extends string,
|
|
452
454
|
TProperties extends Property[],
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
455
|
+
TVectorProfiles extends string = never,
|
|
456
|
+
> = ObjectTypeWithPropertyTokens<
|
|
457
|
+
{
|
|
458
|
+
id: TId
|
|
459
|
+
name: TName
|
|
460
|
+
properties: TProperties
|
|
461
|
+
links: ObjectLink[]
|
|
462
|
+
} & ([TVectorProfiles] extends [never]
|
|
463
|
+
? unknown
|
|
464
|
+
: { search: { vectors: Record<TVectorProfiles, ObjectVectorSearchProfile> } })
|
|
465
|
+
>
|
|
459
466
|
|
|
460
467
|
type DirectLinkTargetFor<TTarget extends ObjectType> = TTarget extends ObjectTypeWithPropertyTokens
|
|
461
|
-
? DirectLinkTarget<
|
|
468
|
+
? DirectLinkTarget<
|
|
469
|
+
TTarget["id"],
|
|
470
|
+
TTarget["name"],
|
|
471
|
+
TTarget["properties"],
|
|
472
|
+
TTarget extends { search: { vectors: infer TProfiles } }
|
|
473
|
+
? Extract<keyof TProfiles, string>
|
|
474
|
+
: never
|
|
475
|
+
>
|
|
462
476
|
: TTarget
|
|
463
477
|
|
|
464
478
|
/**
|
package/src/projections/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export const PROJECTION_RUN_FAILURE_CODES = [
|
|
|
6
6
|
"runtime.cancelled",
|
|
7
7
|
"queue.enqueue_failed",
|
|
8
8
|
"projection.execution_failed",
|
|
9
|
+
"storage.unavailable",
|
|
9
10
|
] as const satisfies readonly [SixbErrorCode, ...SixbErrorCode[]]
|
|
10
11
|
|
|
11
12
|
export type ProjectionRunFailureCode = (typeof PROJECTION_RUN_FAILURE_CODES)[number]
|
package/src/storage/index.ts
CHANGED
|
@@ -449,8 +449,11 @@ export {
|
|
|
449
449
|
snapshotObjectReadExecutionLimits,
|
|
450
450
|
} from "./objects"
|
|
451
451
|
export type {
|
|
452
|
+
AbandonRunSourceMaterializationInput,
|
|
452
453
|
AbandonSourceMaterializationCandidateInput,
|
|
453
454
|
AbandonSourceMaterializationInput,
|
|
455
|
+
AdoptedSourceMaterialization,
|
|
456
|
+
AdoptSourceMaterializationInput,
|
|
454
457
|
ApplyMaterializationChunkInput,
|
|
455
458
|
ApplyMaterializationResult,
|
|
456
459
|
AssertSourceMaterializationExecution,
|
|
@@ -530,9 +533,9 @@ export type {
|
|
|
530
533
|
OntologyStorage,
|
|
531
534
|
OntologyVectorStorage,
|
|
532
535
|
ProjectionOntologyCommitIntent,
|
|
536
|
+
PurgeAbandonedSourceMaterializationsInput,
|
|
533
537
|
PurgePublishedOntologyOutboxInput,
|
|
534
538
|
ReadMaterializationObjectExistenceInput,
|
|
535
|
-
ReclaimSourceMaterializationInput,
|
|
536
539
|
RescheduleOntologyOutboxLeaseInput,
|
|
537
540
|
SourceActivationWrite,
|
|
538
541
|
SourceReplacementLinkState,
|
|
@@ -595,6 +598,7 @@ export {
|
|
|
595
598
|
export type {
|
|
596
599
|
AdvanceProjectionTelemetryCheckpointInput,
|
|
597
600
|
FailProjectionRunEnqueueInput,
|
|
601
|
+
FindSupersedingProjectionRunInput,
|
|
598
602
|
FinishProjectionRunInput,
|
|
599
603
|
LinkProjectionRunRecord,
|
|
600
604
|
LinkProjectionTarget,
|
|
@@ -616,6 +620,7 @@ export type {
|
|
|
616
620
|
ProjectionTarget,
|
|
617
621
|
ProjectionTelemetryCheckpoint,
|
|
618
622
|
QueueProjectionRunInput,
|
|
623
|
+
RecordProjectionAttemptFailureInput,
|
|
619
624
|
RecordProjectionMissingTargetInput,
|
|
620
625
|
StartOrReclaimProjectionRunInput,
|
|
621
626
|
TelemetryProjectionRunRecord,
|
|
@@ -16,8 +16,11 @@ import {
|
|
|
16
16
|
sourceStageRoots,
|
|
17
17
|
} from "../provider"
|
|
18
18
|
import type {
|
|
19
|
+
AbandonRunSourceMaterializationInput,
|
|
19
20
|
AbandonSourceMaterializationCandidateInput,
|
|
20
21
|
AbandonSourceMaterializationInput,
|
|
22
|
+
AdoptedSourceMaterialization,
|
|
23
|
+
AdoptSourceMaterializationInput,
|
|
21
24
|
AssertSourceMaterializationExecution,
|
|
22
25
|
BeginSourceMaterializationInput,
|
|
23
26
|
CleanupTerminalSourceMaterializationsInput,
|
|
@@ -26,7 +29,7 @@ import type {
|
|
|
26
29
|
MarkSourceMaterializationReadyInput,
|
|
27
30
|
OntologySourceRecord,
|
|
28
31
|
OntologySourceStorage,
|
|
29
|
-
|
|
32
|
+
PurgeAbandonedSourceMaterializationsInput,
|
|
30
33
|
StageSourceAssertion,
|
|
31
34
|
StageSourceRowsInput,
|
|
32
35
|
StageSourceRowsResult,
|
|
@@ -38,6 +41,7 @@ import {
|
|
|
38
41
|
assertNonblank,
|
|
39
42
|
type InMemoryOntologyState,
|
|
40
43
|
type InMemorySourceMaterialization,
|
|
44
|
+
type InMemorySourceRoot,
|
|
41
45
|
insertBounded,
|
|
42
46
|
sourceMaterializationKey,
|
|
43
47
|
sourceMaterializationRecord,
|
|
@@ -78,7 +82,7 @@ export class InMemoryOntologySourceStorage implements OntologySourceStorage {
|
|
|
78
82
|
)
|
|
79
83
|
if (nonterminal.length > 0) {
|
|
80
84
|
throw sourceConflict(
|
|
81
|
-
`Projection run '${input.execution.projectionRunId}' already has a nonterminal source materialization;
|
|
85
|
+
`Projection run '${input.execution.projectionRunId}' already has a nonterminal source materialization; adopt it before beginning another.`
|
|
82
86
|
)
|
|
83
87
|
}
|
|
84
88
|
|
|
@@ -191,8 +195,42 @@ export class InMemoryOntologySourceStorage implements OntologySourceStorage {
|
|
|
191
195
|
})
|
|
192
196
|
}
|
|
193
197
|
|
|
198
|
+
async adopt(
|
|
199
|
+
input: AdoptSourceMaterializationInput
|
|
200
|
+
): Promise<AdoptedSourceMaterialization | null> {
|
|
201
|
+
return this.runRootOperation(async () => {
|
|
202
|
+
assertProjectAndSource(input)
|
|
203
|
+
assertSourceExecutionIdentity(input.execution.projectionRunId, input.execution.executionToken)
|
|
204
|
+
assertCanonicalTimestamp(input.adoptedAt, "Source adoptedAt")
|
|
205
|
+
await this.assertCurrentExecution(input)
|
|
206
|
+
const [candidate, ...others] = this.findRunCandidates(
|
|
207
|
+
input.projectId,
|
|
208
|
+
input.source.projectionId,
|
|
209
|
+
input.execution.projectionRunId
|
|
210
|
+
)
|
|
211
|
+
if (!candidate) return null
|
|
212
|
+
if (others.length > 0) throw multipleRunCandidates(input.execution.projectionRunId)
|
|
213
|
+
const [key, materialization] = candidate
|
|
214
|
+
const adopted: InMemorySourceMaterialization = {
|
|
215
|
+
...materialization,
|
|
216
|
+
executionToken: input.execution.executionToken,
|
|
217
|
+
// Workers' clocks differ; adoption never moves the record back in time.
|
|
218
|
+
updatedAt:
|
|
219
|
+
input.adoptedAt > materialization.updatedAt ? input.adoptedAt : materialization.updatedAt,
|
|
220
|
+
}
|
|
221
|
+
this.state.sourceMaterializations.set(key, adopted)
|
|
222
|
+
return {
|
|
223
|
+
record: sourceMaterializationRecord(adopted),
|
|
224
|
+
resumeStagingOrdinal:
|
|
225
|
+
adopted.status === "ready"
|
|
226
|
+
? (adopted.rootCount ?? 0)
|
|
227
|
+
: Math.max(0, ...adopted.ordinalRoots.keys()),
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
|
|
194
232
|
async abandon(input: AbandonSourceMaterializationCandidateInput): Promise<OntologySourceRecord>
|
|
195
|
-
async abandon(input:
|
|
233
|
+
async abandon(input: AbandonRunSourceMaterializationInput): Promise<OntologySourceRecord | null>
|
|
196
234
|
async abandon(input: AbandonSourceMaterializationInput): Promise<OntologySourceRecord | null> {
|
|
197
235
|
return this.runRootOperation(async () => {
|
|
198
236
|
assertProjectAndSource(input)
|
|
@@ -201,7 +239,7 @@ export class InMemoryOntologySourceStorage implements OntologySourceStorage {
|
|
|
201
239
|
await this.assertCurrentExecution(input)
|
|
202
240
|
return input.kind === "candidate"
|
|
203
241
|
? this.abandonCandidate(input)
|
|
204
|
-
: this.
|
|
242
|
+
: this.abandonRunCandidate(input)
|
|
205
243
|
})
|
|
206
244
|
}
|
|
207
245
|
|
|
@@ -211,18 +249,14 @@ export class InMemoryOntologySourceStorage implements OntologySourceStorage {
|
|
|
211
249
|
return this.runRootOperation(() => {
|
|
212
250
|
assertNonblank(input.projectId, "Terminal source cleanup project id")
|
|
213
251
|
assertCanonicalTimestamp(input.terminalBefore, "Terminal source cleanup cutoff")
|
|
214
|
-
|
|
215
|
-
throw new MaterializationValidationError(
|
|
216
|
-
"Terminal source cleanup limit must be a positive safe integer."
|
|
217
|
-
)
|
|
218
|
-
}
|
|
252
|
+
assertCleanupLimit(input.limit)
|
|
219
253
|
|
|
220
254
|
const candidates: [string, InMemorySourceMaterialization][] = []
|
|
221
255
|
for (const entry of this.state.sourceMaterializations.entries()) {
|
|
222
256
|
const materialization = entry[1]
|
|
223
257
|
if (
|
|
224
258
|
materialization.projectId !== input.projectId ||
|
|
225
|
-
|
|
259
|
+
materialization.status !== "superseded" ||
|
|
226
260
|
materialization.terminalAt === null ||
|
|
227
261
|
materialization.terminalAt >= input.terminalBefore
|
|
228
262
|
) {
|
|
@@ -239,42 +273,69 @@ export class InMemoryOntologySourceStorage implements OntologySourceStorage {
|
|
|
239
273
|
insertBounded(candidates, entry, input.limit, compareTerminalMaterializations)
|
|
240
274
|
}
|
|
241
275
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
276
|
+
return this.deleteRetiredRoots(
|
|
277
|
+
candidates,
|
|
278
|
+
input.limit,
|
|
279
|
+
(root) => !root.active && root.retiredAt !== null && root.retiredAt < input.terminalBefore
|
|
280
|
+
)
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async purgeAbandoned(
|
|
285
|
+
input: PurgeAbandonedSourceMaterializationsInput
|
|
286
|
+
): Promise<CleanupTerminalSourceMaterializationsResult> {
|
|
287
|
+
return this.runRootOperation(() => {
|
|
288
|
+
assertNonblank(input.projectId, "Abandoned source purge project id")
|
|
289
|
+
assertCleanupLimit(input.limit)
|
|
290
|
+
const abandoned = [...this.state.sourceMaterializations.entries()]
|
|
291
|
+
.filter(
|
|
292
|
+
([, materialization]) =>
|
|
293
|
+
materialization.projectId === input.projectId && materialization.status === "abandoned"
|
|
294
|
+
)
|
|
295
|
+
.sort(compareTerminalMaterializations)
|
|
296
|
+
return this.deleteRetiredRoots(abandoned, input.limit, () => true)
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private deleteRetiredRoots(
|
|
301
|
+
candidates: readonly [string, InMemorySourceMaterialization][],
|
|
302
|
+
limit: number,
|
|
303
|
+
retired: (root: InMemorySourceRoot) => boolean
|
|
304
|
+
): CleanupTerminalSourceMaterializationsResult {
|
|
305
|
+
let remaining = limit
|
|
306
|
+
let rowsDeleted = 0
|
|
307
|
+
let materializationsDeleted = 0
|
|
308
|
+
for (const [key, candidate] of candidates) {
|
|
309
|
+
if (remaining === 0) break
|
|
310
|
+
const current = this.state.sourceMaterializations.get(key)
|
|
311
|
+
if (current !== candidate) continue
|
|
312
|
+
current.rootOrdinals.clear()
|
|
313
|
+
current.ordinalRoots.clear()
|
|
314
|
+
for (const [rootKey, root] of current.roots) {
|
|
246
315
|
if (remaining === 0) break
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
current.rootOrdinals.clear()
|
|
250
|
-
current.ordinalRoots.clear()
|
|
251
|
-
for (const [rootKey, root] of current.roots) {
|
|
316
|
+
if (!retired(root)) continue
|
|
317
|
+
for (const entityKey of root.entityKeys) {
|
|
252
318
|
if (remaining === 0) break
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
current.rowsByEntity.delete(entityKey)
|
|
258
|
-
root.entityKeys.delete(entityKey)
|
|
259
|
-
rowsDeleted += 1
|
|
260
|
-
remaining -= 1
|
|
261
|
-
}
|
|
262
|
-
if (root.entityKeys.size === 0 && remaining > 0) {
|
|
263
|
-
current.roots.delete(rootKey)
|
|
264
|
-
current.rootOrdinals.delete(rootKey)
|
|
265
|
-
current.ordinalRoots.delete(root.stagingOrdinal)
|
|
266
|
-
rowsDeleted += 1
|
|
267
|
-
remaining -= 1
|
|
268
|
-
}
|
|
319
|
+
current.rowsByEntity.delete(entityKey)
|
|
320
|
+
root.entityKeys.delete(entityKey)
|
|
321
|
+
rowsDeleted += 1
|
|
322
|
+
remaining -= 1
|
|
269
323
|
}
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
324
|
+
if (root.entityKeys.size === 0 && remaining > 0) {
|
|
325
|
+
current.roots.delete(rootKey)
|
|
326
|
+
current.rootOrdinals.delete(rootKey)
|
|
327
|
+
current.ordinalRoots.delete(root.stagingOrdinal)
|
|
328
|
+
rowsDeleted += 1
|
|
273
329
|
remaining -= 1
|
|
274
330
|
}
|
|
275
331
|
}
|
|
276
|
-
|
|
277
|
-
|
|
332
|
+
if (current.roots.size === 0 && current.rowsByEntity.size === 0 && remaining > 0) {
|
|
333
|
+
this.state.sourceMaterializations.delete(key)
|
|
334
|
+
materializationsDeleted += 1
|
|
335
|
+
remaining -= 1
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return { rowsDeleted, materializationsDeleted }
|
|
278
339
|
}
|
|
279
340
|
|
|
280
341
|
async summarizeTerminal(
|
|
@@ -356,26 +417,15 @@ export class InMemoryOntologySourceStorage implements OntologySourceStorage {
|
|
|
356
417
|
return this.transitionToAbandoned(materialization, input.abandonedAt)
|
|
357
418
|
}
|
|
358
419
|
|
|
359
|
-
private
|
|
420
|
+
private abandonRunCandidate(
|
|
421
|
+
input: AbandonRunSourceMaterializationInput
|
|
422
|
+
): OntologySourceRecord | null {
|
|
360
423
|
const candidates = this.findRunCandidates(
|
|
361
424
|
input.projectId,
|
|
362
425
|
input.source.projectionId,
|
|
363
426
|
input.execution.projectionRunId
|
|
364
427
|
)
|
|
365
|
-
if (
|
|
366
|
-
candidates.some(
|
|
367
|
-
([, materialization]) => materialization.executionToken === input.execution.executionToken
|
|
368
|
-
)
|
|
369
|
-
) {
|
|
370
|
-
throw sourceConflict(
|
|
371
|
-
`Projection run '${input.execution.projectionRunId}' already has a source materialization owned by the current execution.`
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
if (candidates.length > 1) {
|
|
375
|
-
throw sourceConflict(
|
|
376
|
-
`Projection run '${input.execution.projectionRunId}' has multiple nonterminal source materializations.`
|
|
377
|
-
)
|
|
378
|
-
}
|
|
428
|
+
if (candidates.length > 1) throw multipleRunCandidates(input.execution.projectionRunId)
|
|
379
429
|
const candidate = candidates[0]?.[1]
|
|
380
430
|
return candidate ? this.transitionToAbandoned(candidate, input.abandonedAt) : null
|
|
381
431
|
}
|
|
@@ -609,6 +659,20 @@ function assertNotBefore(
|
|
|
609
659
|
}
|
|
610
660
|
}
|
|
611
661
|
|
|
662
|
+
function assertCleanupLimit(limit: number): void {
|
|
663
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) {
|
|
664
|
+
throw new MaterializationValidationError(
|
|
665
|
+
"Terminal source cleanup limit must be a positive safe integer."
|
|
666
|
+
)
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function multipleRunCandidates(projectionRunId: string) {
|
|
671
|
+
return sourceConflict(
|
|
672
|
+
`Projection run '${projectionRunId}' has multiple nonterminal source materializations.`
|
|
673
|
+
)
|
|
674
|
+
}
|
|
675
|
+
|
|
612
676
|
function compareTerminalMaterializations(
|
|
613
677
|
[, left]: readonly [string, InMemorySourceMaterialization],
|
|
614
678
|
[, right]: readonly [string, InMemorySourceMaterialization]
|
|
@@ -97,8 +97,11 @@ export type {
|
|
|
97
97
|
} from "./outbox"
|
|
98
98
|
export { ONTOLOGY_OUTBOX_FAILURE_CODES } from "./outbox"
|
|
99
99
|
export type {
|
|
100
|
+
AbandonRunSourceMaterializationInput,
|
|
100
101
|
AbandonSourceMaterializationCandidateInput,
|
|
101
102
|
AbandonSourceMaterializationInput,
|
|
103
|
+
AdoptedSourceMaterialization,
|
|
104
|
+
AdoptSourceMaterializationInput,
|
|
102
105
|
AssertSourceMaterializationExecution,
|
|
103
106
|
AssertSourceMaterializationExecutionInput,
|
|
104
107
|
BeginSourceMaterializationInput,
|
|
@@ -109,7 +112,7 @@ export type {
|
|
|
109
112
|
OntologySourceMaterializationStatus,
|
|
110
113
|
OntologySourceRecord,
|
|
111
114
|
OntologySourceStorage,
|
|
112
|
-
|
|
115
|
+
PurgeAbandonedSourceMaterializationsInput,
|
|
113
116
|
StageSourceAssertion,
|
|
114
117
|
StageSourceRoot,
|
|
115
118
|
StageSourceRowsInput,
|
|
@@ -11,6 +11,8 @@ import type {
|
|
|
11
11
|
ExpectedObjectRevision,
|
|
12
12
|
OntologyLinkRef,
|
|
13
13
|
OntologyObjectRef,
|
|
14
|
+
ProjectionEntityRef,
|
|
15
|
+
ProjectionSourceAssertion,
|
|
14
16
|
} from "../../materialization/model"
|
|
15
17
|
import { linkRefKey, objectRefKey, projectionEntityKey } from "../../materialization/refs"
|
|
16
18
|
import type { OntologyCommitOriginSelector, OntologyCommitWrite } from "./commits"
|
|
@@ -716,7 +718,6 @@ export function sourceStageRow(row: StageSourceAssertion): SourceStageRow {
|
|
|
716
718
|
export interface SourceStageRoot {
|
|
717
719
|
readonly root: StageSourceAssertion["root"]
|
|
718
720
|
readonly rootKey: string
|
|
719
|
-
readonly sortKey: string
|
|
720
721
|
readonly stagingOrdinal: number
|
|
721
722
|
readonly deleted: boolean
|
|
722
723
|
}
|
|
@@ -763,7 +764,6 @@ export function sourceStageRoots(
|
|
|
763
764
|
roots.set(key, {
|
|
764
765
|
root: row.root,
|
|
765
766
|
rootKey: key,
|
|
766
|
-
sortKey: utf8SortKey(key),
|
|
767
767
|
stagingOrdinal: row.stagingOrdinal,
|
|
768
768
|
deleted,
|
|
769
769
|
})
|
|
@@ -965,12 +965,69 @@ export function sourceEntityColumns(entity: StageSourceAssertion["root"]): {
|
|
|
965
965
|
}
|
|
966
966
|
}
|
|
967
967
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
968
|
+
/** The inverse of `projectionEntityKey`, for providers that store only the canonical key. */
|
|
969
|
+
export function sourceEntityFromKey(key: string): ProjectionEntityRef {
|
|
970
|
+
const parts: unknown = JSON.parse(key)
|
|
971
|
+
if (Array.isArray(parts) && parts.every((part) => typeof part === "string")) {
|
|
972
|
+
if (parts[0] === "object" && parts.length === 3) {
|
|
973
|
+
return { kind: "object", ref: { objectTypeId: parts[1]!, primaryId: parts[2]! } }
|
|
974
|
+
}
|
|
975
|
+
if (parts[0] === "link" && parts.length === 6) {
|
|
976
|
+
return {
|
|
977
|
+
kind: "link",
|
|
978
|
+
ref: {
|
|
979
|
+
source: { objectTypeId: parts[1]!, primaryId: parts[2]! },
|
|
980
|
+
linkId: parts[3]!,
|
|
981
|
+
target: { objectTypeId: parts[4]!, primaryId: parts[5]! },
|
|
982
|
+
},
|
|
983
|
+
}
|
|
984
|
+
}
|
|
972
985
|
}
|
|
973
|
-
|
|
986
|
+
throw new MaterializationConflictError(
|
|
987
|
+
"source-materialization",
|
|
988
|
+
`Stored source key ${key} is not a canonical entity key.`
|
|
989
|
+
)
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/** What an assertion carries beyond its identity, or null when that is nothing. */
|
|
993
|
+
export function sourceAssertionPayload(
|
|
994
|
+
assertion: ProjectionSourceAssertion
|
|
995
|
+
): Readonly<Record<string, unknown>> | null {
|
|
996
|
+
const { kind: _kind, ref: _ref, ...payload } = assertion
|
|
997
|
+
return Object.keys(payload).length === 0 ? null : payload
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/** Rebuilds an assertion from its typed identity columns and its payload. */
|
|
1001
|
+
export function sourceAssertionFromColumns(
|
|
1002
|
+
columns: {
|
|
1003
|
+
readonly entity_kind: "object" | "link"
|
|
1004
|
+
readonly object_type_id: string | null
|
|
1005
|
+
readonly primary_id: string | null
|
|
1006
|
+
readonly source_type_id: string | null
|
|
1007
|
+
readonly source_primary_id: string | null
|
|
1008
|
+
readonly link_id: string | null
|
|
1009
|
+
readonly target_type_id: string | null
|
|
1010
|
+
readonly target_primary_id: string | null
|
|
1011
|
+
},
|
|
1012
|
+
payload: unknown
|
|
1013
|
+
): ProjectionSourceAssertion {
|
|
1014
|
+
const rest = (payload ?? {}) as Record<string, unknown>
|
|
1015
|
+
if (columns.entity_kind === "object") {
|
|
1016
|
+
return {
|
|
1017
|
+
kind: "object",
|
|
1018
|
+
ref: { objectTypeId: columns.object_type_id!, primaryId: columns.primary_id! },
|
|
1019
|
+
...rest,
|
|
1020
|
+
} as ProjectionSourceAssertion
|
|
1021
|
+
}
|
|
1022
|
+
return {
|
|
1023
|
+
kind: "link",
|
|
1024
|
+
ref: {
|
|
1025
|
+
source: { objectTypeId: columns.source_type_id!, primaryId: columns.source_primary_id! },
|
|
1026
|
+
linkId: columns.link_id!,
|
|
1027
|
+
target: { objectTypeId: columns.target_type_id!, primaryId: columns.target_primary_id! },
|
|
1028
|
+
},
|
|
1029
|
+
...rest,
|
|
1030
|
+
} as ProjectionSourceAssertion
|
|
974
1031
|
}
|
|
975
1032
|
|
|
976
1033
|
export function isExactStagingManifest(
|