@instruments/materialgraph 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/association-types.d.ts +18 -7
- package/attribution-types.d.ts +2 -2
- package/brand-types.d.ts +8 -0
- package/brands-client.d.ts +5 -36
- package/brands-client.js +7 -33
- package/by-colour-types.d.ts +40 -13
- package/by-spec-types.d.ts +0 -67
- package/by-spec-types.js +7 -5
- package/catalog-discovery-types.d.ts +1 -16
- package/catalogue-client.d.ts +12 -31
- package/catalogue-client.js +10 -46
- package/catalogue-types.d.ts +40 -0
- package/categories-client.d.ts +63 -0
- package/categories-client.js +48 -0
- package/category-types.d.ts +114 -0
- package/client-config.d.ts +2 -4
- package/client-config.js +2 -4
- package/client-vocabulary.d.ts +2 -4
- package/client-vocabulary.js +11 -9
- package/client.d.ts +103 -203
- package/client.js +126 -251
- package/codes-types.d.ts +21 -0
- package/colours-client.d.ts +4 -9
- package/colours-client.js +0 -8
- package/errors.d.ts +1 -1
- package/errors.js +1 -0
- package/identify-types.d.ts +49 -39
- package/identify-types.js +5 -3
- package/index.d.ts +11 -21
- package/index.js +4 -4
- package/list-variant-facets-types.d.ts +60 -0
- package/list-variants-types.d.ts +142 -0
- package/list-variants-types.js +12 -0
- package/match-stream-types.d.ts +13 -0
- package/match-stream-types.js +2 -0
- package/match-stream.js +12 -8
- package/match-types.d.ts +24 -0
- package/material-asset-types.d.ts +69 -49
- package/material-block-types.d.ts +2 -0
- package/material-composition-client.d.ts +21 -0
- package/material-composition-client.js +13 -0
- package/material-composition-types.d.ts +403 -0
- package/material-query-plan-types.d.ts +57 -141
- package/material-resources-client.d.ts +9 -7
- package/material-resources-client.js +19 -4
- package/material-types.d.ts +6 -14
- package/operations.d.ts +1 -1
- package/operations.js +20 -117
- package/package.json +5 -1
- package/palette-search-types.d.ts +59 -24
- package/query-understanding-types.d.ts +27 -5
- package/resolve-client.d.ts +6 -10
- package/resolve-client.js +5 -7
- package/response-schemas.d.ts +20 -0
- package/response-schemas.generated.d.ts +5 -0
- package/response-schemas.generated.js +160 -0
- package/response-schemas.js +113 -0
- package/run-types.d.ts +12 -93
- package/runs.d.ts +1 -37
- package/runs.js +2 -79
- package/schema-resource-types.d.ts +14 -1
- package/search-card-types.d.ts +22 -0
- package/search-index-plan-types.d.ts +70 -0
- package/search-refinement-types.d.ts +8 -38
- package/search-refinement-types.js +1 -0
- package/search-request-types.d.ts +117 -200
- package/search-response-receipt-types.d.ts +12 -268
- package/search-result-validation.d.ts +0 -16
- package/search-result-validation.js +22 -180
- package/spec-facet-types.d.ts +3 -8
- package/spec-types.d.ts +17 -10
- package/spec-types.js +8 -7
- package/specifications.d.ts +13 -55
- package/specifications.js +29 -73
- package/suggest-types.d.ts +4 -10
- package/suggest-types.js +1 -1
- package/types.d.ts +135 -338
- package/webmcp.d.ts +1 -1
- package/webmcp.generated.js +10 -94
- package/brand-most-sampled-types.d.ts +0 -33
- package/browse-types.d.ts +0 -236
- package/client-browse.d.ts +0 -78
- package/client-browse.js +0 -71
- package/client-exploration.d.ts +0 -9
- package/client-exploration.js +0 -5
- package/compare-types.d.ts +0 -89
- package/composition-client.d.ts +0 -33
- package/composition-client.js +0 -28
- package/composition-types.d.ts +0 -455
- package/composition-types.js +0 -10
- package/correction-types.d.ts +0 -88
- package/exploration-types.d.ts +0 -118
- package/exploration-types.js +0 -1
- package/fan-deck-types.d.ts +0 -42
- package/fan-deck-types.js +0 -9
- package/match-rejection-types.d.ts +0 -43
- package/match-rejection-types.js +0 -7
- package/palette-completion-types.d.ts +0 -115
- package/palette-completion-types.js +0 -1
- package/render-assets-types.d.ts +0 -65
- package/render-assets-types.js +0 -1
- package/search-collapse-types.d.ts +0 -69
- package/search-collapse-types.js +0 -1
- package/search-mood-types.d.ts +0 -6
- package/search-mood-types.js +0 -1
- package/search-window-types.d.ts +0 -25
- package/search-window-types.js +0 -1
- package/slot-pool-types.d.ts +0 -372
- package/slot-pool-types.js +0 -1
- /package/{brand-most-sampled-types.js → category-types.js} +0 -0
- /package/{browse-types.js → list-variant-facets-types.js} +0 -0
- /package/{compare-types.js → material-composition-types.js} +0 -0
- /package/{correction-types.js → search-index-plan-types.js} +0 -0
package/association-types.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* with {@link PairingItem}, so the two can never be concatenated into one list.
|
|
11
11
|
* Present them as separate sections, and never describe a pairing as available.
|
|
12
12
|
*/
|
|
13
|
+
import type { CorpusScope } from "./corpus-scope-types.js";
|
|
13
14
|
import type { Cursor, VariantId } from "./identifiers.js";
|
|
14
15
|
import type { ProductTypeReceipt } from "./material-types.js";
|
|
15
16
|
/**
|
|
@@ -54,13 +55,22 @@ export type DeclaredAssociation = {
|
|
|
54
55
|
/** Review receipt; proposed types are never accepted categories. */
|
|
55
56
|
productTypeReceipt: ProductTypeReceipt;
|
|
56
57
|
declared: DeclaredProvenance;
|
|
58
|
+
/** The accepted display category, for a card's kind pill. Null when none is accepted. */
|
|
59
|
+
kindLabel: string | null;
|
|
60
|
+
/** The accepted `price_tier` term (`$` to `$$$$$`). Absent means unknown, never cheap. */
|
|
61
|
+
priceTier?: string;
|
|
62
|
+
/**
|
|
63
|
+
* The eligible variants of this association's product, the set `listVariants`
|
|
64
|
+
* pages. Absent when the product has no eligible variant.
|
|
65
|
+
*/
|
|
66
|
+
colourwayCount?: number;
|
|
57
67
|
};
|
|
58
68
|
/**
|
|
59
69
|
* One page of declared associations.
|
|
60
70
|
*
|
|
61
71
|
* READ `totalAssociations`, NOT `associations.length`, when rendering a count
|
|
62
72
|
* like "Compatible Finishes (128)": the array is one page (up to 48), the total
|
|
63
|
-
* is the whole set for this subject, direction and corpus. A page is not a
|
|
73
|
+
* is the whole set for this subject, direction and corpus scope. A page is not a
|
|
64
74
|
* corpus — walk `nextCursor` before making any claim about the full set.
|
|
65
75
|
*/
|
|
66
76
|
export type DeclaredAssociationsResponse = {
|
|
@@ -71,7 +81,7 @@ export type DeclaredAssociationsResponse = {
|
|
|
71
81
|
*/
|
|
72
82
|
kind: "declared_association";
|
|
73
83
|
associations: DeclaredAssociation[];
|
|
74
|
-
/** The TRUE count for this subject, direction and corpus. Not the page size. */
|
|
84
|
+
/** The TRUE count for this subject, direction and corpus scope. Not the page size. */
|
|
75
85
|
totalAssociations: number;
|
|
76
86
|
/** How many associations this page carries. */
|
|
77
87
|
returnedCount: number;
|
|
@@ -86,16 +96,17 @@ export type AssociatedOptions = {
|
|
|
86
96
|
*/
|
|
87
97
|
limit?: number;
|
|
88
98
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
99
|
+
* Narrows the associations, `totalAssociations` and the cursor to one corpus
|
|
100
|
+
* scope. `materialBankOrderable` keeps associations pointing at a variant
|
|
101
|
+
* carrying a Material Bank id; absent or `all` is the whole declared set.
|
|
102
|
+
* Membership does not establish sampleability; use `sampleableOnly` for that.
|
|
92
103
|
*/
|
|
93
|
-
|
|
104
|
+
corpusScope?: CorpusScope;
|
|
94
105
|
/** Return only associations whose effective sampleability is true. */
|
|
95
106
|
sampleableOnly?: boolean;
|
|
96
107
|
/**
|
|
97
108
|
* The previous response's `nextCursor`, passed back verbatim. A cursor is
|
|
98
|
-
* bound to its subject, direction and corpus
|
|
109
|
+
* bound to its subject, direction and corpus scope - replaying it against a
|
|
99
110
|
* different one is a 400, never a silently different page.
|
|
100
111
|
*/
|
|
101
112
|
cursor?: Cursor;
|
package/attribution-types.d.ts
CHANGED
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
/**
|
|
14
14
|
* The ranking basis, in one vocabulary across both ranked routes.
|
|
15
15
|
*
|
|
16
|
-
* The first
|
|
16
|
+
* The first seven values are `search()`'s `mode` verbatim, and there
|
|
17
17
|
* `attribution.basis === mode` always. `"match"` is what `match()` reports;
|
|
18
18
|
* that route has no `mode`, so this is the only field its outcomes can be
|
|
19
19
|
* grouped by.
|
|
20
20
|
*/
|
|
21
|
-
export type AttributionBasis = "image" | "colour" | "text" | "lexical" | "entity-browse" | "agent" | "match";
|
|
21
|
+
export type AttributionBasis = "image" | "colour" | "text" | "lexical" | "entity-browse" | "agent" | "attribute" | "match";
|
|
22
22
|
/**
|
|
23
23
|
* Envelope-level attribution receipt, on every successful ranked response.
|
|
24
24
|
*
|
package/brand-types.d.ts
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* The SDK's one OFFSET-paginated surface — everything else that pages uses an
|
|
6
6
|
* opaque cursor. `meta` is where the page/corpus distinction is settled here.
|
|
7
7
|
*/
|
|
8
|
+
import type { CorpusScope, CorpusScopeReceipt } from "./corpus-scope-types.js";
|
|
8
9
|
export type BrandsOptions = {
|
|
10
|
+
/**
|
|
11
|
+
* Which corpus to list from. Narrows the brands AND the corpus their counts
|
|
12
|
+
* are drawn from, inside the query. Absent or `"all"` is the whole graph.
|
|
13
|
+
*/
|
|
14
|
+
corpusScope?: CorpusScope;
|
|
9
15
|
/** Fuzzy name filter. Omit for the whole collection. */
|
|
10
16
|
q?: string;
|
|
11
17
|
/** Page size. Never a bound on the collection. */
|
|
@@ -25,6 +31,8 @@ export type BrandCatalogListItem = {
|
|
|
25
31
|
variantCount: number;
|
|
26
32
|
};
|
|
27
33
|
export type BrandCatalogListPage = {
|
|
34
|
+
/** Present only when a narrowing scope applied; absence means the whole graph. */
|
|
35
|
+
corpusScope?: CorpusScopeReceipt;
|
|
28
36
|
/** THIS PAGE. Its length is `meta.count`, never `meta.total`. */
|
|
29
37
|
items: BrandCatalogListItem[];
|
|
30
38
|
/**
|
package/brands-client.d.ts
CHANGED
|
@@ -1,48 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The BRAND lens: the catalogue collection,
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `.brandColourDeck` delegate here; the contract lives in this file.
|
|
2
|
+
* The BRAND lens: the catalogue collection, as a thin wrapper over the shared
|
|
3
|
+
* {@link HttpTransport}. `MaterialGraphClient.brands` delegates here; the
|
|
4
|
+
* contract lives in this file.
|
|
6
5
|
*
|
|
7
|
-
* A brand is a COMPANY, not a catalogue. Every count
|
|
6
|
+
* A brand is a COMPANY, not a catalogue. Every count this read returns is
|
|
8
7
|
* coverage — what MaterialGraph has ingested — and never a claim about how
|
|
9
8
|
* many products the maker sells.
|
|
10
9
|
*/
|
|
11
10
|
import type { BrandCatalogListPage, BrandsOptions } from "./brand-types.js";
|
|
12
|
-
import type { BrandFanDeck } from "./fan-deck-types.js";
|
|
13
11
|
import type { HttpTransport } from "./http-transport.js";
|
|
14
|
-
import type { BrandOptions, BrandProfileResponse } from "./types.js";
|
|
15
12
|
/**
|
|
16
13
|
* THE QUESTION: "whose catalogs are in here, and how big is each?" The SDK's
|
|
17
14
|
* one OFFSET-paginated surface: read `meta.total` for the collection size and
|
|
18
|
-
* `meta.hasMore` to keep walking.
|
|
19
|
-
* brand's profile and trade signals.
|
|
15
|
+
* `meta.hasMore` to keep walking.
|
|
20
16
|
*/
|
|
21
17
|
export declare const listBrands: (transport: HttpTransport, options?: BrandsOptions, signal?: AbortSignal) => Promise<BrandCatalogListPage>;
|
|
22
|
-
/**
|
|
23
|
-
* THE QUESTION: "who is this brand, and what do they claim?" — profile plus the
|
|
24
|
-
* trade/spec signals ON RECORD. `trade` is keyed by attribute id and an ABSENT
|
|
25
|
-
* key means no value is held — never infer `false`. Instead use `search()` to
|
|
26
|
-
* find their materials; this describes the company, not the catalog.
|
|
27
|
-
*/
|
|
28
|
-
export declare const brandProfile: (transport: HttpTransport, brandSlug: string, options?: BrandOptions, signal?: AbortSignal) => Promise<BrandProfileResponse>;
|
|
29
|
-
/**
|
|
30
|
-
* THE QUESTION: "show me this maker's whole range, the way a fan deck reads."
|
|
31
|
-
* Colours grouped by family — creams together, then greys, then browns — and
|
|
32
|
-
* ordered light to dark within each. No stored scalar produces that order: a
|
|
33
|
-
* lightness sort interleaves the whites and the creams, and a reader loses the
|
|
34
|
-
* sense that they are looking at two different families.
|
|
35
|
-
*
|
|
36
|
-
* Deliberately unpaginated, so there is no cursor to walk and no all-brands
|
|
37
|
-
* form: family order is only correct over a COMPLETE range, because the greys
|
|
38
|
-
* cannot be placed against the browns while holding one page of each. A range
|
|
39
|
-
* past the server ceiling reports `truncatedAt` rather than being quietly cut,
|
|
40
|
-
* and an absent `truncatedAt` means the deck is whole.
|
|
41
|
-
*
|
|
42
|
-
* Every swatch carries the maker's PUBLISHED hex — this read never returns a
|
|
43
|
-
* colour derived from imagery. For "what is near this colour, across makers"
|
|
44
|
-
* use `byColour()` instead.
|
|
45
|
-
*
|
|
46
|
-
* @param brandSlug The brand's slug, as `listBrands()` reports it.
|
|
47
|
-
*/
|
|
48
|
-
export declare const brandColourDeck: (transport: HttpTransport, brandSlug: string, signal?: AbortSignal) => Promise<BrandFanDeck>;
|
package/brands-client.js
CHANGED
|
@@ -2,40 +2,14 @@ import { resolveOperation } from "./operations.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* THE QUESTION: "whose catalogs are in here, and how big is each?" The SDK's
|
|
4
4
|
* one OFFSET-paginated surface: read `meta.total` for the collection size and
|
|
5
|
-
* `meta.hasMore` to keep walking.
|
|
6
|
-
* brand's profile and trade signals.
|
|
5
|
+
* `meta.hasMore` to keep walking.
|
|
7
6
|
*/
|
|
8
7
|
export const listBrands = async (transport, options = {}, signal) => await transport.requestJson(resolveOperation("list_brands"), {
|
|
9
|
-
query: {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* key means no value is held — never infer `false`. Instead use `search()` to
|
|
16
|
-
* find their materials; this describes the company, not the catalog.
|
|
17
|
-
*/
|
|
18
|
-
export const brandProfile = async (transport, brandSlug, options, signal) => await transport.requestJson(resolveOperation("get_brand_profile"), { pathParams: { brandSlug }, query: { q: options?.q }, signal });
|
|
19
|
-
/**
|
|
20
|
-
* THE QUESTION: "show me this maker's whole range, the way a fan deck reads."
|
|
21
|
-
* Colours grouped by family — creams together, then greys, then browns — and
|
|
22
|
-
* ordered light to dark within each. No stored scalar produces that order: a
|
|
23
|
-
* lightness sort interleaves the whites and the creams, and a reader loses the
|
|
24
|
-
* sense that they are looking at two different families.
|
|
25
|
-
*
|
|
26
|
-
* Deliberately unpaginated, so there is no cursor to walk and no all-brands
|
|
27
|
-
* form: family order is only correct over a COMPLETE range, because the greys
|
|
28
|
-
* cannot be placed against the browns while holding one page of each. A range
|
|
29
|
-
* past the server ceiling reports `truncatedAt` rather than being quietly cut,
|
|
30
|
-
* and an absent `truncatedAt` means the deck is whole.
|
|
31
|
-
*
|
|
32
|
-
* Every swatch carries the maker's PUBLISHED hex — this read never returns a
|
|
33
|
-
* colour derived from imagery. For "what is near this colour, across makers"
|
|
34
|
-
* use `byColour()` instead.
|
|
35
|
-
*
|
|
36
|
-
* @param brandSlug The brand's slug, as `listBrands()` reports it.
|
|
37
|
-
*/
|
|
38
|
-
export const brandColourDeck = async (transport, brandSlug, signal) => await transport.requestJson(resolveOperation("brand_colour_deck"), {
|
|
39
|
-
pathParams: { brandSlug },
|
|
8
|
+
query: {
|
|
9
|
+
corpusScope: options.corpusScope,
|
|
10
|
+
limit: options.limit,
|
|
11
|
+
offset: options.offset,
|
|
12
|
+
q: options.q,
|
|
13
|
+
},
|
|
40
14
|
signal,
|
|
41
15
|
});
|
package/by-colour-types.d.ts
CHANGED
|
@@ -37,11 +37,22 @@ export type ByColourMatch = {
|
|
|
37
37
|
color: string | null;
|
|
38
38
|
variantName: string | null;
|
|
39
39
|
imageUrl: string | null;
|
|
40
|
+
/**
|
|
41
|
+
* SHA-256 of the displayed image `imageUrl` points at, as a hex digest.
|
|
42
|
+
* ABSENT means no hash is on record, never that there is no image.
|
|
43
|
+
*/
|
|
44
|
+
imageSha256?: string;
|
|
40
45
|
hex: string | null;
|
|
41
46
|
distance: number;
|
|
42
47
|
closeness: number;
|
|
43
48
|
category: MatchCategory | null;
|
|
44
49
|
oklab: OklabTriple | null;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the reported `hex` has a hue compatible with the query colour, by
|
|
52
|
+
* colorscope's `isHueCompatible` at its default thresholds. A flag, never a
|
|
53
|
+
* gate. ABSENT when the match has no hex or the query was a palette.
|
|
54
|
+
*/
|
|
55
|
+
hueCompatible?: boolean;
|
|
45
56
|
/**
|
|
46
57
|
* Where `hex` came from — PER MATCH, never per response. `"declared"`: the
|
|
47
58
|
* manufacturer published it (a paint's own colour system), so it may be
|
|
@@ -111,7 +122,13 @@ export type ColourFamilyGate = {
|
|
|
111
122
|
};
|
|
112
123
|
/** Receipt for the hard category gate and its treatment of unknown typing. */
|
|
113
124
|
export type ColourCategoryGate = {
|
|
114
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* Present when the caller named no category: the page then holds surface
|
|
127
|
+
* materials only (the `materials` product-type groups, listed in
|
|
128
|
+
* `requested`), so lights, taps and furniture do not answer a colour.
|
|
129
|
+
*/
|
|
130
|
+
defaulted?: true;
|
|
131
|
+
/** Category names or keys the gate kept: the caller's, or the default groups. */
|
|
115
132
|
requested: string[];
|
|
116
133
|
/** Only accepted primary product types can establish membership. */
|
|
117
134
|
requiresAcceptedPrimaryProductType: true;
|
|
@@ -121,8 +138,8 @@ export type ColourCategoryGate = {
|
|
|
121
138
|
/**
|
|
122
139
|
* Receipt for the colour-identity collapse that turns a variant-grain ranking
|
|
123
140
|
* into a page of TILES — one per (brand, product, dominant hex), one per stored
|
|
124
|
-
* photograph.
|
|
125
|
-
*
|
|
141
|
+
* photograph. Only responses stored before the one search carry it: the one
|
|
142
|
+
* search pages one row per product, so nothing collapses now.
|
|
126
143
|
*/
|
|
127
144
|
export type ColourCollapse = {
|
|
128
145
|
/** Ranked rows the collapse examined — this page's pool, never a corpus total. */
|
|
@@ -136,17 +153,15 @@ export type ColourCollapse = {
|
|
|
136
153
|
* Receipt naming which retrieval lane answered, and the colours it actually ran
|
|
137
154
|
* on. The live endpoint always sends it.
|
|
138
155
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* different geometries, so `colourDistance` on a match means a different thing
|
|
145
|
-
* in each and is NOT comparable across them.
|
|
156
|
+
* Every live page says `index`: the one search's colour key, the colour's
|
|
157
|
+
* family on the search index, nearest first by OKLab distance. A palette is
|
|
158
|
+
* ordered by its first colour, and `droppedColours` names the rest.
|
|
159
|
+
* `containment` and `palette` appear only on responses stored before the one
|
|
160
|
+
* search.
|
|
146
161
|
*/
|
|
147
162
|
export type ColourLaneReceipt = {
|
|
148
163
|
/** Which lane answered. Widened so a new server lane still type-checks. */
|
|
149
|
-
lane: OpenEnum<"containment" | "palette">;
|
|
164
|
+
lane: OpenEnum<"index" | "containment" | "palette">;
|
|
150
165
|
/** Why this lane, in one sentence, for a human reader. */
|
|
151
166
|
reason: string;
|
|
152
167
|
/**
|
|
@@ -247,7 +262,11 @@ export type ByColourParams = {
|
|
|
247
262
|
l?: number;
|
|
248
263
|
a?: number;
|
|
249
264
|
b?: number;
|
|
250
|
-
/**
|
|
265
|
+
/**
|
|
266
|
+
* HARD category filter — display names or taxonomy ids (repeatable). Absent,
|
|
267
|
+
* the page holds surface materials only (`categoryGate.defaulted`), so
|
|
268
|
+
* lights, taps and furniture do not answer a colour.
|
|
269
|
+
*/
|
|
251
270
|
category?: string | string[];
|
|
252
271
|
/**
|
|
253
272
|
* HARD brand filter (repeatable) — a canonical brand id, exact brand SLUG
|
|
@@ -283,8 +302,16 @@ export type ByColourParams = {
|
|
|
283
302
|
* drop.
|
|
284
303
|
*/
|
|
285
304
|
family?: string;
|
|
286
|
-
/**
|
|
305
|
+
/**
|
|
306
|
+
* Kept so existing callers still parse: every page is ordered nearest first
|
|
307
|
+
* by the one search's colour key, so both values return the same page.
|
|
308
|
+
*/
|
|
287
309
|
order?: "representative" | "nearest";
|
|
310
|
+
/**
|
|
311
|
+
* Order by the colour of an existing Variant: materials the same colour as
|
|
312
|
+
* this one. Used when no hex, colour or OKLab triple is given.
|
|
313
|
+
*/
|
|
314
|
+
variantId?: string;
|
|
288
315
|
/** Maximum OKLab distance to each match's reported hex. Single-colour only. */
|
|
289
316
|
maxColourDistance?: number;
|
|
290
317
|
/** Narrow retrieval inside the server query; absent means the whole graph. */
|
package/by-spec-types.d.ts
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
import type { ValueResolution } from "./catalog-discovery-types.js";
|
|
2
2
|
import type { VerdictCitation } from "./citation-types.js";
|
|
3
|
-
import type { VariantId } from "./identifiers.js";
|
|
4
|
-
/**
|
|
5
|
-
* One criterion a match satisfied, with the trust behind it.
|
|
6
|
-
*
|
|
7
|
-
* `confidence` (0–1) and `sourceBasis` are the CLAIM's provenance, not decoration
|
|
8
|
-
* — quote them wherever the value is quoted. A `null` on either means the trust
|
|
9
|
-
* is unrecorded, which is weaker than a low number, not stronger.
|
|
10
|
-
*/
|
|
11
|
-
export type BySpecMatchedCell = {
|
|
12
|
-
attributeId: string;
|
|
13
|
-
confidence: number | null;
|
|
14
|
-
sourceBasis: string | null;
|
|
15
|
-
};
|
|
16
3
|
/**
|
|
17
4
|
* The six states a verdict cell can report — and what each licenses you to say.
|
|
18
5
|
*
|
|
@@ -97,19 +84,6 @@ export type BySpecVerdict = {
|
|
|
97
84
|
* so search-surface code can name it for what it is rather than duplicating it.
|
|
98
85
|
*/
|
|
99
86
|
export type MaterialVerdict = BySpecVerdict;
|
|
100
|
-
export type BySpecMatch = {
|
|
101
|
-
/** Opaque — round-trip verbatim. */
|
|
102
|
-
variantId: VariantId;
|
|
103
|
-
brand: string;
|
|
104
|
-
product: string;
|
|
105
|
-
variant: string;
|
|
106
|
-
color: string | null;
|
|
107
|
-
imageUrl: string | null;
|
|
108
|
-
hex: string | null;
|
|
109
|
-
matched: BySpecMatchedCell[];
|
|
110
|
-
minConfidence: number | null;
|
|
111
|
-
verdict: BySpecVerdict;
|
|
112
|
-
};
|
|
113
87
|
/**
|
|
114
88
|
* One criterion the server could not resolve to canonical vocabulary, with the
|
|
115
89
|
* resolver's ranked suggestions for it.
|
|
@@ -138,44 +112,3 @@ export type BySpecUnresolvedCriterion = {
|
|
|
138
112
|
/** Ranked candidates for whichever half failed. See {@link ValueResolution}. */
|
|
139
113
|
resolution: ValueResolution;
|
|
140
114
|
};
|
|
141
|
-
/**
|
|
142
|
-
* The find-by-spec envelope — A PAGE, AND NOTHING BUT A PAGE.
|
|
143
|
-
*
|
|
144
|
-
* Read `totalMatches` carefully: despite the name it is the route's own words,
|
|
145
|
-
* "Size of the returned (limited) sample, not the true corpus total" — it is
|
|
146
|
-
* literally `matches.length` under the `limit` you asked for. This surface
|
|
147
|
-
* states NO corpus total, so "N materials meet this specification" is not a
|
|
148
|
-
* claim you can make from one response. Raise `limit`, or say "at least N".
|
|
149
|
-
* `brandsSpanned` is likewise the brand count OF THIS SAMPLE.
|
|
150
|
-
*
|
|
151
|
-
* And check `unresolvedCriteria` BEFORE reading any of that: when it is present
|
|
152
|
-
* the numbers beside it describe a query that never ran.
|
|
153
|
-
*/
|
|
154
|
-
export type BySpecResponse = {
|
|
155
|
-
/** The criteria as parsed — check them before trusting a surprising result. */
|
|
156
|
-
criteria: {
|
|
157
|
-
attribute: string;
|
|
158
|
-
value: string;
|
|
159
|
-
}[];
|
|
160
|
-
/** `matches.length`, i.e. THIS SAMPLE under `limit`. Never a corpus total. */
|
|
161
|
-
totalMatches: number;
|
|
162
|
-
/** Distinct brands in the returned sample — a lower bound on cross-brand reach. */
|
|
163
|
-
brandsSpanned: number;
|
|
164
|
-
/** The sample, photo-first, capped by `limit`. */
|
|
165
|
-
matches: BySpecMatch[];
|
|
166
|
-
/**
|
|
167
|
-
* Present ONLY when a criterion failed exact canonical-vocabulary membership —
|
|
168
|
-
* and its presence means THE QUERY WAS NEVER RUN. A pre-flight gate short-circuits
|
|
169
|
-
* before the search, so the rest of the envelope is a placeholder rather than
|
|
170
|
-
* a finding: `matches` is `[]` and `totalMatches` is `0` because nothing was
|
|
171
|
-
* searched, not because nothing qualifies. Reporting that zero as "no material
|
|
172
|
-
* meets this specification" states a fact about the corpus on the strength of
|
|
173
|
-
* a question nobody asked it.
|
|
174
|
-
*
|
|
175
|
-
* Treat these criteria as UNAPPLIED and surface them: retry with a
|
|
176
|
-
* `resolution.candidates` id (subject to `recommendedAction` — `ambiguous`
|
|
177
|
-
* means ask, not pick), or say the value could not be resolved. Absent means
|
|
178
|
-
* every criterion resolved and the query did run.
|
|
179
|
-
*/
|
|
180
|
-
unresolvedCriteria?: BySpecUnresolvedCriterion[];
|
|
181
|
-
};
|
package/by-spec-types.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
// ── Catalog / spec
|
|
1
|
+
// ── Catalog / spec: verdict wire types ──────────────────────────────────────
|
|
2
2
|
//
|
|
3
|
-
// Hand-maintained mirror of the
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Hand-maintained mirror of the shared CandidateVerdict and of the pre-flight
|
|
4
|
+
// unresolved-criterion contract. The by-spec ROUTE these once described
|
|
5
|
+
// (`catalog_by_spec`) moved to `list_variants`'s `filters` (MG-2222); the
|
|
6
|
+
// verdict and unresolved-criterion shapes below are independent of that route
|
|
7
|
+
// and stay. Split out of `types.ts` to keep that file under its growth
|
|
8
|
+
// baseline; re-exported from `types.ts`.
|
|
7
9
|
export {};
|
|
@@ -6,10 +6,6 @@
|
|
|
6
6
|
* then spend on `mg.bySpec()` or `mg.search({ filters })`.
|
|
7
7
|
*/
|
|
8
8
|
import type { OpenEnum } from "./types.js";
|
|
9
|
-
/** Options for resolving a free-text value against one attribute's dictionary. */
|
|
10
|
-
export type ResolveAttributeValueOptions = {
|
|
11
|
-
limit?: number;
|
|
12
|
-
};
|
|
13
9
|
/**
|
|
14
10
|
* One ranked canonical value candidate. `tier` says HOW it matched, strongest
|
|
15
11
|
* first: `exact_id` > `exact_alias` > `lexical` > `semantic`. A `semantic` hit
|
|
@@ -26,8 +22,7 @@ export type ResolveValueCandidate = {
|
|
|
26
22
|
};
|
|
27
23
|
/**
|
|
28
24
|
* The resolver's verdict on ONE free-text token — the single shape every
|
|
29
|
-
* resolving surface speaks, so a caller learns to read it once.
|
|
30
|
-
* by {@link MaterialGraphClient.resolveAttributeValue}, and carried per bad
|
|
25
|
+
* resolving surface speaks, so a caller learns to read it once. Carried per bad
|
|
31
26
|
* criterion by `bySpec`'s `unresolvedCriteria`.
|
|
32
27
|
*
|
|
33
28
|
* READ `recommendedAction`, NOT JUST `best`. `ambiguous` with a populated
|
|
@@ -52,16 +47,6 @@ export type ValueResolution = {
|
|
|
52
47
|
candidates: ResolveValueCandidate[];
|
|
53
48
|
recommendedAction: OpenEnum<"use_best" | "choose_from_candidates" | "ask_user" | "none_found">;
|
|
54
49
|
};
|
|
55
|
-
/** Response from resolving a free-text value against one attribute's dictionary. */
|
|
56
|
-
export type ResolveAttributeValueResponse = {
|
|
57
|
-
attribute: {
|
|
58
|
-
id: string;
|
|
59
|
-
name: string;
|
|
60
|
-
dictionaryId: string;
|
|
61
|
-
};
|
|
62
|
-
/** The verdict on `q`. Read `recommendedAction` — see {@link ValueResolution}. */
|
|
63
|
-
resolution: ValueResolution;
|
|
64
|
-
};
|
|
65
50
|
/** Options for searching registry attributes and value-dictionary terms together. */
|
|
66
51
|
export type VocabularySearchOptions = {
|
|
67
52
|
limit?: number;
|
package/catalogue-client.d.ts
CHANGED
|
@@ -1,45 +1,26 @@
|
|
|
1
|
-
import type { BrandMostSampledResponse } from "./brand-most-sampled-types.js";
|
|
2
1
|
import type { CatalogDocumentList, CatalogPageListResult, CatalogProductReferenceReadResult, CatalogueChannelCollectionsResponse, CatalogueCollectionsOptions, CatalogueDocumentAccessResult, CataloguePageRepresentationReadResult, CatalogueReferenceBatchResponse } from "./catalogue-types.js";
|
|
3
|
-
import type { CompareInput, CompareResponse } from "./compare-types.js";
|
|
4
|
-
import type { CreateCorrectionInput, CorrectionResponse, CorrectionsListResponse } from "./correction-types.js";
|
|
5
2
|
import type { HttpTransport } from "./http-transport.js";
|
|
6
3
|
import type { VariantId } from "./identifiers.js";
|
|
7
|
-
import type {
|
|
8
|
-
import type { MatchRejection, MatchRejectionList, RejectMatchResultInput } from "./match-rejection-types.js";
|
|
4
|
+
import type { IdentifyResponse, IdentifyVariantInput } from "./identify-types.js";
|
|
9
5
|
import type { SamplizeCatalogueOptions, SamplizeCataloguePage } from "./samplize-catalogue-types.js";
|
|
10
6
|
import type { SamplizeColorVecCache } from "./samplize-colorvec.js";
|
|
11
7
|
/** Catalogue publication operations inherited by the public SDK client. */
|
|
12
8
|
export declare class CatalogueClient {
|
|
13
9
|
#private;
|
|
14
10
|
protected constructor(transport: HttpTransport);
|
|
15
|
-
/** Brand products ranked by observed Material Bank sample-order lines, with window provenance. */
|
|
16
|
-
brandMostSampled(brandId: string, options?: {
|
|
17
|
-
limit?: number;
|
|
18
|
-
}, signal?: AbortSignal): Promise<BrandMostSampledResponse>;
|
|
19
|
-
/** Compare canonical Variants without searching or ranking them. */
|
|
20
|
-
compare(input: CompareInput, signal?: AbortSignal): Promise<CompareResponse>;
|
|
21
|
-
/** Submit confirmed caller-authored review work; never changes accepted truth. */
|
|
22
|
-
createCorrection(input: CreateCorrectionInput, options: {
|
|
23
|
-
idempotencyKey: string;
|
|
24
|
-
signal?: AbortSignal;
|
|
25
|
-
}): Promise<CorrectionResponse>;
|
|
26
|
-
getCorrection(correctionId: string, signal?: AbortSignal): Promise<CorrectionResponse>;
|
|
27
|
-
listCorrections(input?: {
|
|
28
|
-
cursor?: string;
|
|
29
|
-
limit?: number;
|
|
30
|
-
}, signal?: AbortSignal): Promise<CorrectionsListResponse>;
|
|
31
11
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
12
|
+
* THE QUESTION: "what does this manufacturer page or code resolve to in the
|
|
13
|
+
* graph?" Give `input.url` alone, or `input.code` with `input.brandId` (from
|
|
14
|
+
* {@link CatalogueClient.brands} - inherited by {@link MaterialGraphClient})
|
|
15
|
+
* when there is no page to read.
|
|
16
|
+
*
|
|
17
|
+
* Exact and scoreless: a sibling colourway, a similar image or a brand match
|
|
18
|
+
* alone never identifies a variant. Read `data.outcome` - `identified` names
|
|
19
|
+
* an exact stored variant, `placed` an exact brand with no variant match,
|
|
20
|
+
* `ambiguous` carries bounded `candidates`, and `unresolved` states why,
|
|
21
|
+
* never a guess. The submitted URL is never persisted.
|
|
37
22
|
*/
|
|
38
|
-
|
|
39
|
-
/** Read one match response back with every rejection recorded against it. */
|
|
40
|
-
matchRejections(responseId: string, signal?: AbortSignal): Promise<MatchRejectionList>;
|
|
41
|
-
/** Identify the canonical graph subject for one explicitly selected page. */
|
|
42
|
-
identify(input: IdentifySelectedPageInput, signal?: AbortSignal): Promise<IdentifySelectedPageResult>;
|
|
23
|
+
identify(input: IdentifyVariantInput, signal?: AbortSignal): Promise<IdentifyResponse>;
|
|
43
24
|
/** Complete producer-owned vectors and classifications for portable colour matching. */
|
|
44
25
|
samplizeColorVecCache(sourceVersion: string, signal?: AbortSignal): Promise<SamplizeColorVecCache>;
|
|
45
26
|
/** MG-owned full-catalogue facets and directional colour refinement before page limiting. */
|
package/catalogue-client.js
CHANGED
|
@@ -5,54 +5,18 @@ export class CatalogueClient {
|
|
|
5
5
|
constructor(transport) {
|
|
6
6
|
this.#transport = transport;
|
|
7
7
|
}
|
|
8
|
-
/** Brand products ranked by observed Material Bank sample-order lines, with window provenance. */
|
|
9
|
-
async brandMostSampled(brandId, options = {}, signal) {
|
|
10
|
-
return await this.#transport.requestJson(resolveOperation("brands.most_sampled"), { query: { brandId, ...options }, signal });
|
|
11
|
-
}
|
|
12
|
-
/** Compare canonical Variants without searching or ranking them. */
|
|
13
|
-
async compare(input, signal) {
|
|
14
|
-
return await this.#transport.requestJson(resolveOperation("retrieval.compare"), {
|
|
15
|
-
body: input,
|
|
16
|
-
signal,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
/** Submit confirmed caller-authored review work; never changes accepted truth. */
|
|
20
|
-
async createCorrection(input, options) {
|
|
21
|
-
if (!/^[\u0021-\u007E]{1,200}$/u.test(options.idempotencyKey)) {
|
|
22
|
-
throw new Error("A valid Idempotency-Key is required for Correction submission.");
|
|
23
|
-
}
|
|
24
|
-
return await this.#transport.requestJson(resolveOperation("corrections.create"), {
|
|
25
|
-
body: input,
|
|
26
|
-
...options,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
async getCorrection(correctionId, signal) {
|
|
30
|
-
return await this.#transport.requestJson(resolveOperation("corrections.get"), {
|
|
31
|
-
pathParams: { correctionId },
|
|
32
|
-
signal,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
async listCorrections(input = {}, signal) {
|
|
36
|
-
return await this.#transport.requestJson(resolveOperation("corrections.list"), {
|
|
37
|
-
query: input,
|
|
38
|
-
signal,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
8
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
9
|
+
* THE QUESTION: "what does this manufacturer page or code resolve to in the
|
|
10
|
+
* graph?" Give `input.url` alone, or `input.code` with `input.brandId` (from
|
|
11
|
+
* {@link CatalogueClient.brands} - inherited by {@link MaterialGraphClient})
|
|
12
|
+
* when there is no page to read.
|
|
13
|
+
*
|
|
14
|
+
* Exact and scoreless: a sibling colourway, a similar image or a brand match
|
|
15
|
+
* alone never identifies a variant. Read `data.outcome` - `identified` names
|
|
16
|
+
* an exact stored variant, `placed` an exact brand with no variant match,
|
|
17
|
+
* `ambiguous` carries bounded `candidates`, and `unresolved` states why,
|
|
18
|
+
* never a guess. The submitted URL is never persisted.
|
|
47
19
|
*/
|
|
48
|
-
async rejectMatchResult(responseId, input, signal) {
|
|
49
|
-
return await this.#transport.requestJson(resolveOperation("reject_match_result"), { body: input, pathParams: { responseId }, signal });
|
|
50
|
-
}
|
|
51
|
-
/** Read one match response back with every rejection recorded against it. */
|
|
52
|
-
async matchRejections(responseId, signal) {
|
|
53
|
-
return await this.#transport.requestJson(resolveOperation("list_match_rejections"), { pathParams: { responseId }, signal });
|
|
54
|
-
}
|
|
55
|
-
/** Identify the canonical graph subject for one explicitly selected page. */
|
|
56
20
|
async identify(input, signal) {
|
|
57
21
|
return await this.#transport.requestJson(resolveOperation("retrieval.identify"), { body: input, signal });
|
|
58
22
|
}
|
package/catalogue-types.d.ts
CHANGED
|
@@ -57,6 +57,43 @@ export interface CatalogueReference {
|
|
|
57
57
|
status: "verified";
|
|
58
58
|
isPrimary: boolean;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Why a known variant has no verified reference. None of these says the
|
|
62
|
+
* product is missing from the printed book; nobody records how many of a
|
|
63
|
+
* brand's products a publication contains.
|
|
64
|
+
*/
|
|
65
|
+
export type CatalogueReferenceAbsenceReason =
|
|
66
|
+
/**
|
|
67
|
+
* The registry retains no publication for the variant's brand. It says
|
|
68
|
+
* nothing about whether the maker publishes one.
|
|
69
|
+
*/
|
|
70
|
+
"no_publication_on_record"
|
|
71
|
+
/** The edition is known but its document is not retained. */
|
|
72
|
+
| "publication_source_unavailable"
|
|
73
|
+
/** The document is retained but no page has been reviewed. */
|
|
74
|
+
| "publication_not_reviewed"
|
|
75
|
+
/** Pages were reviewed and this product is not among the references yet. */
|
|
76
|
+
| "product_not_yet_referenced";
|
|
77
|
+
/** The brand publication a `no_verified_reference` result was judged against. */
|
|
78
|
+
export type CatalogueReferencePublication = {
|
|
79
|
+
brand: {
|
|
80
|
+
id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
};
|
|
83
|
+
catalogue: {
|
|
84
|
+
id: string;
|
|
85
|
+
title: string;
|
|
86
|
+
};
|
|
87
|
+
/** Null when the edition's document is not retained. */
|
|
88
|
+
documentId: string | null;
|
|
89
|
+
edition: {
|
|
90
|
+
id: string;
|
|
91
|
+
label: string;
|
|
92
|
+
title?: string;
|
|
93
|
+
};
|
|
94
|
+
/** Reviewed references the publication holds; present only when its pages were reviewed. */
|
|
95
|
+
referencedProductCount?: number;
|
|
96
|
+
};
|
|
60
97
|
export type CatalogueReferenceResult = {
|
|
61
98
|
variantId: string;
|
|
62
99
|
status: "verified";
|
|
@@ -64,6 +101,9 @@ export type CatalogueReferenceResult = {
|
|
|
64
101
|
} | {
|
|
65
102
|
variantId: string;
|
|
66
103
|
status: "no_verified_reference";
|
|
104
|
+
reason: CatalogueReferenceAbsenceReason;
|
|
105
|
+
/** Absent only when `reason` is `no_publication_on_record`. */
|
|
106
|
+
publication?: CatalogueReferencePublication;
|
|
67
107
|
} | {
|
|
68
108
|
variantId: string;
|
|
69
109
|
status: "unresolved_variant";
|