@instruments/materialgraph 0.25.0 → 0.27.0
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/association-types.d.ts +38 -27
- package/associations-client.d.ts +4 -4
- package/associations-client.js +3 -10
- package/attribution-types.d.ts +4 -4
- package/brand-types.d.ts +14 -6
- package/brands-client.d.ts +7 -38
- package/brands-client.js +10 -40
- package/by-colour-types.d.ts +58 -31
- package/by-spec-types.d.ts +6 -73
- package/by-spec-types.js +7 -5
- package/catalog-discovery-types.d.ts +11 -26
- package/catalogue-client.d.ts +16 -35
- package/catalogue-client.js +32 -67
- package/catalogue-types.d.ts +44 -4
- package/categories-client.d.ts +63 -0
- package/categories-client.js +48 -0
- package/category-types.d.ts +114 -0
- package/citation-types.d.ts +4 -4
- package/client-config.d.ts +4 -6
- package/client-config.js +2 -4
- package/client-source-material-comments.d.ts +4 -4
- package/client-source-material-comments.js +4 -38
- package/client-vocabulary.d.ts +7 -9
- package/client-vocabulary.js +22 -30
- package/client.d.ts +110 -244
- package/client.js +217 -387
- package/codes-client.d.ts +2 -2
- package/codes-client.js +8 -8
- package/codes-types.d.ts +55 -34
- package/colour-aggregate-types.d.ts +24 -24
- package/colours-client.d.ts +6 -11
- package/colours-client.js +11 -19
- package/coordinate-client.d.ts +2 -2
- package/coordinate-client.js +1 -13
- package/corpus-scope-types.d.ts +3 -3
- package/corpus-scope-types.js +1 -25
- package/demand-batch-types.d.ts +18 -18
- package/demand-types.d.ts +24 -24
- package/errors.d.ts +13 -13
- package/errors.js +54 -52
- package/http-transport.d.ts +13 -21
- package/http-transport.js +31 -28
- package/identify-types.d.ts +54 -44
- package/identify-types.js +5 -3
- package/index.d.ts +11 -27
- package/index.js +4 -6
- package/list-variant-facets-types.d.ts +60 -0
- package/list-variants-types.d.ts +142 -0
- package/list-variants-types.js +12 -0
- package/match-stream-types.d.ts +45 -32
- package/match-stream-types.js +2 -0
- package/match-stream.d.ts +2 -2
- package/match-stream.js +67 -49
- package/match-types.d.ts +32 -8
- package/material-asset-types.d.ts +89 -69
- package/material-block-types.d.ts +8 -6
- package/material-composition-client.d.ts +21 -0
- package/material-composition-client.js +13 -0
- package/material-composition-types.d.ts +403 -0
- package/material-query-plan-types.d.ts +61 -145
- package/material-resources-client.d.ts +12 -10
- package/material-resources-client.js +27 -22
- package/material-types.d.ts +16 -24
- package/ndjson.js +16 -8
- package/operations.d.ts +6 -6
- package/operations.js +29 -156
- package/package.json +5 -1
- package/palette-search-types.d.ts +87 -52
- package/query-understanding-types.d.ts +65 -40
- package/resolve-client.d.ts +8 -12
- package/resolve-client.js +9 -13
- package/resolve-colour-types.d.ts +8 -8
- package/resolve-types.d.ts +10 -10
- package/response-schemas.d.ts +20 -0
- package/response-schemas.generated.d.ts +5 -0
- package/response-schemas.generated.js +160 -0
- package/response-schemas.js +113 -0
- package/run-types.d.ts +64 -145
- package/runs.d.ts +9 -58
- package/runs.js +60 -149
- package/samplize-catalogue-types.d.ts +18 -18
- package/samplize-colorvec.d.ts +20 -20
- package/samplize-colorvec.js +66 -42
- package/schema-resource-types.d.ts +52 -39
- package/schema-resource-types.js +5 -5
- package/search-card-types.d.ts +26 -4
- package/search-index-plan-types.d.ts +70 -0
- package/search-refinement-types.d.ts +10 -40
- package/search-refinement-types.js +1 -0
- package/search-request-types.d.ts +121 -204
- package/search-response-receipt-types.d.ts +13 -253
- package/search-response-types.d.ts +2 -2
- package/search-result-validation.d.ts +3 -19
- package/search-result-validation.js +42 -183
- package/source-material-validation.d.ts +3 -3
- package/source-material-validation.js +35 -39
- package/spec-facet-types.d.ts +11 -16
- package/spec-types.d.ts +23 -16
- package/spec-types.js +8 -7
- package/specifications.d.ts +14 -72
- package/specifications.js +39 -89
- package/sse.d.ts +2 -2
- package/sse.js +32 -16
- package/substitute-types.d.ts +22 -22
- package/suggest-types.d.ts +11 -17
- package/suggest-types.js +3 -3
- package/taxonomy-coverage-types.d.ts +8 -8
- package/types.d.ts +202 -405
- package/validation.d.ts +26 -26
- package/validation.js +97 -92
- package/webmcp.d.ts +3 -3
- package/webmcp.generated.js +10 -93
- package/brand-most-sampled-types.d.ts +0 -33
- package/browse-types.d.ts +0 -236
- package/client-browse.d.ts +0 -78
- package/client-browse.js +0 -72
- package/client-exploration.d.ts +0 -9
- package/client-exploration.js +0 -7
- package/compare-types.d.ts +0 -89
- package/composition-client.d.ts +0 -33
- package/composition-client.js +0 -27
- package/composition-types.d.ts +0 -455
- package/composition-types.js +0 -10
- package/correction-types.d.ts +0 -88
- package/exploration-types.d.ts +0 -118
- package/exploration-types.js +0 -1
- package/fan-deck-types.d.ts +0 -42
- package/fan-deck-types.js +0 -9
- package/match-rejection-types.d.ts +0 -43
- package/match-rejection-types.js +0 -7
- package/palette-completion-types.d.ts +0 -115
- package/palette-completion-types.js +0 -1
- package/project-types.d.ts +0 -79
- package/project-types.js +0 -9
- package/projects.d.ts +0 -13
- package/projects.js +0 -46
- package/render-assets-types.d.ts +0 -65
- package/render-assets-types.js +0 -1
- package/run-events.d.ts +0 -106
- package/run-events.js +0 -32
- package/schedule-reference-types.d.ts +0 -46
- package/schedule-reference-types.js +0 -1
- package/schedule-references-client.d.ts +0 -14
- package/schedule-references-client.js +0 -26
- package/schedule-types.d.ts +0 -261
- package/schedule-types.js +0 -1
- package/search-collapse-types.d.ts +0 -69
- package/search-collapse-types.js +0 -1
- package/search-mood-types.d.ts +0 -6
- package/search-mood-types.js +0 -1
- package/search-window-types.d.ts +0 -25
- package/search-window-types.js +0 -1
- package/slot-pool-types.d.ts +0 -372
- package/slot-pool-types.js +0 -1
- /package/{brand-most-sampled-types.js → category-types.js} +0 -0
- /package/{browse-types.js → list-variant-facets-types.js} +0 -0
- /package/{compare-types.js → material-composition-types.js} +0 -0
- /package/{correction-types.js → search-index-plan-types.js} +0 -0
package/samplize-colorvec.js
CHANGED
|
@@ -3,43 +3,54 @@ export const SAMPLIZE_COLORVEC_RANKING_VERSION = "solid-colorvec-cosine-v2";
|
|
|
3
3
|
export const SAMPLIZE_COLORVEC_EMBEDDING_VERSION = EMBEDDING_VERSION;
|
|
4
4
|
const decodeVector = (encoded) => {
|
|
5
5
|
const bytes = Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0));
|
|
6
|
-
if (bytes.length !== EMBEDDING_VECTOR_SIZE * 4)
|
|
6
|
+
if (bytes.length !== EMBEDDING_VECTOR_SIZE * 4) {
|
|
7
7
|
throw new Error("Invalid colour vector size.");
|
|
8
|
+
}
|
|
8
9
|
const view = new DataView(bytes.buffer);
|
|
9
10
|
return Array.from({ length: EMBEDDING_VECTOR_SIZE }, (_, i) => view.getFloat32(i * 4, true));
|
|
10
11
|
};
|
|
11
12
|
const facets = ["brand", "family", "lightness", "intensity"];
|
|
12
13
|
const identityOrder = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
13
14
|
export const samplizeSolidColorVector = (hex) => {
|
|
14
|
-
if (!/^#[0-9a-f]{6}$/i.test(hex))
|
|
15
|
+
if (!/^#[0-9a-f]{6}$/i.test(hex)) {
|
|
15
16
|
throw new Error("A six-digit published colour is required.");
|
|
17
|
+
}
|
|
16
18
|
return paletteToEmbedding([{ hex, proportion: 1 }], { validateOklab: true });
|
|
17
19
|
};
|
|
18
20
|
/** Canonical constraints are shared by full-cache similarity and constrained text retrieval. */
|
|
19
|
-
export
|
|
21
|
+
export const selectSamplizeEligiblePaints = (paints, input) => {
|
|
20
22
|
const reference = input.reference
|
|
21
23
|
? paints.find((p) => p.variantId === input.reference)
|
|
22
24
|
: undefined;
|
|
23
|
-
if (input.reference && !reference)
|
|
25
|
+
if (input.reference && !reference) {
|
|
24
26
|
throw new Error("The reference is absent from this catalogue version.");
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
+
}
|
|
28
|
+
const low = input.lightnessMin ?? 0;
|
|
29
|
+
const high = input.lightnessMax ?? 1;
|
|
30
|
+
const cool = input.temperatureMin ?? -0.4;
|
|
31
|
+
const warm = input.temperatureMax ?? 0.4;
|
|
27
32
|
if (![low, high, cool, warm].every(Number.isFinite) ||
|
|
28
33
|
low > high ||
|
|
29
|
-
cool > warm)
|
|
34
|
+
cool > warm) {
|
|
30
35
|
throw new Error("Appearance ranges must be finite and ordered.");
|
|
36
|
+
}
|
|
31
37
|
const candidates = paints.filter((p) => {
|
|
32
|
-
if (!reference)
|
|
38
|
+
if (!reference) {
|
|
33
39
|
return true;
|
|
34
|
-
|
|
40
|
+
}
|
|
41
|
+
if (p.variantId === reference.variantId) {
|
|
35
42
|
return false;
|
|
36
|
-
|
|
43
|
+
}
|
|
44
|
+
if (input.direction === "lighter") {
|
|
37
45
|
return p.oklab.L > reference.oklab.L;
|
|
38
|
-
|
|
46
|
+
}
|
|
47
|
+
if (input.direction === "darker") {
|
|
39
48
|
return p.oklab.L < reference.oklab.L;
|
|
40
|
-
|
|
49
|
+
}
|
|
50
|
+
if (input.direction === "muted") {
|
|
41
51
|
return (Math.hypot(p.oklab.a, p.oklab.b) <
|
|
42
52
|
Math.hypot(reference.oklab.a, reference.oklab.b));
|
|
53
|
+
}
|
|
43
54
|
return true;
|
|
44
55
|
});
|
|
45
56
|
const matches = (p, omit) => p.oklab.L >= low &&
|
|
@@ -50,25 +61,30 @@ export function selectSamplizeEligiblePaints(paints, input) {
|
|
|
50
61
|
const counts = {
|
|
51
62
|
brand: {},
|
|
52
63
|
family: {},
|
|
53
|
-
lightness: {},
|
|
54
64
|
intensity: {},
|
|
65
|
+
lightness: {},
|
|
55
66
|
};
|
|
56
|
-
for (const p of candidates)
|
|
57
|
-
for (const f of facets)
|
|
58
|
-
if (matches(p, f))
|
|
67
|
+
for (const p of candidates) {
|
|
68
|
+
for (const f of facets) {
|
|
69
|
+
if (matches(p, f)) {
|
|
59
70
|
counts[f][p[f]] = (counts[f][p[f]] ?? 0) + 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
60
74
|
const eligible = candidates.filter((p) => matches(p));
|
|
61
|
-
return {
|
|
62
|
-
}
|
|
75
|
+
return { counts, eligible, reference };
|
|
76
|
+
};
|
|
63
77
|
/** Official portable MG ranking over its complete versioned sampling-channel projection. */
|
|
64
|
-
export
|
|
78
|
+
export const createSamplizeColorVecIndex = (cache) => {
|
|
65
79
|
if (cache.embeddingVersion !== EMBEDDING_VERSION ||
|
|
66
|
-
cache.rankingVersion !== SAMPLIZE_COLORVEC_RANKING_VERSION)
|
|
80
|
+
cache.rankingVersion !== SAMPLIZE_COLORVEC_RANKING_VERSION) {
|
|
67
81
|
throw new Error("The colour cache uses an incompatible embedding or ranking version. Refresh it before searching.");
|
|
82
|
+
}
|
|
68
83
|
if (!cache.sourceVersion ||
|
|
69
84
|
!cache.dictionaryVersion ||
|
|
70
|
-
!Number.isFinite(Date.parse(cache.generatedAt)))
|
|
85
|
+
!Number.isFinite(Date.parse(cache.generatedAt))) {
|
|
71
86
|
throw new Error("The colour cache is missing its provenance.");
|
|
87
|
+
}
|
|
72
88
|
const paints = cache.paints.map((p) => ({
|
|
73
89
|
...p,
|
|
74
90
|
vector: typeof p.vector === "string" ? decodeVector(p.vector) : p.vector,
|
|
@@ -78,8 +94,9 @@ export function createSamplizeColorVecIndex(cache) {
|
|
|
78
94
|
if (identities.has(paint.variantId) ||
|
|
79
95
|
paint.vector.length !== EMBEDDING_VECTOR_SIZE ||
|
|
80
96
|
!paint.vector.every(Number.isFinite) ||
|
|
81
|
-
![paint.oklab.L, paint.oklab.a, paint.oklab.b].every(Number.isFinite))
|
|
97
|
+
![paint.oklab.L, paint.oklab.a, paint.oklab.b].every(Number.isFinite)) {
|
|
82
98
|
throw new Error("The colour cache contains invalid or duplicate paint records.");
|
|
99
|
+
}
|
|
83
100
|
identities.add(paint.variantId);
|
|
84
101
|
}
|
|
85
102
|
const vectors = new Map();
|
|
@@ -88,8 +105,9 @@ export function createSamplizeColorVecIndex(cache) {
|
|
|
88
105
|
let value = vectors.get(key);
|
|
89
106
|
if (!value) {
|
|
90
107
|
value = samplizeSolidColorVector(hex);
|
|
91
|
-
if (vectors.size >= 512)
|
|
108
|
+
if (vectors.size >= 512) {
|
|
92
109
|
vectors.delete(vectors.keys().next().value);
|
|
110
|
+
}
|
|
93
111
|
vectors.set(key, value);
|
|
94
112
|
}
|
|
95
113
|
return value;
|
|
@@ -97,36 +115,42 @@ export function createSamplizeColorVecIndex(cache) {
|
|
|
97
115
|
return {
|
|
98
116
|
search(input) {
|
|
99
117
|
const limit = input.limit ?? 48;
|
|
100
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
118
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
101
119
|
throw new Error("Choose between 1 and 100 suggestions.");
|
|
120
|
+
}
|
|
102
121
|
const { reference, eligible, counts } = selectSamplizeEligiblePaints(paints, input);
|
|
103
122
|
const palette = (input.palette?.length
|
|
104
123
|
? input.palette
|
|
105
124
|
: [{ hex: input.hex ?? reference?.hex ?? "", proportion: 1 }])
|
|
106
125
|
.map((p) => ({ ...p, hex: p.hex.toLowerCase() }))
|
|
107
|
-
.
|
|
126
|
+
.toSorted((a, b) => b.proportion - a.proportion || identityOrder(a.hex, b.hex));
|
|
108
127
|
if (palette.length > 12 ||
|
|
109
128
|
palette.some((p) => !Number.isFinite(p.proportion) ||
|
|
110
129
|
p.proportion <= 0 ||
|
|
111
|
-
p.proportion > 1))
|
|
130
|
+
p.proportion > 1)) {
|
|
112
131
|
throw new Error("Supply up to twelve positive image colour shares.");
|
|
132
|
+
}
|
|
113
133
|
const total = palette.reduce((sum, p) => sum + p.proportion, 0);
|
|
114
134
|
const buckets = palette.map((p, position) => ({
|
|
115
135
|
...p,
|
|
136
|
+
paints: [],
|
|
116
137
|
position,
|
|
117
|
-
vector: vectorFor(p.hex),
|
|
118
138
|
quota: Math.floor((limit * p.proportion) / total),
|
|
119
139
|
remainder: ((limit * p.proportion) / total) % 1,
|
|
120
|
-
|
|
140
|
+
vector: vectorFor(p.hex),
|
|
121
141
|
}));
|
|
122
142
|
let remaining = limit - buckets.reduce((sum, p) => sum + p.quota, 0);
|
|
123
|
-
for (const p of [...buckets].
|
|
124
|
-
if (remaining-- > 0)
|
|
143
|
+
for (const p of [...buckets].toSorted((a, b) => b.remainder - a.remainder || a.position - b.position)) {
|
|
144
|
+
if (remaining-- > 0) {
|
|
125
145
|
p.quota++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
126
148
|
for (const paint of eligible) {
|
|
127
|
-
let best = buckets[0]
|
|
149
|
+
let best = buckets[0];
|
|
150
|
+
let score = embeddingCosineSimilarity(paint.vector, best.vector);
|
|
128
151
|
for (let i = 1; i < buckets.length; i++) {
|
|
129
|
-
const candidate = buckets[i]
|
|
152
|
+
const candidate = buckets[i];
|
|
153
|
+
const next = embeddingCosineSimilarity(paint.vector, candidate.vector);
|
|
130
154
|
if (next > score) {
|
|
131
155
|
best = candidate;
|
|
132
156
|
score = next;
|
|
@@ -135,33 +159,33 @@ export function createSamplizeColorVecIndex(cache) {
|
|
|
135
159
|
best.paints.push({ id: paint.variantId, score });
|
|
136
160
|
}
|
|
137
161
|
const groups = buckets
|
|
138
|
-
.
|
|
162
|
+
.toSorted((a, b) => b.proportion - a.proportion || a.position - b.position)
|
|
139
163
|
.map((p) => {
|
|
140
164
|
const ids = p.paints
|
|
141
|
-
.
|
|
165
|
+
.toSorted((a, b) => b.score - a.score || identityOrder(a.id, b.id))
|
|
142
166
|
.slice(0, p.quota)
|
|
143
167
|
.map((paint) => paint.id);
|
|
144
168
|
return {
|
|
145
169
|
hex: p.hex,
|
|
170
|
+
ids,
|
|
146
171
|
proportion: p.proportion,
|
|
147
172
|
quota: p.quota,
|
|
148
|
-
ids,
|
|
149
173
|
shortfall: p.quota - ids.length,
|
|
150
174
|
};
|
|
151
175
|
});
|
|
152
176
|
const ids = groups.flatMap((p) => p.ids);
|
|
153
177
|
return {
|
|
154
|
-
|
|
155
|
-
groups,
|
|
156
|
-
limited: eligible.length > ids.length,
|
|
157
|
-
eligibleCount: eligible.length,
|
|
178
|
+
countBasis: "complete-catalogue",
|
|
158
179
|
counts,
|
|
159
|
-
sourceVersion: cache.sourceVersion,
|
|
160
180
|
dictionaryVersion: cache.dictionaryVersion,
|
|
181
|
+
eligibleCount: eligible.length,
|
|
161
182
|
embeddingVersion: cache.embeddingVersion,
|
|
183
|
+
groups,
|
|
184
|
+
ids,
|
|
185
|
+
limited: eligible.length > ids.length,
|
|
162
186
|
rankingVersion: cache.rankingVersion,
|
|
163
|
-
|
|
187
|
+
sourceVersion: cache.sourceVersion,
|
|
164
188
|
};
|
|
165
189
|
},
|
|
166
190
|
};
|
|
167
|
-
}
|
|
191
|
+
};
|
|
@@ -8,40 +8,46 @@ export type SchemaResource = "blocks" | "attributes" | "verticals" | "productTyp
|
|
|
8
8
|
* it must cover cannot drift apart.
|
|
9
9
|
*/
|
|
10
10
|
export declare const SCHEMA_RESOURCE_OPERATION_IDS: {
|
|
11
|
-
readonly blocks: "list_schema_blocks";
|
|
12
11
|
readonly attributes: "list_schema_attributes";
|
|
13
|
-
readonly
|
|
12
|
+
readonly blocks: "list_schema_blocks";
|
|
13
|
+
readonly mappings: "list_schema_mappings";
|
|
14
|
+
readonly productTypeTemplates: "list_schema_product_type_templates";
|
|
14
15
|
readonly productTypes: "list_schema_product_types";
|
|
16
|
+
readonly sourceRequirements: "list_schema_source_requirements";
|
|
15
17
|
readonly units: "list_schema_units";
|
|
16
18
|
readonly valueDictionaries: "list_schema_value_dictionaries";
|
|
17
|
-
readonly
|
|
18
|
-
readonly productTypeTemplates: "list_schema_product_type_templates";
|
|
19
|
-
readonly mappings: "list_schema_mappings";
|
|
19
|
+
readonly verticals: "list_schema_verticals";
|
|
20
20
|
};
|
|
21
21
|
export type SchemaResourceRequest = SchemaResource;
|
|
22
|
-
export
|
|
22
|
+
export type SchemaLifecycle = {
|
|
23
23
|
status: OpenEnum<"draft" | "active" | "deprecated">;
|
|
24
24
|
introducedIn: string;
|
|
25
25
|
deprecatedIn?: string;
|
|
26
26
|
supersededBy?: string;
|
|
27
|
-
}
|
|
28
|
-
export
|
|
27
|
+
};
|
|
28
|
+
export type SchemaExternalMapping = {
|
|
29
29
|
target: OpenEnum<"schema_org" | "ifc_pset" | "bsdd" | "iso_23387" | "eclass" | "gs1_gdm" | "gdsn" | "etim" | "uniclass">;
|
|
30
30
|
targetPath: string;
|
|
31
31
|
mappingType: OpenEnum<"direct" | "transform" | "derived" | "classification" | "semantic">;
|
|
32
|
+
/**
|
|
33
|
+
* SKOS mapping strength, read from the MaterialGraph side. Only `exact`
|
|
34
|
+
* licenses substituting one concept for the other.
|
|
35
|
+
*/
|
|
36
|
+
matchStrength?: SchemaMatchStrength;
|
|
32
37
|
notes?: string;
|
|
33
|
-
}
|
|
34
|
-
export
|
|
38
|
+
};
|
|
39
|
+
export type SchemaMatchStrength = OpenEnum<"exact" | "close" | "broad" | "narrow" | "related">;
|
|
40
|
+
export type SchemaBlockItem = {
|
|
35
41
|
id: string;
|
|
36
42
|
semanticId: string;
|
|
37
43
|
lifecycle: SchemaLifecycle;
|
|
38
44
|
name: string;
|
|
39
45
|
description: string;
|
|
40
46
|
attributeIds: string[];
|
|
41
|
-
}
|
|
42
|
-
export type KnownSchemaQuantityKind = "length" | "area" | "volume" | "mass" | "time" | "temperature" | "currency" | "ratio" | "density" | "coverage" | "emissions" | "force" | "power" | "voltage" | "current" | "frequency" | "luminous_flux" | "color_temperature" | "count" | "unitless";
|
|
47
|
+
};
|
|
48
|
+
export type KnownSchemaQuantityKind = "length" | "area" | "volume" | "mass" | "time" | "temperature" | "currency" | "ratio" | "density" | "coverage" | "emissions" | "force" | "thermal_conductivity" | "power" | "voltage" | "current" | "frequency" | "luminous_flux" | "color_temperature" | "count" | "unitless";
|
|
43
49
|
export type SchemaQuantityKind = OpenEnum<KnownSchemaQuantityKind>;
|
|
44
|
-
export
|
|
50
|
+
export type SchemaAttributeItem = {
|
|
45
51
|
id: string;
|
|
46
52
|
semanticId: string;
|
|
47
53
|
lifecycle: SchemaLifecycle;
|
|
@@ -58,14 +64,14 @@ export interface SchemaAttributeItem {
|
|
|
58
64
|
comparable: boolean;
|
|
59
65
|
usedInBlocks: string[];
|
|
60
66
|
enumValues: string[] | null;
|
|
61
|
-
}
|
|
62
|
-
export
|
|
67
|
+
};
|
|
68
|
+
export type SchemaVerticalItem = {
|
|
63
69
|
id: string;
|
|
64
70
|
displayName: string;
|
|
65
71
|
description: string;
|
|
66
|
-
}
|
|
72
|
+
};
|
|
67
73
|
export type SchemaApplicability = OpenEnum<"required" | "recommended" | "optional" | "unusual">;
|
|
68
|
-
export
|
|
74
|
+
export type SchemaProductTypeBlock = {
|
|
69
75
|
blockId: string;
|
|
70
76
|
applicability: SchemaApplicability;
|
|
71
77
|
requiredAttributes?: string[];
|
|
@@ -74,19 +80,21 @@ export interface SchemaProductTypeBlock {
|
|
|
74
80
|
completenessWeight?: number;
|
|
75
81
|
notes?: string;
|
|
76
82
|
optional?: boolean;
|
|
77
|
-
}
|
|
78
|
-
export
|
|
83
|
+
};
|
|
84
|
+
export type SchemaProductTypeItem = {
|
|
79
85
|
id: string;
|
|
80
86
|
name: string;
|
|
81
87
|
description?: string;
|
|
88
|
+
/** Display names this type carried before a rename, kept so they still find it. */
|
|
89
|
+
formerNames?: string[];
|
|
82
90
|
verticalId: string;
|
|
83
91
|
parentProductTypeGroupId?: string;
|
|
84
92
|
blocks: SchemaProductTypeBlock[];
|
|
85
93
|
productTypeSpecificAttributes?: string[];
|
|
86
94
|
semanticId: string;
|
|
87
95
|
lifecycle: SchemaLifecycle;
|
|
88
|
-
}
|
|
89
|
-
export
|
|
96
|
+
};
|
|
97
|
+
export type SchemaUnitItem = {
|
|
90
98
|
id: string;
|
|
91
99
|
name: string;
|
|
92
100
|
symbol: string;
|
|
@@ -97,10 +105,14 @@ export interface SchemaUnitItem {
|
|
|
97
105
|
offset?: number;
|
|
98
106
|
};
|
|
99
107
|
notes?: string;
|
|
108
|
+
/** UN/CEFACT Rec 20 common code (schema.org `unitCode`); absent when Rec 20 has none. */
|
|
109
|
+
uncefactCode?: string;
|
|
110
|
+
/** QUDT unit IRI, where exactly one QUDT unit matches. */
|
|
111
|
+
qudtUnit?: string;
|
|
100
112
|
semanticId: string;
|
|
101
113
|
lifecycle: SchemaLifecycle;
|
|
102
|
-
}
|
|
103
|
-
export
|
|
114
|
+
};
|
|
115
|
+
export type SchemaValueDictionaryTerm = {
|
|
104
116
|
id: string;
|
|
105
117
|
label: string;
|
|
106
118
|
aliases?: string[];
|
|
@@ -108,20 +120,20 @@ export interface SchemaValueDictionaryTerm {
|
|
|
108
120
|
externalMappings?: SchemaExternalMapping[];
|
|
109
121
|
semanticId: string;
|
|
110
122
|
lifecycle: SchemaLifecycle;
|
|
111
|
-
}
|
|
112
|
-
export
|
|
123
|
+
};
|
|
124
|
+
export type SchemaValueDictionaryItem = {
|
|
113
125
|
id: string;
|
|
114
126
|
name: string;
|
|
115
127
|
description: string;
|
|
116
128
|
terms: SchemaValueDictionaryTerm[];
|
|
117
129
|
semanticId: string;
|
|
118
130
|
lifecycle: SchemaLifecycle;
|
|
119
|
-
}
|
|
131
|
+
};
|
|
120
132
|
export type KnownSchemaSourceType = "manufacturer_page" | "technical_data_sheet" | "safety_data_sheet" | "test_report" | "certificate" | "image" | "commerce_page" | "catalog_pdf" | "derived_analysis";
|
|
121
133
|
export type SchemaSourceType = OpenEnum<KnownSchemaSourceType>;
|
|
122
134
|
export type KnownSchemaSourceMethod = "manual_review" | "agent_extract" | "pdf_extract" | "image_analysis" | "html_scrape" | "structured_feed" | "calculation";
|
|
123
135
|
export type SchemaSourceMethod = OpenEnum<KnownSchemaSourceMethod>;
|
|
124
|
-
export
|
|
136
|
+
export type SchemaSourceRequirementItem = {
|
|
125
137
|
id: string;
|
|
126
138
|
name: string;
|
|
127
139
|
description: string;
|
|
@@ -130,11 +142,11 @@ export interface SchemaSourceRequirementItem {
|
|
|
130
142
|
minConfidence: number;
|
|
131
143
|
reviewRequired: boolean;
|
|
132
144
|
freshnessDays?: number;
|
|
133
|
-
sourceBasis?: OpenEnum<"declared" | "derived"
|
|
145
|
+
sourceBasis?: OpenEnum<"declared" | "derived">;
|
|
134
146
|
semanticId: string;
|
|
135
147
|
lifecycle: SchemaLifecycle;
|
|
136
|
-
}
|
|
137
|
-
export
|
|
148
|
+
};
|
|
149
|
+
export type SchemaProductTypeTemplateBlock = {
|
|
138
150
|
blockId: string;
|
|
139
151
|
applicability: SchemaApplicability;
|
|
140
152
|
requiredAttributes?: string[];
|
|
@@ -142,8 +154,8 @@ export interface SchemaProductTypeTemplateBlock {
|
|
|
142
154
|
sourceRequirementId?: string;
|
|
143
155
|
completenessWeight?: number;
|
|
144
156
|
notes?: string;
|
|
145
|
-
}
|
|
146
|
-
export
|
|
157
|
+
};
|
|
158
|
+
export type SchemaProductTypeTemplateItem = {
|
|
147
159
|
id: string;
|
|
148
160
|
name: string;
|
|
149
161
|
productTypeId: string;
|
|
@@ -152,17 +164,18 @@ export interface SchemaProductTypeTemplateItem {
|
|
|
152
164
|
notes?: string;
|
|
153
165
|
semanticId: string;
|
|
154
166
|
lifecycle: SchemaLifecycle;
|
|
155
|
-
}
|
|
156
|
-
export
|
|
167
|
+
};
|
|
168
|
+
export type SchemaMappingItem = {
|
|
157
169
|
target: SchemaExternalMapping["target"];
|
|
158
170
|
subjectKind?: OpenEnum<"attribute" | "block" | "product_type" | "template" | "unit" | "value_dictionary" | "value_dictionary_term">;
|
|
159
171
|
subjectId?: string;
|
|
160
172
|
canonicalPath: string;
|
|
161
173
|
targetPath: string;
|
|
162
174
|
mappingType: SchemaExternalMapping["mappingType"];
|
|
175
|
+
matchStrength?: SchemaMatchStrength;
|
|
163
176
|
notes?: string;
|
|
164
|
-
}
|
|
165
|
-
export
|
|
177
|
+
};
|
|
178
|
+
export type SchemaResourceItemMap = {
|
|
166
179
|
blocks: SchemaBlockItem;
|
|
167
180
|
attributes: SchemaAttributeItem;
|
|
168
181
|
verticals: SchemaVerticalItem;
|
|
@@ -172,10 +185,10 @@ export interface SchemaResourceItemMap {
|
|
|
172
185
|
sourceRequirements: SchemaSourceRequirementItem;
|
|
173
186
|
productTypeTemplates: SchemaProductTypeTemplateItem;
|
|
174
187
|
mappings: SchemaMappingItem;
|
|
175
|
-
}
|
|
176
|
-
export
|
|
188
|
+
};
|
|
189
|
+
export type SchemaResourceResponse<K extends SchemaResource = SchemaResource> = {
|
|
177
190
|
kind: K;
|
|
178
191
|
schemaVersion: string;
|
|
179
192
|
items: SchemaResourceItemMap[K][];
|
|
180
193
|
totalCount: number;
|
|
181
|
-
}
|
|
194
|
+
};
|
package/schema-resource-types.js
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* it must cover cannot drift apart.
|
|
6
6
|
*/
|
|
7
7
|
export const SCHEMA_RESOURCE_OPERATION_IDS = {
|
|
8
|
-
blocks: "list_schema_blocks",
|
|
9
8
|
attributes: "list_schema_attributes",
|
|
10
|
-
|
|
9
|
+
blocks: "list_schema_blocks",
|
|
10
|
+
mappings: "list_schema_mappings",
|
|
11
|
+
productTypeTemplates: "list_schema_product_type_templates",
|
|
11
12
|
productTypes: "list_schema_product_types",
|
|
13
|
+
sourceRequirements: "list_schema_source_requirements",
|
|
12
14
|
units: "list_schema_units",
|
|
13
15
|
valueDictionaries: "list_schema_value_dictionaries",
|
|
14
|
-
|
|
15
|
-
productTypeTemplates: "list_schema_product_type_templates",
|
|
16
|
-
mappings: "list_schema_mappings",
|
|
16
|
+
verticals: "list_schema_verticals",
|
|
17
17
|
};
|
package/search-card-types.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type { OpenEnum, SearchData, SearchResponse } from "./types.js";
|
|
|
19
19
|
* `variantId` at `view: "full"` or via `material()` before claiming anything the
|
|
20
20
|
* card does not carry.
|
|
21
21
|
*/
|
|
22
|
-
export
|
|
22
|
+
export type SearchCardItem = {
|
|
23
23
|
/** Accepted sampleability fact. Absent means unknown, never false. */
|
|
24
24
|
sampleable?: boolean;
|
|
25
25
|
/** Opaque — round-trip verbatim. */
|
|
@@ -31,6 +31,19 @@ export interface SearchCardItem {
|
|
|
31
31
|
name: string;
|
|
32
32
|
variantName: string | null;
|
|
33
33
|
imageUrl: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Key a
|
|
36
|
+
* cache or dedupe on it rather than the URL. ABSENT means no hash is on
|
|
37
|
+
* record, never that there is no image.
|
|
38
|
+
*/
|
|
39
|
+
imageSha256?: string;
|
|
40
|
+
/**
|
|
41
|
+
* How many eligible variants the row's product has, the same set
|
|
42
|
+
* `listVariants` pages, so a follow-up list returns this many: the card's
|
|
43
|
+
* "12 colourways". ABSENT means the product is unknown or has no eligible
|
|
44
|
+
* variant.
|
|
45
|
+
*/
|
|
46
|
+
variantCount?: number;
|
|
34
47
|
/**
|
|
35
48
|
* The manufacturer's own item code, the same key the full item carries.
|
|
36
49
|
* Reach for it when two cards read alike: `name` is the PRODUCT name, and a
|
|
@@ -54,11 +67,20 @@ export interface SearchCardItem {
|
|
|
54
67
|
* attribute rather than a list of candidates.
|
|
55
68
|
*/
|
|
56
69
|
attributes?: Record<string, string | string[] | null>;
|
|
57
|
-
}
|
|
70
|
+
};
|
|
58
71
|
/** The `view:"card"` response form — the lean grid projection of {@link SearchResponse}. */
|
|
59
|
-
export
|
|
72
|
+
export type SearchCardResponse = {
|
|
60
73
|
data: Omit<SearchData, "view" | "results"> & {
|
|
61
74
|
view: OpenEnum<"card">;
|
|
62
75
|
results: SearchCardItem[];
|
|
63
76
|
};
|
|
64
|
-
}
|
|
77
|
+
} & Omit<SearchResponse, "data">;
|
|
78
|
+
/**
|
|
79
|
+
* The request forms the server answers with {@link SearchCardResponse}:
|
|
80
|
+
* `view: "card"`, or `intent: "typeahead"`, which forces the card view.
|
|
81
|
+
*/
|
|
82
|
+
export type CardProjectionRequest = {
|
|
83
|
+
view: "card";
|
|
84
|
+
} | {
|
|
85
|
+
intent: "typeahead";
|
|
86
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module search-index-plan-types
|
|
3
|
+
* @description The plan the one search ran on, as `/search` reports it under
|
|
4
|
+
* `explain.plan` (ADR 0031). Mirrors `searchIndexPlanReceiptSchema` in
|
|
5
|
+
* `@materialgraph/products/search-index/plan-schema`; `key-parity.test.ts`
|
|
6
|
+
* holds the two to the same fields.
|
|
7
|
+
*/
|
|
8
|
+
import type { CorpusScope } from "./corpus-scope-types.js";
|
|
9
|
+
/** One attribute the plan wants: its terms, or any value when `presence`. */
|
|
10
|
+
export type SearchIndexPlanWant = {
|
|
11
|
+
attributeId: string;
|
|
12
|
+
/** Share of the category's materials stating the attribute, 0 to 1. */
|
|
13
|
+
fill: number;
|
|
14
|
+
/** The words it was read from, or `"(filter)"` for a caller's filter. */
|
|
15
|
+
phrase: string;
|
|
16
|
+
/** Any stated value satisfies it; `terms` is then empty. */
|
|
17
|
+
presence?: true;
|
|
18
|
+
/** A hard want removes rows; a soft one only counts toward the order. */
|
|
19
|
+
strength: "hard" | "soft";
|
|
20
|
+
terms: string[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The query's plan: the category, makers, wanted and excluded attribute terms,
|
|
24
|
+
* the colour, the words left for text, and the caller's corpus scope.
|
|
25
|
+
*/
|
|
26
|
+
export type SearchIndexPlan = {
|
|
27
|
+
brands: {
|
|
28
|
+
ids: string[];
|
|
29
|
+
names: string[];
|
|
30
|
+
phrase: string;
|
|
31
|
+
} | null;
|
|
32
|
+
category: {
|
|
33
|
+
label: string;
|
|
34
|
+
phrase: string;
|
|
35
|
+
productTypeIds: string[];
|
|
36
|
+
} | null;
|
|
37
|
+
colour: {
|
|
38
|
+
family12: string[];
|
|
39
|
+
familyId: string;
|
|
40
|
+
hex: string;
|
|
41
|
+
oklab: [number, number, number];
|
|
42
|
+
phrase: string;
|
|
43
|
+
} | null;
|
|
44
|
+
/** Present only when the caller sent a scope narrower than the whole graph. */
|
|
45
|
+
corpusScope?: Exclude<CorpusScope, "all">;
|
|
46
|
+
excludeBrands: string[];
|
|
47
|
+
excludes: {
|
|
48
|
+
attributeId: string;
|
|
49
|
+
phrase: string;
|
|
50
|
+
term: string;
|
|
51
|
+
}[];
|
|
52
|
+
/** Words the reading did not place, left for the text match. */
|
|
53
|
+
leftover: string[];
|
|
54
|
+
normalised: string;
|
|
55
|
+
softAlone: boolean;
|
|
56
|
+
vendorColourNames: string[];
|
|
57
|
+
wants: SearchIndexPlanWant[];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Which reading a search ran on (`version`, `source`), whether it came from
|
|
61
|
+
* the cache, the plan itself, and its signature, so two runs of one request
|
|
62
|
+
* can be compared plan for plan.
|
|
63
|
+
*/
|
|
64
|
+
export type SearchPlanReceipt = {
|
|
65
|
+
cached: boolean;
|
|
66
|
+
plan: SearchIndexPlan;
|
|
67
|
+
signature: string;
|
|
68
|
+
source: "dictionary" | "jev";
|
|
69
|
+
version: string;
|
|
70
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
import type { SearchInput } from "./types.js";
|
|
1
|
+
/** The spec-filter vocabulary MaterialGraph's filter and preference inputs share. */
|
|
3
2
|
/**
|
|
4
3
|
* A hard canonical-attribute filter accepted by the search engine — a term match
|
|
5
4
|
* (`{ attributeId, term }`), a presence check (`{ attributeId, hasValue: true }`)
|
|
@@ -23,7 +22,7 @@ import type { SearchInput } from "./types.js";
|
|
|
23
22
|
* of this object — without it, "no GREENGUARD results" reads as "nobody is
|
|
24
23
|
* certified" when it means "nobody is certified TO THIS EVIDENTIAL STANDARD".
|
|
25
24
|
*/
|
|
26
|
-
export
|
|
25
|
+
export type SearchFilterTrust = {
|
|
27
26
|
/** Confidence floor, 0–1. A value below it is excluded, not marked failed. */
|
|
28
27
|
minConfidence?: number;
|
|
29
28
|
/**
|
|
@@ -45,7 +44,7 @@ export interface SearchFilterTrust {
|
|
|
45
44
|
sourceBasis?: "catalog_feed" | "declared" | "derived";
|
|
46
45
|
/** Fold the attribute's own registry confidence requirement in, server-side. */
|
|
47
46
|
meetsRequirement?: true;
|
|
48
|
-
}
|
|
47
|
+
};
|
|
49
48
|
/**
|
|
50
49
|
* One HARD criterion. Applied as a restriction BEFORE ranking, so a filtered
|
|
51
50
|
* search's empty result means "nothing on record satisfies this", never "nothing
|
|
@@ -57,10 +56,16 @@ export type SearchFilter = {
|
|
|
57
56
|
term: string;
|
|
58
57
|
trust?: SearchFilterTrust;
|
|
59
58
|
} | {
|
|
60
|
-
/** Known effective values are required, and this term must be absent. */
|
|
61
59
|
attributeId: string;
|
|
62
60
|
excludesTerm: string;
|
|
63
61
|
trust?: SearchFilterTrust;
|
|
62
|
+
/**
|
|
63
|
+
* What an UNKNOWN effective value does. Absent or `"drop"` (default)
|
|
64
|
+
* requires a known effective value — a variant that never states the
|
|
65
|
+
* attribute does not pass. `"pass"` admits it — a variant only fails by
|
|
66
|
+
* STATING the excluded term.
|
|
67
|
+
*/
|
|
68
|
+
whenUnstated?: "drop" | "pass";
|
|
64
69
|
}
|
|
65
70
|
/**
|
|
66
71
|
* TERM SET — the attribute must equal any ONE of these. OR within the entry;
|
|
@@ -96,38 +101,3 @@ export type SearchFilter = {
|
|
|
96
101
|
max?: number;
|
|
97
102
|
trust?: SearchFilterTrust;
|
|
98
103
|
};
|
|
99
|
-
/** One structured refinement returned with a search response. */
|
|
100
|
-
export interface SearchSuggestion {
|
|
101
|
-
label: string;
|
|
102
|
-
/** Complete replacement request, not a partial patch. */
|
|
103
|
-
request: SearchInput;
|
|
104
|
-
}
|
|
105
|
-
/** One reading a {@link SearchDisambiguation} offers. */
|
|
106
|
-
export interface SearchInterpretation {
|
|
107
|
-
id: string;
|
|
108
|
-
label: string;
|
|
109
|
-
kind: string;
|
|
110
|
-
/** True for the reading that ran; all false means the engine chose none. */
|
|
111
|
-
isDefault: boolean;
|
|
112
|
-
/** The colour this reading resolved to, when the ambiguity was a colour one. */
|
|
113
|
-
hex?: string;
|
|
114
|
-
/** Complete replacement request, not a partial patch. */
|
|
115
|
-
request: SearchInput;
|
|
116
|
-
}
|
|
117
|
-
/** The governed ambiguity classes emitted by MaterialGraph search. */
|
|
118
|
-
export type SearchDisambiguationKind = "compliance-phrase" | "colour-material" | "paint-colour" | "paint-identity";
|
|
119
|
-
/**
|
|
120
|
-
* The server saying a query had multiple defensible readings.
|
|
121
|
-
*
|
|
122
|
-
* The reading that ran is flagged `isDefault`; every reading is false when the
|
|
123
|
-
* engine deliberately chose none. Each carries a complete executable request,
|
|
124
|
-
* so choosing a reading is a re-issue rather than a patch. Ignoring this block does not
|
|
125
|
-
* make the ambiguity go away — it makes it invisible to the person who asked.
|
|
126
|
-
*/
|
|
127
|
-
export interface SearchDisambiguation {
|
|
128
|
-
/** Compliance, colour-material, paint-colour, or paint-identity ambiguity. */
|
|
129
|
-
kind: SearchDisambiguationKind;
|
|
130
|
-
/** The ambiguous term or phrase. */
|
|
131
|
-
term: string;
|
|
132
|
-
interpretations: SearchInterpretation[];
|
|
133
|
-
}
|