@instruments/materialgraph 3.0.2 → 3.2.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 +20 -20
- package/brand-types.d.ts +6 -6
- package/by-spec-types.d.ts +6 -6
- package/catalog-discovery-types.d.ts +4 -4
- package/categories-client.d.ts +3 -3
- package/category-types.d.ts +18 -18
- package/client-config.d.ts +2 -2
- package/client-response-schema.d.ts +2 -2
- package/client-response-schema.js +4 -4
- package/client-vocabulary.js +1 -1
- package/client.d.ts +1 -1
- package/client.js +14 -10
- package/color-profiles-types.d.ts +8 -8
- package/color-wire-types.d.ts +6 -6
- package/colors-client.d.ts +3 -3
- package/discovery-context-types.d.ts +8 -8
- package/errors.d.ts +12 -13
- package/errors.js +84 -74
- package/find-sampled-together-types.d.ts +6 -6
- package/find-variants-by-color-types.d.ts +30 -30
- package/find-variants-by-vector-types.d.ts +13 -13
- package/get-variant-types.d.ts +11 -7
- package/http-transport.d.ts +14 -10
- package/http-transport.js +14 -12
- package/image-reference-types.d.ts +2 -2
- package/index.d.ts +2 -2
- package/json.d.ts +18 -0
- package/json.js +36 -0
- package/list-enum-values-types.d.ts +8 -8
- package/list-sampled-together-pairs-types.d.ts +6 -6
- package/list-variant-facets-types.d.ts +8 -8
- package/list-variants-types.d.ts +59 -29
- package/material-asset-types.d.ts +37 -24
- package/material-block-types.d.ts +6 -6
- package/material-types.d.ts +6 -6
- package/nearest-paints-types.d.ts +8 -8
- package/operation-responses.d.ts +2 -2
- package/operations.d.ts +1 -1
- package/operations.js +1 -1
- package/package.json +1 -1
- package/parse-operation-response.d.ts +4 -3
- package/parse-operation-response.js +112 -135
- package/resolve-color-types.d.ts +6 -6
- package/resolve-variant-types.d.ts +10 -10
- package/response-schema-catalog.d.ts +8 -0
- package/response-schema-catalog.js +82 -0
- package/response-schemas.d.ts +32 -3
- package/response-schemas.generated.js +26 -25
- package/response-schemas.js +5 -77
- package/schema-resource-types.d.ts +12 -12
- package/search-catalog-subset-types.d.ts +2 -2
- package/search-variants-types.d.ts +12 -12
- package/source-material-types.d.ts +6 -6
- package/source-material.js +2 -32
- package/types.d.ts +38 -38
- package/webmcp.d.ts +10 -4
- package/webmcp.generated.js +5 -4
package/errors.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
/** Error and rate-limit contracts for the retry-free MaterialGraph SDK. */
|
|
2
1
|
export type MaterialGraphErrorKind = "problem" | "simple" | "network" | "timeout" | "aborted" | "rate_limited" | "unexpected";
|
|
3
2
|
export type SanitizedErrorValue = null | boolean | number | string | SanitizedErrorValue[] | SanitizedIssue;
|
|
4
3
|
/** A bounded, recursively sanitized validation-issue record. */
|
|
5
|
-
export
|
|
4
|
+
export interface SanitizedIssue {
|
|
6
5
|
[key: string]: SanitizedErrorValue;
|
|
7
|
-
}
|
|
6
|
+
}
|
|
8
7
|
/** Normalized RFC 7807 body. Unknown response fields are intentionally discarded. */
|
|
9
|
-
export
|
|
8
|
+
export interface ProblemDetail {
|
|
10
9
|
type: string;
|
|
11
10
|
title: string;
|
|
12
11
|
status: number;
|
|
@@ -23,27 +22,27 @@ export type ProblemDetail = {
|
|
|
23
22
|
* not carry them. See {@link MATERIALGRAPH_PROBLEM_EXTENSIONS}.
|
|
24
23
|
*/
|
|
25
24
|
readonly [extension: string]: unknown;
|
|
26
|
-
}
|
|
25
|
+
}
|
|
27
26
|
/** Normalized residual `{ error }` body. Unknown response fields are discarded. */
|
|
28
|
-
export
|
|
27
|
+
export interface SimpleErrorBody {
|
|
29
28
|
/** The vector and variant routes' machine-readable code, when the body is `{ code, message }`. */
|
|
30
29
|
code?: string;
|
|
31
30
|
error: string;
|
|
32
31
|
issues?: SanitizedIssue[];
|
|
33
|
-
}
|
|
32
|
+
}
|
|
34
33
|
/** Parsed `X-RateLimit-*` / `Retry-After` headers. `null` means absent. */
|
|
35
|
-
export
|
|
34
|
+
export interface RateLimit {
|
|
36
35
|
limit: number | null;
|
|
37
36
|
remaining: number | null;
|
|
38
37
|
reset: number | null;
|
|
39
38
|
retryAfter: number | null;
|
|
40
|
-
}
|
|
41
|
-
export
|
|
39
|
+
}
|
|
40
|
+
export interface MaterialGraphRequestMetadata {
|
|
42
41
|
method: string;
|
|
43
42
|
origin: string;
|
|
44
43
|
path: string;
|
|
45
|
-
}
|
|
46
|
-
export
|
|
44
|
+
}
|
|
45
|
+
export interface MaterialGraphErrorInit {
|
|
47
46
|
kind: MaterialGraphErrorKind;
|
|
48
47
|
status?: number;
|
|
49
48
|
retriable: boolean;
|
|
@@ -56,7 +55,7 @@ export type MaterialGraphErrorInit = {
|
|
|
56
55
|
path?: string;
|
|
57
56
|
/** Accepted for compatibility but deliberately never retained on the public error. */
|
|
58
57
|
cause?: unknown;
|
|
59
|
-
}
|
|
58
|
+
}
|
|
60
59
|
type ResponseErrorInput = {
|
|
61
60
|
status: number;
|
|
62
61
|
body: unknown;
|
package/errors.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Error and rate-limit contracts for the retry-free MaterialGraph SDK. */
|
|
2
|
+
import { isJsonNumber, isJsonObject, isJsonString, toJsonValue, } from "./json.js";
|
|
2
3
|
const RETRIABLE_STATUS = new Set([502, 503, 504]);
|
|
3
4
|
/**
|
|
4
5
|
* MaterialGraph's documented problem EXTENSION members — the only non-standard
|
|
@@ -45,7 +46,6 @@ const MAX_UNEXPECTED_TEXT = 768;
|
|
|
45
46
|
const MAX_EXTENSION_DEPTH = 8;
|
|
46
47
|
const MAX_EXTENSION_ITEMS = 100;
|
|
47
48
|
const MAX_EXTENSION_STRING = 1024;
|
|
48
|
-
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
49
49
|
const redact = (text, secrets) => {
|
|
50
50
|
let sanitized = text;
|
|
51
51
|
for (const secret of secrets) {
|
|
@@ -67,35 +67,35 @@ const requestMetadata = (input) => ({
|
|
|
67
67
|
origin: input.origin,
|
|
68
68
|
path: input.path,
|
|
69
69
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
70
|
+
/** Redact, cap and drop non-JSON from one object, at most {@link MAX_EXTENSION_DEPTH} levels deep. */
|
|
71
|
+
const sanitizeObject = (value, secrets, depth) => {
|
|
72
|
+
const sanitizeItem = (item, itemDepth) => {
|
|
73
|
+
if (itemDepth >= MAX_EXTENSION_DEPTH) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
if (item === null || item === true || item === false) {
|
|
77
|
+
return item;
|
|
78
|
+
}
|
|
79
|
+
if (isJsonNumber(item)) {
|
|
80
|
+
return Number.isFinite(item) ? item : undefined;
|
|
81
|
+
}
|
|
82
|
+
if (isJsonString(item)) {
|
|
83
|
+
return safeString(item, secrets);
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(item)) {
|
|
86
|
+
return item
|
|
87
|
+
.slice(0, MAX_EXTENSION_ITEMS)
|
|
88
|
+
.map((child) => sanitizeItem(child, itemDepth + 1))
|
|
89
|
+
.filter((child) => child !== undefined);
|
|
90
|
+
}
|
|
91
|
+
return isJsonObject(item)
|
|
92
|
+
? sanitizeObject(item, secrets, itemDepth)
|
|
93
|
+
: undefined;
|
|
94
|
+
};
|
|
95
95
|
const entries = Object.entries(value)
|
|
96
96
|
.slice(0, MAX_EXTENSION_ITEMS)
|
|
97
97
|
.flatMap(([key, item]) => {
|
|
98
|
-
const sanitized =
|
|
98
|
+
const sanitized = sanitizeItem(item, depth + 1);
|
|
99
99
|
return sanitized === undefined
|
|
100
100
|
? []
|
|
101
101
|
: [[safeString(key, secrets), sanitized]];
|
|
@@ -108,12 +108,11 @@ const sanitizeIssues = (value, secrets) => {
|
|
|
108
108
|
}
|
|
109
109
|
return value
|
|
110
110
|
.slice(0, MAX_EXTENSION_ITEMS)
|
|
111
|
-
.filter(
|
|
112
|
-
.map((issue) =>
|
|
111
|
+
.filter(isJsonObject)
|
|
112
|
+
.map((issue) => sanitizeObject(issue, secrets, 0));
|
|
113
113
|
};
|
|
114
114
|
const sanitizeSuggestions = (value, secrets) => {
|
|
115
|
-
if (!Array.isArray(value) ||
|
|
116
|
-
!value.every((suggestion) => typeof suggestion === "string")) {
|
|
115
|
+
if (!Array.isArray(value) || !value.every(isJsonString)) {
|
|
117
116
|
return undefined;
|
|
118
117
|
}
|
|
119
118
|
return value
|
|
@@ -121,62 +120,72 @@ const sanitizeSuggestions = (value, secrets) => {
|
|
|
121
120
|
.map((suggestion) => safeString(suggestion, secrets));
|
|
122
121
|
};
|
|
123
122
|
const normalizeProblem = (body, secrets) => {
|
|
124
|
-
if (!
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
(
|
|
123
|
+
if (!isJsonObject(body)) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const { detail, doc_uri: docUri, instance, is_retriable: retriable, status, title, trace_id: traceId, type, } = body;
|
|
127
|
+
if (!isJsonString(type) ||
|
|
128
|
+
!isJsonString(title) ||
|
|
129
|
+
!isJsonNumber(status) ||
|
|
130
|
+
!isJsonString(detail) ||
|
|
131
|
+
(retriable !== true && retriable !== false) ||
|
|
132
|
+
!isJsonString(traceId) ||
|
|
133
|
+
(instance !== undefined && !isJsonString(instance))) {
|
|
132
134
|
return undefined;
|
|
133
135
|
}
|
|
134
|
-
const suggestions = sanitizeSuggestions(body.suggestions, secrets);
|
|
135
|
-
const issues = sanitizeIssues(body.issues, secrets);
|
|
136
136
|
// Extensions FIRST so a malformed one can never shadow a standard member
|
|
137
|
-
// below. `
|
|
137
|
+
// below. `sanitizeObject` is the existing redaction and depth/item caps —
|
|
138
138
|
// this is that machinery finally being reached, not a second sanitizer.
|
|
139
|
-
const extensions =
|
|
140
|
-
|
|
139
|
+
const extensions = sanitizeObject(Object.fromEntries(Object.entries(body).filter(([key]) => PROBLEM_EXTENSION_KEYS.has(key))), secrets, 0);
|
|
140
|
+
const problem = {
|
|
141
141
|
...extensions,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
status
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
: { instance: safeString(body.instance, secrets) }),
|
|
149
|
-
is_retriable: body.is_retriable,
|
|
150
|
-
trace_id: safeString(body.trace_id, secrets),
|
|
151
|
-
...(suggestions === undefined ? {} : { suggestions }),
|
|
152
|
-
...(typeof body.doc_uri === "string"
|
|
153
|
-
? { doc_uri: safeString(body.doc_uri, secrets) }
|
|
154
|
-
: {}),
|
|
155
|
-
...(issues === undefined ? {} : { issues }),
|
|
142
|
+
detail: safeString(detail, secrets),
|
|
143
|
+
is_retriable: retriable,
|
|
144
|
+
status,
|
|
145
|
+
title: safeString(title, secrets),
|
|
146
|
+
trace_id: safeString(traceId, secrets),
|
|
147
|
+
type: safeString(type, secrets),
|
|
156
148
|
};
|
|
149
|
+
if (instance !== undefined) {
|
|
150
|
+
problem.instance = safeString(instance, secrets);
|
|
151
|
+
}
|
|
152
|
+
const suggestions = sanitizeSuggestions(body.suggestions, secrets);
|
|
153
|
+
if (suggestions !== undefined) {
|
|
154
|
+
problem.suggestions = suggestions;
|
|
155
|
+
}
|
|
156
|
+
if (isJsonString(docUri)) {
|
|
157
|
+
problem.doc_uri = safeString(docUri, secrets);
|
|
158
|
+
}
|
|
159
|
+
const issues = sanitizeIssues(body.issues, secrets);
|
|
160
|
+
if (issues !== undefined) {
|
|
161
|
+
problem.issues = issues;
|
|
162
|
+
}
|
|
163
|
+
return problem;
|
|
157
164
|
};
|
|
158
165
|
const normalizeSimple = (body, secrets) => {
|
|
159
|
-
if (!
|
|
166
|
+
if (!isJsonObject(body)) {
|
|
160
167
|
return undefined;
|
|
161
168
|
}
|
|
162
|
-
const
|
|
169
|
+
const { code, error, message } = body;
|
|
170
|
+
let simple;
|
|
163
171
|
// `{ code, message }` is the vector routes' error body; keep its code.
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
code: safeString(body.code, secrets),
|
|
169
|
-
error: safeString(body.message, secrets),
|
|
170
|
-
...(issues === undefined ? {} : { issues }),
|
|
172
|
+
if (!isJsonString(error) && isJsonString(code) && isJsonString(message)) {
|
|
173
|
+
simple = {
|
|
174
|
+
code: safeString(code, secrets),
|
|
175
|
+
error: safeString(message, secrets),
|
|
171
176
|
};
|
|
172
177
|
}
|
|
173
|
-
if (
|
|
178
|
+
else if (isJsonString(error)) {
|
|
179
|
+
simple = { error: safeString(error, secrets) };
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
174
182
|
return undefined;
|
|
175
183
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
184
|
+
const issues = sanitizeIssues(body.issues, secrets);
|
|
185
|
+
if (issues !== undefined) {
|
|
186
|
+
simple.issues = issues;
|
|
187
|
+
}
|
|
188
|
+
return simple;
|
|
180
189
|
};
|
|
181
190
|
const unexpectedMessage = (status, responseText, secrets) => {
|
|
182
191
|
const sanitized = redact(responseText, secrets)
|
|
@@ -251,8 +260,9 @@ export class MaterialGraphError extends Error {
|
|
|
251
260
|
}
|
|
252
261
|
static fromResponse(input) {
|
|
253
262
|
const secrets = secretVariants(input.apiKey, input.queryValues);
|
|
254
|
-
const
|
|
255
|
-
const
|
|
263
|
+
const body = toJsonValue(input.body);
|
|
264
|
+
const problem = normalizeProblem(body, secrets);
|
|
265
|
+
const simple = problem === undefined ? normalizeSimple(body, secrets) : undefined;
|
|
256
266
|
const retriable = RETRIABLE_STATUS.has(input.status);
|
|
257
267
|
const metadata = requestMetadata(input);
|
|
258
268
|
if (input.status === 429) {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/** The closed sector vocabulary co-specification evidence is tagged with. */
|
|
13
13
|
export type SampledTogetherProjectType = "Workplace" | "Residential" | "Institution Education" | "Hospitality: Hotel" | "Mixed-Use & Multi-Unit Residential" | "Healthcare" | "Hospitality: Restaurant" | "Government" | "Senior Living" | "Retail" | "Other" | "Sports Entertainment" | "Wellness" | "Medical Dental" | "Aviation" | "Industrial" | "Tech" | "Transportation" | "Single Family" | "Condominium Cooperative" | "Marine" | "Power & Energy" | "University Design Program: Interior Design" | "Non-Billable" | "University Design Program: Interior Architecture" | "University Design Program: Architecture" | "Historic Preservation";
|
|
14
14
|
/** At least one of `variantIds` and `materials`, at most twelve together. */
|
|
15
|
-
export
|
|
15
|
+
export interface FindSampledTogetherInput {
|
|
16
16
|
/** Optional row fields: image adds imageUrl, color adds swatches. */
|
|
17
17
|
include?: ("image" | "color")[];
|
|
18
18
|
/** Materials to return, default 20, at most 100. */
|
|
@@ -23,8 +23,8 @@ export type FindSampledTogetherInput = {
|
|
|
23
23
|
projectType?: SampledTogetherProjectType;
|
|
24
24
|
/** Variants to find sampled-together materials for. */
|
|
25
25
|
variantIds?: string[];
|
|
26
|
-
}
|
|
27
|
-
export
|
|
26
|
+
}
|
|
27
|
+
export interface FindSampledTogetherRow {
|
|
28
28
|
brand: string;
|
|
29
29
|
/** Palette likeness to the seeds. Present with `include: ["color"]`; never reorders. */
|
|
30
30
|
colorFit?: number | null;
|
|
@@ -49,8 +49,8 @@ export type FindSampledTogetherRow = {
|
|
|
49
49
|
/** The trimmed source variant label; null when unknown or for a paint color sample. Separate from surface finish, color family and derived color names. */
|
|
50
50
|
variantLabel: string | null;
|
|
51
51
|
variantName: string | null;
|
|
52
|
-
}
|
|
53
|
-
export
|
|
52
|
+
}
|
|
53
|
+
export interface FindSampledTogetherOutput {
|
|
54
54
|
/** Other brands first; within each, product type groups in turn, each group best first (seeds matched, then lift weighted by projects); one row per product. */
|
|
55
55
|
sampledTogether: FindSampledTogetherRow[];
|
|
56
56
|
/** The seeds as resolved, so a caller sees what a name became. */
|
|
@@ -71,4 +71,4 @@ export type FindSampledTogetherOutput = {
|
|
|
71
71
|
excludedBySearchCatalogSubset?: string[];
|
|
72
72
|
/** References that matched no variant. */
|
|
73
73
|
unresolved: string[];
|
|
74
|
-
}
|
|
74
|
+
}
|
|
@@ -15,7 +15,7 @@ import type { ImageReferenceInput } from "./image-reference-types.js";
|
|
|
15
15
|
import type { SearchCatalogSubset, SearchCatalogSubsetReceipt } from "./search-catalog-subset-types.js";
|
|
16
16
|
export type FindVariantsByColorMode = "contains" | "palette" | "rerank";
|
|
17
17
|
/** One color condition. `role` defaults to `required`; every other field defaults to absent/false/0. */
|
|
18
|
-
export
|
|
18
|
+
export interface ColorConditionInput {
|
|
19
19
|
/** Name, code or hex (e.g. "sage green"). */
|
|
20
20
|
color?: string;
|
|
21
21
|
/** Must be the swatch's largest color. */
|
|
@@ -25,8 +25,8 @@ export type ColorConditionInput = {
|
|
|
25
25
|
share?: number;
|
|
26
26
|
/** Maximum share, e.g. an accent. */
|
|
27
27
|
shareMax?: number;
|
|
28
|
-
}
|
|
29
|
-
export
|
|
28
|
+
}
|
|
29
|
+
export interface FindVariantsByColorInput {
|
|
30
30
|
/** Brand slugs or names to filter to. */
|
|
31
31
|
brands?: string[];
|
|
32
32
|
/** One entry per color (exactly one for rerank). */
|
|
@@ -45,8 +45,8 @@ export type FindVariantsByColorInput = {
|
|
|
45
45
|
targetVariantId?: string;
|
|
46
46
|
/** Ids to reorder by color (rerank). */
|
|
47
47
|
variantIds?: string[];
|
|
48
|
-
}
|
|
49
|
-
export
|
|
48
|
+
}
|
|
49
|
+
export interface ColorConditionReceipt {
|
|
50
50
|
/** CIEDE2000 difference to the assigned settled swatch. Never a probability. */
|
|
51
51
|
distance: number;
|
|
52
52
|
hex: string;
|
|
@@ -56,8 +56,8 @@ export type ColorConditionReceipt = {
|
|
|
56
56
|
proportion: number;
|
|
57
57
|
/** Requested share used for ColorVec retrieval, palette only; null otherwise. */
|
|
58
58
|
target: number | null;
|
|
59
|
-
}
|
|
60
|
-
export
|
|
59
|
+
}
|
|
60
|
+
export interface PaintCatalogVariant {
|
|
61
61
|
brand: string;
|
|
62
62
|
color: string | null;
|
|
63
63
|
imageUrl: string | null;
|
|
@@ -65,8 +65,8 @@ export type PaintCatalogVariant = {
|
|
|
65
65
|
product: string;
|
|
66
66
|
variantId: string;
|
|
67
67
|
variantName: string | null;
|
|
68
|
-
}
|
|
69
|
-
export
|
|
68
|
+
}
|
|
69
|
+
export interface ResolvedColor {
|
|
70
70
|
/** Other meanings of the same words, offered: ColorScope's color when a paint's exact name led. */
|
|
71
71
|
alternatives?: ColorAlternative[];
|
|
72
72
|
catalogVariant: PaintCatalogVariant | null;
|
|
@@ -76,21 +76,21 @@ export type ResolvedColor = {
|
|
|
76
76
|
kind: "point" | "region";
|
|
77
77
|
/** Image-extracted or stored target-variant swatch share; else null. */
|
|
78
78
|
share: number | null;
|
|
79
|
-
}
|
|
80
|
-
export
|
|
79
|
+
}
|
|
80
|
+
export interface ColorAlternative {
|
|
81
81
|
code?: string;
|
|
82
82
|
hex: string;
|
|
83
83
|
libraryId: string;
|
|
84
84
|
libraryName: string;
|
|
85
85
|
name: string;
|
|
86
86
|
query: string;
|
|
87
|
-
}
|
|
88
|
-
export
|
|
87
|
+
}
|
|
88
|
+
export interface UnresolvedColor {
|
|
89
89
|
alternatives: ColorAlternative[];
|
|
90
90
|
index: number;
|
|
91
91
|
input: string | null;
|
|
92
|
-
}
|
|
93
|
-
export
|
|
92
|
+
}
|
|
93
|
+
export interface ColorVariantMatch {
|
|
94
94
|
/** The trimmed source variant label; null when unknown or for a paint color sample. Separate from surface finish, color family and derived color names. */
|
|
95
95
|
variantLabel: string | null;
|
|
96
96
|
productType: {
|
|
@@ -116,8 +116,8 @@ export type ColorVariantMatch = {
|
|
|
116
116
|
productId: string;
|
|
117
117
|
variantId: string;
|
|
118
118
|
variantName: string;
|
|
119
|
-
}
|
|
120
|
-
export
|
|
119
|
+
}
|
|
120
|
+
export interface ColorPageInfo {
|
|
121
121
|
endCursor: string | null;
|
|
122
122
|
hasNextPage: boolean;
|
|
123
123
|
/**
|
|
@@ -128,15 +128,15 @@ export type ColorPageInfo = {
|
|
|
128
128
|
* the page where paging stops at the pool's 400 cap.
|
|
129
129
|
*/
|
|
130
130
|
poolTruncated: boolean;
|
|
131
|
-
}
|
|
132
|
-
|
|
131
|
+
}
|
|
132
|
+
interface ContainsOrPaletteResult {
|
|
133
133
|
/** Color-matched candidates dropped by `list_variants`' hard filters or eligibility. */
|
|
134
134
|
gatedOut: number;
|
|
135
135
|
matches: ColorVariantMatch[];
|
|
136
136
|
pageInfo: ColorPageInfo;
|
|
137
137
|
resolvedColors: ResolvedColor[];
|
|
138
138
|
unresolvedColors: UnresolvedColor[];
|
|
139
|
-
}
|
|
139
|
+
}
|
|
140
140
|
export type FindVariantsByColorContainsResult = ContainsOrPaletteResult & {
|
|
141
141
|
mode: "contains";
|
|
142
142
|
};
|
|
@@ -144,7 +144,7 @@ export type FindVariantsByColorPaletteResult = ContainsOrPaletteResult & {
|
|
|
144
144
|
mode: "palette";
|
|
145
145
|
};
|
|
146
146
|
/** `reference.candidates`/`reference.seed`'s shape — mirrors `compare-color-similarity.ts`'s own seed, unlike `matches[]` below. */
|
|
147
|
-
export
|
|
147
|
+
export interface ColorRankedSeed {
|
|
148
148
|
brand: string;
|
|
149
149
|
brandSlug: string;
|
|
150
150
|
color: string | null;
|
|
@@ -155,9 +155,9 @@ export type ColorRankedSeed = {
|
|
|
155
155
|
variantId: string;
|
|
156
156
|
/** The variant's own name — paint colorway names live here (label contract). */
|
|
157
157
|
variantName: string | null;
|
|
158
|
-
}
|
|
158
|
+
}
|
|
159
159
|
/** RERANK's own card — the same shape `ColorVariantMatch` above (`brandId`, `code`), plus its perceptual distance. */
|
|
160
|
-
export
|
|
160
|
+
export interface ColorRankMatch {
|
|
161
161
|
/** The trimmed source variant label; null when unknown or for a paint color sample. Separate from surface finish, color family and derived color names. */
|
|
162
162
|
variantLabel: string | null;
|
|
163
163
|
brand: string;
|
|
@@ -171,13 +171,13 @@ export type ColorRankMatch = {
|
|
|
171
171
|
productId: string;
|
|
172
172
|
variantId: string;
|
|
173
173
|
variantName: string | null;
|
|
174
|
-
}
|
|
175
|
-
export
|
|
174
|
+
}
|
|
175
|
+
export interface ResolvedColorReference {
|
|
176
176
|
hex: string;
|
|
177
177
|
name: string | null;
|
|
178
178
|
ref: string;
|
|
179
|
-
}
|
|
180
|
-
export
|
|
179
|
+
}
|
|
180
|
+
export interface CompareColorSimilarityReference {
|
|
181
181
|
/** Best-per-brand candidates when `resolution === "ambiguous"`; empty otherwise. */
|
|
182
182
|
candidates: ColorRankedSeed[];
|
|
183
183
|
/** The resolved color when the reference was a `color`, else null. */
|
|
@@ -197,8 +197,8 @@ export type CompareColorSimilarityReference = {
|
|
|
197
197
|
resolution: "resolved" | "ambiguous";
|
|
198
198
|
/** The resolved seed when the reference was a `material`/`variantId`, else null. */
|
|
199
199
|
seed: ColorRankedSeed | null;
|
|
200
|
-
}
|
|
201
|
-
export
|
|
200
|
+
}
|
|
201
|
+
export interface FindVariantsByColorRerankResult {
|
|
202
202
|
/** Present ONLY when the request narrowed it. ABSENT means the whole graph. */
|
|
203
203
|
searchCatalogSubset?: SearchCatalogSubsetReceipt;
|
|
204
204
|
/** Real variant ids outside `searchCatalogSubset` or the materials catalog. Present when a scope narrowed or any was excluded. */
|
|
@@ -212,6 +212,6 @@ export type FindVariantsByColorRerankResult = {
|
|
|
212
212
|
resolvedColors: ResolvedColor[];
|
|
213
213
|
/** Candidate ids that did not resolve to any variant. */
|
|
214
214
|
unresolved: string[];
|
|
215
|
-
}
|
|
215
|
+
}
|
|
216
216
|
export type FindVariantsByColorOutput = FindVariantsByColorContainsResult | FindVariantsByColorPaletteResult | FindVariantsByColorRerankResult;
|
|
217
217
|
export {};
|
|
@@ -12,14 +12,14 @@ import type { FilterGroups, VariantCard } from "./list-variants-types.js";
|
|
|
12
12
|
import type { SearchCatalogSubset } from "./search-catalog-subset-types.js";
|
|
13
13
|
export declare const FIND_VARIANTS_BY_VECTOR_MODES: readonly ["text", "image", "text_and_image"];
|
|
14
14
|
export type FindVariantsByVectorMode = (typeof FIND_VARIANTS_BY_VECTOR_MODES)[number];
|
|
15
|
-
export
|
|
15
|
+
export interface FindVariantsByVectorQuery {
|
|
16
16
|
/** One to six image references, each with exactly one field. Several are combined into one query, and every seed image's variant is left out. Only for image modes. Each image that has to be embedded spends one of the embed requests. */
|
|
17
17
|
images?: ImageReferenceInput[];
|
|
18
18
|
mode: FindVariantsByVectorMode;
|
|
19
19
|
/** Description, mood words included. Only for text modes. */
|
|
20
20
|
text?: string;
|
|
21
|
-
}
|
|
22
|
-
export
|
|
21
|
+
}
|
|
22
|
+
export interface FindVariantsByVectorInput {
|
|
23
23
|
/** Attribute or block ids to add. */
|
|
24
24
|
attributes?: string[];
|
|
25
25
|
/** Variant ids to leave out. A seed image's own variant is always left out. */
|
|
@@ -30,26 +30,26 @@ export type FindVariantsByVectorInput = {
|
|
|
30
30
|
query: FindVariantsByVectorQuery;
|
|
31
31
|
/** Only this corpus scope. Absent or all: every variant. */
|
|
32
32
|
searchCatalogSubset?: SearchCatalogSubset;
|
|
33
|
-
}
|
|
33
|
+
}
|
|
34
34
|
export type FindVariantsByVectorItem = Omit<VariantCard, "materialBankId"> & {
|
|
35
35
|
/** The variant's Material Bank SKU; null means none is recorded. Always present here, unlike `list_variants`' optional field. */
|
|
36
36
|
materialBankId: string | null;
|
|
37
37
|
/** Voyage cosine to the query. Ranks only; not a probability. */
|
|
38
38
|
similarity: number;
|
|
39
39
|
};
|
|
40
|
-
export
|
|
40
|
+
export interface FindVariantsByVectorReference {
|
|
41
41
|
id: string;
|
|
42
42
|
kind: "url" | "assetId" | "variantId" | "sourceId";
|
|
43
|
-
}
|
|
44
|
-
export
|
|
43
|
+
}
|
|
44
|
+
export interface FindVariantsByVectorScan {
|
|
45
45
|
/** True when no further candidates match; false means more may exist. */
|
|
46
46
|
exhausted: boolean;
|
|
47
47
|
read: number;
|
|
48
48
|
rejected: number;
|
|
49
49
|
/** How filters reached the vector search. Always "metadata": every filter runs inside the kNN. */
|
|
50
50
|
route: "lane" | "metadata" | "allowlist";
|
|
51
|
-
}
|
|
52
|
-
export
|
|
51
|
+
}
|
|
52
|
+
export interface FindVariantsByVectorTimings {
|
|
53
53
|
embedMs: number;
|
|
54
54
|
/** Time spent filtering outside the kNN. Always 0: filters run inside it. */
|
|
55
55
|
filterMs: number;
|
|
@@ -57,8 +57,8 @@ export type FindVariantsByVectorTimings = {
|
|
|
57
57
|
totalMs: number;
|
|
58
58
|
vectorMs: number;
|
|
59
59
|
verifyMs: number;
|
|
60
|
-
}
|
|
61
|
-
export
|
|
60
|
+
}
|
|
61
|
+
export interface FindVariantsByVectorOutput {
|
|
62
62
|
/** Explicit `{field: "variant", op: "in"}` filter ids that name a real variant outside the materials catalog — present only when at least one did. */
|
|
63
63
|
excludedBySearchCatalogSubset?: string[];
|
|
64
64
|
items: FindVariantsByVectorItem[];
|
|
@@ -71,6 +71,6 @@ export type FindVariantsByVectorOutput = {
|
|
|
71
71
|
timings: FindVariantsByVectorTimings;
|
|
72
72
|
/** Explicit `{field: "variant", op: "in"}` filter ids that named no eligible variant — present only when at least one did. */
|
|
73
73
|
unresolvedVariantIds?: string[];
|
|
74
|
-
/**
|
|
74
|
+
/** Filter fields no variant in scope states at all. Present only on an empty page, so its absence means the empty page is a genuine no-match. */
|
|
75
75
|
unstated?: string[];
|
|
76
|
-
}
|
|
76
|
+
}
|
package/get-variant-types.d.ts
CHANGED
|
@@ -7,22 +7,24 @@
|
|
|
7
7
|
* `__tests__/contract-parity.test.ts` keeps the mirror honest against the
|
|
8
8
|
* server types.
|
|
9
9
|
*/
|
|
10
|
-
import type { ListVariantsNotApplicable, ListVariantsSpecifications, SampleSubject } from "./list-variants-types.js";
|
|
10
|
+
import type { ListVariantsNotApplicable, ListVariantsSpecifications, SampleSubject, VariantObservations } from "./list-variants-types.js";
|
|
11
11
|
import type { VariantColorPalette } from "./material-block-types.js";
|
|
12
12
|
/** The detail to add under `specifications`; absent, the answer is the compact item alone. */
|
|
13
|
-
export
|
|
13
|
+
export interface GetVariantOptions {
|
|
14
14
|
/** Canonical attribute ids, e.g. `["nrc"]`. */
|
|
15
15
|
attributes?: readonly string[];
|
|
16
16
|
/** Canonical block ids, returned whole, e.g. `["acoustic"]`. */
|
|
17
17
|
blocks?: readonly string[];
|
|
18
|
+
/** Observation attribute ids, e.g. `["sample_size"]`, returned under `observations` by channel. */
|
|
19
|
+
observations?: readonly string[];
|
|
18
20
|
/** Add `ifc`: the IFC 4.3 manufacturer property set and classification references. */
|
|
19
21
|
ifc?: boolean;
|
|
20
|
-
}
|
|
22
|
+
}
|
|
21
23
|
/**
|
|
22
24
|
* The variant as an IFC 4.3 type states it. Properties the record does not
|
|
23
25
|
* hold are left out, so an absent property is unknown.
|
|
24
26
|
*/
|
|
25
|
-
export
|
|
27
|
+
export interface GetVariantIfc {
|
|
26
28
|
propertySets: {
|
|
27
29
|
name: "Pset_ManufacturerTypeInformation";
|
|
28
30
|
properties: {
|
|
@@ -39,13 +41,13 @@ export type GetVariantIfc = {
|
|
|
39
41
|
name?: string;
|
|
40
42
|
edition?: string;
|
|
41
43
|
}[];
|
|
42
|
-
}
|
|
44
|
+
}
|
|
43
45
|
/**
|
|
44
46
|
* One variant: the compact identity, and `specifications` only for the
|
|
45
47
|
* attributes and blocks that were asked for. Only stated values appear there:
|
|
46
48
|
* an unknown value, and a block with none, is absent, never false or zero.
|
|
47
49
|
*/
|
|
48
|
-
export
|
|
50
|
+
export interface GetVariantOutput {
|
|
49
51
|
/** Whether this variant may appear in its Brand's catalog. Material-only lists also require Search Catalog membership. Reads by id include ineligible variants. */
|
|
50
52
|
eligible: boolean;
|
|
51
53
|
channels: string[];
|
|
@@ -98,6 +100,8 @@ export type GetVariantOutput = {
|
|
|
98
100
|
variantLabel: string | null;
|
|
99
101
|
/** Requested blocks or attributes the variant's product type does not carry. */
|
|
100
102
|
notApplicable?: ListVariantsNotApplicable;
|
|
103
|
+
/** Present when `observations` was asked for and the variant has any. */
|
|
104
|
+
observations?: VariantObservations;
|
|
101
105
|
/** Present when `ifc` was asked for. */
|
|
102
106
|
ifc?: GetVariantIfc;
|
|
103
107
|
product: {
|
|
@@ -113,4 +117,4 @@ export type GetVariantOutput = {
|
|
|
113
117
|
};
|
|
114
118
|
url: string | null;
|
|
115
119
|
variantId: string;
|
|
116
|
-
}
|
|
120
|
+
}
|