@instruments/materialgraph 0.6.0 → 0.7.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/brand-types.d.ts +20 -1
- package/brand-types.js +7 -0
- package/by-spec-types.d.ts +62 -3
- package/catalog-discovery-types.d.ts +19 -2
- package/client-browse.d.ts +7 -1
- package/client.d.ts +339 -53
- package/client.js +316 -33
- package/codes-client.d.ts +36 -0
- package/codes-client.js +26 -0
- package/codes-types.d.ts +77 -11
- package/colours-client.d.ts +41 -6
- package/colours-client.js +27 -6
- package/composition-types.d.ts +27 -18
- package/demand-batch-types.d.ts +118 -0
- package/demand-batch-types.js +1 -0
- package/demand-types.d.ts +134 -0
- package/demand-types.js +1 -0
- package/identifiers.d.ts +71 -0
- package/identifiers.js +26 -0
- package/index.d.ts +1 -0
- package/material-asset-types.d.ts +20 -1
- package/material-block-types.d.ts +30 -1
- package/material-types.d.ts +45 -7
- package/package.json +1 -1
- package/palette-search-types.d.ts +17 -2
- package/project-types.d.ts +20 -8
- package/project-types.js +0 -7
- package/run-types.d.ts +20 -8
- package/schedule-types.d.ts +18 -7
- package/schedule-types.js +0 -11
- package/schema-resource-types.d.ts +15 -0
- package/search-refinement-types.d.ts +24 -4
- package/spec-types.d.ts +14 -5
- package/spec-types.js +14 -5
- package/suggest-types.d.ts +10 -1
- package/suggest-types.js +5 -0
- package/types.d.ts +215 -214
package/types.d.ts
CHANGED
|
@@ -11,8 +11,22 @@
|
|
|
11
11
|
* that mirrors a server enum is therefore widened with `(string & {})` so a new
|
|
12
12
|
* server value still type-checks, and objects that may grow fields are read
|
|
13
13
|
* structurally (unknown keys pass through untouched — the client never strips).
|
|
14
|
+
*
|
|
15
|
+
* READING CONTRACT — the three things callers get wrong, stated once here and
|
|
16
|
+
* repeated on the types where each one bites:
|
|
17
|
+
* 1. **Ids are opaque.** Round-trip them verbatim; never parse or construct
|
|
18
|
+
* one. See `./identifiers.ts` for which strings are opaque tokens and which
|
|
19
|
+
* are canonical vocabulary you discover.
|
|
20
|
+
* 2. **Absent is not false.** An optional field that is missing means UNKNOWN,
|
|
21
|
+
* not "known to be absent in reality" — most dangerously for booleans.
|
|
22
|
+
* Values carry `confidence` and `sourceBasis`; report them as claims.
|
|
23
|
+
* 3. **A page is not a corpus.** `results.length` is this page.
|
|
24
|
+
* {@link CountedTotal} — with the `basis` it states — is the claim about the
|
|
25
|
+
* match set. Follow the cursor for the rest, and never report a page size as
|
|
26
|
+
* a total.
|
|
14
27
|
*/
|
|
15
28
|
import type { BySpecVerdict } from "./by-spec-types.js";
|
|
29
|
+
import type { Cursor, ProductId, VariantId } from "./identifiers.js";
|
|
16
30
|
import type { MaterialDetail, MaterialTile } from "./material-types.js";
|
|
17
31
|
import type { SearchFilter, SearchSuggestion } from "./search-refinement-types.js";
|
|
18
32
|
/** A widened string-literal union: known members autocomplete, unknown values still type-check. */
|
|
@@ -79,13 +93,22 @@ export interface VisualMeaning {
|
|
|
79
93
|
version?: string;
|
|
80
94
|
appliedAt?: string;
|
|
81
95
|
}
|
|
82
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* One material in a search / match result list.
|
|
98
|
+
*
|
|
99
|
+
* ABSENT IS NOT FALSE. The optional fields here (`colourMeta`, `signals`,
|
|
100
|
+
* `retired`, `siblingCount`, `visualMeanings`, `verdict`) are absent when the
|
|
101
|
+
* request did not ask for them or the graph holds no answer — never because the
|
|
102
|
+
* answer is "no". A missing `retired` is not "still current"; a missing
|
|
103
|
+
* `visualMeanings` is not "this material has no visual meaning".
|
|
104
|
+
*/
|
|
83
105
|
export interface SearchResultItem {
|
|
84
|
-
|
|
106
|
+
/** Opaque — round-trip verbatim into `material()`, `pairings()`, `similarTo`. */
|
|
107
|
+
variantId: VariantId;
|
|
85
108
|
brand: string;
|
|
86
109
|
product: string;
|
|
87
110
|
brandSlug: string | null;
|
|
88
|
-
productId:
|
|
111
|
+
productId: ProductId | null;
|
|
89
112
|
color: string | null;
|
|
90
113
|
variantName: string | null;
|
|
91
114
|
imageUrl: string | null;
|
|
@@ -112,10 +135,18 @@ export interface SearchResultItem {
|
|
|
112
135
|
*/
|
|
113
136
|
verdict?: BySpecVerdict;
|
|
114
137
|
}
|
|
115
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* The lean `view:"card"` result item — identity + name + thumbnail + score.
|
|
140
|
+
*
|
|
141
|
+
* A PROJECTION, not a smaller answer: a field the card omits (palette, verdict,
|
|
142
|
+
* signals, availability) is unread here, never known-absent. Re-read the same
|
|
143
|
+
* `variantId` at `view: "full"` or via `material()` before claiming anything the
|
|
144
|
+
* card does not carry.
|
|
145
|
+
*/
|
|
116
146
|
export interface SearchCardItem {
|
|
117
|
-
|
|
118
|
-
|
|
147
|
+
/** Opaque — round-trip verbatim. */
|
|
148
|
+
variantId: VariantId;
|
|
149
|
+
productId: ProductId | null;
|
|
119
150
|
brandSlug: string | null;
|
|
120
151
|
brand: string;
|
|
121
152
|
/** Product name (the full item's `product`). */
|
|
@@ -125,15 +156,26 @@ export interface SearchCardItem {
|
|
|
125
156
|
score: number;
|
|
126
157
|
}
|
|
127
158
|
/**
|
|
128
|
-
* A feed total with its honesty basis
|
|
129
|
-
*
|
|
130
|
-
*
|
|
159
|
+
* A feed total with its honesty basis — THE CLAIM ABOUT THE MATCH SET, which is
|
|
160
|
+
* a different number from `results.length` (this page).
|
|
161
|
+
*
|
|
162
|
+
* `exact` — the true count (≤ the cap of 1,000, or a facet-MV read). Say "473
|
|
163
|
+
* materials match".
|
|
164
|
+
* `lowerBound` — a floor (cap hit, ANN-pool bound, or a degraded count). Say
|
|
165
|
+
* "at least 1,000", never "1,000". Never a silent approximation.
|
|
166
|
+
*
|
|
167
|
+
* A response with no `counts` at all states no total: `count: true` is opt-in,
|
|
168
|
+
* and the absence of a total is not a total of zero.
|
|
131
169
|
*/
|
|
132
170
|
export interface CountedTotal {
|
|
133
171
|
value: number;
|
|
134
172
|
basis: OpenEnum<"exact" | "lowerBound">;
|
|
135
173
|
}
|
|
136
|
-
/**
|
|
174
|
+
/**
|
|
175
|
+
* Feed counts — present ONLY under `count:true` or `collapse:"product"`. This is
|
|
176
|
+
* the corpus-level claim; `results.length` is the page. Never report one as the
|
|
177
|
+
* other.
|
|
178
|
+
*/
|
|
137
179
|
export interface SearchCounts {
|
|
138
180
|
variants: CountedTotal;
|
|
139
181
|
products?: CountedTotal;
|
|
@@ -152,14 +194,21 @@ export interface SearchRerankReport {
|
|
|
152
194
|
* {@link SearchCardItem}s. Every other field is shared. `counts` is present
|
|
153
195
|
* under `count:true` or `collapse:"product"` (replacing the former
|
|
154
196
|
* `variantCount`/`productCount`).
|
|
197
|
+
*
|
|
198
|
+
* A PAGE, NOT A CORPUS. `results.length` is what you were handed;
|
|
199
|
+
* {@link SearchCounts} is the only statement about the match set, and only when
|
|
200
|
+
* you asked for it. Follow `cursor` for the rest. "I found 24 materials" is
|
|
201
|
+
* wrong whenever `limit` was 24.
|
|
155
202
|
*/
|
|
156
203
|
export interface SearchResponse {
|
|
157
204
|
view: OpenEnum<"full" | "card">;
|
|
205
|
+
/** THIS PAGE. Its length is a page size, never a total. */
|
|
158
206
|
results: SearchResultItem[];
|
|
159
207
|
suggestions: SearchSuggestion[];
|
|
160
208
|
mode: SearchMode;
|
|
161
209
|
maxScore: number;
|
|
162
|
-
|
|
210
|
+
/** Opaque keyset for the next page. Absent = end of the walk, not an error. */
|
|
211
|
+
cursor?: Cursor;
|
|
163
212
|
rerank?: SearchRerankReport;
|
|
164
213
|
counts?: SearchCounts;
|
|
165
214
|
note?: string;
|
|
@@ -180,8 +229,17 @@ export interface MatchCategoryInference {
|
|
|
180
229
|
displayName: string;
|
|
181
230
|
boost: number;
|
|
182
231
|
}
|
|
183
|
-
/**
|
|
232
|
+
/**
|
|
233
|
+
* The Material Match response (non-streaming form).
|
|
234
|
+
*
|
|
235
|
+
* `poolSize` is the candidate pool the floor was applied to, NOT a corpus total
|
|
236
|
+
* and NOT "how many materials look like this". An empty `results` with
|
|
237
|
+
* `droppedBelowFloor > 0` means "candidates existed and none was good enough" —
|
|
238
|
+
* a different answer from `poolSize: 0`, which means the image found nothing to
|
|
239
|
+
* search against at all.
|
|
240
|
+
*/
|
|
184
241
|
export interface MatchResponse {
|
|
242
|
+
/** THIS answer, capped by `limit`. Not a total. */
|
|
185
243
|
results: SearchResultItem[];
|
|
186
244
|
inferredCategories: MatchCategoryInference[];
|
|
187
245
|
qualityFloor: number;
|
|
@@ -195,9 +253,17 @@ export interface MatchCategory {
|
|
|
195
253
|
group: string | null;
|
|
196
254
|
type: string | null;
|
|
197
255
|
}
|
|
198
|
-
/**
|
|
256
|
+
/**
|
|
257
|
+
* One colour-palette match.
|
|
258
|
+
*
|
|
259
|
+
* `hex`, `distance` and `closeness` are OKLab geometry over colour EXTRACTED
|
|
260
|
+
* FROM PRODUCT IMAGERY, not declared by the manufacturer. Report it as visual
|
|
261
|
+
* likeness ("reads close to this colour"), never as a stated colour
|
|
262
|
+
* specification.
|
|
263
|
+
*/
|
|
199
264
|
export interface ByColourMatch {
|
|
200
|
-
|
|
265
|
+
/** Opaque — round-trip verbatim. */
|
|
266
|
+
variantId: VariantId;
|
|
201
267
|
brand: string;
|
|
202
268
|
product: string;
|
|
203
269
|
color: string | null;
|
|
@@ -216,16 +282,18 @@ export interface ByColourResponse {
|
|
|
216
282
|
categories?: string[];
|
|
217
283
|
oklab?: OklabTriple;
|
|
218
284
|
};
|
|
285
|
+
/** `matches.length` — THIS PAGE. Not a corpus total; this surface states none. */
|
|
219
286
|
count: number;
|
|
220
287
|
matches: ByColourMatch[];
|
|
221
288
|
}
|
|
222
289
|
/** One item from the pure colour-scalar browse. */
|
|
223
290
|
export interface BrowseResultItem {
|
|
224
|
-
|
|
291
|
+
/** Opaque — round-trip verbatim. */
|
|
292
|
+
variantId: VariantId;
|
|
225
293
|
brand: string;
|
|
226
294
|
product: string;
|
|
227
295
|
brandSlug: string | null;
|
|
228
|
-
productId:
|
|
296
|
+
productId: ProductId | null;
|
|
229
297
|
color: string | null;
|
|
230
298
|
variantName: string | null;
|
|
231
299
|
imageUrl: string | null;
|
|
@@ -236,10 +304,17 @@ export interface BrowseResultItem {
|
|
|
236
304
|
};
|
|
237
305
|
retired?: boolean;
|
|
238
306
|
}
|
|
239
|
-
/**
|
|
307
|
+
/**
|
|
308
|
+
* A single page of the colour browse — the SDK's one genuinely cursor-paginated
|
|
309
|
+
* surface. `results.length` is this page and the browse states no total at all,
|
|
310
|
+
* so a corpus claim can only come from walking every page
|
|
311
|
+
* (`client.browse.pages(...)` does the loop).
|
|
312
|
+
*/
|
|
240
313
|
export interface BrowseResponse {
|
|
314
|
+
/** THIS PAGE. */
|
|
241
315
|
results: BrowseResultItem[];
|
|
242
|
-
|
|
316
|
+
/** Opaque keyset for the next page. Absent = the walk is finished. */
|
|
317
|
+
cursor?: Cursor;
|
|
243
318
|
}
|
|
244
319
|
export type ColourDictionaryId = OpenEnum<"colour_family" | "colour_mood" | "colour_undertone">;
|
|
245
320
|
export interface ColourFacetTerm {
|
|
@@ -285,17 +360,34 @@ export interface ProjectTypeShare {
|
|
|
285
360
|
projectType: string;
|
|
286
361
|
projectCount: number;
|
|
287
362
|
}
|
|
288
|
-
/**
|
|
363
|
+
/**
|
|
364
|
+
* A pairing item from the behavioural arm — real order evidence, or board
|
|
365
|
+
* curation when this seed has no order edges.
|
|
366
|
+
*
|
|
367
|
+
* WHAT YOU MAY CLAIM, per `source`:
|
|
368
|
+
* - `cospec` — real ORDER co-occurrence. The two materials were ordered
|
|
369
|
+
* together on real projects. "Specified together" is honest here.
|
|
370
|
+
* - `considered` — BOARD ACTIVITY only (moodboard curation). Somebody put them
|
|
371
|
+
* on a board together; nobody is known to have bought them together. Say
|
|
372
|
+
* "often boarded together" / "considered alongside" and NEVER "specified
|
|
373
|
+
* together". The server falls back to this arm seed-by-seed when the seed
|
|
374
|
+
* carries no `sampled` edges, so a single response can be entirely
|
|
375
|
+
* `considered`.
|
|
376
|
+
*
|
|
377
|
+
* See {@link ColourPairing} for the third, non-evidential arm.
|
|
378
|
+
*/
|
|
289
379
|
export interface CospecPairing {
|
|
380
|
+
/** The evidence tier. `cospec` = orders; `considered` = boards. Read it before phrasing. */
|
|
290
381
|
source: "cospec" | "considered";
|
|
291
|
-
|
|
382
|
+
/** Opaque — round-trip verbatim. */
|
|
383
|
+
variantId: VariantId;
|
|
292
384
|
brand: string;
|
|
293
385
|
product: string;
|
|
294
386
|
color: string | null;
|
|
295
387
|
variantName: string | null;
|
|
296
388
|
imageUrl: string | null;
|
|
297
389
|
brandSlug: string;
|
|
298
|
-
productId:
|
|
390
|
+
productId: ProductId;
|
|
299
391
|
category: string | null;
|
|
300
392
|
projectCount: number;
|
|
301
393
|
customerCount: number;
|
|
@@ -303,18 +395,63 @@ export interface CospecPairing {
|
|
|
303
395
|
liftLabel: string;
|
|
304
396
|
demand: CompanionDemand | null;
|
|
305
397
|
topProjectTypes: ProjectTypeShare[];
|
|
398
|
+
/** Graph-owned colour ranking facts, present only for an explicitly ordered rail. */
|
|
399
|
+
ranking?: PairingRanking;
|
|
306
400
|
}
|
|
307
|
-
/**
|
|
401
|
+
/**
|
|
402
|
+
* A pairing item topped up from colour palette-similarity — a LOOK-ALIKE, not
|
|
403
|
+
* evidence. Nobody ordered these together and nobody boarded them together; the
|
|
404
|
+
* palettes sit near each other in OKLab. Say "shares a palette with" and never
|
|
405
|
+
* "specified together" or "often paired with".
|
|
406
|
+
*/
|
|
308
407
|
export interface ColourPairing extends MaterialTile {
|
|
309
408
|
source: "colour";
|
|
310
409
|
score: number;
|
|
410
|
+
/** Graph-owned colour ranking facts, present only for an explicitly ordered rail. */
|
|
411
|
+
ranking?: PairingRanking;
|
|
412
|
+
}
|
|
413
|
+
export type PairingOrderMode = "relevance" | "lightness_asc" | "lightness_desc";
|
|
414
|
+
export type PairingCorpus = "all" | "material_bank";
|
|
415
|
+
export interface PairingRanking {
|
|
416
|
+
anchorColourSimilarity: number | null;
|
|
417
|
+
lightness: number | null;
|
|
418
|
+
anchorColourSimilarityMeasurable: boolean;
|
|
419
|
+
lightnessMeasurable: boolean;
|
|
420
|
+
basis: OpenEnum<"dominant_colour_oklab">;
|
|
421
|
+
}
|
|
422
|
+
export interface PairingOrdering {
|
|
423
|
+
requested: OpenEnum<PairingOrderMode>;
|
|
424
|
+
applied: OpenEnum<PairingOrderMode>;
|
|
425
|
+
direction: OpenEnum<"ascending" | "descending">;
|
|
426
|
+
anchorColourBasis: OpenEnum<"one_minus_oklab_euclidean_distance">;
|
|
427
|
+
colourSpace: OpenEnum<"oklab">;
|
|
428
|
+
lightnessRange: {
|
|
429
|
+
min: 0;
|
|
430
|
+
max: 1;
|
|
431
|
+
};
|
|
432
|
+
missingValues: OpenEnum<"last">;
|
|
433
|
+
tieBreak: OpenEnum<"variantId_asc">;
|
|
311
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* One pairing, discriminated by `source` into three tiers of very different
|
|
437
|
+
* strength: `cospec` (real orders) > `considered` (board activity) > `colour`
|
|
438
|
+
* (palette look-alike). Branch on `source` before you write a sentence about it.
|
|
439
|
+
*/
|
|
312
440
|
export type PairingItem = CospecPairing | ColourPairing;
|
|
313
441
|
export interface PairingsResponse {
|
|
314
442
|
seed: MaterialTile;
|
|
443
|
+
/** A rail, not a ranked corpus — mixed evidence tiers, capped by `limit`. */
|
|
315
444
|
items: PairingItem[];
|
|
316
|
-
/**
|
|
445
|
+
/**
|
|
446
|
+
* How many `items` came from real ORDER evidence (`source: "cospec"`). Zero
|
|
447
|
+
* with a full rail means every item is board activity or colour look-alike —
|
|
448
|
+
* check it before presenting the rail as demand evidence.
|
|
449
|
+
*/
|
|
317
450
|
cospecCount: number;
|
|
451
|
+
/** Present only when `order` was requested. Evidence tiers remain independent. */
|
|
452
|
+
ordering?: PairingOrdering;
|
|
453
|
+
/** Opaque continuation bound to the seed, filters, corpus, and order. */
|
|
454
|
+
nextCursor?: Cursor;
|
|
318
455
|
}
|
|
319
456
|
export interface MaterialResponse {
|
|
320
457
|
material: MaterialDetail;
|
|
@@ -324,15 +461,23 @@ export interface MaterialResponse {
|
|
|
324
461
|
export interface SiblingsResponse {
|
|
325
462
|
siblings: MaterialTile[];
|
|
326
463
|
}
|
|
327
|
-
/**
|
|
464
|
+
/**
|
|
465
|
+
* Batch read of tile projections. `materials` is NOT positional — resolve by
|
|
466
|
+
* `variantId`, and read `missingIds` rather than inferring absence from length.
|
|
467
|
+
*/
|
|
328
468
|
export interface MaterialsBatchTileResponse {
|
|
329
469
|
materials: MaterialTile[];
|
|
330
|
-
|
|
470
|
+
/** Requested ids that resolved to nothing. Echoed verbatim, opaque. */
|
|
471
|
+
missingIds: VariantId[];
|
|
331
472
|
}
|
|
332
|
-
/**
|
|
473
|
+
/**
|
|
474
|
+
* Batch read of detail projections. `materials` is NOT positional — resolve by
|
|
475
|
+
* `variantId`, and read `missingIds` rather than inferring absence from length.
|
|
476
|
+
*/
|
|
333
477
|
export interface MaterialsBatchDetailResponse {
|
|
334
478
|
materials: MaterialDetail[];
|
|
335
|
-
|
|
479
|
+
/** Requested ids that resolved to nothing. Echoed verbatim, opaque. */
|
|
480
|
+
missingIds: VariantId[];
|
|
336
481
|
}
|
|
337
482
|
export interface ResolveColourResponse {
|
|
338
483
|
match: {
|
|
@@ -414,7 +559,7 @@ export interface SearchInput {
|
|
|
414
559
|
* seed variant, so it is the only form `verdicts` can diff a candidate against.
|
|
415
560
|
*/
|
|
416
561
|
similarTo?: {
|
|
417
|
-
variantId:
|
|
562
|
+
variantId: VariantId;
|
|
418
563
|
} | {
|
|
419
564
|
vector: string;
|
|
420
565
|
};
|
|
@@ -438,11 +583,16 @@ export interface SearchInput {
|
|
|
438
583
|
* demotes a failed/missing preferred hit WITHIN its page only.
|
|
439
584
|
*/
|
|
440
585
|
preferences?: SearchFilter[];
|
|
586
|
+
/** Page size — the size of ONE page, never a bound on the match set. */
|
|
441
587
|
limit?: number;
|
|
442
|
-
cursor
|
|
588
|
+
/** The previous response's `cursor`, passed back verbatim. Never synthesise one. */
|
|
589
|
+
cursor?: Cursor;
|
|
443
590
|
explain?: boolean;
|
|
444
591
|
collapse?: OpenEnum<"none" | "product">;
|
|
445
|
-
/**
|
|
592
|
+
/**
|
|
593
|
+
* Opt-in feed total: EXACT up to 1,000, `lowerBound` beyond / for ANN pools.
|
|
594
|
+
* Without it the response states NO total — and a page size is not one.
|
|
595
|
+
*/
|
|
446
596
|
count?: boolean;
|
|
447
597
|
/** Only return materials with at least one catalog image. Default false (full catalog). */
|
|
448
598
|
hasImages?: boolean;
|
|
@@ -464,7 +614,8 @@ export interface SearchGetParams {
|
|
|
464
614
|
mood?: string;
|
|
465
615
|
sort?: OpenEnum<"relevance" | "light" | "dark" | "vivid" | "muted" | "colourful">;
|
|
466
616
|
tol?: OpenEnum<"tight" | "normal" | "loose">;
|
|
467
|
-
|
|
617
|
+
/** Seed the search from this variant's image. Opaque — pass it through verbatim. */
|
|
618
|
+
variantId?: VariantId;
|
|
468
619
|
limit?: number;
|
|
469
620
|
/** "0" or "1" — include per-signal `signals` on each result. */
|
|
470
621
|
explain?: OpenEnum<"0" | "1">;
|
|
@@ -492,7 +643,12 @@ export interface ByColourParams {
|
|
|
492
643
|
/** Params for the pure colour `search/browse` surface. */
|
|
493
644
|
export interface BrowseParams {
|
|
494
645
|
sort: OpenEnum<"light" | "dark" | "vivid" | "muted" | "colourful">;
|
|
495
|
-
|
|
646
|
+
/**
|
|
647
|
+
* The previous page's `cursor`, verbatim. Opaque keyset state — not an offset.
|
|
648
|
+
* Changing `sort`, `limit` or `types` invalidates it.
|
|
649
|
+
*/
|
|
650
|
+
cursor?: Cursor;
|
|
651
|
+
/** Page size. */
|
|
496
652
|
limit?: number;
|
|
497
653
|
/** Comma-separated product-type ids to restrict the browse to. */
|
|
498
654
|
types?: string;
|
|
@@ -525,7 +681,14 @@ export interface MatchInput {
|
|
|
525
681
|
}
|
|
526
682
|
/** Options for a batch material read. */
|
|
527
683
|
export interface MaterialsBatchOptions {
|
|
684
|
+
/** Projection depth. `tile` omits fields rather than reporting them absent. */
|
|
528
685
|
view?: "tile" | "detail";
|
|
686
|
+
/**
|
|
687
|
+
* Which id space `ids` are in — MaterialGraph's own opaque `variantId`
|
|
688
|
+
* (default) or Material Bank's `materialBankId`. Both are opaque; they are NOT
|
|
689
|
+
* interchangeable, and passing one under the other's `idKind` returns
|
|
690
|
+
* `missingIds`, not an error.
|
|
691
|
+
*/
|
|
529
692
|
idKind?: OpenEnum<"variantId" | "materialBankId">;
|
|
530
693
|
}
|
|
531
694
|
/** Options for a pairings read. */
|
|
@@ -533,6 +696,12 @@ export interface PairingsOptions {
|
|
|
533
696
|
/** Comma-separated coarse category display names; filters both arms. */
|
|
534
697
|
categories?: string;
|
|
535
698
|
limit?: number;
|
|
699
|
+
/** Graph-owned order applied within fixed cospec → considered → colour tiers. */
|
|
700
|
+
order?: PairingOrderMode;
|
|
701
|
+
/** Optional Material Bank/orderable gate; requires an explicit `order`. */
|
|
702
|
+
corpus?: PairingCorpus;
|
|
703
|
+
/** The previous response's `nextCursor`, passed back verbatim. */
|
|
704
|
+
cursor?: Cursor;
|
|
536
705
|
}
|
|
537
706
|
/** Options for `catalog/attributes/resolve`. */
|
|
538
707
|
export interface ResolveAttributeOptions {
|
|
@@ -543,184 +712,28 @@ export interface ResolveAttributeOptions {
|
|
|
543
712
|
export interface BySpecOptions {
|
|
544
713
|
limit?: number;
|
|
545
714
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
variantId: string;
|
|
549
|
-
brand: string;
|
|
550
|
-
product: string;
|
|
551
|
-
color: string | null;
|
|
552
|
-
variantName: string | null;
|
|
553
|
-
imageUrl: string | null;
|
|
554
|
-
brandSlug: string;
|
|
555
|
-
productId: string;
|
|
556
|
-
}
|
|
715
|
+
export type * from "./demand-types.js";
|
|
716
|
+
/** One quarter's tally. Sparse across a series — an absent quarter is not a zero. */
|
|
557
717
|
export interface DemandQuarter {
|
|
558
718
|
quarter: string;
|
|
559
719
|
specCount: number;
|
|
560
720
|
projectCount: number;
|
|
561
721
|
}
|
|
562
|
-
/** Headline demand stats for a seed: counts, quarterly series, momentum. */
|
|
563
|
-
export interface MaterialDemandStats {
|
|
564
|
-
specCount: number;
|
|
565
|
-
projectCount: number;
|
|
566
|
-
customerCount: number;
|
|
567
|
-
byQuarter: DemandQuarter[];
|
|
568
|
-
momentum: DemandMomentum;
|
|
569
|
-
}
|
|
570
|
-
/** `getMaterialDemand` result, passed through verbatim by the `/demand` route. */
|
|
571
|
-
export interface MaterialDemandResult {
|
|
572
|
-
found: boolean;
|
|
573
|
-
query: string;
|
|
574
|
-
seed: DemandSeed | null;
|
|
575
|
-
window: "trailing_36mo";
|
|
576
|
-
demand: MaterialDemandStats | null;
|
|
577
|
-
}
|
|
578
722
|
/**
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
723
|
+
* Which behavioural signal a demand read is scoped to — and therefore what a
|
|
724
|
+
* number drawn from it may honestly be called.
|
|
725
|
+
*
|
|
726
|
+
* - `sampled` — real ORDER co-occurrence. The default everywhere. Present as
|
|
727
|
+
* "specified together" / "specified on N projects".
|
|
728
|
+
* - `considered` — board / moodboard CURATION. Somebody assembled them; nobody
|
|
729
|
+
* is known to have bought them. Present as "considered alongside", never as
|
|
730
|
+
* a specification.
|
|
731
|
+
* - `specified` — the won tier. STATS ONLY: no co-specification edges are built
|
|
732
|
+
* at this grain, so asking for `specified` companions is a rejected request,
|
|
733
|
+
* not an empty result.
|
|
582
734
|
*/
|
|
583
|
-
export interface CoSpecifiedResult {
|
|
584
|
-
found: boolean;
|
|
585
|
-
resolution: OpenEnum<"resolved" | "ambiguous" | "not_found">;
|
|
586
|
-
query: string;
|
|
587
|
-
seed: DemandSeed | null;
|
|
588
|
-
seedCategory: string | null;
|
|
589
|
-
seedAlternatives: DemandSeed[];
|
|
590
|
-
companions?: unknown[];
|
|
591
|
-
}
|
|
592
|
-
/** The `/api/v1/demand` envelope — both domain reads side by side, verbatim. */
|
|
593
|
-
export interface DemandResponse {
|
|
594
|
-
query: string;
|
|
595
|
-
demand: MaterialDemandResult;
|
|
596
|
-
cospec: CoSpecifiedResult;
|
|
597
|
-
}
|
|
598
|
-
/** Which behavioural signal candidate demand is read from. */
|
|
599
735
|
export type DemandSignal = OpenEnum<"sampled" | "considered" | "specified">;
|
|
600
|
-
|
|
601
|
-
* Body for `POST /api/v1/demand/batch` — enrich 1–48 already-selected candidate
|
|
602
|
-
* ids with their real specification demand, in input order and cardinality.
|
|
603
|
-
*/
|
|
604
|
-
export interface DemandBatchInput {
|
|
605
|
-
/** 1–48 canonical variant ids. Order AND cardinality are preserved — duplicates are echoed, never collapsed. */
|
|
606
|
-
variantIds: string[];
|
|
607
|
-
/** The behavioural signal to read demand from. Defaults to `sampled` (order co-occurrence) server-side. */
|
|
608
|
-
signal?: DemandSignal;
|
|
609
|
-
/** Optional declared context (e.g. `{ projectType: "hospitality" }`) — echoed for provenance, never used to rank or filter. */
|
|
610
|
-
context?: Record<string, string>;
|
|
611
|
-
}
|
|
612
|
-
/** Headline population behind the metric — this variant's own counts. */
|
|
613
|
-
export interface DemandBatchPopulation {
|
|
614
|
-
specCount: number;
|
|
615
|
-
projectCount: number;
|
|
616
|
-
customerCount: number;
|
|
617
|
-
}
|
|
618
|
-
/** The consideration→specification funnel (project-grain; `exclusionRate` is annotate-only). */
|
|
619
|
-
export interface DemandBatchFunnel {
|
|
620
|
-
consideredProjects: number;
|
|
621
|
-
specifiedProjects: number;
|
|
622
|
-
excludedCount: number;
|
|
623
|
-
exclusionRate: number;
|
|
624
|
-
}
|
|
625
|
-
/** Per-result guardrail status — present on `internal` (`mg:admin`) results only. */
|
|
626
|
-
export interface DemandBatchEvidence {
|
|
627
|
-
belowPrivacyFloor: boolean;
|
|
628
|
-
belowQualityFloor: boolean;
|
|
629
|
-
suppressedForPublic: boolean;
|
|
630
|
-
}
|
|
631
|
-
/** A variant that carries a usable demand signal. */
|
|
632
|
-
export interface DemandBatchAvailableResult {
|
|
633
|
-
variantId: string;
|
|
634
|
-
state: "available";
|
|
635
|
-
population: DemandBatchPopulation;
|
|
636
|
-
/** Exact per-quarter counts (sparse — zero-spec quarters are absent). */
|
|
637
|
-
intervals: DemandQuarter[];
|
|
638
|
-
momentum: DemandMomentum;
|
|
639
|
-
/** The funnel; null when the signal is not `sampled` or no `considered` row/session exists. */
|
|
640
|
-
funnel: DemandBatchFunnel | null;
|
|
641
|
-
/** Exact guardrail evidence for `internal` callers; null for public. */
|
|
642
|
-
evidence: DemandBatchEvidence | null;
|
|
643
|
-
}
|
|
644
|
-
/** A variant with a stats row that is below the public quality floor. */
|
|
645
|
-
export interface DemandBatchInsufficientResult {
|
|
646
|
-
variantId: string;
|
|
647
|
-
state: "insufficient_data";
|
|
648
|
-
}
|
|
649
|
-
/** A variant with no stats — indistinguishable from a privacy-suppressed one for public callers. */
|
|
650
|
-
export interface DemandBatchNoSignalResult {
|
|
651
|
-
variantId: string;
|
|
652
|
-
state: "no_signal";
|
|
653
|
-
}
|
|
654
|
-
/** A requested id that resolves to no real variant. */
|
|
655
|
-
export interface DemandBatchUnknownResult {
|
|
656
|
-
variantId: string;
|
|
657
|
-
state: "unknown_variant";
|
|
658
|
-
}
|
|
659
|
-
/** One discriminated result per input id, in input order and cardinality. */
|
|
660
|
-
export type DemandBatchResult = DemandBatchAvailableResult | DemandBatchInsufficientResult | DemandBatchNoSignalResult | DemandBatchUnknownResult;
|
|
661
|
-
/** The `POST /api/v1/demand/batch` envelope. */
|
|
662
|
-
export interface DemandBatchResponse {
|
|
663
|
-
/** The completed ingestion-session id these counts were mined in (the dataset generation). */
|
|
664
|
-
generationId: string;
|
|
665
|
-
metric: "specification_demand";
|
|
666
|
-
/** The metric universe — the window and signal the counts are scoped to. */
|
|
667
|
-
universe: {
|
|
668
|
-
window: "trailing_36mo";
|
|
669
|
-
signal: DemandSignal;
|
|
670
|
-
description: string;
|
|
671
|
-
};
|
|
672
|
-
/** The guardrail status under which `results` were projected. */
|
|
673
|
-
guardrail: {
|
|
674
|
-
audience: OpenEnum<"public" | "internal">;
|
|
675
|
-
minProjectCount: number;
|
|
676
|
-
minCustomerCount: number;
|
|
677
|
-
};
|
|
678
|
-
/** Outcome tallies over `results` — never a denominator for the metric. */
|
|
679
|
-
coverage: {
|
|
680
|
-
requested: number;
|
|
681
|
-
available: number;
|
|
682
|
-
insufficientData: number;
|
|
683
|
-
noSignal: number;
|
|
684
|
-
unknownVariant: number;
|
|
685
|
-
};
|
|
686
|
-
/** The echoed declared context, or null when none was supplied. */
|
|
687
|
-
context: Record<string, string> | null;
|
|
688
|
-
results: DemandBatchResult[];
|
|
689
|
-
}
|
|
690
|
-
export interface CoordinateSeed extends DemandSeed {
|
|
691
|
-
/** The input reference this seed resolved from. */
|
|
692
|
-
resolvedFrom: string;
|
|
693
|
-
}
|
|
694
|
-
export interface CoordinateCompanion {
|
|
695
|
-
variantId: string;
|
|
696
|
-
brand: string;
|
|
697
|
-
product: string;
|
|
698
|
-
color: string | null;
|
|
699
|
-
variantName: string | null;
|
|
700
|
-
imageUrl: string | null;
|
|
701
|
-
brandSlug: string;
|
|
702
|
-
productId: string;
|
|
703
|
-
totalLift: number;
|
|
704
|
-
liftLabel: string;
|
|
705
|
-
seedMatchCount: number;
|
|
706
|
-
seedContributions: Array<{
|
|
707
|
-
seedVariantId: string;
|
|
708
|
-
lift: number;
|
|
709
|
-
}>;
|
|
710
|
-
demand: CompanionDemand | null;
|
|
711
|
-
swatches: Array<{
|
|
712
|
-
hex: string;
|
|
713
|
-
proportion: number;
|
|
714
|
-
}>;
|
|
715
|
-
/** Annotate-only appearance similarity — never reorders companions in v1. */
|
|
716
|
-
colourFit: number | null;
|
|
717
|
-
}
|
|
718
|
-
export interface CoordinateResponse {
|
|
719
|
-
seeds: CoordinateSeed[];
|
|
720
|
-
unresolved: string[];
|
|
721
|
-
window: "trailing_36mo";
|
|
722
|
-
companions: CoordinateCompanion[];
|
|
723
|
-
}
|
|
736
|
+
export type * from "./demand-batch-types.js";
|
|
724
737
|
export interface ExtractedPalette {
|
|
725
738
|
colors: Array<{
|
|
726
739
|
hex: string;
|
|
@@ -848,18 +861,6 @@ export interface BrandProfileResponse {
|
|
|
848
861
|
name: string;
|
|
849
862
|
}>;
|
|
850
863
|
}
|
|
851
|
-
/** Seed a demand read by EXACTLY ONE of `variantId` or `material`. */
|
|
852
|
-
export interface DemandParams {
|
|
853
|
-
variantId?: string;
|
|
854
|
-
material?: string;
|
|
855
|
-
}
|
|
856
|
-
/** Body for `POST /api/v1/pairings/coordinate`. */
|
|
857
|
-
export interface CoordinateInput {
|
|
858
|
-
materials?: string[];
|
|
859
|
-
variantIds?: string[];
|
|
860
|
-
projectType?: string;
|
|
861
|
-
limit?: number;
|
|
862
|
-
}
|
|
863
864
|
/** Body for `POST /api/v1/search/palettes/extract`. */
|
|
864
865
|
export interface ExtractPaletteInput {
|
|
865
866
|
/** The query image as a data URI or bare base64 string. */
|