@instruments/materialgraph 0.25.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.
Files changed (158) hide show
  1. package/association-types.d.ts +38 -27
  2. package/associations-client.d.ts +4 -4
  3. package/associations-client.js +3 -10
  4. package/attribution-types.d.ts +4 -4
  5. package/brand-types.d.ts +14 -6
  6. package/brands-client.d.ts +7 -38
  7. package/brands-client.js +10 -40
  8. package/by-colour-types.d.ts +58 -31
  9. package/by-spec-types.d.ts +6 -73
  10. package/by-spec-types.js +7 -5
  11. package/catalog-discovery-types.d.ts +11 -26
  12. package/catalogue-client.d.ts +16 -35
  13. package/catalogue-client.js +32 -67
  14. package/catalogue-types.d.ts +44 -4
  15. package/categories-client.d.ts +63 -0
  16. package/categories-client.js +48 -0
  17. package/category-types.d.ts +114 -0
  18. package/citation-types.d.ts +4 -4
  19. package/client-config.d.ts +4 -6
  20. package/client-config.js +2 -4
  21. package/client-source-material-comments.d.ts +4 -4
  22. package/client-source-material-comments.js +4 -38
  23. package/client-vocabulary.d.ts +7 -9
  24. package/client-vocabulary.js +22 -30
  25. package/client.d.ts +110 -244
  26. package/client.js +217 -387
  27. package/codes-client.d.ts +2 -2
  28. package/codes-client.js +8 -8
  29. package/codes-types.d.ts +55 -34
  30. package/colour-aggregate-types.d.ts +24 -24
  31. package/colours-client.d.ts +6 -11
  32. package/colours-client.js +11 -19
  33. package/coordinate-client.d.ts +2 -2
  34. package/coordinate-client.js +1 -13
  35. package/corpus-scope-types.d.ts +3 -3
  36. package/corpus-scope-types.js +1 -25
  37. package/demand-batch-types.d.ts +18 -18
  38. package/demand-types.d.ts +24 -24
  39. package/errors.d.ts +13 -13
  40. package/errors.js +54 -52
  41. package/http-transport.d.ts +13 -21
  42. package/http-transport.js +31 -28
  43. package/identify-types.d.ts +54 -44
  44. package/identify-types.js +5 -3
  45. package/index.d.ts +11 -27
  46. package/index.js +4 -6
  47. package/list-variant-facets-types.d.ts +60 -0
  48. package/list-variants-types.d.ts +142 -0
  49. package/list-variants-types.js +12 -0
  50. package/match-stream-types.d.ts +45 -32
  51. package/match-stream-types.js +2 -0
  52. package/match-stream.d.ts +2 -2
  53. package/match-stream.js +67 -49
  54. package/match-types.d.ts +32 -8
  55. package/material-asset-types.d.ts +89 -69
  56. package/material-block-types.d.ts +8 -6
  57. package/material-composition-client.d.ts +21 -0
  58. package/material-composition-client.js +13 -0
  59. package/material-composition-types.d.ts +403 -0
  60. package/material-query-plan-types.d.ts +61 -145
  61. package/material-resources-client.d.ts +12 -10
  62. package/material-resources-client.js +27 -22
  63. package/material-types.d.ts +16 -24
  64. package/ndjson.js +16 -8
  65. package/operations.d.ts +6 -6
  66. package/operations.js +29 -156
  67. package/package.json +5 -1
  68. package/palette-search-types.d.ts +87 -52
  69. package/query-understanding-types.d.ts +65 -40
  70. package/resolve-client.d.ts +8 -12
  71. package/resolve-client.js +9 -13
  72. package/resolve-colour-types.d.ts +8 -8
  73. package/resolve-types.d.ts +10 -10
  74. package/response-schemas.d.ts +20 -0
  75. package/response-schemas.generated.d.ts +5 -0
  76. package/response-schemas.generated.js +160 -0
  77. package/response-schemas.js +113 -0
  78. package/run-types.d.ts +64 -145
  79. package/runs.d.ts +9 -58
  80. package/runs.js +60 -149
  81. package/samplize-catalogue-types.d.ts +18 -18
  82. package/samplize-colorvec.d.ts +20 -20
  83. package/samplize-colorvec.js +66 -42
  84. package/schema-resource-types.d.ts +52 -39
  85. package/schema-resource-types.js +5 -5
  86. package/search-card-types.d.ts +26 -4
  87. package/search-index-plan-types.d.ts +70 -0
  88. package/search-refinement-types.d.ts +10 -40
  89. package/search-refinement-types.js +1 -0
  90. package/search-request-types.d.ts +121 -204
  91. package/search-response-receipt-types.d.ts +13 -253
  92. package/search-response-types.d.ts +2 -2
  93. package/search-result-validation.d.ts +3 -19
  94. package/search-result-validation.js +42 -183
  95. package/source-material-validation.d.ts +3 -3
  96. package/source-material-validation.js +35 -39
  97. package/spec-facet-types.d.ts +11 -16
  98. package/spec-types.d.ts +23 -16
  99. package/spec-types.js +8 -7
  100. package/specifications.d.ts +14 -72
  101. package/specifications.js +39 -89
  102. package/sse.d.ts +2 -2
  103. package/sse.js +32 -16
  104. package/substitute-types.d.ts +22 -22
  105. package/suggest-types.d.ts +11 -17
  106. package/suggest-types.js +3 -3
  107. package/taxonomy-coverage-types.d.ts +8 -8
  108. package/types.d.ts +202 -405
  109. package/validation.d.ts +26 -26
  110. package/validation.js +97 -92
  111. package/webmcp.d.ts +3 -3
  112. package/webmcp.generated.js +10 -93
  113. package/brand-most-sampled-types.d.ts +0 -33
  114. package/browse-types.d.ts +0 -236
  115. package/client-browse.d.ts +0 -78
  116. package/client-browse.js +0 -72
  117. package/client-exploration.d.ts +0 -9
  118. package/client-exploration.js +0 -7
  119. package/compare-types.d.ts +0 -89
  120. package/composition-client.d.ts +0 -33
  121. package/composition-client.js +0 -27
  122. package/composition-types.d.ts +0 -455
  123. package/composition-types.js +0 -10
  124. package/correction-types.d.ts +0 -88
  125. package/exploration-types.d.ts +0 -118
  126. package/exploration-types.js +0 -1
  127. package/fan-deck-types.d.ts +0 -42
  128. package/fan-deck-types.js +0 -9
  129. package/match-rejection-types.d.ts +0 -43
  130. package/match-rejection-types.js +0 -7
  131. package/palette-completion-types.d.ts +0 -115
  132. package/palette-completion-types.js +0 -1
  133. package/project-types.d.ts +0 -79
  134. package/project-types.js +0 -9
  135. package/projects.d.ts +0 -13
  136. package/projects.js +0 -46
  137. package/render-assets-types.d.ts +0 -65
  138. package/render-assets-types.js +0 -1
  139. package/run-events.d.ts +0 -106
  140. package/run-events.js +0 -32
  141. package/schedule-reference-types.d.ts +0 -46
  142. package/schedule-reference-types.js +0 -1
  143. package/schedule-references-client.d.ts +0 -14
  144. package/schedule-references-client.js +0 -26
  145. package/schedule-types.d.ts +0 -261
  146. package/schedule-types.js +0 -1
  147. package/search-collapse-types.d.ts +0 -69
  148. package/search-collapse-types.js +0 -1
  149. package/search-mood-types.d.ts +0 -6
  150. package/search-mood-types.js +0 -1
  151. package/search-window-types.d.ts +0 -25
  152. package/search-window-types.js +0 -1
  153. package/slot-pool-types.d.ts +0 -372
  154. package/slot-pool-types.js +0 -1
  155. /package/{brand-most-sampled-types.js → category-types.js} +0 -0
  156. /package/{browse-types.js → list-variant-facets-types.js} +0 -0
  157. /package/{compare-types.js → material-composition-types.js} +0 -0
  158. /package/{correction-types.js → search-index-plan-types.js} +0 -0
@@ -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 interface 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
  *
@@ -36,7 +23,7 @@ export type BySpecVerdictState = "matched" | "deviated" | "failed" | "unverified
36
23
  * Hand-mirrors the `AttributeVerdict` contract from `@materialgraph/contracts`;
37
24
  * the OpenAPI `CatalogBySpecResponse` schema is the source of truth on the wire.
38
25
  */
39
- export interface BySpecVerdictCell {
26
+ export type BySpecVerdictCell = {
40
27
  attributeId: string;
41
28
  state: BySpecVerdictState;
42
29
  strength: "required" | "preferred";
@@ -73,7 +60,7 @@ export interface BySpecVerdictCell {
73
60
  */
74
61
  trustGap: "below_confidence" | "basis_unmet" | "proposed" | null;
75
62
  citation?: VerdictCitation;
76
- }
63
+ };
77
64
  /**
78
65
  * A match's full report card: every cell, the rolled-up grade, weakest confidence.
79
66
  *
@@ -86,30 +73,17 @@ export interface BySpecVerdictCell {
86
73
  * `minConfidence` is the WEAKEST cell's confidence — the honest ceiling on the
87
74
  * whole card, not an average. Quote it alongside the grade.
88
75
  */
89
- export interface BySpecVerdict {
76
+ export type BySpecVerdict = {
90
77
  cells: BySpecVerdictCell[];
91
78
  grade: "meets_all" | "close" | "hard_no";
92
79
  minConfidence: number | null;
93
- }
80
+ };
94
81
  /**
95
82
  * The verdict a materials-search hit carries (MG-625). It IS the shared
96
83
  * {@link BySpecVerdict} shape — the single CandidateVerdict mirror — aliased here
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 interface 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.
@@ -128,7 +102,7 @@ export interface BySpecMatch {
128
102
  * EVERY miss is reported, not just the first, so one round trip is enough to fix
129
103
  * a whole spec.
130
104
  */
131
- export interface BySpecUnresolvedCriterion {
105
+ export type BySpecUnresolvedCriterion = {
132
106
  /** The parsed attribute id, after the route's surrounding-whitespace trim. */
133
107
  attributeId: string;
134
108
  /** The parsed value — never overwritten by the attribute id when that id is unknown. */
@@ -137,45 +111,4 @@ export interface BySpecUnresolvedCriterion {
137
111
  reason?: "unknown_attribute_or_term" | "not_a_specification";
138
112
  /** Ranked candidates for whichever half failed. See {@link ValueResolution}. */
139
113
  resolution: ValueResolution;
140
- }
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 interface BySpecResponse {
155
- /** The criteria as parsed — check them before trusting a surprising result. */
156
- criteria: Array<{
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
- }
114
+ };
package/by-spec-types.js CHANGED
@@ -1,7 +1,9 @@
1
- // ── Catalog / spec — find-by-spec wire types ─────────────────────────────────
1
+ // ── Catalog / spec: verdict wire types ──────────────────────────────────────
2
2
  //
3
- // Hand-maintained mirror of the `CatalogBySpecResponse` OpenAPI schema (the
4
- // source of truth on the wire); the `sdk-openapi-parity` test gates this against
5
- // the generated spec. Split out of `types.ts` to keep that file under its growth
6
- // baseline; re-exported from `types.ts` so importers see no change.
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,16 +6,12 @@
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 interface 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
16
12
  * is a guess worth confirming, not an equivalence.
17
13
  */
18
- export interface ResolveValueCandidate {
14
+ export type ResolveValueCandidate = {
19
15
  id: string;
20
16
  label: string;
21
17
  dictionaryId?: string;
@@ -23,11 +19,10 @@ export interface ResolveValueCandidate {
23
19
  tier: OpenEnum<"exact_id" | "exact_alias" | "lexical" | "semantic">;
24
20
  /** Present only for a colour_family candidate resolved via the colorscope fallback. */
25
21
  via?: OpenEnum<"colorscope">;
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. Returned whole
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
@@ -45,36 +40,26 @@ export interface ResolveValueCandidate {
45
40
  * `query` is the trimmed token that was actually resolved, which is how you tell
46
41
  * WHICH half of a failed `attribute:value` pair was the problem.
47
42
  */
48
- export interface ValueResolution {
43
+ export type ValueResolution = {
49
44
  status: OpenEnum<"resolved" | "ambiguous" | "unresolved">;
50
45
  query: string;
51
46
  best: ResolveValueCandidate | null;
52
47
  candidates: ResolveValueCandidate[];
53
48
  recommendedAction: OpenEnum<"use_best" | "choose_from_candidates" | "ask_user" | "none_found">;
54
- }
55
- /** Response from resolving a free-text value against one attribute's dictionary. */
56
- export interface 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
- }
49
+ };
65
50
  /** Options for searching registry attributes and value-dictionary terms together. */
66
- export interface VocabularySearchOptions {
51
+ export type VocabularySearchOptions = {
67
52
  limit?: number;
68
53
  kind?: "attribute" | "term";
69
- }
54
+ };
70
55
  /** One ranked cross-vocabulary candidate. */
71
- export interface VocabularySearchCandidate extends ResolveValueCandidate {
56
+ export type VocabularySearchCandidate = {
72
57
  kind: OpenEnum<"attribute" | "term">;
73
58
  /** Present for terms: attributes whose value dictionary owns this term. */
74
59
  attributeIds?: string[];
75
- }
60
+ } & ResolveValueCandidate;
76
61
  /** Response from the cross-vocabulary catalog search. */
77
- export interface VocabularySearchResponse {
62
+ export type VocabularySearchResponse = {
78
63
  query: string;
79
64
  results: VocabularySearchCandidate[];
80
- }
65
+ };
@@ -1,53 +1,34 @@
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 { IdentifySelectedPageInput, IdentifySelectedPageResult } from "./identify-types.js";
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
- * Record "not this" on one result a match showed, against the response it
33
- * came from. `responseId` is that response's `attribution.responseId`; the
34
- * call needs the same key the match was made with. Repeating a rejection
35
- * returns the original receipt. This judges the match ranking and is never a
36
- * catalogue correction - wrong product facts go through `createCorrection`.
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
- rejectMatchResult(responseId: string, input: RejectMatchResultInput, signal?: AbortSignal): Promise<MatchRejection>;
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. */
46
27
  samplizeCatalogueSearch(input: {
47
- palette?: Array<{
28
+ palette?: {
48
29
  hex: string;
49
30
  proportion: number;
50
- }>;
31
+ }[];
51
32
  query?: string;
52
33
  reference?: string;
53
34
  direction?: "similar" | "lighter" | "darker" | "muted";
@@ -73,13 +54,13 @@ export declare class CatalogueClient {
73
54
  rankingVersion?: string;
74
55
  dictionaryVersion?: string;
75
56
  eligibleCount?: number;
76
- groups?: Array<{
57
+ groups?: {
77
58
  hex: string;
78
59
  proportion: number;
79
60
  quota: number;
80
61
  ids: string[];
81
62
  shortfall: number;
82
- }>;
63
+ }[];
83
64
  ids: string[];
84
65
  limited: boolean;
85
66
  sourceVersion: string;
@@ -5,79 +5,44 @@ 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
- brandMostSampled(brandId, options = {}, signal) {
10
- return this.#transport.requestJson(resolveOperation("brands.most_sampled"), { query: { brandId, ...options }, signal });
11
- }
12
- /** Compare canonical Variants without searching or ranking them. */
13
- compare(input, signal) {
14
- return 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
- createCorrection(input, options) {
21
- if (!/^[\x21-\x7e]{1,200}$/.test(options.idempotencyKey))
22
- throw new Error("A valid Idempotency-Key is required for Correction submission.");
23
- return this.#transport.requestJson(resolveOperation("corrections.create"), {
24
- body: input,
25
- ...options,
26
- });
27
- }
28
- getCorrection(correctionId, signal) {
29
- return this.#transport.requestJson(resolveOperation("corrections.get"), {
30
- pathParams: { correctionId },
31
- signal,
32
- });
33
- }
34
- listCorrections(input = {}, signal) {
35
- return this.#transport.requestJson(resolveOperation("corrections.list"), {
36
- query: input,
37
- signal,
38
- });
39
- }
40
8
  /**
41
- * Record "not this" on one result a match showed, against the response it
42
- * came from. `responseId` is that response's `attribution.responseId`; the
43
- * call needs the same key the match was made with. Repeating a rejection
44
- * returns the original receipt. This judges the match ranking and is never a
45
- * catalogue correction - wrong product facts go through `createCorrection`.
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.
46
19
  */
47
- rejectMatchResult(responseId, input, signal) {
48
- return this.#transport.requestJson(resolveOperation("reject_match_result"), { pathParams: { responseId }, body: input, signal });
49
- }
50
- /** Read one match response back with every rejection recorded against it. */
51
- matchRejections(responseId, signal) {
52
- return this.#transport.requestJson(resolveOperation("list_match_rejections"), { pathParams: { responseId }, signal });
53
- }
54
- /** Identify the canonical graph subject for one explicitly selected page. */
55
- identify(input, signal) {
56
- return this.#transport.requestJson(resolveOperation("retrieval.identify"), { body: input, signal });
20
+ async identify(input, signal) {
21
+ return await this.#transport.requestJson(resolveOperation("retrieval.identify"), { body: input, signal });
57
22
  }
58
23
  /** Complete producer-owned vectors and classifications for portable colour matching. */
59
- samplizeColorVecCache(sourceVersion, signal) {
60
- return this.#transport.requestJson(resolveOperation("samplize_colorvec_cache"), { query: { sourceVersion }, signal });
24
+ async samplizeColorVecCache(sourceVersion, signal) {
25
+ return await this.#transport.requestJson(resolveOperation("samplize_colorvec_cache"), { query: { sourceVersion }, signal });
61
26
  }
62
27
  /** MG-owned full-catalogue facets and directional colour refinement before page limiting. */
63
- samplizeCatalogueSearch(input, signal) {
64
- return this.#transport.requestJson(resolveOperation("samplize_catalogue_search"), { body: input, signal });
28
+ async samplizeCatalogueSearch(input, signal) {
29
+ return await this.#transport.requestJson(resolveOperation("samplize_catalogue_search"), { body: input, signal });
65
30
  }
66
31
  /** Complete version-pinned Samplize paint corpus; stock never limits eligibility. */
67
- samplizeCatalogue(options = {}, signal) {
68
- return this.#transport.requestJson(resolveOperation("samplize_catalogue_products"), { query: { ...options }, signal });
32
+ async samplizeCatalogue(options = {}, signal) {
33
+ return await this.#transport.requestJson(resolveOperation("samplize_catalogue_products"), { query: { ...options }, signal });
69
34
  }
70
35
  /**
71
36
  * Read exact, verified brand-publication page relationships for variants.
72
37
  * Missing evidence stays explicit; this operation never guesses a page from
73
38
  * a generic PDF.
74
39
  */
75
- catalogueReferences(input, signal) {
76
- return this.#transport.requestJson(resolveOperation("get_catalogue_references_batch"), { body: input, signal });
40
+ async catalogueReferences(input, signal) {
41
+ return await this.#transport.requestJson(resolveOperation("get_catalogue_references_batch"), { body: input, signal });
77
42
  }
78
43
  /** List product collections with governed catalogue-channel membership. */
79
- catalogueCollections(options = {}, signal) {
80
- return this.#transport.requestJson(resolveOperation("list_catalogue_channel_collections"), {
44
+ async catalogueCollections(options = {}, signal) {
45
+ return await this.#transport.requestJson(resolveOperation("list_catalogue_channel_collections"), {
81
46
  query: {
82
47
  limit: options.limit,
83
48
  offset: options.offset,
@@ -87,23 +52,23 @@ export class CatalogueClient {
87
52
  });
88
53
  }
89
54
  /** List immutable catalog documents retained from verified source material. */
90
- catalogs(signal) {
91
- return this.#transport.requestJson(resolveOperation("list_catalog_documents"), { signal });
55
+ async catalogs(signal) {
56
+ return await this.#transport.requestJson(resolveOperation("list_catalog_documents"), { signal });
92
57
  }
93
58
  /** List stable one-based page identities and their representation status. */
94
- catalogPages(catalogId, options = {}, signal) {
95
- return this.#transport.requestJson(resolveOperation("list_catalog_pages"), { pathParams: { catalogId }, query: options, signal });
59
+ async catalogPages(catalogId, options = {}, signal) {
60
+ return await this.#transport.requestJson(resolveOperation("list_catalog_pages"), { pathParams: { catalogId }, query: options, signal });
96
61
  }
97
62
  /** Read a retained page representation or its exact missing-artifact receipt. */
98
- catalogPageRepresentation(pageId, signal) {
99
- return this.#transport.requestJson(resolveOperation("get_catalog_page_representation"), { pathParams: { pageId }, signal });
63
+ async catalogPageRepresentation(pageId, signal) {
64
+ return await this.#transport.requestJson(resolveOperation("get_catalog_page_representation"), { pathParams: { pageId }, signal });
100
65
  }
101
66
  /** Read every verified product/page reference for one retained catalog. */
102
- catalogReferences(catalogId, signal) {
103
- return this.#transport.requestJson(resolveOperation("list_catalog_product_references"), { pathParams: { catalogId }, signal });
67
+ async catalogReferences(catalogId, signal) {
68
+ return await this.#transport.requestJson(resolveOperation("list_catalog_product_references"), { pathParams: { catalogId }, signal });
104
69
  }
105
70
  /** Resolve browser-safe access to one immutable catalogue document. */
106
- catalogueDocumentAccess(documentId, signal) {
107
- return this.#transport.requestJson(resolveOperation("get_catalogue_document_access"), { pathParams: { documentId }, signal });
71
+ async catalogueDocumentAccess(documentId, signal) {
72
+ return await this.#transport.requestJson(resolveOperation("get_catalogue_document_access"), { pathParams: { documentId }, signal });
108
73
  }
109
74
  }
@@ -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";
@@ -188,10 +228,10 @@ export interface CatalogAvailableReceipt {
188
228
  pageCount: number;
189
229
  };
190
230
  render: {
191
- failedPages: Array<{
231
+ failedPages: {
192
232
  documentPage: number;
193
233
  reason: string;
194
- }>;
234
+ }[];
195
235
  renderedPages: number;
196
236
  status: "complete" | "partial" | "not_recorded";
197
237
  };
@@ -347,10 +387,10 @@ export type CatalogPageListResult = {
347
387
  };
348
388
  representationCoverage: {
349
389
  available: number;
350
- failuresByReason: Array<{
390
+ failuresByReason: {
351
391
  count: number;
352
392
  reason: "retained_representation_not_found";
353
- }>;
393
+ }[];
354
394
  total: number;
355
395
  unavailable: number;
356
396
  };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The category-tree surface, namespaced as `mg.categories` (MG-2226). Replaces
3
+ * `taxonomy()` / `GET /api/v1/taxonomy/categories`, retired with no shim.
4
+ *
5
+ * `list()` pages the tree (roots, one node's children, or a name/meaning
6
+ * search), and `get(id)` reads one node in full: its place, the names and
7
+ * phrases that find it, and the canonical taxonomy concepts it relates to.
8
+ *
9
+ * A category id is a TREE KEY, never a canonical `product_category` value,
10
+ * see {@link CategoryItem.id}. `list()` items are lean (id, name, parent,
11
+ * whether it has children, and how it matched); `get(id)` has the rest. Page
12
+ * with `pageInfo.nextCursor` as `cursor`, repeating the same `query` and
13
+ * `parentId`.
14
+ *
15
+ * The namespace holds no transport of its own: the client hands it a bound
16
+ * `get` callback, so auth, rate-limit accounting and error shaping stay in
17
+ * exactly one place. `mg.browse` and `mg.codes` set the precedent for a
18
+ * namespace over flat methods.
19
+ */
20
+ import type { CategoriesGetResult, CategoriesListInput, CategoriesListResult } from "./category-types.js";
21
+ import type { QueryParams } from "./http-transport.js";
22
+ import type { SdkOperationId } from "./operations.js";
23
+ /** The client's own request primitive, handed down so this file owns no transport. */
24
+ export type CategoriesTransport = {
25
+ get<T>(operationId: SdkOperationId, query?: QueryParams, signal?: AbortSignal, pathParams?: Readonly<Record<string, string>>): Promise<T>;
26
+ };
27
+ export declare class CategoriesClient {
28
+ #private;
29
+ constructor(transport: CategoriesTransport);
30
+ /**
31
+ * One bounded page of the category tree (GET `/api/v1/categories`). With
32
+ * nothing set, the top-level categories; `parentId` alone, that category's
33
+ * direct children; `query`, every category (or only `parentId` and
34
+ * everything under it) by name, phrase, near spelling or meaning: the
35
+ * first method that finds anything wins, and every match it finds is
36
+ * returned, ranked by method then distance.
37
+ *
38
+ * An unknown `parentId`, or a cursor from another `query`/`parentId`, is a
39
+ * 400. No match is a successful empty page, never an error.
40
+ *
41
+ * @example
42
+ * const roots = await mg.categories.list();
43
+ * const tiles = await mg.categories.list({ parentId: "tile_surfaces" });
44
+ * const found = await mg.categories.list({ query: "wallpaper" });
45
+ */
46
+ list(input?: CategoriesListInput, signal?: AbortSignal): Promise<CategoriesListResult>;
47
+ /**
48
+ * One category by id (GET `/api/v1/categories/{id}`): its place in the tree
49
+ * (ancestors, children), the names and phrases that find it, and the
50
+ * canonical taxonomy concepts it relates to. `productCategory.concepts[].termId`
51
+ * is what a record's `product_category` attribute holds; category filters
52
+ * elsewhere take the id, never that termId.
53
+ *
54
+ * An id that names no category is a 404; a canonical `product_category`
55
+ * termId passed as `id` is a 404 naming it as one, so find the category with
56
+ * {@link CategoriesClient.list} instead.
57
+ *
58
+ * @example
59
+ * const category = await mg.categories.get("wall_paneling");
60
+ * category.productCategory.concepts.map((c) => c.termId); // ["wall_panel"]
61
+ */
62
+ get(id: string, signal?: AbortSignal): Promise<CategoriesGetResult>;
63
+ }
@@ -0,0 +1,48 @@
1
+ export class CategoriesClient {
2
+ #transport;
3
+ constructor(transport) {
4
+ this.#transport = transport;
5
+ }
6
+ /**
7
+ * One bounded page of the category tree (GET `/api/v1/categories`). With
8
+ * nothing set, the top-level categories; `parentId` alone, that category's
9
+ * direct children; `query`, every category (or only `parentId` and
10
+ * everything under it) by name, phrase, near spelling or meaning: the
11
+ * first method that finds anything wins, and every match it finds is
12
+ * returned, ranked by method then distance.
13
+ *
14
+ * An unknown `parentId`, or a cursor from another `query`/`parentId`, is a
15
+ * 400. No match is a successful empty page, never an error.
16
+ *
17
+ * @example
18
+ * const roots = await mg.categories.list();
19
+ * const tiles = await mg.categories.list({ parentId: "tile_surfaces" });
20
+ * const found = await mg.categories.list({ query: "wallpaper" });
21
+ */
22
+ async list(input = {}, signal) {
23
+ return await this.#transport.get("list_categories", {
24
+ cursor: input.cursor,
25
+ limit: input.limit,
26
+ parentId: input.parentId,
27
+ query: input.query,
28
+ }, signal);
29
+ }
30
+ /**
31
+ * One category by id (GET `/api/v1/categories/{id}`): its place in the tree
32
+ * (ancestors, children), the names and phrases that find it, and the
33
+ * canonical taxonomy concepts it relates to. `productCategory.concepts[].termId`
34
+ * is what a record's `product_category` attribute holds; category filters
35
+ * elsewhere take the id, never that termId.
36
+ *
37
+ * An id that names no category is a 404; a canonical `product_category`
38
+ * termId passed as `id` is a 404 naming it as one, so find the category with
39
+ * {@link CategoriesClient.list} instead.
40
+ *
41
+ * @example
42
+ * const category = await mg.categories.get("wall_paneling");
43
+ * category.productCategory.concepts.map((c) => c.termId); // ["wall_panel"]
44
+ */
45
+ async get(id, signal) {
46
+ return await this.#transport.get("get_category", undefined, signal, { id });
47
+ }
48
+ }