@sixb/core 0.1.3 → 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 +17 -18
- 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/context-compaction.d.ts +40 -0
- package/dist/agents/context-compaction.d.ts.map +1 -0
- package/dist/agents/ids.d.ts +2 -0
- package/dist/agents/ids.d.ts.map +1 -1
- package/dist/agents/index.d.ts +6 -5
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +42 -37
- package/dist/agents/index.js.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 +4 -2
- package/dist/agents/streams.js.map +1 -1
- package/dist/agents/types.d.ts +9 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/validation.d.ts +1 -1
- package/dist/agents/validation.d.ts.map +1 -1
- package/dist/auth/index.js +7 -3
- 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 +30 -31
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/{chunk-xmggaxg4.js → chunk-1wk20wn3.js} +188 -21
- package/dist/{chunk-xmggaxg4.js.map → chunk-1wk20wn3.js.map} +7 -5
- package/dist/{chunk-1ywq4hzk.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} +3 -3
- package/dist/{chunk-f1cyvnrk.js → chunk-7gw7mepb.js} +259 -9
- package/dist/chunk-7gw7mepb.js.map +14 -0
- package/dist/{chunk-wb4051cx.js → chunk-819wnjz8.js} +11 -5
- package/dist/chunk-819wnjz8.js.map +12 -0
- package/dist/{chunk-pxtrxm3p.js → chunk-a09jx26t.js} +1 -1
- package/dist/{chunk-ettb0cy4.js → chunk-afjpa2hs.js} +59 -29
- package/dist/{chunk-ettb0cy4.js.map → chunk-afjpa2hs.js.map} +5 -5
- package/dist/{chunk-177ed2mp.js → chunk-c43qr6s0.js} +229 -97
- package/dist/{chunk-177ed2mp.js.map → chunk-c43qr6s0.js.map} +9 -9
- package/dist/{chunk-261ag4t4.js → chunk-cbkm2vam.js} +3 -3
- package/dist/{chunk-zpw39qhj.js → chunk-dm72y8wt.js} +25 -2
- package/dist/chunk-dm72y8wt.js.map +10 -0
- package/dist/{chunk-kqxgf6kv.js → chunk-drjqm1aa.js} +16 -1
- package/dist/{chunk-kqxgf6kv.js.map → chunk-drjqm1aa.js.map} +3 -3
- package/dist/chunk-dysw7nsm.js.map +1 -1
- package/dist/{chunk-4aw0jwk0.js → chunk-f6erf2vv.js} +1 -1
- package/dist/{chunk-4z3n1dzt.js → chunk-f83ka50g.js} +131 -25
- package/dist/chunk-f83ka50g.js.map +23 -0
- package/dist/{chunk-km4rkj4t.js → chunk-g13869yf.js} +3 -3
- package/dist/{chunk-c8bw2b6c.js → chunk-hbeh8j9w.js} +2 -2
- package/dist/{chunk-n5x5y80a.js → chunk-nzw7sm3b.js} +2 -2
- package/dist/{chunk-3rsf30p4.js → chunk-pn8n8sba.js} +16 -15
- package/dist/{chunk-3rsf30p4.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-4p9rh7jj.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-bv41fmjn.js → chunk-s31d0qmq.js} +57 -20
- package/dist/{chunk-bv41fmjn.js.map → chunk-s31d0qmq.js.map} +8 -7
- package/dist/{chunk-c6cfqydk.js → chunk-sxwk41qa.js} +1 -1
- package/dist/chunk-t0jjkep3.js.map +1 -1
- package/dist/{chunk-d6y2wsfg.js → chunk-tek1qwgm.js} +6 -6
- package/dist/{chunk-d6y2wsfg.js.map → chunk-tek1qwgm.js.map} +1 -1
- package/dist/{chunk-d2adj15j.js → chunk-tkdscva6.js} +1 -1
- package/dist/{chunk-ttba8x6z.js → chunk-tycbzedm.js} +2 -2
- package/dist/{chunk-z8j83gzd.js → chunk-x2yw73hy.js} +1 -1
- package/dist/{chunk-qer6am8w.js → chunk-xdf9yswn.js} +1 -1
- package/dist/execution/agent.js +26 -27
- package/dist/execution/agent.js.map +1 -1
- package/dist/execution/primitive.js +26 -27
- package/dist/execution/primitive.js.map +2 -2
- package/dist/execution/request.js +27 -28
- package/dist/execution/request.js.map +2 -2
- package/dist/http/index.js +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -53
- 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/materializer/index.js +15 -16
- package/dist/materializer/index.js.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 +19 -20
- 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 +15 -16
- package/dist/pipelines/index.js.map +1 -1
- package/dist/projections/builders.d.ts +33 -4
- package/dist/projections/builders.d.ts.map +1 -1
- package/dist/projections/index.d.ts +1 -1
- package/dist/projections/index.d.ts.map +1 -1
- package/dist/projections/internal.js +15 -16
- 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/types.d.ts +12 -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/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 +4 -0
- package/dist/storage/agents/in-memory.d.ts.map +1 -1
- package/dist/storage/agents/provider.js +9 -5
- package/dist/storage/agents/provider.js.map +1 -1
- package/dist/storage/agents/types.d.ts +5 -0
- package/dist/storage/agents/types.d.ts.map +1 -1
- package/dist/storage/ai-cost/provider.js +1 -1
- 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/index.d.ts +3 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +19 -14
- 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/provider.js +1 -1
- package/dist/storage/workflow-runs/provider.js +9 -5
- package/dist/storage/workflow-runs/provider.js.map +1 -1
- package/dist/syncs/index.js +15 -16
- package/dist/syncs/index.js.map +1 -1
- package/dist/testing/agent-storage-contract.d.ts.map +1 -1
- 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.js +455 -40
- package/dist/testing/index.js.map +7 -7
- package/dist/testing/lake-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 +13 -14
- package/dist/webhooks/internal.js.map +2 -2
- package/dist/workflows/index.js +27 -28
- package/dist/workflows/index.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/builders.ts +3 -3
- package/src/agents/context-compaction.ts +261 -0
- package/src/agents/ids.ts +5 -0
- package/src/agents/index.ts +18 -9
- package/src/agents/streams.ts +56 -0
- package/src/agents/types.ts +10 -0
- package/src/agents/validation.ts +35 -5
- package/src/http/api-routes.ts +7 -7
- package/src/index.ts +14 -0
- package/src/lake-storage/types.ts +2 -1
- 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 +220 -15
- package/src/projections/index.ts +1 -0
- package/src/projections/ownership.ts +5 -5
- package/src/projections/registry.ts +9 -3
- package/src/projections/revision.ts +31 -5
- package/src/projections/run-dispatch.ts +10 -1
- package/src/projections/types.ts +13 -9
- package/src/projections/validation.ts +61 -19
- package/src/query.ts +2 -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 +15 -0
- package/src/storage/agents/types.ts +5 -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/index.ts +11 -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/provider-header-validation.ts +2 -2
- package/src/testing/agent-storage-contract.ts +12 -0
- package/src/testing/ai-usage-storage-contract.ts +35 -0
- package/src/testing/effective-storage-contract.ts +194 -4
- package/src/testing/lake-storage-contract.ts +56 -0
- package/src/testing/object-query-contract.ts +208 -1
- package/dist/agents/prompt.d.ts +0 -21
- package/dist/agents/prompt.d.ts.map +0 -1
- package/dist/chunk-4z3n1dzt.js.map +0 -23
- 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-f1cyvnrk.js.map +0 -13
- package/dist/chunk-wb4051cx.js.map +0 -12
- package/dist/chunk-zpw39qhj.js.map +0 -10
- package/src/agents/prompt.ts +0 -85
- /package/dist/{chunk-1ywq4hzk.js.map → chunk-1yz3x65y.js.map} +0 -0
- /package/dist/{chunk-gqdd7508.js.map → chunk-4rh2m6zg.js.map} +0 -0
- /package/dist/{chunk-pxtrxm3p.js.map → chunk-a09jx26t.js.map} +0 -0
- /package/dist/{chunk-261ag4t4.js.map → chunk-cbkm2vam.js.map} +0 -0
- /package/dist/{chunk-4aw0jwk0.js.map → chunk-f6erf2vv.js.map} +0 -0
- /package/dist/{chunk-km4rkj4t.js.map → chunk-g13869yf.js.map} +0 -0
- /package/dist/{chunk-c8bw2b6c.js.map → chunk-hbeh8j9w.js.map} +0 -0
- /package/dist/{chunk-n5x5y80a.js.map → chunk-nzw7sm3b.js.map} +0 -0
- /package/dist/{chunk-4p9rh7jj.js.map → chunk-rs1wbvy6.js.map} +0 -0
- /package/dist/{chunk-c6cfqydk.js.map → chunk-sxwk41qa.js.map} +0 -0
- /package/dist/{chunk-d2adj15j.js.map → chunk-tkdscva6.js.map} +0 -0
- /package/dist/{chunk-ttba8x6z.js.map → chunk-tycbzedm.js.map} +0 -0
- /package/dist/{chunk-z8j83gzd.js.map → chunk-x2yw73hy.js.map} +0 -0
- /package/dist/{chunk-qer6am8w.js.map → chunk-xdf9yswn.js.map} +0 -0
|
@@ -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
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ObjectRef,
|
|
3
|
+
ObjectType,
|
|
4
|
+
OntologyRegistry,
|
|
5
|
+
Property,
|
|
6
|
+
Schema,
|
|
7
|
+
ValueType,
|
|
8
|
+
} from "../../ontology"
|
|
2
9
|
import { normalizeDecimalValue } from "../../ontology"
|
|
3
10
|
import { formatUnknownObjectTypeMessage } from "../../ontology/errors"
|
|
4
11
|
import { validatePropertyValue, validateSchemaValue } from "../../ontology/validation"
|
|
@@ -30,11 +37,12 @@ export interface ObjectQueryValidationOptions {
|
|
|
30
37
|
ontology: OntologyRegistry
|
|
31
38
|
maxLimit?: number
|
|
32
39
|
maxPageSize?: number
|
|
40
|
+
maxRefs?: number
|
|
33
41
|
normalize?: boolean
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
type QueryValidationContext = Required<
|
|
37
|
-
Pick<ObjectQueryValidationOptions, "maxLimit" | "maxPageSize">
|
|
45
|
+
Pick<ObjectQueryValidationOptions, "maxLimit" | "maxPageSize" | "maxRefs">
|
|
38
46
|
> & {
|
|
39
47
|
ontology: OntologyRegistry
|
|
40
48
|
valueTypesById: ReadonlyMap<string, ValueType>
|
|
@@ -53,6 +61,7 @@ interface TextFieldResolution {
|
|
|
53
61
|
|
|
54
62
|
const DEFAULT_MAX_LIMIT = 1_000
|
|
55
63
|
const DEFAULT_MAX_PAGE_SIZE = 1_000
|
|
64
|
+
const DEFAULT_MAX_REFS = 1_000
|
|
56
65
|
|
|
57
66
|
export function validateObjectQuery(
|
|
58
67
|
query: ObjectQuery,
|
|
@@ -96,6 +105,7 @@ function createValidationContext(options: ObjectQueryValidationOptions): QueryVa
|
|
|
96
105
|
valueTypesById: options.ontology.getValueTypesById(),
|
|
97
106
|
maxLimit: options.maxLimit ?? DEFAULT_MAX_LIMIT,
|
|
98
107
|
maxPageSize: options.maxPageSize ?? DEFAULT_MAX_PAGE_SIZE,
|
|
108
|
+
maxRefs: options.maxRefs ?? DEFAULT_MAX_REFS,
|
|
99
109
|
issues: [],
|
|
100
110
|
touchedObjectTypeIds: new Set<string>(),
|
|
101
111
|
}
|
|
@@ -125,6 +135,8 @@ function dispatchQueryNode(
|
|
|
125
135
|
switch (query.kind) {
|
|
126
136
|
case "start":
|
|
127
137
|
return validateStart(query.objectTypeId, query.includeSubtypes, path, ctx)
|
|
138
|
+
case "refs":
|
|
139
|
+
return validateRefs(query.refs, path, ctx)
|
|
128
140
|
case "filter": {
|
|
129
141
|
const input = validateQueryNode(query.input, `${path}.input`, ctx)
|
|
130
142
|
const predicate = validatePredicate(query.predicate, input.result, `${path}.predicate`, ctx)
|
|
@@ -199,6 +211,50 @@ function dispatchQueryNode(
|
|
|
199
211
|
}
|
|
200
212
|
}
|
|
201
213
|
|
|
214
|
+
function validateRefs(
|
|
215
|
+
refs: readonly ObjectRef[],
|
|
216
|
+
path: string,
|
|
217
|
+
ctx: QueryValidationContext
|
|
218
|
+
): QueryValidationResult {
|
|
219
|
+
if (refs.length === 0) {
|
|
220
|
+
addIssue(ctx, `${path}.refs`, "empty_refs", "refs must include at least one object reference")
|
|
221
|
+
}
|
|
222
|
+
if (refs.length > ctx.maxRefs) {
|
|
223
|
+
addIssue(
|
|
224
|
+
ctx,
|
|
225
|
+
`${path}.refs`,
|
|
226
|
+
"too_many_refs",
|
|
227
|
+
`refs must include at most ${ctx.maxRefs} object references`
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const objectTypeIds = new Set<string>()
|
|
232
|
+
refs.forEach((ref, index) => {
|
|
233
|
+
const refPath = `${path}.refs[${index}]`
|
|
234
|
+
if (!ref.objectTypeId) {
|
|
235
|
+
addIssue(ctx, `${refPath}.objectTypeId`, "missing_object_type", "objectTypeId is required")
|
|
236
|
+
} else if (!ctx.ontology.getObjectTypeById(ref.objectTypeId)) {
|
|
237
|
+
addIssue(
|
|
238
|
+
ctx,
|
|
239
|
+
`${refPath}.objectTypeId`,
|
|
240
|
+
"unknown_object_type",
|
|
241
|
+
formatUnknownObjectTypeMessage(ref.objectTypeId)
|
|
242
|
+
)
|
|
243
|
+
} else {
|
|
244
|
+
objectTypeIds.add(ref.objectTypeId)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!ref.primaryId) {
|
|
248
|
+
addIssue(ctx, `${refPath}.primaryId`, "missing_primary_id", "primaryId is required")
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
result: { objectTypeIds: [...objectTypeIds] },
|
|
254
|
+
query: { kind: "refs", refs: refs.map((ref) => ({ ...ref })) },
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
202
258
|
function validateStart(
|
|
203
259
|
objectTypeId: string,
|
|
204
260
|
includeSubtypes: boolean | undefined,
|