@instruments/materialgraph 0.28.0 → 0.30.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/brands-client.d.ts +1 -1
- package/by-colour-types.d.ts +4 -4
- package/catalogue-client.d.ts +3 -3
- package/catalogue-client.js +3 -3
- package/catalogue-types.d.ts +1 -1
- package/client-vocabulary.d.ts +3 -5
- package/client-vocabulary.js +9 -6
- package/client.d.ts +73 -174
- package/client.js +85 -211
- package/colour-region-types.d.ts +18 -0
- package/colours-client.d.ts +10 -83
- package/colours-client.js +1 -85
- package/find-variants-by-colour-types.d.ts +197 -0
- package/find-variants-by-vector-types.d.ts +67 -0
- package/find-variants-by-vector-types.js +5 -0
- package/get-variant-types.d.ts +50 -0
- package/get-variant-types.js +10 -0
- package/identifiers.d.ts +1 -1
- package/identifiers.js +1 -1
- package/image-reference-types.d.ts +18 -0
- package/index.d.ts +8 -7
- package/index.js +1 -1
- package/list-enum-values-types.d.ts +58 -0
- package/list-variants-types.d.ts +6 -2
- package/material-asset-types.d.ts +4 -3
- package/material-types.d.ts +11 -150
- package/operations.d.ts +1 -1
- package/operations.js +26 -88
- package/package.json +1 -1
- package/palette-search-types.d.ts +3 -49
- package/resolve-colour-types.d.ts +5 -5
- package/resolve-variant-types.d.ts +75 -0
- package/{identify-types.js → resolve-variant-types.js} +2 -2
- package/response-schemas.generated.d.ts +1 -1
- package/response-schemas.generated.js +45 -84
- package/run-types.d.ts +23 -216
- package/runs.d.ts +10 -58
- package/runs.js +19 -106
- package/schema-resource-types.d.ts +2 -139
- package/schema-resource-types.js +0 -8
- package/search-card-types.d.ts +1 -1
- package/search-index-plan-types.d.ts +4 -1
- package/search-request-types.d.ts +10 -2
- package/spec-types.d.ts +4 -4
- package/spec-types.js +2 -2
- package/sse.d.ts +2 -2
- package/sse.js +2 -2
- package/types.d.ts +4 -38
- package/webmcp.generated.js +3 -3
- package/workflows-client.d.ts +54 -0
- package/workflows-client.js +41 -0
- package/client-source-material-comments.d.ts +0 -51
- package/client-source-material-comments.js +0 -6
- package/codes-client.d.ts +0 -118
- package/codes-client.js +0 -99
- package/codes-types.d.ts +0 -325
- package/colour-aggregate-types.d.ts +0 -163
- package/coordinate-client.d.ts +0 -23
- package/coordinate-client.js +0 -13
- package/demand-batch-types.d.ts +0 -118
- package/demand-types.d.ts +0 -154
- package/identify-types.d.ts +0 -82
- package/material-composition-client.d.ts +0 -21
- package/material-composition-client.js +0 -13
- package/material-composition-types.d.ts +0 -403
- package/material-composition-types.js +0 -1
- package/source-material-validation.d.ts +0 -7
- package/source-material-validation.js +0 -214
- package/spec-facet-types.d.ts +0 -48
- package/spec-facet-types.js +0 -7
- package/substitute-types.d.ts +0 -102
- package/substitute-types.js +0 -1
- package/suggest-types.d.ts +0 -67
- package/suggest-types.js +0 -28
- package/taxonomy-coverage-types.d.ts +0 -34
- package/taxonomy-coverage-types.js +0 -1
- /package/{codes-types.js → colour-region-types.js} +0 -0
- /package/{colour-aggregate-types.js → find-variants-by-colour-types.js} +0 -0
- /package/{demand-batch-types.js → image-reference-types.js} +0 -0
- /package/{demand-types.js → list-enum-values-types.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenEnum } from "./types.js";
|
|
2
|
-
/** The
|
|
3
|
-
export type SchemaResource = "
|
|
2
|
+
/** The governed static resources. */
|
|
3
|
+
export type SchemaResource = "valueDictionaries";
|
|
4
4
|
/**
|
|
5
5
|
* Resource → the operation that serves it. Internal to the SDK (`index.ts`
|
|
6
6
|
* re-exports this module's TYPES only), and it lives beside
|
|
@@ -8,15 +8,7 @@ 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 attributes: "list_schema_attributes";
|
|
12
|
-
readonly blocks: "list_schema_blocks";
|
|
13
|
-
readonly mappings: "list_schema_mappings";
|
|
14
|
-
readonly productTypeTemplates: "list_schema_product_type_templates";
|
|
15
|
-
readonly productTypes: "list_schema_product_types";
|
|
16
|
-
readonly sourceRequirements: "list_schema_source_requirements";
|
|
17
|
-
readonly units: "list_schema_units";
|
|
18
11
|
readonly valueDictionaries: "list_schema_value_dictionaries";
|
|
19
|
-
readonly verticals: "list_schema_verticals";
|
|
20
12
|
};
|
|
21
13
|
export type SchemaResourceRequest = SchemaResource;
|
|
22
14
|
export type SchemaLifecycle = {
|
|
@@ -37,81 +29,6 @@ export type SchemaExternalMapping = {
|
|
|
37
29
|
notes?: string;
|
|
38
30
|
};
|
|
39
31
|
export type SchemaMatchStrength = OpenEnum<"exact" | "close" | "broad" | "narrow" | "related">;
|
|
40
|
-
export type SchemaBlockItem = {
|
|
41
|
-
id: string;
|
|
42
|
-
semanticId: string;
|
|
43
|
-
lifecycle: SchemaLifecycle;
|
|
44
|
-
name: string;
|
|
45
|
-
description: string;
|
|
46
|
-
attributeIds: string[];
|
|
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";
|
|
49
|
-
export type SchemaQuantityKind = OpenEnum<KnownSchemaQuantityKind>;
|
|
50
|
-
export type SchemaAttributeItem = {
|
|
51
|
-
id: string;
|
|
52
|
-
semanticId: string;
|
|
53
|
-
lifecycle: SchemaLifecycle;
|
|
54
|
-
name: string;
|
|
55
|
-
description: string;
|
|
56
|
-
valueKind: OpenEnum<"string" | "text" | "integer" | "number" | "boolean" | "enum" | "object" | "reference">;
|
|
57
|
-
quantityKind: SchemaQuantityKind | null;
|
|
58
|
-
canonicalUnitId: string | null;
|
|
59
|
-
acceptedUnitIds: string[];
|
|
60
|
-
valueDictionaryId: string | null;
|
|
61
|
-
defaultSourceRequirementId: string | null;
|
|
62
|
-
externalMappings: SchemaExternalMapping[];
|
|
63
|
-
searchFacet: boolean;
|
|
64
|
-
comparable: boolean;
|
|
65
|
-
usedInBlocks: string[];
|
|
66
|
-
enumValues: string[] | null;
|
|
67
|
-
};
|
|
68
|
-
export type SchemaVerticalItem = {
|
|
69
|
-
id: string;
|
|
70
|
-
displayName: string;
|
|
71
|
-
description: string;
|
|
72
|
-
};
|
|
73
|
-
export type SchemaApplicability = OpenEnum<"required" | "recommended" | "optional" | "unusual">;
|
|
74
|
-
export type SchemaProductTypeBlock = {
|
|
75
|
-
blockId: string;
|
|
76
|
-
applicability: SchemaApplicability;
|
|
77
|
-
requiredAttributes?: string[];
|
|
78
|
-
optionalAttributes?: string[];
|
|
79
|
-
sourceRequirementId?: string;
|
|
80
|
-
completenessWeight?: number;
|
|
81
|
-
notes?: string;
|
|
82
|
-
optional?: boolean;
|
|
83
|
-
};
|
|
84
|
-
export type SchemaProductTypeItem = {
|
|
85
|
-
id: string;
|
|
86
|
-
name: string;
|
|
87
|
-
description?: string;
|
|
88
|
-
/** Display names this type carried before a rename, kept so they still find it. */
|
|
89
|
-
formerNames?: string[];
|
|
90
|
-
verticalId: string;
|
|
91
|
-
parentProductTypeGroupId?: string;
|
|
92
|
-
blocks: SchemaProductTypeBlock[];
|
|
93
|
-
productTypeSpecificAttributes?: string[];
|
|
94
|
-
semanticId: string;
|
|
95
|
-
lifecycle: SchemaLifecycle;
|
|
96
|
-
};
|
|
97
|
-
export type SchemaUnitItem = {
|
|
98
|
-
id: string;
|
|
99
|
-
name: string;
|
|
100
|
-
symbol: string;
|
|
101
|
-
quantityKind: SchemaQuantityKind;
|
|
102
|
-
acceptedSourceUnits?: string[];
|
|
103
|
-
conversionToCanonical?: {
|
|
104
|
-
factor: number;
|
|
105
|
-
offset?: number;
|
|
106
|
-
};
|
|
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;
|
|
112
|
-
semanticId: string;
|
|
113
|
-
lifecycle: SchemaLifecycle;
|
|
114
|
-
};
|
|
115
32
|
export type SchemaValueDictionaryTerm = {
|
|
116
33
|
id: string;
|
|
117
34
|
label: string;
|
|
@@ -129,62 +46,8 @@ export type SchemaValueDictionaryItem = {
|
|
|
129
46
|
semanticId: string;
|
|
130
47
|
lifecycle: SchemaLifecycle;
|
|
131
48
|
};
|
|
132
|
-
export type KnownSchemaSourceType = "manufacturer_page" | "technical_data_sheet" | "safety_data_sheet" | "test_report" | "certificate" | "image" | "commerce_page" | "catalog_pdf" | "derived_analysis";
|
|
133
|
-
export type SchemaSourceType = OpenEnum<KnownSchemaSourceType>;
|
|
134
|
-
export type KnownSchemaSourceMethod = "manual_review" | "agent_extract" | "pdf_extract" | "image_analysis" | "html_scrape" | "structured_feed" | "calculation";
|
|
135
|
-
export type SchemaSourceMethod = OpenEnum<KnownSchemaSourceMethod>;
|
|
136
|
-
export type SchemaSourceRequirementItem = {
|
|
137
|
-
id: string;
|
|
138
|
-
name: string;
|
|
139
|
-
description: string;
|
|
140
|
-
allowedSourceTypes: SchemaSourceType[];
|
|
141
|
-
allowedMethods: SchemaSourceMethod[];
|
|
142
|
-
minConfidence: number;
|
|
143
|
-
reviewRequired: boolean;
|
|
144
|
-
freshnessDays?: number;
|
|
145
|
-
sourceBasis?: OpenEnum<"declared" | "derived">;
|
|
146
|
-
semanticId: string;
|
|
147
|
-
lifecycle: SchemaLifecycle;
|
|
148
|
-
};
|
|
149
|
-
export type SchemaProductTypeTemplateBlock = {
|
|
150
|
-
blockId: string;
|
|
151
|
-
applicability: SchemaApplicability;
|
|
152
|
-
requiredAttributes?: string[];
|
|
153
|
-
optionalAttributes?: string[];
|
|
154
|
-
sourceRequirementId?: string;
|
|
155
|
-
completenessWeight?: number;
|
|
156
|
-
notes?: string;
|
|
157
|
-
};
|
|
158
|
-
export type SchemaProductTypeTemplateItem = {
|
|
159
|
-
id: string;
|
|
160
|
-
name: string;
|
|
161
|
-
productTypeId: string;
|
|
162
|
-
blocks: SchemaProductTypeTemplateBlock[];
|
|
163
|
-
defaultSourceRequirementId?: string;
|
|
164
|
-
notes?: string;
|
|
165
|
-
semanticId: string;
|
|
166
|
-
lifecycle: SchemaLifecycle;
|
|
167
|
-
};
|
|
168
|
-
export type SchemaMappingItem = {
|
|
169
|
-
target: SchemaExternalMapping["target"];
|
|
170
|
-
subjectKind?: OpenEnum<"attribute" | "block" | "product_type" | "template" | "unit" | "value_dictionary" | "value_dictionary_term">;
|
|
171
|
-
subjectId?: string;
|
|
172
|
-
canonicalPath: string;
|
|
173
|
-
targetPath: string;
|
|
174
|
-
mappingType: SchemaExternalMapping["mappingType"];
|
|
175
|
-
matchStrength?: SchemaMatchStrength;
|
|
176
|
-
notes?: string;
|
|
177
|
-
};
|
|
178
49
|
export type SchemaResourceItemMap = {
|
|
179
|
-
blocks: SchemaBlockItem;
|
|
180
|
-
attributes: SchemaAttributeItem;
|
|
181
|
-
verticals: SchemaVerticalItem;
|
|
182
|
-
productTypes: SchemaProductTypeItem;
|
|
183
|
-
units: SchemaUnitItem;
|
|
184
50
|
valueDictionaries: SchemaValueDictionaryItem;
|
|
185
|
-
sourceRequirements: SchemaSourceRequirementItem;
|
|
186
|
-
productTypeTemplates: SchemaProductTypeTemplateItem;
|
|
187
|
-
mappings: SchemaMappingItem;
|
|
188
51
|
};
|
|
189
52
|
export type SchemaResourceResponse<K extends SchemaResource = SchemaResource> = {
|
|
190
53
|
kind: K;
|
package/schema-resource-types.js
CHANGED
|
@@ -5,13 +5,5 @@
|
|
|
5
5
|
* it must cover cannot drift apart.
|
|
6
6
|
*/
|
|
7
7
|
export const SCHEMA_RESOURCE_OPERATION_IDS = {
|
|
8
|
-
attributes: "list_schema_attributes",
|
|
9
|
-
blocks: "list_schema_blocks",
|
|
10
|
-
mappings: "list_schema_mappings",
|
|
11
|
-
productTypeTemplates: "list_schema_product_type_templates",
|
|
12
|
-
productTypes: "list_schema_product_types",
|
|
13
|
-
sourceRequirements: "list_schema_source_requirements",
|
|
14
|
-
units: "list_schema_units",
|
|
15
8
|
valueDictionaries: "list_schema_value_dictionaries",
|
|
16
|
-
verticals: "list_schema_verticals",
|
|
17
9
|
};
|
package/search-card-types.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type { OpenEnum, SearchData, SearchResponse } from "./types.js";
|
|
|
16
16
|
*
|
|
17
17
|
* A PROJECTION, not a smaller answer: a field the card omits (palette, verdict,
|
|
18
18
|
* signals, availability) is unread here, never known-absent. Re-read the same
|
|
19
|
-
* `variantId` at `view: "full"` or via `
|
|
19
|
+
* `variantId` at `view: "full"` or via `getVariant()` before claiming anything the
|
|
20
20
|
* card does not carry.
|
|
21
21
|
*/
|
|
22
22
|
export type SearchCardItem = {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* `@materialgraph/products/search-index/plan-schema`; `key-parity.test.ts`
|
|
6
6
|
* holds the two to the same fields.
|
|
7
7
|
*/
|
|
8
|
+
import type { ColourRegionRange } from "./colour-region-types.js";
|
|
8
9
|
import type { CorpusScope } from "./corpus-scope-types.js";
|
|
9
10
|
/** One attribute the plan wants: its terms, or any value when `presence`. */
|
|
10
11
|
export type SearchIndexPlanWant = {
|
|
@@ -20,7 +21,7 @@ export type SearchIndexPlanWant = {
|
|
|
20
21
|
terms: string[];
|
|
21
22
|
};
|
|
22
23
|
/**
|
|
23
|
-
* The query's plan: the category,
|
|
24
|
+
* The query's plan: the category, brands, wanted and excluded attribute terms,
|
|
24
25
|
* the colour, the words left for text, and the caller's corpus scope.
|
|
25
26
|
*/
|
|
26
27
|
export type SearchIndexPlan = {
|
|
@@ -40,6 +41,8 @@ export type SearchIndexPlan = {
|
|
|
40
41
|
hex: string;
|
|
41
42
|
oklab: [number, number, number];
|
|
42
43
|
phrase: string;
|
|
44
|
+
/** The colour's region, when the plan holds one rather than a point. */
|
|
45
|
+
range?: ColourRegionRange;
|
|
43
46
|
} | null;
|
|
44
47
|
/** Present only when the caller sent a scope narrower than the whole graph. */
|
|
45
48
|
corpusScope?: Exclude<CorpusScope, "all">;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* repo's source-size gate; every name here is re-exported from `types.ts`, so
|
|
6
6
|
* no import path changes.
|
|
7
7
|
*/
|
|
8
|
+
import type { ColourRegionRange } from "./colour-region-types.js";
|
|
8
9
|
import type { CorpusScope } from "./corpus-scope-types.js";
|
|
9
10
|
import type { Cursor, VariantId } from "./identifiers.js";
|
|
10
11
|
import type { OpenEnum, SearchImageInput } from "./types.js";
|
|
@@ -93,16 +94,23 @@ export type SearchInput = {
|
|
|
93
94
|
* existing Variant. The page is the colour's family, nearest first by OKLab
|
|
94
95
|
* distance; it replaces any colour read from `text`. A Variant with no colour
|
|
95
96
|
* on the index is a 400.
|
|
97
|
+
*
|
|
98
|
+
* `oklab` and `range` are additive: send them when you already resolved the
|
|
99
|
+
* exact OKLab point or the named colour's region (see `resolveColour()`), and
|
|
100
|
+
* the plan carries that colour without re-deriving it from `hex`. `hex` stays
|
|
101
|
+
* required.
|
|
96
102
|
*/
|
|
97
103
|
colour?: {
|
|
98
104
|
hex: string;
|
|
105
|
+
oklab?: [number, number, number];
|
|
106
|
+
range?: ColourRegionRange;
|
|
99
107
|
} | {
|
|
100
108
|
variantId: VariantId;
|
|
101
109
|
};
|
|
102
110
|
/**
|
|
103
|
-
*
|
|
111
|
+
* Brands the page must come from: canonical brand ids, exact slugs
|
|
104
112
|
* ("sherwin-williams") or exact display names ("Sherwin-Williams"), up to
|
|
105
|
-
* 50. They replace the
|
|
113
|
+
* 50. They replace the brands `text` was read as. An empty list is the
|
|
106
114
|
* same request as omitting it — every brand. An unrecognised value is a
|
|
107
115
|
* 400 naming it; a display name shared by more than one brand is a 400
|
|
108
116
|
* naming the exact slugs to choose between; a brand MaterialGraph holds no
|
package/spec-types.d.ts
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* object literal for anything else). Reach for it when the spec is the
|
|
23
23
|
* whole question and ranking would be noise.
|
|
24
24
|
*
|
|
25
|
-
* Discover the tokens before you spend them: `client.
|
|
26
|
-
*
|
|
25
|
+
* Discover the tokens before you spend them: `client.listVariantFacets()` for
|
|
26
|
+
* the live values of the attributes you name, `client.attributeValues()` for one attribute's
|
|
27
27
|
* values, `client.listAttributes({ query })` to turn a phrase into a canonical
|
|
28
28
|
* attribute id. A hand-guessed token returns an honest empty answer, which is
|
|
29
29
|
* the hardest kind of bug to see.
|
|
@@ -57,8 +57,8 @@ export type CertificationProgrammeAttributeId = typeof CERTIFICATION_PROGRAMME_A
|
|
|
57
57
|
/**
|
|
58
58
|
* A term-equality spec criterion: the attribute must carry this canonical value,
|
|
59
59
|
* e.g. `{ attributeId: "fire_classifications", term: "astm_e84_class_a" }`.
|
|
60
|
-
* Discover valid `attributeId`/`term` pairs via `client.
|
|
61
|
-
* and `client.
|
|
60
|
+
* Discover valid `attributeId`/`term` pairs via `client.listVariantFacets()`
|
|
61
|
+
* and `client.listEnumValues()`, or find an attribute from free text with
|
|
62
62
|
* `client.listAttributes({ query })`.
|
|
63
63
|
*/
|
|
64
64
|
export type SpecTermFilter = {
|
package/spec-types.js
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* object literal for anything else). Reach for it when the spec is the
|
|
23
23
|
* whole question and ranking would be noise.
|
|
24
24
|
*
|
|
25
|
-
* Discover the tokens before you spend them: `client.
|
|
26
|
-
*
|
|
25
|
+
* Discover the tokens before you spend them: `client.listVariantFacets()` for
|
|
26
|
+
* the live values of the attributes you name, `client.attributeValues()` for one attribute's
|
|
27
27
|
* values, `client.listAttributes({ query })` to turn a phrase into a canonical
|
|
28
28
|
* attribute id. A hand-guessed token returns an honest empty answer, which is
|
|
29
29
|
* the hardest kind of bug to see.
|
package/sse.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A minimal, dependency-free Server-Sent Events reader — the primitive behind
|
|
3
|
-
* {@link
|
|
3
|
+
* {@link WorkflowsClient.streamRunEvents}. Hand-rolled (no `eventsource`,
|
|
4
4
|
* no `undici`) so the SDK stays zero-runtime-dep and works unchanged inside
|
|
5
5
|
* Node route handlers, where `fetch` yields a byte `ReadableStream`.
|
|
6
6
|
*
|
|
7
7
|
* The parser follows the WHATWG event-stream tokenizer closely enough for the
|
|
8
|
-
* `/api/v1/runs/{runId}/events` contract: `\n`, `\r\n`, and `\r` line endings,
|
|
8
|
+
* `/api/v1/workflows/{workflowId}/runs/{runId}/events` contract: `\n`, `\r\n`, and `\r` line endings,
|
|
9
9
|
* multi-line `data:` accumulation, comment (`:`-prefixed) lines, and a single
|
|
10
10
|
* optional leading space after the field colon. Frames split across network
|
|
11
11
|
* chunks are held in an internal buffer until their terminating blank line.
|
package/sse.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A minimal, dependency-free Server-Sent Events reader — the primitive behind
|
|
3
|
-
* {@link
|
|
3
|
+
* {@link WorkflowsClient.streamRunEvents}. Hand-rolled (no `eventsource`,
|
|
4
4
|
* no `undici`) so the SDK stays zero-runtime-dep and works unchanged inside
|
|
5
5
|
* Node route handlers, where `fetch` yields a byte `ReadableStream`.
|
|
6
6
|
*
|
|
7
7
|
* The parser follows the WHATWG event-stream tokenizer closely enough for the
|
|
8
|
-
* `/api/v1/runs/{runId}/events` contract: `\n`, `\r\n`, and `\r` line endings,
|
|
8
|
+
* `/api/v1/workflows/{workflowId}/runs/{runId}/events` contract: `\n`, `\r\n`, and `\r` line endings,
|
|
9
9
|
* multi-line `data:` accumulation, comment (`:`-prefixed) lines, and a single
|
|
10
10
|
* optional leading space after the field colon. Frames split across network
|
|
11
11
|
* chunks are held in an internal buffer until their terminating blank line.
|
package/types.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ import type { ResponseAttribution } from "./attribution-types.js";
|
|
|
28
28
|
import type { CorpusScope } from "./corpus-scope-types.js";
|
|
29
29
|
import type { Cursor, ProductId, VariantId } from "./identifiers.js";
|
|
30
30
|
import type { FilterOp } from "./list-variants-types.js";
|
|
31
|
-
import type {
|
|
31
|
+
import type { MaterialTile } from "./material-types.js";
|
|
32
32
|
import type { SearchMode, SearchResponseExplainReceipts } from "./search-response-receipt-types.js";
|
|
33
33
|
export type { SearchResponse } from "./search-response-types.js";
|
|
34
34
|
export type * from "./search-response-receipt-types.js";
|
|
@@ -77,7 +77,7 @@ export type MaterialColour = {
|
|
|
77
77
|
};
|
|
78
78
|
/** Where the served image came from. */
|
|
79
79
|
export type ImageSource = OpenEnum<"r2" | "origin">;
|
|
80
|
-
export type {
|
|
80
|
+
export type { MaterialAvailability, MaterialTile } from "./material-types.js";
|
|
81
81
|
/**
|
|
82
82
|
* Match only: the image-space cosine between the query image and this row's
|
|
83
83
|
* image, in [0,1]. Null when it was not measured.
|
|
@@ -98,7 +98,7 @@ export type SearchResultItem = {
|
|
|
98
98
|
resultId?: string;
|
|
99
99
|
/** Accepted sampleability fact. Absent means unknown, never false. */
|
|
100
100
|
sampleable?: boolean;
|
|
101
|
-
/** Opaque — round-trip verbatim into `
|
|
101
|
+
/** Opaque — round-trip verbatim into `getVariant()`, `pairings()`, `similarTo`. */
|
|
102
102
|
variantId: VariantId;
|
|
103
103
|
brand: string;
|
|
104
104
|
product: string;
|
|
@@ -485,17 +485,6 @@ export type PairingsResponse = {
|
|
|
485
485
|
/** Opaque continuation bound to the seed, filters, corpus, and order. */
|
|
486
486
|
nextCursor?: Cursor;
|
|
487
487
|
};
|
|
488
|
-
export type MaterialResponse = {
|
|
489
|
-
material: MaterialDetail;
|
|
490
|
-
};
|
|
491
|
-
export type SuggestColourResponse = {
|
|
492
|
-
suggestions: {
|
|
493
|
-
term: string;
|
|
494
|
-
hex: string;
|
|
495
|
-
libraryId?: string;
|
|
496
|
-
kind: string;
|
|
497
|
-
}[];
|
|
498
|
-
};
|
|
499
488
|
/**
|
|
500
489
|
* How a {@link AttributeListItem} matched the query. Declared here rather than
|
|
501
490
|
* imported: this package is published, so it may not reach across into
|
|
@@ -554,7 +543,6 @@ export type ListAttributesResult = {
|
|
|
554
543
|
};
|
|
555
544
|
export type * from "./catalog-discovery-types.js";
|
|
556
545
|
export type * from "./resolve-colour-types.js";
|
|
557
|
-
export type * from "./suggest-types.js";
|
|
558
546
|
export type * from "./by-spec-types.js";
|
|
559
547
|
export type WhoamiResponse = {
|
|
560
548
|
principal: string;
|
|
@@ -578,6 +566,7 @@ export type SearchImageInput = {
|
|
|
578
566
|
};
|
|
579
567
|
export type { SearchGetParams, SearchIndexFilter, SearchInput, } from "./search-request-types.js";
|
|
580
568
|
export type { SearchIndexPlan, SearchPlanReceipt, } from "./search-index-plan-types.js";
|
|
569
|
+
export type { ColourRegionRange } from "./colour-region-types.js";
|
|
581
570
|
/** Options for a pairings read. */
|
|
582
571
|
export type PairingsOptions = {
|
|
583
572
|
/** Comma-separated coarse category display names; filters both arms. */
|
|
@@ -608,28 +597,6 @@ export type ListAttributesOptions = {
|
|
|
608
597
|
/** `pageInfo.endCursor` from the previous page, with the same query and scope. */
|
|
609
598
|
cursor?: string;
|
|
610
599
|
};
|
|
611
|
-
export type * from "./demand-types.js";
|
|
612
|
-
/** One quarter's tally. Sparse across a series — an absent quarter is not a zero. */
|
|
613
|
-
export type DemandQuarter = {
|
|
614
|
-
quarter: string;
|
|
615
|
-
specCount: number;
|
|
616
|
-
projectCount: number;
|
|
617
|
-
};
|
|
618
|
-
/**
|
|
619
|
-
* Which behavioural signal a demand read is scoped to — and therefore what a
|
|
620
|
-
* number drawn from it may honestly be called.
|
|
621
|
-
*
|
|
622
|
-
* - `sampled` — real ORDER co-occurrence. The default everywhere. Present as
|
|
623
|
-
* "specified together" / "specified on N projects".
|
|
624
|
-
* - `considered` — board / moodboard CURATION. Somebody assembled them; nobody
|
|
625
|
-
* is known to have bought them. Present as "considered alongside", never as
|
|
626
|
-
* a specification.
|
|
627
|
-
* - `specified` — the won tier. STATS ONLY: no co-specification edges are built
|
|
628
|
-
* at this grain, so asking for `specified` companions is a rejected request,
|
|
629
|
-
* not an empty result.
|
|
630
|
-
*/
|
|
631
|
-
export type DemandSignal = OpenEnum<"sampled" | "considered" | "specified">;
|
|
632
|
-
export type * from "./demand-batch-types.js";
|
|
633
600
|
export type ExtractedPalette = {
|
|
634
601
|
colors: {
|
|
635
602
|
hex: string;
|
|
@@ -647,7 +614,6 @@ export type ExtractedPalette = {
|
|
|
647
614
|
export type ExtractPaletteResponse = {
|
|
648
615
|
palette: ExtractedPalette | null;
|
|
649
616
|
};
|
|
650
|
-
export type * from "./spec-facet-types.js";
|
|
651
617
|
/** Body for `POST /api/v1/search/palettes/extract`. */
|
|
652
618
|
export type ExtractPaletteInput = {
|
|
653
619
|
/** The query image as a data URI or bare base64 string. */
|
package/webmcp.generated.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const json = [
|
|
2
|
-
"[{\"annotations\":{\"readOnlyHint\":true,\"untrustedContentHint\":true},\"description\":\"The stable, authenticated search endpoint, POST JSON-body form: `text`, a raw `image` (`url` or `base64`, embedded server-side) or a `similarTo` seed (`variantId`, `materialBankId` or a pre-computed image-space `vector`), a `category`, `filters` and a `corpusScope`, and `limit`, `cursor`, `view` and `explain`. Every request runs the one search over the index (ADR 0031): the query's plan is read from the cache or the dictionaries (brands, categories, colours and attributes are read from the words), one query runs on the search index, and the page is hydrated in the order the index gave. No model runs while the caller waits. A word no material carries may be corrected first; the response then carries `correctedQuery: { from, to }` and its `note` says which results it shows. Results are one per product. A caller may also send a `category` (a hard gate that replaces the category the words were read as), attribute `filters` (hard token sets: a term, a term set, an exclusion or a presence check; OR within one attribute, AND across attributes) and a `corpusScope`. Each becomes a field of the query's plan and runs in the same index query; none of them changes the order. A category or filters can define a page without words. `explain.plan.plan` shows the plan with them on it, and `explain.plan.signature` covers them, so one request gives one signature. A look-alike search reads the seed's nearest materials from the image namespace; the index keeps those inside whatever the words filter to and orders them by image similarity. A field the contract does not declare is a 400 naming it, with near misses; weights, mood, colours, text modes and sorts are no longer part of the request, and brands and colours are read from `text`. `?explain=1` on the query string is honoured as a shorthand for body `explain: true`; an explicit body `explain` (true or false) always wins. The `query` echo never carries raw image bytes or a vector, only `{ type }`. Send `Accept: application/x-ndjson` for one `{ type: \\\"response\\\", status, body }` line carrying exactly what the buffered form answers. Search is dynamic, so success responses carry `Cache-Control: no-store`. Requires the `mg:read` bearer scope.\",\"inputSchema\":{\"$ref\":\"#/$defs/schema0\",\"$defs\":{\"schema0\":{\"type\":\"object\",\"properties\":{\"brands\":{\"description\":\"
|
|
2
|
+
"[{\"annotations\":{\"readOnlyHint\":true,\"untrustedContentHint\":true},\"description\":\"The stable, authenticated search endpoint, POST JSON-body form: `text`, a raw `image` (`url` or `base64`, embedded server-side) or a `similarTo` seed (`variantId`, `materialBankId` or a pre-computed image-space `vector`), a `category`, `filters` and a `corpusScope`, and `limit`, `cursor`, `view` and `explain`. Every request runs the one search over the index (ADR 0031): the query's plan is read from the cache or the dictionaries (brands, categories, colours and attributes are read from the words), one query runs on the search index, and the page is hydrated in the order the index gave. No model runs while the caller waits. A word no material carries may be corrected first; the response then carries `correctedQuery: { from, to }` and its `note` says which results it shows. Results are one per product. A caller may also send a `category` (a hard gate that replaces the category the words were read as), attribute `filters` (hard token sets: a term, a term set, an exclusion or a presence check; OR within one attribute, AND across attributes) and a `corpusScope`. Each becomes a field of the query's plan and runs in the same index query; none of them changes the order. A category or filters can define a page without words. `explain.plan.plan` shows the plan with them on it, and `explain.plan.signature` covers them, so one request gives one signature. A look-alike search reads the seed's nearest materials from the image namespace; the index keeps those inside whatever the words filter to and orders them by image similarity. A field the contract does not declare is a 400 naming it, with near misses; weights, mood, colours, text modes and sorts are no longer part of the request, and brands and colours are read from `text`. `?explain=1` on the query string is honoured as a shorthand for body `explain: true`; an explicit body `explain` (true or false) always wins. The `query` echo never carries raw image bytes or a vector, only `{ type }`. Send `Accept: application/x-ndjson` for one `{ type: \\\"response\\\", status, body }` line carrying exactly what the buffered form answers. Search is dynamic, so success responses carry `Cache-Control: no-store`. Requires the `mg:read` bearer scope.\",\"inputSchema\":{\"$ref\":\"#/$defs/schema0\",\"$defs\":{\"schema0\":{\"type\":\"object\",\"properties\":{\"brands\":{\"description\":\"Brands the page must come from: canonical brand ids, exact slugs (\\\"sherwin-williams\\\") or exact display names (\\\"Sherwin-Williams\\\"). They replace the brands `text` was read as. An empty list is the same request as omitting it — every brand. An unrecognised value is a 400 naming it; a display name shared by more than one brand is a 400 naming the exact slugs to choose between; a brand MaterialGraph holds no materials under is a 400 naming a populated sibling when one exists.\",\"maxItems\":50,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1}},\"category\":{\"type\":\"object\",\"properties\":{\"filter\":{\"minItems\":1,\"maxItems\":50,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Only these public categories are returned: category-group or product-type display names (case-insensitive) or taxonomy keys. A group stands for every product type under it. An unknown value is a 400 listing every valid name.\"}},\"required\":[\"filter\"],\"additionalProperties\":false,\"description\":\"A hard category gate. It replaces the category the words were read as.\"},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"pattern\":\"^#?[0-9a-f]{6}$\",\"description\":\"The colour to order by, e.g. \\\"#9CAF88\\\".\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\"",
|
|
3
3
|
",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"hex\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"variantId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A Variant whose own colour to order by: materials the same colour as this one. A Variant with no colour on the index is a 400.\"}},\"required\":[\"variantId\"],\"additionalProperties\":false}],\"description\":\"Order the page by a colour: `hex`, or `variantId` for the colour of an existing Variant. The page is the colour's family, nearest first by OKLab distance; it replaces any colour read from `text`.\"},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"all\",\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"],\"description\":\"Which corpus to answer from. samplizeCatalogue admits published US paint colours regardless of stock. ABSENT (or 'all') means the WHOLE GRAPH — every material MaterialGraph knows, orderable or not; absence is never a narrower default. Three transaction-oriented scopes gate on governed CHANNEL membership: 'materialBankNaOrderable' (Material Bank North America, ~277,000 materials), 'materialBankEuOrderable' (Material Bank Europe, ~65,000) and 'designShopOrderable' (DesignShop, ~34,000, with the products DesignShop hides from browse excluded). 'materialBankNaAndCatalogue' is the one-query union of Material Bank North America and the governed Catalogue editorial discovery corpus; that union does not by itself claim every member is transactable. 'materialBankOrderable' is NOT one of them: it selects materials carrying a Material Bank identity, which is a provenance signal rather than a channel one, and it admits 98.4% of the graph — use it to exclude crawl-sourced brands, not to mean orderable. A scope answers membership in its named governed corpus, never suitability: scope on channel, then refine on sector. Every scope is applied INSIDE the query: `limit` fills with eligible rows and `counts` describe the scoped corpus, which post-filtering a page cannot give you. An unknown value is a 400 naming it, never a silent fall back to the whole graph.\"},\"cursor\":{\"description\":\"Opaque cursor from a previous response's `cursor`, for the next page of the same query. A cursor from another query is a 409 telling the caller to restart from the first page.\",\"type\":\"string\",\"minLength\":1},\"explain\":{\"description\":\"Add `timings`: wall-clock milliseconds for reading the plan (`planMs`), the index query (`indexMs`) and hydrating the page (`pageMs`), and `explain.plan`: the receipt of the plan the search ran on, with the plan itself.\",\"type\":\"boolean\"},\"filters\":{\"minItems\":1,\"maxItems\":24,\"type\":\"array\",\"items\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"term\":{\"type\":\"string\",\"minLength\":1,\"description\":\"The canonical term the value must carry, e.g. \\\"textile\\\".\"}},\"required\":[\"attributeId\",\"term\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"terms\":{\"minItems\":1,\"maxItems\":50,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Canonical terms, any one of which satisfies the filter.\"}},\"required\":[\"attributeId\",\"terms\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"excludesTerm\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A canonical term the value must not carry. A material ",
|
|
4
4
|
"that states nothing for the attribute passes.\"}},\"required\":[\"attributeId\",\"excludesTerm\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"hasValue\":{\"type\":\"boolean\",\"const\":true,\"description\":\"Require any stated value.\"}},\"required\":[\"attributeId\",\"hasValue\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A number the search index cuts into bands: a numeric attribute such as \\\"nrc_rating\\\" or \\\"lead_time_days\\\", a dimensions lens such as \\\"dimensions.thickness_mm\\\" or \\\"dimensions.short_side_mm\\\" (millimetres), or a composition share such as \\\"composition_weighted.wool\\\" (0 to 1).\"},\"max\":{\"description\":\"Inclusive upper bound. Omit for a floor.\",\"type\":\"number\"},\"min\":{\"description\":\"Inclusive lower bound. Omit for a ceiling.\",\"type\":\"number\"}},\"required\":[\"attributeId\"],\"additionalProperties\":false}]},\"description\":\"Attribute filters, every one hard, run as token sets on the search index. Each entry is a term (`attributeId` + `term`), a term set (`attributeId` + `terms`, any one satisfies it), an exclusion (`attributeId` + `excludesTerm`; a material stating nothing passes), a presence check (`attributeId` + `hasValue: true`) or a numeric range (`attributeId` + `min` and/or `max`, inclusive), read as the number bands wholly inside it, so a bound between two band edges is read inward and a value the index cannot prove in range is left out. Entries on one attribute are OR'd; entries on different attributes AND together. They are added to what the words were read as and change no ordering. An attribute or term the index does not carry is a 400 naming it.\"},\"image\":{\"description\":\"A query image to search by (URL or base64). It is embedded, and the page is its nearest materials in the image namespace; `text`, when also given, narrows them.\",\"oneOf\":[{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"const\":\"url\"},\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"HTTP(S) URL of the query image. MUST be an https URL.\"}},\"required\":[\"type\",\"url\"]},{\"type\":\"object\",\"properties\":{\"data\":{\"type\":\"string\",\"minLength\":1,\"description\":\"Base64-encoded image bytes (or a data URI) the caller already holds — e.g. a form upload — so there is nothing to host.\"},\"type\":{\"type\":\"string\",\"const\":\"base64\"}},\"required\":[\"data\",\"type\"]}],\"type\":\"object\"},\"limit\":{\"description\":\"Products per page (max 60). Absent, the search's own page size.\",\"type\":\"integer\",\"minimum\":1,\"maximum\":60},\"returnAttributes\":{\"maxItems\":8,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Attribute ids whose RESOLVED VALUE should ride each result, under `attributes` keyed by attribute id. Values resolve with the normal variant-over-product precedence. THREE STATES, and they are different: an attribute you did not ask for is not a key at all; an attribute you asked for that this variant carries no accepted value for is `null`; anything else is the value (a string, or an array for a multi-valued attribute). An unknown attribute id is refused naming it, never silently dropped. Pair it with `filters` to show what you filtered on.\"},\"similarTo\":{\"description\":\"Find materials that LOOK like a seed: `variantId` seeds from an existing Variant's image, `materialBankId` from a Material Bank SKU (an unknown SKU is a 400 naming it), `vector` from a pre-computed image-space halfvec literal (`[a,b,...]`). `text`, when also given, narrows the look-alikes.\",\"anyOf\":[{\"type\":\"object\",\"properties\":{\"variantId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"variantId\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"materialBankId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"materialBankId\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"vector\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"vector\"],\"additionalProperties\":false}]},\"text",
|
|
5
5
|
"\":{\"description\":\"Free-text query (\\\"oak flooring\\\", \\\"sage green velvet\\\", \\\"Kvadrat wool\\\"). Brands, categories, colours and attributes are read from the words unless `brands`, `category`, `colour` or `filters` says so instead; a word no material carries may be corrected, and the response says so under `correctedQuery`. May be omitted when `brands`, `category` or `filters` says what to find.\",\"type\":\"string\",\"maxLength\":500},\"view\":{\"default\":\"full\",\"description\":\"Result projection. \\\"full\\\" (default) returns the complete result items; \\\"card\\\" the lean grid projection. The response echoes `view`, which discriminates the `results` union.\",\"type\":\"string\",\"enum\":[\"full\",\"card\"]}},\"additionalProperties\":false}}},\"method\":\"POST\",\"name\":\"search\",\"operationId\":\"search_materials_post\",\"outputSchema\":{\"$ref\":\"#/$defs/schema0\",\"$defs\":{\"schema0\":{\"type\":\"object\",\"properties\":{\"data\":{\"oneOf\":[{\"type\":\"object\",\"properties\":{\"results\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"resultId\":{\"type\":\"string\",\"description\":\"This exact hit's attribution key — `<responseId>:<rank>`, where rank is 1-based within THIS response. Unique across pages, because each page is its own response with its own id. Store it verbatim next to the outcome; it is opaque, and `attribution.responseId` is the field to group by.\"},\"variantId\":{\"type\":\"string\"},\"brand\":{\"type\":\"string\"},\"product\":{\"type\":\"string\"},\"brandSlug\":{\"type\":[\"string\",\"null\"]},\"productId\":{\"type\":[\"string\",\"null\"]},\"materialBankId\":{\"description\":\"The variant's Material Bank SKU — the ONE EXTERNAL identifier on a result, in contrast to the OPAQUE `variantId`: it is the id you are expected to match against Material Bank's own catalogue (carts, ordering and analytics all key on it), so a result list can be joined without a second lookup. Populated by the search and by Match alike. ABSENT means no MB identity is known for the variant, never that the SKU cannot be ordered; presence is the orderability tell, absence is silence.\",\"type\":\"string\"},\"manufacturerCode\":{\"description\":\"The governed manufacturer/source-native item code from `variants.code` (for example \\\"GADLC02\\\"). Populated when the full-result retrieval source carries that canonical field; Match always hydrates it from the variant row. ABSENT means unknown or an older external serving projection, never an invented code. Independent of materialBankId.\",\"type\":\"string\"},\"projectSaveCapability\":{\"description\":\"Explicit source-governed permission to save this exact source-coded variant to a Project. ABSENT means unknown/not allowed; it is never inferred from the brand or name.\",\"type\":\"string\",\"const\":\"allowed\"},\"sampleable\":{\"description\":\"Whether a physical sample is explicitly known to be orderable. Absent means unknown, never unavailable.\",\"type\":\"boolean\"},\"sourceStatus\":{\"description\":\"The governed data status supporting Project capture. ABSENT means unknown. Provisional data remains source-backed but is not a verified catalogue claim.\",\"type\":\"string\",\"const\":\"provisional\"},\"productType\":{\"type\":\"string\"},\"color\":{\"type\":[\"string\",\"null\"]},\"variantName\":{\"type\":[\"string\",\"null\"]},\"imageUrl\":{\"type\":[\"string\",\"null\"]},\"imageSha256\":{\"description\":\"SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Lets a caller key a cache or dedupe on the asset rather than its URL. ABSENT means no hash is on record, never that there is no image.\",\"type\":\"string\"},\"hasImage\":{\"type\":\"boolean\"},\"variantCount\":{\"description\":\"How many eligible variants the row's product has, the same set `list_variants` pages, so a follow-up list of the product returns this many: the card's \\\"12 colourways\\\". ABSENT means the product is unknown or has no eligible variant.\",\"type\":\"integer\",\"exclusiveMinimum\":0,\"maximum\":9007199254740991},\"palette\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"description\":\"`#rrggbb` of the swatch, as extracted from the product image.\"},\"name\":{\"description\":\"Stored human colour name for the swatch, when one was extracted.\",\"type\":[\"string\",\"null\"]},\"proportion\":{",
|
|
6
6
|
"\"type\":\"number\",\"description\":\"The swatch's share of the analysed image, in [0,1].\"}},\"required\":[\"hex\",\"proportion\"],\"additionalProperties\":false},\"description\":\"The material's main-image palette — the FULL stored palette, uncapped and in stored order. Colours are EXTRACTED FROM PRODUCT IMAGERY (visual likeness, never a declared colour specification). A one-swatch palette means the extractor found one colour — solid-colour materials are genuinely monochrome — never that the list was trimmed. This array is always present: EMPTY means nothing is on record (unknown), not 'this material has no colours'.\"},\"colourMeta\":{\"type\":\"object\",\"properties\":{\"dominantFamily\":{\"type\":\"string\"},\"dominantHex\":{\"type\":\"string\"},\"mood\":{\"type\":\"string\"}},\"additionalProperties\":false},\"colourChip\":{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"description\":\"`#rrggbb` to fill the chip with. EXTRACTED FROM the product image (a visual likeness), never a manufacturer-declared colour specification — surfaces must not present it as one.\"}},\"required\":[\"hex\"],\"additionalProperties\":false,\"description\":\"Present when this material's product imagery carries nothing beyond one colour, so a surface should render that colour rather than the photograph. Set for COATINGS (paints, primers, stains, floor coatings) whose stored palette quantises to a single swatch — a paint's photo is a flat fill, and the colour we hold structured beats a JPEG of it. ABSENT means the question was not established (unknown product type, unextracted or multi-swatch palette) and the image should be rendered; it NEVER asserts 'this is not a coating'.\"},\"attributes\":{\"description\":\"Resolved attribute values for the ids sent in `returnAttributes`, keyed by attribute id. ABSENT entirely when `returnAttributes` was not sent. A key present with `null` means this variant carries no accepted value for that attribute — absent is not empty and neither is null: the three states are distinct on purpose. Values resolve with the normal variant-over-product precedence.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}},{\"type\":\"null\"}]}},\"colourBand\":{\"description\":\"`colourDistance` as a word (identical / very close / close / related / different), or null when unmeasurable. Absent when the colour stage did not run.\",\"type\":[\"string\",\"null\"]},\"colourDistance\":{\"description\":\"Match only. OKLab earth mover's distance between the query crop's palette and this material's, reading both palettes' proportions, so a colour that is a small share of the product cannot carry the match. Under 0.1 the colour AGREES, and the page lists agreeing rows first. `null` means the material carries no stored palette — UNKNOWN colour, never 'no colour' and never 'distant'. Absent when the colour stage did not run.\",\"type\":[\"number\",\"null\"]},\"confidence\":{\"description\":\"Match only (MG-1031). How close this material is to the query, as an ABSOLUTE image-space similarity in [0,1], not adjusted for colour — the same unit as `qualityFloor` and `comparison.bestRejected`, so all three can be drawn on one axis. Never normalised against the page, so the number means the same thing across runs. It is the TRUE value and may reach 1; rendering it so that no card claims '100%' is the consumer's job (round toward zero, or show '99%+'). Capping it here would put it on a different ceiling from `bestRejected`, which publishes the same unit uncapped. A Match page is ordered by colour agreement (`colourDistance` under 0.1, then unmeasured, then the rest) and then by this number, so inside each of those sets it never rises down the page. Distinct from `score`, which is the retrieval score on the `[0, maxScore]` scale and does not order a Match page. Absent outside Match.\",\"type\":\"number\",\"minimum\":0,\"maximum\":1},\"confidenceBand\":{\"description\":\"`confidence` as a word, banded on the engine's measured readings (strong >= 0.85, good >= 0.72, fair >= 0.55 = the default quality floor, weak below it and reachable only under `includeBelowFloor",
|
|
7
7
|
"`). Present exactly when `confidence` is.\",\"type\":\"string\",\"enum\":[\"strong\",\"good\",\"fair\",\"weak\"]},\"score\":{\"type\":\"number\",\"description\":\"The selected mode's weighted primary score on the `[0, maxScore]` scale. On a Match page this is the retrieval score and does NOT order the page; the order is colour agreement, then `confidence`.\"},\"signals\":{\"description\":\"Match only: the measured image similarity the row carries.\",\"type\":\"object\",\"properties\":{\"image\":{\"description\":\"Image-space cosine between the query image and this row's image, in [0,1]. Null when it was not measured.\",\"type\":[\"number\",\"null\"]}},\"required\":[\"image\"],\"additionalProperties\":false},\"retired\":{\"description\":\"MB lists the SKU as not visible/retired; demoted in ranking. Omitted when false.\",\"type\":\"boolean\"},\"belowFloor\":{\"description\":\"Present (true) only on quality-floor rejects returned under includeBelowFloor — the item failed the match image-quality floor and would be dropped by default.\",\"type\":\"boolean\"},\"admittedOnColour\":{\"description\":\"Present (true) only on Match rows the colour probe admitted: this material is as close in colour as the catalogue gets, and its image similarity is BELOW the match quality floor by design. It is on the page because no image-retrieved row is nearer in colour, not because it cleared the floor — so a consumer can present it as a colour answer or suppress it knowingly, and a quality check can tell a designed admission from a genuine floor leak. Absent (never false) on rows that came through image retrieval. Distinct from `belowFloor`, which marks rejects returned only under `includeBelowFloor`.\",\"type\":\"boolean\"}},\"required\":[\"variantId\",\"brand\",\"product\",\"brandSlug\",\"productId\",\"color\",\"variantName\",\"imageUrl\",\"hasImage\",\"palette\",\"score\"],\"additionalProperties\":false}},\"view\":{\"default\":\"full\",\"description\":\"Projection echo — always 'full' on this envelope variant.\",\"type\":\"string\",\"const\":\"full\"},\"correctedQuery\":{\"description\":\"Present when a word no material carries was corrected before the search ran: `from` is the query as typed (normalised), `to` the phrasing the page shows results for.\",\"type\":\"object\",\"properties\":{\"from\":{\"type\":\"string\"},\"to\":{\"type\":\"string\"}},\"required\":[\"from\",\"to\"],\"additionalProperties\":false},\"attribution\":{\"type\":\"object\",\"properties\":{\"basis\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\",\"match\"],\"description\":\"The ranking basis, groupable across both ranked routes. On /api/v1/search this is the envelope's `mode` verbatim; /api/v1/search/match reports 'match'. Group your stored outcomes by this field.\"},\"issuedAt\":{\"type\":\"string\",\"description\":\"ISO-8601 timestamp of when this response was assembled, so a stored outcome carries its own age without a second lookup.\"},\"responseId\":{\"type\":\"string\",\"description\":\"This response's stable id — the same value as the `X-Request-Id` header. Store it next to the outcome (an order, a save, a click) to join that outcome back to the ranking that produced it. Opaque: round-trip it verbatim, never parse it.\"}},\"required\":[\"basis\",\"issuedAt\",\"responseId\"],\"additionalProperties\":false,\"description\":\"Result attribution receipt. Present on every successful ranked response. Nothing on our side retains it — what you store IS the record.\"},\"suggestions\":{\"default\":[],\"description\":\"Always empty: the one search offers no refinements. Read nothing from it.\",\"maxItems\":0,\"type\":\"array\",\"items\":{\"not\":{}}},\"mode\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\"],\"description\":\"What ordered the page: 'image' (a look-alike: image similarity to the seed), 'colour' (the words or the caller named a colour: colour distance inside that colour's family), 'lexical' (the query's words, ranked by text rank on the index), 'attribute' (no words left to rank on: the category and filters define the page), or 'agent' (the search agent chose these variants and their order; scores are rank-based, 1 for the first result falling linearly, and `maxScore` is 1).\"},\"maxScore\":{\"type\":\"number\"},\"note\":{\"type\":\"string\"},\"cursor\":{",
|
|
8
|
-
"\"type\":\"string\"},\"timings\":{\"description\":\"Wall-clock milliseconds per step of the search, keyed by step id. The key set is open and depends on the path a query took, so read it by iterating rather than by naming a key. Present only when `explain` is set: diagnostic, not part of the ranking contract.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"type\":\"number\"}},\"explain\":{\"description\":\"Present only under `explain`: the receipt of the plan the search ran on. Diagnostic, like `timings`.\",\"type\":\"object\",\"properties\":{\"plan\":{\"type\":\"object\",\"properties\":{\"cached\":{\"type\":\"boolean\"},\"plan\":{\"type\":\"object\",\"properties\":{\"brands\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"ids\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"names\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"phrase\":{\"type\":\"string\"}},\"required\":[\"ids\",\"names\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"category\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"label\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"productTypeIds\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"label\",\"phrase\",\"productTypeIds\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"family12\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"familyId\":{\"type\":\"string\"},\"hex\":{\"type\":\"string\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"phrase\":{\"type\":\"string\"},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"family12\",\"familyId\",\"hex\",\"oklab\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"]},\"excludeBrands\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"excludes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"term\":{\"type\":\"string\"}},\"required\":[\"attributeId\",\"phrase\",\"term\"],\"additionalProperties\":false}},\"leftover\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"normalised\":{\"type\":\"string\"},\"softAlone\":{\"type\":\"boolean\"},\"vendorColourNames\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"wants\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"fill\":{\"type\":\"number\"},\"phrase\":{\"type\":\"string\"},\"presence\":{\"type\":\"boolean\",\"const\":true},\"strength\":{\"type\":\"string\",\"enum\":[\"hard\",\"soft\"]},\"terms\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"attributeId\",\"fill\",\"phrase\",\"strength\",\"terms\"],\"additionalProperties\":false}}},\"required\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false,\"description\":\"The plan the search ran on: the category,
|
|
8
|
+
"\"type\":\"string\"},\"timings\":{\"description\":\"Wall-clock milliseconds per step of the search, keyed by step id. The key set is open and depends on the path a query took, so read it by iterating rather than by naming a key. Present only when `explain` is set: diagnostic, not part of the ranking contract.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"type\":\"number\"}},\"explain\":{\"description\":\"Present only under `explain`: the receipt of the plan the search ran on. Diagnostic, like `timings`.\",\"type\":\"object\",\"properties\":{\"plan\":{\"type\":\"object\",\"properties\":{\"cached\":{\"type\":\"boolean\"},\"plan\":{\"type\":\"object\",\"properties\":{\"brands\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"ids\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"names\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"phrase\":{\"type\":\"string\"}},\"required\":[\"ids\",\"names\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"category\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"label\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"productTypeIds\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"label\",\"phrase\",\"productTypeIds\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"family12\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"familyId\":{\"type\":\"string\"},\"hex\":{\"type\":\"string\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"phrase\":{\"type\":\"string\"},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"family12\",\"familyId\",\"hex\",\"oklab\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"]},\"excludeBrands\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"excludes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"term\":{\"type\":\"string\"}},\"required\":[\"attributeId\",\"phrase\",\"term\"],\"additionalProperties\":false}},\"leftover\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"normalised\":{\"type\":\"string\"},\"softAlone\":{\"type\":\"boolean\"},\"vendorColourNames\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"wants\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"fill\":{\"type\":\"number\"},\"phrase\":{\"type\":\"string\"},\"presence\":{\"type\":\"boolean\",\"const\":true},\"strength\":{\"type\":\"string\",\"enum\":[\"hard\",\"soft\"]},\"terms\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"attributeId\",\"fill\",\"phrase\",\"strength\",\"terms\"],\"additionalProperties\":false}}},\"required\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false,\"description\":\"The plan the search ran on: the category, brands, wanted and excluded attribute terms (each hard or soft, with its fill), the colour, the words left for text, and the caller's corpus scope when one was sent.\"},\"signature\":{\"type\":\"string\"},\"source\":{\"type\":\"string\",\"enum\":[\"dictionary\",\"jev\"]},\"version\":{\"type\":\"string\"}},\"required\":[\"cached\",\"plan\",\"signature\",\"source\",\"version\"],\"additionalProperties\":false}},\"required\":[\"plan\"],\"additionalProperties\":false},\"query\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}},\"seed\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}}},\"required\":[\"results\",\"view\",\"suggestions\",\"mode\",\"maxScore\",\"query\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"results\":{\"ty",
|
|
9
9
|
"pe\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributes\":{\"description\":\"Resolved attribute values for the ids sent in `returnAttributes`, keyed by attribute id. ABSENT entirely when `returnAttributes` was not sent. A key present with `null` means this variant carries no accepted value for that attribute — absent is not empty and neither is null: the three states are distinct on purpose. Values resolve with the normal variant-over-product precedence.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}},{\"type\":\"null\"}]}},\"brand\":{\"type\":\"string\"},\"brandSlug\":{\"type\":[\"string\",\"null\"]},\"imageSha256\":{\"description\":\"SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Lets a caller key a cache or dedupe on the asset rather than its URL. ABSENT means no hash is on record, never that there is no image.\",\"type\":\"string\"},\"imageUrl\":{\"type\":[\"string\",\"null\"]},\"manufacturerCode\":{\"description\":\"The governed manufacturer/source-native item code from `variants.code` (for example \\\"K-7265-BV\\\") — the same key and the same value the full item publishes. It is what separates two cards a reader cannot otherwise tell apart: brand, product name and variant name are shared by 280,334 of 371,515 cardable variants, because `name` is the PRODUCT name and a paint product is a whole collection. ABSENT means no code is recorded for the variant, never an invented one.\",\"type\":\"string\"},\"name\":{\"type\":\"string\",\"description\":\"Product name (the full item's `product`).\"},\"productId\":{\"type\":[\"string\",\"null\"]},\"projectSaveCapability\":{\"type\":\"string\",\"const\":\"allowed\"},\"resultId\":{\"type\":\"string\",\"description\":\"This exact hit's attribution key — `<responseId>:<rank>`, where rank is 1-based within THIS response. Unique across pages, because each page is its own response with its own id. Store it verbatim next to the outcome; it is opaque, and `attribution.responseId` is the field to group by.\"},\"sampleable\":{\"description\":\"Whether a physical sample is explicitly known to be orderable. Absent means unknown, never unavailable.\",\"type\":\"boolean\"},\"score\":{\"type\":\"number\"},\"sourceStatus\":{\"type\":\"string\",\"const\":\"provisional\"},\"variantCount\":{\"description\":\"How many eligible variants the row's product has, the same set `list_variants` pages, so a follow-up list of the product returns this many: the card's \\\"12 colourways\\\". ABSENT means the product is unknown or has no eligible variant.\",\"type\":\"integer\",\"exclusiveMinimum\":0,\"maximum\":9007199254740991},\"variantId\":{\"type\":\"string\"},\"variantName\":{\"type\":[\"string\",\"null\"]}},\"required\":[\"brand\",\"brandSlug\",\"imageUrl\",\"name\",\"productId\",\"score\",\"variantId\",\"variantName\"],\"additionalProperties\":false}},\"view\":{\"type\":\"string\",\"const\":\"card\",\"description\":\"Projection echo — always 'card' on this envelope variant.\"},\"correctedQuery\":{\"description\":\"Present when a word no material carries was corrected before the search ran: `from` is the query as typed (normalised), `to` the phrasing the page shows results for.\",\"type\":\"object\",\"properties\":{\"from\":{\"type\":\"string\"},\"to\":{\"type\":\"string\"}},\"required\":[\"from\",\"to\"],\"additionalProperties\":false},\"attribution\":{\"type\":\"object\",\"properties\":{\"basis\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\",\"match\"],\"description\":\"The ranking basis, groupable across both ranked routes. On /api/v1/search this is the envelope's `mode` verbatim; /api/v1/search/match reports 'match'. Group your stored outcomes by this field.\"},\"issuedAt\":{\"type\":\"string\",\"description\":\"ISO-8601 timestamp of when this response was assembled, so a stored outcome carries its own age without a second lookup.\"},\"responseId\":{\"type\":\"string\",\"description\":\"This response's stable id — the same value as the `X-Request-Id` header. Store it next to the outcome (an order, a save, a click) to join that outcome back to the ranking that produced it. Opaque: round-trip it verbatim, never parse it.\"}},\"required\":[\"basis\",\"issuedAt\",\"responseId\"],\"additionalProperties\":fals",
|
|
10
10
|
"e,\"description\":\"Result attribution receipt. Present on every successful ranked response. Nothing on our side retains it — what you store IS the record.\"},\"suggestions\":{\"default\":[],\"description\":\"Always empty: the one search offers no refinements. Read nothing from it.\",\"maxItems\":0,\"type\":\"array\",\"items\":{\"not\":{}}},\"mode\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\"],\"description\":\"What ordered the page: 'image' (a look-alike: image similarity to the seed), 'colour' (the words or the caller named a colour: colour distance inside that colour's family), 'lexical' (the query's words, ranked by text rank on the index), 'attribute' (no words left to rank on: the category and filters define the page), or 'agent' (the search agent chose these variants and their order; scores are rank-based, 1 for the first result falling linearly, and `maxScore` is 1).\"},\"maxScore\":{\"type\":\"number\"},\"note\":{\"type\":\"string\"},\"cursor\":{\"type\":\"string\"},\"timings\":{\"description\":\"Wall-clock milliseconds per step of the search, keyed by step id. The key set is open and depends on the path a query took, so read it by iterating rather than by naming a key. Present only when `explain` is set: diagnostic, not part of the ranking contract.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"type\":\"number\"}},\"explain\":{\"description\":\"Present only under `explain`: the receipt of the plan the search ran on. Diagnostic, like `timings`.\",\"type\":\"object\",\"properties\":{\"plan\":{\"type\":\"object\",\"properties\":{\"cached\":{\"type\":\"boolean\"},\"plan\":{\"type\":\"object\",\"properties\":{\"brands\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"ids\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"names\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"phrase\":{\"type\":\"string\"}},\"required\":[\"ids\",\"names\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"category\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"label\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"productTypeIds\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"label\",\"phrase\",\"productTypeIds\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"family12\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"familyId\":{\"type\":\"string\"},\"hex\":{\"type\":\"string\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"phrase\":{\"type\":\"string\"},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"family12\",\"familyId\",\"hex\",\"oklab\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"]},\"excludeBrands\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"excludes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"term\":{\"type\":\"string\"}},\"required\":[\"attributeId\",\"phrase\",\"term\"],\"additionalProperties\":false}},\"leftover\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"normalised\":{\"type\":\"string\"},\"softAlone\":{\"type\":\"boolean\"},\"vendorColourNames\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"wants\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"fill\":{\"type\":\"number\"},\"phrase\":{\"type\":\"string\"},\"presence\":{\"type\":\"boolean\",\"const\":true},\"strength\":{\"type\":\"string\",\"enum\":[\"hard\",\"soft\"]},\"terms\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"attributeId\",\"fill\",\"phrase\",\"strength\",\"terms\"],\"additionalProperties\":false}}},\"req",
|
|
11
|
-
"uired\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false,\"description\":\"The plan the search ran on: the category,
|
|
11
|
+
"uired\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false,\"description\":\"The plan the search ran on: the category, brands, wanted and excluded attribute terms (each hard or soft, with its fill), the colour, the words left for text, and the caller's corpus scope when one was sent.\"},\"signature\":{\"type\":\"string\"},\"source\":{\"type\":\"string\",\"enum\":[\"dictionary\",\"jev\"]},\"version\":{\"type\":\"string\"}},\"required\":[\"cached\",\"plan\",\"signature\",\"source\",\"version\"],\"additionalProperties\":false}},\"required\":[\"plan\"],\"additionalProperties\":false},\"query\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}},\"seed\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}}},\"required\":[\"results\",\"view\",\"suggestions\",\"mode\",\"maxScore\",\"query\"],\"additionalProperties\":false}],\"type\":\"object\"},\"links\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false},\"meta\":{\"type\":\"object\",\"properties\":{\"operationId\":{\"type\":\"string\",\"enum\":[\"search_materials_post\",\"search_materials_get\"]},\"requestId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"operationId\",\"requestId\"],\"additionalProperties\":false},\"warnings\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1}}},\"required\":[\"data\",\"links\",\"meta\",\"warnings\"],\"additionalProperties\":false}}},\"path\":\"/api/v1/search\",\"requiredHeaders\":[],\"requiresVisibleConfirmation\":false}]",
|
|
12
12
|
].join("");
|
|
13
13
|
export const WEBMCP_TOOLS = JSON.parse(json);
|