@instruments/materialgraph 0.26.0 → 0.27.1

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 (113) hide show
  1. package/association-types.d.ts +18 -7
  2. package/attribution-types.d.ts +2 -2
  3. package/brand-types.d.ts +8 -0
  4. package/brands-client.d.ts +5 -36
  5. package/brands-client.js +7 -33
  6. package/by-colour-types.d.ts +40 -13
  7. package/by-spec-types.d.ts +0 -67
  8. package/by-spec-types.js +7 -5
  9. package/catalog-discovery-types.d.ts +1 -16
  10. package/catalogue-client.d.ts +12 -31
  11. package/catalogue-client.js +10 -46
  12. package/catalogue-types.d.ts +40 -0
  13. package/categories-client.d.ts +63 -0
  14. package/categories-client.js +48 -0
  15. package/category-types.d.ts +114 -0
  16. package/client-config.d.ts +2 -4
  17. package/client-config.js +2 -4
  18. package/client-vocabulary.d.ts +2 -4
  19. package/client-vocabulary.js +11 -9
  20. package/client.d.ts +103 -203
  21. package/client.js +128 -251
  22. package/codes-types.d.ts +21 -0
  23. package/colours-client.d.ts +4 -9
  24. package/colours-client.js +0 -8
  25. package/errors.d.ts +1 -1
  26. package/errors.js +1 -0
  27. package/identify-types.d.ts +49 -39
  28. package/identify-types.js +5 -3
  29. package/index.d.ts +11 -21
  30. package/index.js +4 -4
  31. package/list-variant-facets-types.d.ts +60 -0
  32. package/list-variants-types.d.ts +149 -0
  33. package/list-variants-types.js +12 -0
  34. package/match-stream-types.d.ts +13 -0
  35. package/match-stream-types.js +2 -0
  36. package/match-stream.js +12 -8
  37. package/match-types.d.ts +24 -0
  38. package/material-asset-types.d.ts +69 -49
  39. package/material-block-types.d.ts +2 -0
  40. package/material-composition-client.d.ts +21 -0
  41. package/material-composition-client.js +13 -0
  42. package/material-composition-types.d.ts +403 -0
  43. package/material-query-plan-types.d.ts +57 -141
  44. package/material-resources-client.d.ts +9 -7
  45. package/material-resources-client.js +19 -4
  46. package/material-types.d.ts +6 -14
  47. package/operations.d.ts +1 -1
  48. package/operations.js +20 -117
  49. package/package.json +5 -1
  50. package/palette-search-types.d.ts +59 -24
  51. package/query-understanding-types.d.ts +27 -5
  52. package/resolve-client.d.ts +6 -10
  53. package/resolve-client.js +5 -7
  54. package/response-schemas.d.ts +20 -0
  55. package/response-schemas.generated.d.ts +5 -0
  56. package/response-schemas.generated.js +160 -0
  57. package/response-schemas.js +113 -0
  58. package/run-types.d.ts +12 -93
  59. package/runs.d.ts +1 -37
  60. package/runs.js +2 -79
  61. package/schema-resource-types.d.ts +14 -1
  62. package/search-card-types.d.ts +22 -0
  63. package/search-index-plan-types.d.ts +70 -0
  64. package/search-refinement-types.d.ts +8 -38
  65. package/search-refinement-types.js +1 -0
  66. package/search-request-types.d.ts +117 -200
  67. package/search-response-receipt-types.d.ts +12 -268
  68. package/search-result-validation.d.ts +0 -16
  69. package/search-result-validation.js +22 -180
  70. package/spec-facet-types.d.ts +3 -8
  71. package/spec-types.d.ts +17 -10
  72. package/spec-types.js +8 -7
  73. package/specifications.d.ts +13 -55
  74. package/specifications.js +29 -73
  75. package/suggest-types.d.ts +4 -10
  76. package/suggest-types.js +1 -1
  77. package/types.d.ts +135 -338
  78. package/webmcp.d.ts +1 -1
  79. package/webmcp.generated.js +10 -94
  80. package/brand-most-sampled-types.d.ts +0 -33
  81. package/browse-types.d.ts +0 -236
  82. package/client-browse.d.ts +0 -78
  83. package/client-browse.js +0 -71
  84. package/client-exploration.d.ts +0 -9
  85. package/client-exploration.js +0 -5
  86. package/compare-types.d.ts +0 -89
  87. package/composition-client.d.ts +0 -33
  88. package/composition-client.js +0 -28
  89. package/composition-types.d.ts +0 -455
  90. package/composition-types.js +0 -10
  91. package/correction-types.d.ts +0 -88
  92. package/exploration-types.d.ts +0 -118
  93. package/exploration-types.js +0 -1
  94. package/fan-deck-types.d.ts +0 -42
  95. package/fan-deck-types.js +0 -9
  96. package/match-rejection-types.d.ts +0 -43
  97. package/match-rejection-types.js +0 -7
  98. package/palette-completion-types.d.ts +0 -115
  99. package/palette-completion-types.js +0 -1
  100. package/render-assets-types.d.ts +0 -65
  101. package/render-assets-types.js +0 -1
  102. package/search-collapse-types.d.ts +0 -69
  103. package/search-collapse-types.js +0 -1
  104. package/search-mood-types.d.ts +0 -6
  105. package/search-mood-types.js +0 -1
  106. package/search-window-types.d.ts +0 -25
  107. package/search-window-types.js +0 -1
  108. package/slot-pool-types.d.ts +0 -372
  109. package/slot-pool-types.js +0 -1
  110. /package/{brand-most-sampled-types.js → category-types.js} +0 -0
  111. /package/{browse-types.js → list-variant-facets-types.js} +0 -0
  112. /package/{compare-types.js → material-composition-types.js} +0 -0
  113. /package/{correction-types.js → search-index-plan-types.js} +0 -0
@@ -9,8 +9,8 @@ import type { SdkOperationId } from "./operations.js";
9
9
  * client facade: "how much colour does the graph hold at all" (`stats`), "what
10
10
  * colours does this category come in" (`profiles`), "what goes with these
11
11
  * colours" (`palette`), and "what moves from this colour to that one"
12
- * (`gradient`). `mg.codes` and `mg.browse` set the precedent for a namespace
13
- * when a capability is a family rather than a single verb.
12
+ * (`gradient`). `mg.codes` sets the precedent for a namespace when a
13
+ * capability is a family rather than a single verb.
14
14
  *
15
15
  * The namespace holds no transport of its own: the client hands it a bound
16
16
  * `get`/`post`, so auth, rate-limit accounting and error shaping stay in one
@@ -28,14 +28,13 @@ import type { SdkOperationId } from "./operations.js";
28
28
  * convenience wrapper.
29
29
  * - A colour NAME rather than a hex → `mg.resolveColour(name)` first.
30
30
  * - Colour WORDS (families, moods, undertones) → `mg.colourFacets()`.
31
- * - Walking the corpus by lightness/vividness → `mg.browse({ sort })`.
32
- * - Colour as one signal among words, a seed and a mood → `mg.search(...)`.
31
+ * - Walking the corpus by lightness/vividness → `mg.listVariants({ orderBy })`.
32
+ * - Colour as one signal among words and a seed → `mg.search(...)`.
33
33
  *
34
34
  * And the honesty rule the whole lens rests on: every colour here is DERIVED
35
35
  * FROM PRODUCT IMAGERY, not declared by the manufacturer. Report visual
36
36
  * likeness, never a stated colour specification.
37
37
  */
38
- import type { PaletteCompleteInput, PaletteCompleteResponse, PaletteDiscoverInput, PaletteDiscoverResponse } from "./palette-completion-types.js";
39
38
  import type { SearchGradientInput, SearchGradientResponse, SearchPaletteInput, SearchPaletteResponse } from "./palette-search-types.js";
40
39
  /** The client's own request primitives, handed down so this file owns no transport. */
41
40
  export type ColoursTransport = {
@@ -45,10 +44,6 @@ export type ColoursTransport = {
45
44
  export declare class ColoursClient {
46
45
  #private;
47
46
  constructor(transport: ColoursTransport);
48
- /** Complete exact retained colors against a shared published interior reference. No Cart mutation. */
49
- complete(input: PaletteCompleteInput, signal?: AbortSignal): Promise<PaletteCompleteResponse>;
50
- /** Browse diverse published interior compositions against a version-pinned eligible catalogue. */
51
- discover(input: PaletteDiscoverInput, signal?: AbortSignal): Promise<PaletteDiscoverResponse>;
52
47
  /**
53
48
  * THE QUESTION: "what colours does this CATEGORY come in?" — the representative
54
49
  * palette of 1–8 categories in ONE call (GET `/api/v1/colours/profiles`).
package/colours-client.js CHANGED
@@ -3,14 +3,6 @@ export class ColoursClient {
3
3
  constructor(transport) {
4
4
  this.#transport = transport;
5
5
  }
6
- /** Complete exact retained colors against a shared published interior reference. No Cart mutation. */
7
- async complete(input, signal) {
8
- return await this.#transport.post("complete_interior_palette", input, signal);
9
- }
10
- /** Browse diverse published interior compositions against a version-pinned eligible catalogue. */
11
- async discover(input, signal) {
12
- return await this.#transport.get("discover_interior_palettes", { ...input }, signal);
13
- }
14
6
  /**
15
7
  * THE QUESTION: "what colours does this CATEGORY come in?" — the representative
16
8
  * palette of 1–8 categories in ONE call (GET `/api/v1/colours/profiles`).
package/errors.d.ts CHANGED
@@ -89,7 +89,7 @@ type TransportErrorInput = {
89
89
  * member to a problem response means adding it here too, and
90
90
  * `problem-extension-parity.test.ts` fails when the two disagree.
91
91
  */
92
- export declare const MATERIALGRAPH_PROBLEM_EXTENSIONS: readonly ["ambiguous_brands", "brand_candidates", "content_length", "did_you_mean", "empty_brands", "limit_bytes", "missing_env", "orderable_attributes", "populated_alternatives", "unknown_attributes", "unknown_brands", "unknown_fields", "unorderable_attribute", "valid_group_keys", "valid_type_keys"];
92
+ export declare const MATERIALGRAPH_PROBLEM_EXTENSIONS: readonly ["ambiguous_brands", "brand_candidates", "content_length", "did_you_mean", "empty_brands", "limit_bytes", "missing_env", "orderable_attributes", "populated_alternatives", "refused_criteria", "unknown_attributes", "unknown_brands", "unknown_fields", "unorderable_attribute", "valid_group_keys", "valid_type_keys"];
93
93
  /** The one error class thrown by all SDK transport and HTTP failures. */
94
94
  export declare class MaterialGraphError extends Error {
95
95
  readonly kind: MaterialGraphErrorKind;
package/errors.js CHANGED
@@ -32,6 +32,7 @@ export const MATERIALGRAPH_PROBLEM_EXTENSIONS = [
32
32
  "missing_env",
33
33
  "orderable_attributes",
34
34
  "populated_alternatives",
35
+ "refused_criteria",
35
36
  "unknown_attributes",
36
37
  "unknown_brands",
37
38
  "unknown_fields",
@@ -1,67 +1,77 @@
1
1
  /**
2
- * Public wire types for `POST /api/v1/identify`.
2
+ * Public wire types for `POST /api/v1/identify` (MG-1672's `resolve_variant`
3
+ * contract).
3
4
  *
4
- * These intentionally mirror the domain-owned Zod contract rather than
5
- * importing it: the published SDK must carry no workspace package dependency.
5
+ * These intentionally mirror the domain-owned Zod contract
6
+ * (`@materialgraph/products/identify-contract`) rather than importing it: the
7
+ * published SDK must carry no workspace package dependency.
6
8
  */
7
- export type IdentifySelectedPageInput = {
8
- url: string;
9
- title?: string;
10
- selectedText?: string;
11
- productLabels?: string[];
12
- brandLabels?: string[];
13
- /** Manufacturer code visibly supplied by the selected page. */
14
- manufacturerCode?: string;
15
- imageUrls?: string[];
16
- colourHexes?: string[];
9
+ /**
10
+ * What `mg.identify()` accepts. Give `url` alone, or `code` with `brandId`
11
+ * (from `mg.brands()`) when there is no page to read. `labels` are product
12
+ * names visible on the page, sent only to tell several URL candidates apart -
13
+ * they never widen a search or invent an identity on their own.
14
+ */
15
+ export type IdentifyVariantInput = {
16
+ url?: string;
17
+ code?: string;
18
+ brandId?: string;
19
+ labels?: string[];
17
20
  };
18
- export type IdentifySelectedPageSubject = {
19
- kind: "variant" | "product" | "brand";
21
+ /** One identified, placed or bounded-candidate subject. */
22
+ export type IdentifySubject = {
23
+ kind: "variant" | "brand";
20
24
  id: string;
21
25
  name: string;
26
+ code?: string;
22
27
  brand?: {
23
28
  id: string;
24
29
  name: string;
25
- slug: string;
26
30
  };
27
31
  };
28
- export type IdentifySelectedPageEvidence = {
29
- kind: "manufacturer-url" | "brand-homepage" | "visible-identity" | "visual" | "colour";
32
+ /** What stood behind an outcome. Exact and scoreless: never a similarity guess. */
33
+ export type IdentifyEvidence = {
34
+ kind: "manufacturer-url" | "brand-homepage" | "manufacturer-code" | "visible-label";
30
35
  url?: string;
31
36
  detail: string;
32
37
  };
33
- type IdentifySelectedPageDataBase = {
34
- receipt: {
35
- submittedUrl: string;
36
- normalizedUrl: string;
37
- normalizationSteps: string[];
38
- };
39
- evidence: IdentifySelectedPageEvidence[];
38
+ /** The submitted URL, normalised, and the steps that normalisation took. Absent for a code-only call. */
39
+ export type IdentifyReceipt = {
40
+ submittedUrl: string;
41
+ normalizedUrl: string;
42
+ normalizationSteps: string[];
40
43
  };
41
- export type IdentifySelectedPageData = (IdentifySelectedPageDataBase & {
44
+ type IdentifyResultBase = {
45
+ evidence: IdentifyEvidence[];
46
+ receipt?: IdentifyReceipt;
47
+ };
48
+ /**
49
+ * Why nothing was identified. Absent and empty differ: this names what was
50
+ * looked for and not found, never a similarity guess.
51
+ */
52
+ export type IdentifyUnresolvedReason = "no-stored-url" | "no-code-match";
53
+ /** Exact identities only - no rung carries a similarity score. */
54
+ export type IdentifyResult = (IdentifyResultBase & {
42
55
  outcome: "identified";
43
- rung: "lookup" | "disambiguate";
44
- subject: IdentifySelectedPageSubject & {
56
+ subject: IdentifySubject & {
45
57
  kind: "variant";
46
58
  };
47
- }) | (IdentifySelectedPageDataBase & {
59
+ }) | (IdentifyResultBase & {
48
60
  outcome: "placed";
49
- rung: "lookup";
50
- subject: IdentifySelectedPageSubject & {
51
- kind: "product" | "brand";
61
+ subject: IdentifySubject & {
62
+ kind: "brand";
52
63
  };
53
- }) | (IdentifySelectedPageDataBase & {
64
+ }) | (IdentifyResultBase & {
54
65
  outcome: "ambiguous";
55
- rung: "lookup" | "disambiguate" | "match" | "color";
56
- candidates: IdentifySelectedPageSubject[];
66
+ candidates: IdentifySubject[];
57
67
  truncated: boolean;
58
- }) | (IdentifySelectedPageDataBase & {
68
+ }) | (IdentifyResultBase & {
59
69
  outcome: "unresolved";
60
- rung?: "match" | "color";
70
+ reason: IdentifyUnresolvedReason;
61
71
  });
62
72
  /** The canonical callable-operation envelope returned by `identify()`. */
63
- export type IdentifySelectedPageResult = {
64
- data: IdentifySelectedPageData;
73
+ export type IdentifyResponse = {
74
+ data: IdentifyResult;
65
75
  meta: {
66
76
  operationId: "retrieval.identify";
67
77
  requestId: string;
package/identify-types.js CHANGED
@@ -1,7 +1,9 @@
1
1
  /**
2
- * Public wire types for `POST /api/v1/identify`.
2
+ * Public wire types for `POST /api/v1/identify` (MG-1672's `resolve_variant`
3
+ * contract).
3
4
  *
4
- * These intentionally mirror the domain-owned Zod contract rather than
5
- * importing it: the published SDK must carry no workspace package dependency.
5
+ * These intentionally mirror the domain-owned Zod contract
6
+ * (`@materialgraph/products/identify-contract`) rather than importing it: the
7
+ * published SDK must carry no workspace package dependency.
6
8
  */
7
9
  export {};
package/index.d.ts CHANGED
@@ -1,29 +1,23 @@
1
- export { MaterialGraphClient, DEFAULT_BASE_URL, MAX_BATCH_IDS, } from "./client.js";
2
- export type { CompareInput, CompareTarget, CompareCell, CompareResult, CompareResponse, } from "./compare-types.js";
3
- export type { CorrectionJson, CorrectionSubject, CorrectionTarget, CorrectionEvidence, CreateCorrectionInput, Correction, CorrectionResponse, CorrectionsListResponse, } from "./correction-types.js";
4
- export type { MaterialGraphClientOptions, BrowseNamespace, ExplorationNamespace, SourceMaterialCommentsNamespace, } from "./client.js";
1
+ export { MaterialGraphClient, DEFAULT_BASE_URL } from "./client.js";
2
+ export type { MaterialGraphClientOptions, SourceMaterialCommentsNamespace, } from "./client.js";
3
+ export type * from "./list-variants-types.js";
4
+ export type * from "./list-variant-facets-types.js";
5
5
  export { MATERIALGRAPH_API_VERSION, SDK_OPERATIONS } from "./operations.js";
6
6
  export type { SdkOperation, SdkOperationId } from "./operations.js";
7
7
  export type * from "./identifiers.js";
8
- export type * from "./exploration-types.js";
9
8
  export { TERMINAL_RUN_EVENT_TYPES } from "./run-types.js";
10
9
  export type * from "./run-types.js";
11
10
  export type * from "./citation-types.js";
12
- export { VARY_AXES } from "./composition-types.js";
13
- export type * from "./composition-types.js";
14
- export type * from "./slot-pool-types.js";
11
+ export type * from "./material-composition-types.js";
15
12
  export { MATERIALGRAPH_PROBLEM_EXTENSIONS, MaterialGraphError, } from "./errors.js";
16
13
  export type { MaterialGraphErrorInit, MaterialGraphErrorKind, MaterialGraphRequestMetadata, ProblemDetail, RateLimit, SanitizedErrorValue, SanitizedIssue, SimpleErrorBody, } from "./errors.js";
17
14
  export type * from "./types.js";
18
- export type * from "./search-collapse-types.js";
19
15
  export type * from "./search-card-types.js";
20
- export type * from "./match-types.js";
21
16
  export type * from "./identify-types.js";
22
- export type * from "./browse-types.js";
23
17
  export type * from "./catalogue-types.js";
24
18
  export type * from "./by-colour-types.js";
25
- export { MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
26
- export type * from "./match-stream-types.js";
19
+ export { CategoriesClient } from "./categories-client.js";
20
+ export type * from "./category-types.js";
27
21
  export { CodesClient } from "./codes-client.js";
28
22
  export type * from "./codes-types.js";
29
23
  export { ColoursClient } from "./colours-client.js";
@@ -31,23 +25,19 @@ export type { ColoursTransport } from "./colours-client.js";
31
25
  export type * from "./colour-aggregate-types.js";
32
26
  export type * from "./palette-search-types.js";
33
27
  export type * from "./query-understanding-types.js";
28
+ export type * from "./match-types.js";
29
+ export { MATCH_ERROR_REASONS, MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
30
+ export type * from "./match-stream-types.js";
34
31
  export type * from "./material-query-plan-types.js";
35
32
  export type * from "./association-types.js";
36
33
  export type * from "./brand-types.js";
37
- export type * from "./fan-deck-types.js";
38
34
  export type * from "./material-asset-types.js";
39
- export type * from "./render-assets-types.js";
40
35
  export type * from "./material-block-types.js";
41
36
  export type * from "./schema-resource-types.js";
42
37
  export type * from "./taxonomy-coverage-types.js";
43
- export type * from "./substitute-types.js";
44
38
  export type * from "./search-refinement-types.js";
45
- export type * from "./search-window-types.js";
46
39
  export type * from "./attribution-types.js";
47
- export type * from "./match-rejection-types.js";
48
40
  export { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID } from "./spec-types.js";
49
41
  export type * from "./spec-types.js";
50
- export { certificationProgramme, certificationProgrammeCriterion, hasSpec, specCriterion, specRangeCriterion, specTerm, } from "./specifications.js";
42
+ export { certificationProgramme, hasSpec, specTerm } from "./specifications.js";
51
43
  export type { SamplizePublicationSource, SamplizeLrvObservation, SamplizeDemand, SamplizeCollectionMembership, SamplizeCatalogueOptions, SamplizeCataloguePage, SamplizeCatalogueProduct, SamplizeHexObservation, } from "./samplize-catalogue-types.js";
52
- export type { PaletteCompleteInput, PaletteCompleteResponse, PaletteDiscoverInput, PaletteDiscoverResponse, } from "./palette-completion-types.js";
53
- export type { BrandMostSampledResponse } from "./brand-most-sampled-types.js";
package/index.js CHANGED
@@ -1,10 +1,10 @@
1
- export { MaterialGraphClient, DEFAULT_BASE_URL, MAX_BATCH_IDS, } from "./client.js";
1
+ export { MaterialGraphClient, DEFAULT_BASE_URL } from "./client.js";
2
2
  export { MATERIALGRAPH_API_VERSION, SDK_OPERATIONS } from "./operations.js";
3
3
  export { TERMINAL_RUN_EVENT_TYPES } from "./run-types.js";
4
- export { VARY_AXES } from "./composition-types.js";
5
4
  export { MATERIALGRAPH_PROBLEM_EXTENSIONS, MaterialGraphError, } from "./errors.js";
6
- export { MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
5
+ export { CategoriesClient } from "./categories-client.js";
7
6
  export { CodesClient } from "./codes-client.js";
8
7
  export { ColoursClient } from "./colours-client.js";
8
+ export { MATCH_ERROR_REASONS, MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
9
9
  export { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID } from "./spec-types.js";
10
- export { certificationProgramme, certificationProgrammeCriterion, hasSpec, specCriterion, specRangeCriterion, specTerm, } from "./specifications.js";
10
+ export { certificationProgramme, hasSpec, specTerm } from "./specifications.js";
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @module list-variant-facets-types
3
+ * @description Hand-maintained mirror of `list_variant_facets`'s (MG-2294)
4
+ * input and output wire shapes. The source of truth is
5
+ * `packages/products/src/variants/list-variant-facets.ts` (the input) and
6
+ * `list-variant-facets-contract.ts` (the output); this SDK has no runtime
7
+ * dependency on `@materialgraph/products`, so the shapes are copied here and
8
+ * `contract-parity.test.ts` keeps them honest.
9
+ */
10
+ import type { CorpusScope } from "./corpus-scope-types.js";
11
+ import type { FilterGroups } from "./list-variants-types.js";
12
+ export type ListVariantFacetsInput = {
13
+ /** 1–10 facetable attribute ids. Find them with `listAttributes()`. */
14
+ attributeIds: string[];
15
+ /** The same kind-grouped filter tree `listVariants()` takes. */
16
+ /** Count only this corpus scope; absent or `all` counts every variant. */
17
+ corpusScope?: CorpusScope;
18
+ filters?: FilterGroups;
19
+ /** Top values per categorical or boolean facet, 1–50. Defaults to 10. */
20
+ valuesPerFacet?: number;
21
+ };
22
+ export type VariantFacetValue = {
23
+ /** The canonical value `listVariants()`' `filters` accepts for this attribute. */
24
+ value: string;
25
+ label: string;
26
+ /** Distinct eligible variants under the supplied filters carrying this value. */
27
+ variantCount: number;
28
+ };
29
+ type VariantFacetBase = {
30
+ attributeId: string;
31
+ name: string;
32
+ /** Eligible variants recording no accepted value: unknown, never false or zero. */
33
+ missingVariantCount: number;
34
+ };
35
+ export type CategoricalVariantFacet = VariantFacetBase & {
36
+ kind: "categorical";
37
+ values: VariantFacetValue[];
38
+ /** More observed values exist than `values` shows. */
39
+ hasMoreValues: boolean;
40
+ };
41
+ export type BooleanVariantFacet = VariantFacetBase & {
42
+ kind: "boolean";
43
+ values: VariantFacetValue[];
44
+ hasMoreValues: boolean;
45
+ };
46
+ export type NumericVariantFacet = VariantFacetBase & {
47
+ kind: "numeric";
48
+ /** Observed minimum in the attribute's canonical unit; null when no variant records a value. */
49
+ min: number | null;
50
+ max: number | null;
51
+ unitId: string | null;
52
+ };
53
+ export type VariantFacet = CategoricalVariantFacet | BooleanVariantFacet | NumericVariantFacet;
54
+ export type ListVariantFacetsOutput = {
55
+ /** Eligible variants matching every hard condition: the denominator of every count. */
56
+ matchedVariantCount: number;
57
+ /** One per requested attribute, in request order. */
58
+ facets: VariantFacet[];
59
+ };
60
+ export {};
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @module list-variants-types
3
+ * @description Hand-maintained mirror of `list_variants`'s (MG-2222) input and
4
+ * output wire shapes. The source of truth is
5
+ * `packages/products/src/variants/variant-conditions.ts` (the filter grammar)
6
+ * and `packages/products/src/variants/list-variants-contract.ts` (the output),
7
+ * but this SDK has no RUNTIME dependency on `@materialgraph/products` (it's a
8
+ * devDependency only, for the parity tests in `__tests__/`), so the shapes are
9
+ * copied here rather than imported. `contract-parity.test.ts` keeps this
10
+ * mirror honest against the server types.
11
+ */
12
+ import type { CorpusScope } from "./corpus-scope-types.js";
13
+ export type FilterOp = "in" | "not_in" | "all" | "exists" | "missing" | "eq" | "gt" | "gte" | "lt" | "lte";
14
+ export type FilterTermCondition = {
15
+ field: string;
16
+ op: "in" | "all" | "not_in";
17
+ values: string[];
18
+ };
19
+ export type FilterNumericCondition = {
20
+ field: string;
21
+ op: "eq" | "gt" | "gte" | "lt" | "lte";
22
+ value: number;
23
+ };
24
+ export type FilterPresenceCondition = {
25
+ field: string;
26
+ op: "exists" | "missing";
27
+ };
28
+ /**
29
+ * One filter condition, whichever of the three fully-required shapes. No
30
+ * `unit` key (a numeric value is in the attribute's own canonical unit).
31
+ */
32
+ export type FilterCondition = FilterTermCondition | FilterNumericCondition | FilterPresenceCondition;
33
+ /**
34
+ * `filters`: kind-grouped, not a flat list (MG-2222) — `{terms, numbers,
35
+ * presence}`. Every condition across all three arrays must match (AND); OR
36
+ * within one field is `in`. Send only the arrays you need; an omitted or
37
+ * empty array carries no conditions.
38
+ */
39
+ export type FilterGroups = {
40
+ terms?: FilterTermCondition[];
41
+ numbers?: FilterNumericCondition[];
42
+ presence?: FilterPresenceCondition[];
43
+ };
44
+ /** `optionalFilters`: the same kind-grouped shape as `filters`, with every entry also carrying a required `weight` (1–10). Ranks matched items; never excludes. */
45
+ export type OptionalFilterGroups = {
46
+ terms?: (FilterTermCondition & {
47
+ weight: number;
48
+ })[];
49
+ numbers?: (FilterNumericCondition & {
50
+ weight: number;
51
+ })[];
52
+ presence?: (FilterPresenceCondition & {
53
+ weight: number;
54
+ })[];
55
+ };
56
+ export type OrderByEntry = {
57
+ direction: "asc" | "desc";
58
+ /** A numeric attribute id. */
59
+ field: string;
60
+ };
61
+ export type ListVariantsInclude = "image" | "url";
62
+ export type ListVariantsCollapse = "product";
63
+ export type ListVariantsInput = {
64
+ /** Attribute ids to project under each item's `specifications`. */
65
+ attributes?: string[];
66
+ /**
67
+ * `product`: one row per product, its lead colourway by the page's order,
68
+ * with `variantCount` saying how many colourways stand behind it. The
69
+ * cursor pages products.
70
+ */
71
+ collapse?: ListVariantsCollapse;
72
+ /**
73
+ * Only variants in this corpus scope: the rows, the page and the cursor.
74
+ * Absent or `all` is every variant.
75
+ */
76
+ corpusScope?: CorpusScope;
77
+ cursor?: string;
78
+ /** Every condition, across `terms`/`numbers`/`presence`, must match. */
79
+ filters?: FilterGroups;
80
+ include?: ListVariantsInclude[];
81
+ /** 1–50; defaults to 10. */
82
+ limit?: number;
83
+ /**
84
+ * Find by name (MG-2222): every word must start a word of the product or
85
+ * variant name. Combines with `filters` as an additional AND condition;
86
+ * ambiguous matches are all returned rather than guessed between.
87
+ */
88
+ name?: string;
89
+ /** Rank only — never excludes. */
90
+ optionalFilters?: OptionalFilterGroups;
91
+ orderBy?: OrderByEntry[];
92
+ };
93
+ /**
94
+ * `score` sums the weights of the matched `optionalFilters`; `matched` lists
95
+ * their positions in the flattened terms-then-numbers-then-presence order
96
+ * the server reads `optionalFilters` in, not the caller's own array shape.
97
+ */
98
+ export type ListVariantsPreference = {
99
+ matched: number[];
100
+ score: number;
101
+ };
102
+ /** `{ [blockId]: { [attributeId]: value } }`. Null means the value is unknown. */
103
+ export type ListVariantsSpecifications = Record<string, Record<string, unknown>>;
104
+ export type ListVariantsNotApplicable = {
105
+ attributes?: string[];
106
+ blocks?: string[];
107
+ };
108
+ /**
109
+ * One list item: the compact identity needed to pick a variant, with image
110
+ * and maker page only when requested (`include`) and selected attributes
111
+ * under `specifications`. Leaner than `get_variant`'s item on purpose.
112
+ */
113
+ export type ListVariantsItem = {
114
+ category: string;
115
+ code: string | null;
116
+ image?: string | null;
117
+ maker: {
118
+ id: string;
119
+ name: string;
120
+ };
121
+ /** The variant's Material Bank SKU. Absent means none is recorded. */
122
+ materialBankId?: string;
123
+ name: string;
124
+ notApplicable?: ListVariantsNotApplicable;
125
+ preference?: ListVariantsPreference;
126
+ product: {
127
+ id: string;
128
+ name: string;
129
+ };
130
+ specifications?: ListVariantsSpecifications;
131
+ url?: string | null;
132
+ /**
133
+ * The eligible variants of this item's product, the set `listVariants`
134
+ * pages. Absent when none is counted.
135
+ */
136
+ variantCount?: number;
137
+ variantId: string;
138
+ };
139
+ export type ListVariantsOutput = {
140
+ items: ListVariantsItem[];
141
+ pageInfo: {
142
+ endCursor: string | null;
143
+ hasNextPage: boolean;
144
+ };
145
+ /** False: nothing from this page on meets any `optionalFilters` entry. Absent when not measured. */
146
+ preferenceMatchesRemain?: boolean;
147
+ /** Explicit `{field: "variant", op: "in"}` ids anywhere in `filters.terms` that did not resolve to an eligible variant in the requested `corpusScope`. */
148
+ unresolvedVariantIds?: string[];
149
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @module list-variants-types
3
+ * @description Hand-maintained mirror of `list_variants`'s (MG-2222) input and
4
+ * output wire shapes. The source of truth is
5
+ * `packages/products/src/variants/variant-conditions.ts` (the filter grammar)
6
+ * and `packages/products/src/variants/list-variants-contract.ts` (the output),
7
+ * but this SDK has no RUNTIME dependency on `@materialgraph/products` (it's a
8
+ * devDependency only, for the parity tests in `__tests__/`), so the shapes are
9
+ * copied here rather than imported. `contract-parity.test.ts` keeps this
10
+ * mirror honest against the server types.
11
+ */
12
+ export {};
@@ -21,6 +21,9 @@ import type { SearchResultItem } from "./types.js";
21
21
  /** How the workflow classified the uploaded image. */
22
22
  export declare const MATCH_IMAGE_TYPES: readonly ["swatch", "installation", "flatplan"];
23
23
  export type MatchImageType = (typeof MATCH_IMAGE_TYPES)[number];
24
+ /** Why a Match run ended on an `error` frame (MG-730). */
25
+ export declare const MATCH_ERROR_REASONS: readonly ["upstream_unavailable", "failed"];
26
+ export type MatchErrorReason = (typeof MATCH_ERROR_REASONS)[number];
24
27
  /** What a detected surface is FOR — the element the material would serve. */
25
28
  export declare const MATCH_MATERIAL_FUNCTIONS: readonly ["flooring", "wall_surface", "ceiling", "partition", "upholstery", "millwork", "countertop", "accent", "sample"];
26
29
  export type MatchMaterialFunction = (typeof MATCH_MATERIAL_FUNCTIONS)[number];
@@ -61,6 +64,8 @@ export type MatchDetectedSurface = {
61
64
  boundingBox: MatchBoundingBox;
62
65
  /** JPEG data-URI crop used for Match retrieval — the thumbnail to show. */
63
66
  cropDataUri?: string;
67
+ /** The `construction_methods` dictionary term the detector's finish names. */
68
+ construction?: string;
64
69
  };
65
70
  /**
66
71
  * One surface's matching state and its ranked results. The same `surface.id`
@@ -288,6 +293,14 @@ export type MatchStreamCompleteEvent = {
288
293
  export type MatchStreamErrorEvent = {
289
294
  type: "error";
290
295
  message: string;
296
+ /**
297
+ * `upstream_unavailable`: a provider (vision, embedding, vector index) could
298
+ * not answer, so nothing was looked at and a retry may succeed. `failed`: the
299
+ * run broke on something else. Absent from servers older than MG-730.
300
+ */
301
+ reason?: MatchErrorReason;
302
+ /** True only for `upstream_unavailable`. Absent from servers older than MG-730. */
303
+ retriable?: boolean;
291
304
  };
292
305
  /** One frame of the Match progress stream, discriminated by `type`. */
293
306
  export type MatchStreamEvent = MatchStreamStepEvent | MatchStreamClassifiedEvent | MatchStreamSurfacesEvent | MatchStreamSurfaceEvent | MatchStreamHeartbeatEvent | MatchStreamCompleteEvent | MatchStreamErrorEvent;
@@ -4,6 +4,8 @@ export const MATCH_IMAGE_TYPES = [
4
4
  "installation",
5
5
  "flatplan",
6
6
  ];
7
+ /** Why a Match run ended on an `error` frame (MG-730). */
8
+ export const MATCH_ERROR_REASONS = ["upstream_unavailable", "failed"];
7
9
  /** What a detected surface is FOR — the element the material would serve. */
8
10
  export const MATCH_MATERIAL_FUNCTIONS = [
9
11
  "flooring",
package/match-stream.js CHANGED
@@ -35,10 +35,9 @@
35
35
  * objects (`createMatchNdjsonStream`), so `parse` output is not what the wire
36
36
  * carries; reshaping to match it would invent a normalisation that never
37
37
  * happened.
38
- * 2. Stripping needs the COMPLETE key inventory of `searchResultItemSchema`,
39
- * whose closure reaches `candidateVerdictSchema` in `@materialgraph/contracts`
40
- * — a recursive hand-mirror that would have to stay in step forever, and a
41
- * wider surface than the validation it would serve.
38
+ * 2. Stripping needs the COMPLETE key inventory of `searchResultItemSchema`
39
+ * — a hand-mirror that would have to stay in step forever, and a wider
40
+ * surface than the validation it would serve.
42
41
  * 3. An additive server field then reaches consumers without an SDK release,
43
42
  * which matters while new EVENT types still require one (MG-658).
44
43
  * The ONE exception is `.default([])`: an omitted `results` / `inferredCategories`
@@ -50,12 +49,10 @@
50
49
  * optional string, `MatchCategoryInference` items, and every
51
50
  * `SearchResultItem` in `results[]` are checked exhaustively. Item validation is
52
51
  * the shared `checkSearchResultItem` (`search-result-validation.ts`), which
53
- * mirrors `searchResultItemSchema` and its whole closure down to
54
- * `candidateVerdictSchema` — including both of its `.superRefine()` cross-field
55
- * invariants.
52
+ * mirrors `searchResultItemSchema` and its whole closure.
56
53
  */
57
54
  import { MaterialGraphError } from "./errors.js";
58
- import { MATCH_IMAGE_TYPES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
55
+ import { MATCH_ERROR_REASONS, MATCH_IMAGE_TYPES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
59
56
  import { readNdjsonLines } from "./ndjson.js";
60
57
  import { findSdkOperation } from "./operations.js";
61
58
  import { checkSearchResultItems } from "./search-result-validation.js";
@@ -212,6 +209,13 @@ const readFrame = (value, fail) => {
212
209
  }
213
210
  case "error": {
214
211
  requireString(record.message, "`message`", fail);
212
+ if (record.reason !== undefined) {
213
+ requireEnum(record.reason, MATCH_ERROR_REASONS, "`reason`", fail);
214
+ }
215
+ if (record.retriable !== undefined &&
216
+ typeof record.retriable !== "boolean") {
217
+ throw fail("`retriable` must be a boolean");
218
+ }
215
219
  return record;
216
220
  }
217
221
  default: {
package/match-types.d.ts CHANGED
@@ -9,6 +9,7 @@ import type { CorpusScope } from "./corpus-scope-types.js";
9
9
  * along its natural seam: everything a caller of `client.match()` needs, and
10
10
  * nothing else. The STREAMING contracts live in `match-stream-types.ts`.
11
11
  */
12
+ import type { MatchWorkflowResult } from "./match-stream-types.js";
12
13
  import type { SearchFilter } from "./search-refinement-types.js";
13
14
  import type { OpenEnum, PaletteSwatch, SearchResultItem } from "./types.js";
14
15
  /** An inferred product-type category from the query image, with its boost. */
@@ -74,6 +75,29 @@ export type MatchResponse = {
74
75
  segmentPalette?: PaletteSwatch[] | null;
75
76
  note?: string;
76
77
  };
78
+ /**
79
+ * What a BUFFERED `match()` actually answers with, either shape.
80
+ *
81
+ * An IMAGE input (`imageBase64` or `imageUrl`) runs the same workflow the
82
+ * stream lane runs — image kind first, then the swatch shortcut or the scene
83
+ * route — and answers in {@link MatchWorkflowResult}. A `vector` input has no
84
+ * bytes to read a kind from and keeps the thin {@link MatchResponse} leaf.
85
+ * The server declares exactly this as an `anyOf` of the two.
86
+ *
87
+ * TELL THEM APART BY A FIELD THAT ONLY ONE HAS, never by what you sent:
88
+ * `imageType` is required on the workflow shape and absent from the leaf, and
89
+ * `qualityFloor` is required on the leaf and absent from the workflow shape.
90
+ *
91
+ * ```ts
92
+ * const answer = await client.match({ imageBase64 });
93
+ * if ("imageType" in answer) {
94
+ * for (const surface of answer.surfaces) render(surface);
95
+ * } else {
96
+ * report(answer.qualityFloor, answer.droppedBelowFloor);
97
+ * }
98
+ * ```
99
+ */
100
+ export type MatchAnswer = MatchResponse | MatchWorkflowResult;
77
101
  /** The Material Match request body — exactly one of `imageBase64`, `imageUrl`, `vector`. */
78
102
  export type MatchInput = {
79
103
  imageBase64?: string;