@instruments/materialgraph 0.38.0 → 0.40.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/associations-client.js +12 -3
- package/by-spec-types.d.ts +1 -1
- package/catalogue-types.d.ts +36 -37
- package/categories-client.d.ts +2 -2
- package/client-response-schema.d.ts +3 -0
- package/client-response-schema.js +79 -0
- package/client.d.ts +9 -4
- package/client.js +46 -18
- package/colors-client.d.ts +5 -2
- package/colors-client.js +4 -0
- package/errors.d.ts +4 -4
- package/errors.js +13 -10
- package/find-variants-by-color-types.d.ts +10 -8
- package/find-variants-by-vector-types.d.ts +3 -0
- package/get-variant-types.d.ts +22 -1
- package/http-transport.d.ts +2 -1
- package/http-transport.js +12 -10
- package/index.d.ts +22 -21
- package/material-block-types.d.ts +7 -1
- package/material-resources-client.js +4 -1
- package/nearest-paints-types.d.ts +33 -0
- package/nearest-paints-types.js +1 -0
- package/operation-responses.d.ts +65 -0
- package/operation-responses.js +1 -0
- package/operations.d.ts +4 -12
- package/operations.generated.d.ts +11 -0
- package/operations.generated.js +189 -0
- package/operations.js +10 -178
- package/package.json +2 -2
- package/parse-operation-response.d.ts +5 -0
- package/parse-operation-response.js +202 -0
- package/response-schemas.generated.d.ts +1 -1
- package/response-schemas.generated.js +35 -32
- package/runs.d.ts +2 -1
- package/runs.js +45 -12
- package/samplize-catalogue-types.d.ts +8 -8
- package/samplize-colorvec.js +111 -80
- package/sse.d.ts +2 -1
- package/sse.js +7 -5
- package/types.d.ts +6 -6
package/associations-client.js
CHANGED
|
@@ -17,7 +17,10 @@ import { resolveOperation } from "./operations.js";
|
|
|
17
17
|
*
|
|
18
18
|
* @param variantId The PRODUCT variant. Opaque — pass back exactly what you were given.
|
|
19
19
|
*/
|
|
20
|
-
export const declaredFinishes = async (transport, variantId, options, signal) => await transport.requestJson(resolveOperation("list_associated_finishes"), {
|
|
20
|
+
export const declaredFinishes = async (transport, variantId, options, signal) => await transport.requestJson(resolveOperation("list_associated_finishes"), {
|
|
21
|
+
query: { variantId, ...options },
|
|
22
|
+
signal,
|
|
23
|
+
});
|
|
21
24
|
/**
|
|
22
25
|
* THE QUESTION: "what furniture takes THIS fabric?" — the products the
|
|
23
26
|
* BRAND declares a finish variant is available on (GET
|
|
@@ -32,6 +35,12 @@ export const declaredFinishes = async (transport, variantId, options, signal) =>
|
|
|
32
35
|
*
|
|
33
36
|
* @param variantId The FINISH variant. Opaque — pass back exactly what you were given.
|
|
34
37
|
*/
|
|
35
|
-
export const declaredProducts = async (transport, variantId, options, signal) => await transport.requestJson(resolveOperation("list_associated_products"), {
|
|
38
|
+
export const declaredProducts = async (transport, variantId, options, signal) => await transport.requestJson(resolveOperation("list_associated_products"), {
|
|
39
|
+
query: { variantId, ...options },
|
|
40
|
+
signal,
|
|
41
|
+
});
|
|
36
42
|
/** Read brand-declared applicability without collapsing Product/Variant default attribute level. */
|
|
37
|
-
export const applicability = async (transport, options, signal) => await transport.requestJson(resolveOperation("get_applicability"), {
|
|
43
|
+
export const applicability = async (transport, options, signal) => await transport.requestJson(resolveOperation("get_applicability"), {
|
|
44
|
+
query: options,
|
|
45
|
+
signal,
|
|
46
|
+
});
|
package/by-spec-types.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export type BySpecVerdictCell = {
|
|
|
50
50
|
/** Trust in `value`, 0–1. Null = unrecorded, which is weaker than a low score. */
|
|
51
51
|
confidence: number | null;
|
|
52
52
|
/** Where `value` came from (`tested` > `declared` > `catalog_feed` > `derived`). */
|
|
53
|
-
|
|
53
|
+
valueSource: string | null;
|
|
54
54
|
/**
|
|
55
55
|
* Why an `unverified` cell missed the bar; null otherwise.
|
|
56
56
|
* - `below_confidence` — the value is real but scored under the floor.
|
package/catalogue-types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** A verified product location in a specific immutable brand publication. */
|
|
2
|
-
export
|
|
2
|
+
export type CatalogueReference = {
|
|
3
3
|
anchor: {
|
|
4
4
|
coordinateSpace: "normalized_0_1000";
|
|
5
5
|
/** Page carrying the printed code; defaults to page.documentPage. Do not draw it on another page. */
|
|
@@ -56,7 +56,7 @@ export interface CatalogueReference {
|
|
|
56
56
|
};
|
|
57
57
|
status: "verified";
|
|
58
58
|
isPrimary: boolean;
|
|
59
|
-
}
|
|
59
|
+
};
|
|
60
60
|
/**
|
|
61
61
|
* Why a known variant has no verified reference. None of these says the
|
|
62
62
|
* product is missing from the printed book; nobody records how many of a
|
|
@@ -114,7 +114,7 @@ export type CatalogueReferenceResult = {
|
|
|
114
114
|
variantId: string;
|
|
115
115
|
status: "upstream_failure";
|
|
116
116
|
};
|
|
117
|
-
export
|
|
117
|
+
export type CatalogueReferenceBatchResponse = {
|
|
118
118
|
results: CatalogueReferenceResult[];
|
|
119
119
|
coverage: {
|
|
120
120
|
requested: number;
|
|
@@ -124,25 +124,23 @@ export interface CatalogueReferenceBatchResponse {
|
|
|
124
124
|
unavailable: number;
|
|
125
125
|
upstreamFailure: number;
|
|
126
126
|
};
|
|
127
|
-
}
|
|
127
|
+
};
|
|
128
128
|
/** Bounds for the flat catalogue-channel collection shelf. */
|
|
129
|
-
export
|
|
129
|
+
export type CatalogueCollectionsOptions = {
|
|
130
130
|
limit?: number;
|
|
131
131
|
offset?: number;
|
|
132
132
|
sampleLimit?: number;
|
|
133
|
-
}
|
|
133
|
+
};
|
|
134
134
|
/** One representative product image carried by a catalogue collection. */
|
|
135
|
-
export
|
|
136
|
-
assetId: string;
|
|
135
|
+
export type CatalogueCollectionSampleProduct = {
|
|
137
136
|
imageUrl: string;
|
|
138
|
-
sourceImageUrl: string;
|
|
139
137
|
productId: string;
|
|
140
138
|
productName: string;
|
|
141
139
|
variantId: string;
|
|
142
140
|
variantName: string | null;
|
|
143
|
-
}
|
|
141
|
+
};
|
|
144
142
|
/** A product collection whose variants have governed catalogue membership. */
|
|
145
|
-
export
|
|
143
|
+
export type CatalogueChannelCollection = {
|
|
146
144
|
id: string;
|
|
147
145
|
slug: string;
|
|
148
146
|
name: string;
|
|
@@ -150,9 +148,9 @@ export interface CatalogueChannelCollection {
|
|
|
150
148
|
productCount: number;
|
|
151
149
|
variantCount: number;
|
|
152
150
|
sampleProducts: CatalogueCollectionSampleProduct[];
|
|
153
|
-
}
|
|
151
|
+
};
|
|
154
152
|
/** The flat, paginated catalogue-channel collection read model. */
|
|
155
|
-
export
|
|
153
|
+
export type CatalogueChannelCollectionsResponse = {
|
|
156
154
|
collections: CatalogueChannelCollection[];
|
|
157
155
|
channel: {
|
|
158
156
|
token: "catalogue";
|
|
@@ -168,14 +166,14 @@ export interface CatalogueChannelCollectionsResponse {
|
|
|
168
166
|
offset: number;
|
|
169
167
|
hasMore: boolean;
|
|
170
168
|
};
|
|
171
|
-
}
|
|
172
|
-
export
|
|
169
|
+
};
|
|
170
|
+
export type CatalogueDocumentAccess = {
|
|
173
171
|
documentId: string;
|
|
174
172
|
contentType: "application/pdf";
|
|
175
173
|
readerUrl: string;
|
|
176
174
|
originalUrl: string;
|
|
177
175
|
byteRanges: "supported" | "unknown";
|
|
178
|
-
}
|
|
176
|
+
};
|
|
179
177
|
export type CatalogueDocumentAccessResult = {
|
|
180
178
|
documentId: string;
|
|
181
179
|
status: "available";
|
|
@@ -193,7 +191,7 @@ export type CatalogueDocumentAccessResult = {
|
|
|
193
191
|
documentId: string;
|
|
194
192
|
status: "upstream_failure";
|
|
195
193
|
};
|
|
196
|
-
export
|
|
194
|
+
export type CatalogDocument = {
|
|
197
195
|
availability: "available";
|
|
198
196
|
brand: {
|
|
199
197
|
id: string;
|
|
@@ -211,13 +209,13 @@ export interface CatalogDocument {
|
|
|
211
209
|
productStatus: "partial" | "not_processed";
|
|
212
210
|
receipt: CatalogAvailableReceipt;
|
|
213
211
|
title: string;
|
|
214
|
-
}
|
|
215
|
-
export
|
|
212
|
+
};
|
|
213
|
+
export type CatalogEdition = {
|
|
216
214
|
id: string;
|
|
217
215
|
label: string;
|
|
218
216
|
title: string;
|
|
219
|
-
}
|
|
220
|
-
export
|
|
217
|
+
};
|
|
218
|
+
export type CatalogAvailableReceipt = {
|
|
221
219
|
extraction: {
|
|
222
220
|
references: number;
|
|
223
221
|
status: "partial" | "not_processed";
|
|
@@ -240,17 +238,17 @@ export interface CatalogAvailableReceipt {
|
|
|
240
238
|
algorithm: "sha256";
|
|
241
239
|
value: string;
|
|
242
240
|
};
|
|
243
|
-
|
|
241
|
+
valueSource: "brand_supplied";
|
|
244
242
|
retainedUrl: string;
|
|
245
243
|
status: "retained";
|
|
246
244
|
};
|
|
247
|
-
}
|
|
248
|
-
export
|
|
245
|
+
};
|
|
246
|
+
export type CatalogFailureReceipt = {
|
|
249
247
|
count: number;
|
|
250
248
|
reason: string;
|
|
251
249
|
stage: "source" | "render" | "extraction";
|
|
252
|
-
}
|
|
253
|
-
export
|
|
250
|
+
};
|
|
251
|
+
export type UnavailableCatalogDocument = {
|
|
254
252
|
availability: "source_unavailable";
|
|
255
253
|
brand: {
|
|
256
254
|
id: string;
|
|
@@ -282,13 +280,13 @@ export interface UnavailableCatalogDocument {
|
|
|
282
280
|
};
|
|
283
281
|
};
|
|
284
282
|
title: string;
|
|
285
|
-
}
|
|
283
|
+
};
|
|
286
284
|
export type CatalogPublication = CatalogDocument | UnavailableCatalogDocument;
|
|
287
|
-
export
|
|
285
|
+
export type CatalogDocumentList = {
|
|
288
286
|
catalogs: CatalogPublication[];
|
|
289
287
|
source: "verified-source-material-registry";
|
|
290
|
-
}
|
|
291
|
-
export
|
|
288
|
+
};
|
|
289
|
+
export type CatalogProductReferenceList = {
|
|
292
290
|
catalog: CatalogDocument;
|
|
293
291
|
coverage: {
|
|
294
292
|
documentPages: {
|
|
@@ -313,22 +311,23 @@ export interface CatalogProductReferenceList {
|
|
|
313
311
|
references: CatalogueReference[];
|
|
314
312
|
source: "verified-source-material-registry";
|
|
315
313
|
status: "available";
|
|
316
|
-
}
|
|
317
|
-
export
|
|
314
|
+
};
|
|
315
|
+
export type CatalogProductReferenceUnavailable = {
|
|
318
316
|
catalog: UnavailableCatalogDocument;
|
|
319
317
|
reason: "retained_source_not_found";
|
|
320
318
|
status: "source_unavailable";
|
|
321
|
-
}
|
|
319
|
+
};
|
|
322
320
|
export type CatalogProductReferenceReadResult = CatalogProductReferenceList | CatalogProductReferenceUnavailable;
|
|
323
|
-
export
|
|
321
|
+
export type CataloguePageRequiredArtifact = {
|
|
324
322
|
mediaType: "image/webp";
|
|
325
323
|
version: "catalogue-page-webp-v1";
|
|
326
|
-
}
|
|
327
|
-
export
|
|
324
|
+
};
|
|
325
|
+
export type CataloguePageAvailableArtifact = {
|
|
328
326
|
bucket: "materialgraph";
|
|
329
327
|
key: string;
|
|
330
328
|
url: string;
|
|
331
|
-
|
|
329
|
+
mediaType: CataloguePageRequiredArtifact["mediaType"];
|
|
330
|
+
};
|
|
332
331
|
export type CataloguePage = {
|
|
333
332
|
catalogId: string;
|
|
334
333
|
documentId: string;
|
package/categories-client.d.ts
CHANGED
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { CategoriesGetResult, CategoriesListInput, CategoriesListResult } from "./category-types.js";
|
|
19
19
|
import type { QueryParams } from "./http-transport.js";
|
|
20
|
-
import type {
|
|
20
|
+
import type { JsonOperationId, OperationResponses } from "./operation-responses.js";
|
|
21
21
|
/** The client's own request primitive, handed down so this file owns no transport. */
|
|
22
22
|
export type CategoriesTransport = {
|
|
23
|
-
get<
|
|
23
|
+
get<K extends JsonOperationId>(operationId: K, query?: QueryParams, signal?: AbortSignal, pathParams?: Readonly<Record<string, string>>): Promise<OperationResponses[K]>;
|
|
24
24
|
};
|
|
25
25
|
export declare class CategoriesClient {
|
|
26
26
|
#private;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2
|
+
// Only the fields declared as OpenEnum in the SDK are open here. Union
|
|
3
|
+
// discriminants stay closed so their associated object shapes remain true.
|
|
4
|
+
const openStrings = new Set([
|
|
5
|
+
"CategoryColorProfilesResponse.profiles.level",
|
|
6
|
+
"FindVariantsByColorResponse.searchCatalogueSubset.scope",
|
|
7
|
+
"GetCategoryResponse.kind",
|
|
8
|
+
"ListAttributesResponse.items.match.method",
|
|
9
|
+
"ListCategoriesResponse.items.match.method",
|
|
10
|
+
"ListEnumValuesResponse.items.match.method",
|
|
11
|
+
"MaterialBlockProjection.blocks.status",
|
|
12
|
+
"MaterialBlockProjection.blocks.fields.status",
|
|
13
|
+
"MaterialTile.availability",
|
|
14
|
+
"MaterialTile.imageSource",
|
|
15
|
+
"PairingItem.availability",
|
|
16
|
+
"PairingItem.imageSource",
|
|
17
|
+
"PairingItem.demand.momentum.state",
|
|
18
|
+
"PairingItem.ranking.basis",
|
|
19
|
+
"PairingOrdering.anchorColorBasis",
|
|
20
|
+
"PairingOrdering.applied",
|
|
21
|
+
"PairingOrdering.colorSpace",
|
|
22
|
+
"PairingOrdering.direction",
|
|
23
|
+
"PairingOrdering.missingValues",
|
|
24
|
+
"PairingOrdering.requested",
|
|
25
|
+
"PairingOrdering.tieBreak",
|
|
26
|
+
"ProductDocumentPage.coverage.productUnion.state",
|
|
27
|
+
"ProductDocumentPage.coverage.requestedVariant.state",
|
|
28
|
+
"ProductDocumentPage.coverage.sources.state",
|
|
29
|
+
"ProductDocumentPage.documents.declarations.status",
|
|
30
|
+
"ProductDocumentPage.documents.documentTypes",
|
|
31
|
+
"ProductDocumentPage.documents.status",
|
|
32
|
+
"PublicRun.status",
|
|
33
|
+
"ResolveColorResponse.match.libraryType",
|
|
34
|
+
"ResolveColorResponse.match.variant.reason",
|
|
35
|
+
"SchemaValueDictionariesResponse.items.lifecycle.status",
|
|
36
|
+
"SchemaValueDictionariesResponse.items.terms.lifecycle.status",
|
|
37
|
+
"SchemaValueDictionariesResponse.items.terms.externalMappings.mappingType",
|
|
38
|
+
"SchemaValueDictionariesResponse.items.terms.externalMappings.matchStrength",
|
|
39
|
+
"SchemaValueDictionariesResponse.items.terms.externalMappings.target",
|
|
40
|
+
"SourceMaterialBatchReceipt.sources.role",
|
|
41
|
+
"VariantAssetPage.documentCoverage",
|
|
42
|
+
"VariantAssetPage.items.availability",
|
|
43
|
+
"VariantAssetPage.items.documentTypes",
|
|
44
|
+
"VariantAssetPage.items.imageRole",
|
|
45
|
+
"VariantAssetPage.items.kind",
|
|
46
|
+
"VariantAssetPage.items.presentation",
|
|
47
|
+
]);
|
|
48
|
+
/** Adapt a fresh producer schema to the SDK's existing open string enums. */
|
|
49
|
+
export const openClientResponseEnums = (schema) => {
|
|
50
|
+
const visit = (node, path) => {
|
|
51
|
+
if (!isRecord(node)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (node.type === "string" && openStrings.has(path)) {
|
|
55
|
+
delete node.enum;
|
|
56
|
+
delete node.const;
|
|
57
|
+
}
|
|
58
|
+
if (isRecord(node.$defs)) {
|
|
59
|
+
for (const [name, definition] of Object.entries(node.$defs)) {
|
|
60
|
+
visit(definition, name);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (isRecord(node.properties)) {
|
|
64
|
+
for (const [name, property] of Object.entries(node.properties)) {
|
|
65
|
+
visit(property, `${path}.${name}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
visit(node.items, path);
|
|
69
|
+
for (const keyword of ["anyOf", "allOf", "oneOf", "prefixItems"]) {
|
|
70
|
+
const children = node[keyword];
|
|
71
|
+
if (Array.isArray(children)) {
|
|
72
|
+
for (const child of children) {
|
|
73
|
+
visit(child, path);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
visit(schema, "");
|
|
79
|
+
};
|
package/client.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ import type { SchemaResource, SchemaResourceResponse } from "./schema-resource-t
|
|
|
19
19
|
import type { SearchVariantsInput, SearchVariantsOutput } from "./search-variants-types.js";
|
|
20
20
|
import type { ExtractPaletteInput, ExtractPaletteResponse, ListAttributesOptions, ListAttributesResult, PairingsOptions, PairingsResponse, ResolveColorOptions, ResolveColorResponse, WhoamiResponse } from "./types.js";
|
|
21
21
|
import { WorkflowsClient } from "./workflows-client.js";
|
|
22
|
-
export
|
|
22
|
+
export { DEFAULT_BASE_URL } from "./client-config.js";
|
|
23
|
+
export type { MaterialGraphClientOptions } from "./client-config.js";
|
|
23
24
|
/**
|
|
24
25
|
* The MaterialGraph client — every lens on the graph, on one object.
|
|
25
26
|
*
|
|
@@ -83,7 +84,7 @@ export declare class MaterialGraphClient extends CatalogueClient {
|
|
|
83
84
|
* Color is usually derived from product imagery, which is visual likeness,
|
|
84
85
|
* not a color specification. A brand's declared color, such as a paint's
|
|
85
86
|
* published hex, wins where MaterialGraph holds one, and each value's
|
|
86
|
-
*
|
|
87
|
+
* Value Source says which.
|
|
87
88
|
*/
|
|
88
89
|
readonly colors: ColorsClient;
|
|
89
90
|
/**
|
|
@@ -96,6 +97,10 @@ export declare class MaterialGraphClient extends CatalogueClient {
|
|
|
96
97
|
readonly workflows: WorkflowsClient;
|
|
97
98
|
constructor(options: MaterialGraphClientOptions);
|
|
98
99
|
get lastRateLimit(): RateLimit | null;
|
|
100
|
+
/** Current catalogue generation; authenticated, no SQL and no rate-limit charge. */
|
|
101
|
+
getCatalogueGeneration(signal?: AbortSignal): Promise<{
|
|
102
|
+
generation: number;
|
|
103
|
+
}>;
|
|
99
104
|
/**
|
|
100
105
|
* THE QUESTION: "tell me about THIS variant" (GET
|
|
101
106
|
* `/api/v1/variants/{variantId}`, `get_variant`).
|
|
@@ -191,7 +196,7 @@ export declare class MaterialGraphClient extends CatalogueClient {
|
|
|
191
196
|
searchVariants(input: SearchVariantsInput, signal?: AbortSignal): Promise<SearchVariantsOutput>;
|
|
192
197
|
/**
|
|
193
198
|
* THE QUESTION: "which variants hold, resemble, or can be ranked by, this
|
|
194
|
-
* color?" (
|
|
199
|
+
* color?" (GET `/api/v1/variants/by-color`, MG-2217/MG-2230/MG-2247).
|
|
195
200
|
* One required `mode`: `contains` (a swatch for every required `colors[]`
|
|
196
201
|
* condition), `palette` (whole-palette closeness to `colors[]`, an
|
|
197
202
|
* image's extracted palette, or `targetVariantId`'s own palette) or
|
|
@@ -199,7 +204,7 @@ export declare class MaterialGraphClient extends CatalogueClient {
|
|
|
199
204
|
*/
|
|
200
205
|
findVariantsByColor(input: FindVariantsByColorInput, signal?: AbortSignal): Promise<FindVariantsByColorOutput>;
|
|
201
206
|
/**
|
|
202
|
-
* THE QUESTION: "what did designers sample together with these?" (
|
|
207
|
+
* THE QUESTION: "what did designers sample together with these?" (GET
|
|
203
208
|
* `/api/v1/variants/sampled-together`, MG-2332). Give `variantIds` and/or
|
|
204
209
|
* `materials` (free-text names, one variant each, at most twelve together);
|
|
205
210
|
* the materials come back other brands first, then the most projects, each
|
package/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { applicability, declaredFinishes, declaredProducts, } from "./associations-client.js";
|
|
2
2
|
import { listBrands } from "./brands-client.js";
|
|
3
3
|
import { CatalogueClient } from "./catalogue-client.js";
|
|
4
4
|
import { CategoriesClient } from "./categories-client.js";
|
|
@@ -14,7 +14,7 @@ import { uploadSourceMaterial } from "./runs.js";
|
|
|
14
14
|
import { SCHEMA_RESOURCE_OPERATION_IDS } from "./schema-resource-types.js";
|
|
15
15
|
import { WorkflowsClient } from "./workflows-client.js";
|
|
16
16
|
// Re-exported whole so `index.ts` and every existing importer keep their path.
|
|
17
|
-
export
|
|
17
|
+
export { DEFAULT_BASE_URL } from "./client-config.js";
|
|
18
18
|
/**
|
|
19
19
|
* The MaterialGraph client — every lens on the graph, on one object.
|
|
20
20
|
*
|
|
@@ -77,7 +77,7 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
77
77
|
* Color is usually derived from product imagery, which is visual likeness,
|
|
78
78
|
* not a color specification. A brand's declared color, such as a paint's
|
|
79
79
|
* published hex, wins where MaterialGraph holds one, and each value's
|
|
80
|
-
*
|
|
80
|
+
* Value Source says which.
|
|
81
81
|
*/
|
|
82
82
|
colors;
|
|
83
83
|
/**
|
|
@@ -126,6 +126,10 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
126
126
|
signal,
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
+
/** Current catalogue generation; authenticated, no SQL and no rate-limit charge. */
|
|
130
|
+
async getCatalogueGeneration(signal) {
|
|
131
|
+
return await this.#get("get_catalogue_generation", undefined, signal);
|
|
132
|
+
}
|
|
129
133
|
// ── Materials ──────────────────────────────────────────────────────────────
|
|
130
134
|
/**
|
|
131
135
|
* THE QUESTION: "tell me about THIS variant" (GET
|
|
@@ -146,10 +150,12 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
146
150
|
*/
|
|
147
151
|
async getVariant(variantId, options, signal) {
|
|
148
152
|
return await this.#get("get_variant", {
|
|
149
|
-
attributes: options?.attributes
|
|
153
|
+
attributes: options?.attributes !== undefined && options.attributes.length > 0
|
|
150
154
|
? options.attributes.join(",")
|
|
151
155
|
: undefined,
|
|
152
|
-
blocks: options?.blocks
|
|
156
|
+
blocks: options?.blocks !== undefined && options.blocks.length > 0
|
|
157
|
+
? options.blocks.join(",")
|
|
158
|
+
: undefined,
|
|
153
159
|
}, signal, { variantId });
|
|
154
160
|
}
|
|
155
161
|
async materialBlocks(variantId, signal) {
|
|
@@ -168,7 +174,8 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
168
174
|
* what the corpus actually holds.
|
|
169
175
|
*/
|
|
170
176
|
async schema(resource, signal) {
|
|
171
|
-
|
|
177
|
+
const response = await this.#get(SCHEMA_RESOURCE_OPERATION_IDS[resource], undefined, signal);
|
|
178
|
+
return { ...response, kind: resource };
|
|
172
179
|
}
|
|
173
180
|
/**
|
|
174
181
|
* THE QUESTION: "what goes WITH this material?" — the companionship rail, hung
|
|
@@ -190,14 +197,14 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
190
197
|
}
|
|
191
198
|
/** "What finishes does the brand declare for THIS product?" - {@link declaredFinishes}. */
|
|
192
199
|
async associatedFinishes(variantId, options, signal) {
|
|
193
|
-
return await
|
|
200
|
+
return await declaredFinishes(this.#transport, variantId, options, signal);
|
|
194
201
|
}
|
|
195
202
|
/** "What products does the brand declare THIS finish for?" - {@link declaredProducts}. */
|
|
196
203
|
async associatedProducts(variantId, options, signal) {
|
|
197
|
-
return await
|
|
204
|
+
return await declaredProducts(this.#transport, variantId, options, signal);
|
|
198
205
|
}
|
|
199
206
|
async applicability(options, signal) {
|
|
200
|
-
return await
|
|
207
|
+
return await applicability(this.#transport, options, signal);
|
|
201
208
|
}
|
|
202
209
|
/**
|
|
203
210
|
* THE QUESTION: "eligible variants matching these hard filters, ranked and
|
|
@@ -221,24 +228,30 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
221
228
|
*/
|
|
222
229
|
async listVariants(input, signal) {
|
|
223
230
|
return await this.#get("list_variants", {
|
|
224
|
-
attributes: input.attributes
|
|
231
|
+
attributes: input.attributes !== undefined && input.attributes.length > 0
|
|
225
232
|
? input.attributes.join(",")
|
|
226
233
|
: undefined,
|
|
227
234
|
collapse: input.collapse,
|
|
228
|
-
colors: input.colors
|
|
235
|
+
colors: input.colors !== undefined && input.colors.length > 0
|
|
236
|
+
? JSON.stringify(input.colors)
|
|
237
|
+
: undefined,
|
|
229
238
|
searchCatalogueSubset: input.searchCatalogueSubset,
|
|
230
239
|
cursor: input.cursor,
|
|
231
240
|
filters: input.filters ? JSON.stringify(input.filters) : undefined,
|
|
232
|
-
include: input.include
|
|
241
|
+
include: input.include !== undefined && input.include.length > 0
|
|
242
|
+
? input.include.join(",")
|
|
243
|
+
: undefined,
|
|
233
244
|
limit: input.limit,
|
|
234
245
|
name: input.name,
|
|
235
246
|
optionalFilters: input.optionalFilters
|
|
236
247
|
? JSON.stringify(input.optionalFilters)
|
|
237
248
|
: undefined,
|
|
238
|
-
orderBy: input.orderBy
|
|
249
|
+
orderBy: input.orderBy !== undefined && input.orderBy.length > 0
|
|
239
250
|
? JSON.stringify(input.orderBy)
|
|
240
251
|
: undefined,
|
|
241
|
-
words: input.words
|
|
252
|
+
words: input.words !== undefined && input.words.length > 0
|
|
253
|
+
? input.words.join(",")
|
|
254
|
+
: undefined,
|
|
242
255
|
}, signal);
|
|
243
256
|
}
|
|
244
257
|
/**
|
|
@@ -272,17 +285,32 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
272
285
|
}
|
|
273
286
|
/**
|
|
274
287
|
* THE QUESTION: "which variants hold, resemble, or can be ranked by, this
|
|
275
|
-
* color?" (
|
|
288
|
+
* color?" (GET `/api/v1/variants/by-color`, MG-2217/MG-2230/MG-2247).
|
|
276
289
|
* One required `mode`: `contains` (a swatch for every required `colors[]`
|
|
277
290
|
* condition), `palette` (whole-palette closeness to `colors[]`, an
|
|
278
291
|
* image's extracted palette, or `targetVariantId`'s own palette) or
|
|
279
292
|
* `rerank` (reorder a held `variantIds` set by color closeness).
|
|
280
293
|
*/
|
|
281
294
|
async findVariantsByColor(input, signal) {
|
|
282
|
-
|
|
295
|
+
const { colors, image, ...rest } = input;
|
|
296
|
+
const query = { ...rest };
|
|
297
|
+
for (const [index, entry] of (colors ?? []).entries()) {
|
|
298
|
+
query[`color${index}`] = entry.color;
|
|
299
|
+
query[`color${index}.share`] = entry.share;
|
|
300
|
+
query[`color${index}.shareMax`] = entry.shareMax;
|
|
301
|
+
query[`color${index}.dominant`] = entry.dominant;
|
|
302
|
+
query[`color${index}.role`] = entry.role;
|
|
303
|
+
}
|
|
304
|
+
if (image) {
|
|
305
|
+
query.imageAssetId = image.assetId;
|
|
306
|
+
query.imageSourceId = image.sourceId;
|
|
307
|
+
query.imageUrl = image.url;
|
|
308
|
+
query.imageVariantId = image.variantId;
|
|
309
|
+
}
|
|
310
|
+
return await this.#get("find_variants_by_color", query, signal);
|
|
283
311
|
}
|
|
284
312
|
/**
|
|
285
|
-
* THE QUESTION: "what did designers sample together with these?" (
|
|
313
|
+
* THE QUESTION: "what did designers sample together with these?" (GET
|
|
286
314
|
* `/api/v1/variants/sampled-together`, MG-2332). Give `variantIds` and/or
|
|
287
315
|
* `materials` (free-text names, one variant each, at most twelve together);
|
|
288
316
|
* the materials come back other brands first, then the most projects, each
|
|
@@ -292,7 +320,7 @@ export class MaterialGraphClient extends CatalogueClient {
|
|
|
292
320
|
* before presenting: a scheme of four that resolved two is a different claim.
|
|
293
321
|
*/
|
|
294
322
|
async findSampledTogether(input, signal) {
|
|
295
|
-
return await this.#
|
|
323
|
+
return await this.#get("find_sampled_together", { ...input }, signal);
|
|
296
324
|
}
|
|
297
325
|
/**
|
|
298
326
|
* THE QUESTION: "what looks or feels like this?" (POST
|
package/colors-client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CategoryColorProfilesResponse, ColorProfilesParams } from "./color-profiles-types.js";
|
|
2
2
|
import type { QueryParams } from "./http-transport.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { NearestPaintsParams, NearestPaintsOutput } from "./nearest-paints-types.js";
|
|
4
|
+
import type { JsonOperationId, OperationResponses } from "./operation-responses.js";
|
|
4
5
|
/**
|
|
5
6
|
* The color surface, namespaced as `mg.colors` - `profiles`, the colors a
|
|
6
7
|
* category comes in.
|
|
@@ -29,11 +30,13 @@ import type { SdkOperationId } from "./operations.js";
|
|
|
29
30
|
*/
|
|
30
31
|
/** The client's own request primitives, handed down so this file owns no transport. */
|
|
31
32
|
export type ColorsTransport = {
|
|
32
|
-
get<
|
|
33
|
+
get<K extends JsonOperationId>(operationId: K, query?: QueryParams, signal?: AbortSignal): Promise<OperationResponses[K]>;
|
|
33
34
|
};
|
|
34
35
|
export declare class ColorsClient {
|
|
35
36
|
#private;
|
|
36
37
|
constructor(transport: ColorsTransport);
|
|
38
|
+
/** Nearest Samplize catalogue paints for up to twelve hexes, deduplicated in input order. */
|
|
39
|
+
nearestPaints(params: NearestPaintsParams, signal?: AbortSignal): Promise<NearestPaintsOutput>;
|
|
37
40
|
/**
|
|
38
41
|
* THE QUESTION: "what colors does this CATEGORY come in?" - the
|
|
39
42
|
* representative palette of 1 to 8 categories in ONE call (GET
|
package/colors-client.js
CHANGED
|
@@ -3,6 +3,10 @@ export class ColorsClient {
|
|
|
3
3
|
constructor(transport) {
|
|
4
4
|
this.#transport = transport;
|
|
5
5
|
}
|
|
6
|
+
/** Nearest Samplize catalogue paints for up to twelve hexes, deduplicated in input order. */
|
|
7
|
+
async nearestPaints(params, signal) {
|
|
8
|
+
return await this.#transport.get("find_nearest_paints", { hex: params.hexes, limit: params.limit }, signal);
|
|
9
|
+
}
|
|
6
10
|
/**
|
|
7
11
|
* THE QUESTION: "what colors does this CATEGORY come in?" - the
|
|
8
12
|
* representative palette of 1 to 8 categories in ONE call (GET
|
package/errors.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type SanitizedIssue = {
|
|
|
6
6
|
[key: string]: SanitizedErrorValue;
|
|
7
7
|
};
|
|
8
8
|
/** Normalized RFC 7807 body. Unknown response fields are intentionally discarded. */
|
|
9
|
-
export
|
|
9
|
+
export type ProblemDetail = {
|
|
10
10
|
type: string;
|
|
11
11
|
title: string;
|
|
12
12
|
status: number;
|
|
@@ -23,7 +23,7 @@ export interface ProblemDetail {
|
|
|
23
23
|
* not carry them. See {@link MATERIALGRAPH_PROBLEM_EXTENSIONS}.
|
|
24
24
|
*/
|
|
25
25
|
readonly [extension: string]: unknown;
|
|
26
|
-
}
|
|
26
|
+
};
|
|
27
27
|
/** Normalized residual `{ error }` body. Unknown response fields are discarded. */
|
|
28
28
|
export type SimpleErrorBody = {
|
|
29
29
|
error: string;
|
|
@@ -41,7 +41,7 @@ export type MaterialGraphRequestMetadata = {
|
|
|
41
41
|
origin: string;
|
|
42
42
|
path: string;
|
|
43
43
|
};
|
|
44
|
-
export
|
|
44
|
+
export type MaterialGraphErrorInit = {
|
|
45
45
|
kind: MaterialGraphErrorKind;
|
|
46
46
|
status?: number;
|
|
47
47
|
retriable: boolean;
|
|
@@ -54,7 +54,7 @@ export interface MaterialGraphErrorInit {
|
|
|
54
54
|
path?: string;
|
|
55
55
|
/** Accepted for compatibility but deliberately never retained on the public error. */
|
|
56
56
|
cause?: unknown;
|
|
57
|
-
}
|
|
57
|
+
};
|
|
58
58
|
type ResponseErrorInput = {
|
|
59
59
|
status: number;
|
|
60
60
|
body: unknown;
|
package/errors.js
CHANGED
|
@@ -47,12 +47,15 @@ const MAX_EXTENSION_DEPTH = 8;
|
|
|
47
47
|
const MAX_EXTENSION_ITEMS = 100;
|
|
48
48
|
const MAX_EXTENSION_STRING = 1024;
|
|
49
49
|
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
50
|
-
const redact = (text, secrets) =>
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const redact = (text, secrets) => {
|
|
51
|
+
let sanitized = text;
|
|
52
|
+
for (const secret of secrets) {
|
|
53
|
+
if (secret.length > 0) {
|
|
54
|
+
sanitized = sanitized.split(secret).join("[REDACTED]");
|
|
55
|
+
}
|
|
53
56
|
}
|
|
54
|
-
return sanitized
|
|
55
|
-
}
|
|
57
|
+
return sanitized;
|
|
58
|
+
};
|
|
56
59
|
const safeString = (text, secrets) => redact(text, secrets).slice(0, MAX_EXTENSION_STRING);
|
|
57
60
|
const secretVariants = (apiKey, queryValues) => [
|
|
58
61
|
apiKey,
|
|
@@ -65,7 +68,7 @@ const requestMetadata = (input) => ({
|
|
|
65
68
|
origin: input.origin,
|
|
66
69
|
path: input.path,
|
|
67
70
|
});
|
|
68
|
-
|
|
71
|
+
const sanitizeValue = (value, secrets, depth = 0) => {
|
|
69
72
|
if (depth >= MAX_EXTENSION_DEPTH) {
|
|
70
73
|
return undefined;
|
|
71
74
|
}
|
|
@@ -88,8 +91,8 @@ function sanitizeValue(value, secrets, depth = 0) {
|
|
|
88
91
|
return undefined;
|
|
89
92
|
}
|
|
90
93
|
return sanitizeRecord(value, secrets, depth);
|
|
91
|
-
}
|
|
92
|
-
|
|
94
|
+
};
|
|
95
|
+
const sanitizeRecord = (value, secrets, depth) => {
|
|
93
96
|
const entries = Object.entries(value)
|
|
94
97
|
.slice(0, MAX_EXTENSION_ITEMS)
|
|
95
98
|
.flatMap(([key, item]) => {
|
|
@@ -99,7 +102,7 @@ function sanitizeRecord(value, secrets, depth) {
|
|
|
99
102
|
: [[safeString(key, secrets), sanitized]];
|
|
100
103
|
});
|
|
101
104
|
return Object.fromEntries(entries);
|
|
102
|
-
}
|
|
105
|
+
};
|
|
103
106
|
const sanitizeIssues = (value, secrets) => {
|
|
104
107
|
if (!Array.isArray(value)) {
|
|
105
108
|
return undefined;
|
|
@@ -111,7 +114,7 @@ const sanitizeIssues = (value, secrets) => {
|
|
|
111
114
|
};
|
|
112
115
|
const sanitizeSuggestions = (value, secrets) => {
|
|
113
116
|
if (!Array.isArray(value) ||
|
|
114
|
-
value.
|
|
117
|
+
!value.every((suggestion) => typeof suggestion === "string")) {
|
|
115
118
|
return undefined;
|
|
116
119
|
}
|
|
117
120
|
return value
|