@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,22 +1,12 @@
1
+ import type { CertificationProgrammeFilter, SpecExclusionFilter, SpecPresenceFilter, SpecTermFilter } from "./spec-types.js";
1
2
  /**
2
- * Zero-dependency builders for the specification surface. Turn a plain-language
3
- * spec intent into a typed criterion the SDK's two spec operations accept:
3
+ * A hard criterion excluding one canonical value.
4
4
  *
5
- * - `search({ filters })` takes {@link SpecFilter} objects — a spec gate layered
6
- * onto a ranked (colour / visual / lexical) search. Build them with
7
- * {@link specTerm}, {@link hasSpec}, and {@link certificationProgramme}.
8
- * - `bySpec(specs)` takes `attribute:value` strings — the value-anchored,
9
- * spec-only primitive. Build them with {@link specCriterion} and
10
- * {@link certificationProgrammeCriterion}.
11
- *
12
- * The point of these helpers: Desk (and any spec-driven caller) never has to
13
- * remember that a certification programme lives under a VIRTUAL attribute, nor
14
- * hand-format the `attribute:value` string the `bySpec` route splits on its
15
- * first `:`.
5
+ * By default retains only variants with a KNOWN value (unstated does not
6
+ * pass). Pass `whenUnstated: "pass"` to admit unstated variants too — only a
7
+ * variant that STATES the excluded term is dropped.
16
8
  */
17
- import { type CertificationProgrammeFilter, type SpecExclusionFilter, type SpecPresenceFilter, type SpecTermFilter } from "./spec-types.js";
18
- /** A hard criterion excluding one known canonical value while retaining only variants with known values. */
19
- export declare function excludeSpec(attributeId: string, excludesTerm: string): SpecExclusionFilter;
9
+ export declare const excludeSpec: (attributeId: string, excludesTerm: string, whenUnstated?: "drop" | "pass") => SpecExclusionFilter;
20
10
  /**
21
11
  * A term-equality criterion for `search({ filters })` — the attribute must
22
12
  * carry this canonical value.
@@ -25,7 +15,7 @@ export declare function excludeSpec(attributeId: string, excludesTerm: string):
25
15
  * // "same fire class as the seed"
26
16
  * client.search({ similarTo: { variantId }, filters: [specTerm("fire_classifications", "astm_e84_class_a")] });
27
17
  */
28
- export declare function specTerm(attributeId: string, term: string): SpecTermFilter;
18
+ export declare const specTerm: (attributeId: string, term: string) => SpecTermFilter;
29
19
  /**
30
20
  * A presence criterion for `search({ filters })` — the attribute must have ANY
31
21
  * accepted value.
@@ -34,67 +24,19 @@ export declare function specTerm(attributeId: string, term: string): SpecTermFil
34
24
  * // "…and it must have an EPD on record"
35
25
  * client.search({ similarTo: { variantId }, filters: [hasSpec("environmental_product_declaration")] });
36
26
  */
37
- export declare function hasSpec(attributeId: string): SpecPresenceFilter;
27
+ export declare const hasSpec: (attributeId: string) => SpecPresenceFilter;
38
28
  /**
39
29
  * A certification-programme criterion for `search({ filters })`, pinned to the
40
30
  * virtual attribute so a programme matches wherever it landed at ingest
41
31
  * (compliance / sustainability / material-health / VOC buckets).
42
32
  *
43
- * The value may be a display name or alias ("GREENGUARD Gold", "LEED") — the
44
- * server resolves it to its canonical programme token before matching — or a
45
- * canonical token directly (e.g. `greenguard_certificate`,
46
- * `has_greenguard_gold_certification`).
33
+ * The value is a canonical programme token (e.g. `greenguard_certificate`,
34
+ * `has_greenguard_gold_certification`). The one search matches tokens on its
35
+ * index and does not resolve display names, so a name such as
36
+ * "GREENGUARD Gold" is a 400 naming the term.
47
37
  *
48
38
  * @example
49
39
  * // "find a GREENGUARD-certified alternative"
50
- * client.search({ similarTo: { variantId: seed }, filters: [certificationProgramme("GREENGUARD Gold")] });
51
- */
52
- export declare function certificationProgramme(programme: string): CertificationProgrammeFilter;
53
- /**
54
- * An `attribute:value` criterion string for `bySpec`. The `bySpec` route splits
55
- * on the FIRST `:`, so a value may itself contain colons; the attribute id may
56
- * not.
57
- *
58
- * @example
59
- * client.bySpec([specCriterion("primary_material", "textile"), specCriterion("fire_classifications", "astm_e84_class_a")]);
60
- */
61
- export declare function specCriterion(attributeId: string, value: string): string;
62
- /**
63
- * An `attribute:min..max` RANGE criterion string for `bySpec`, for a
64
- * NUMBER-valued spec (`light_reflectance_value`, `nrc_rating`,
65
- * `slip_resistance_dcof`, …). Pass the result in `bySpec`'s `ranges` option.
66
- *
67
- * BOTH BOUNDS ARE INCLUSIVE — `{ min: 60 }` matches a value of exactly 60 —
68
- * because spec language is written that way ("LRV of 60 or more", "DCOF ≥ 0.42")
69
- * and because inclusive-both-ends means adjacent ranges overlap at the join
70
- * rather than leaving a gap that hides products.
71
- *
72
- * At least one bound is REQUIRED: a range with neither is a presence check, and
73
- * this throws rather than sending a criterion the server would have to refuse.
74
- * Discover which attributes take a range — and the span they actually occupy —
75
- * from `specificationFacets()`: those are the facets with `kind: "numeric"`.
76
- *
77
- * @example
78
- * // light paints, every brand at once
79
- * client.bySpec([], { ranges: [specRangeCriterion("light_reflectance_value", { min: 60 })] });
80
- * @example
81
- * // a mid-tone band
82
- * specRangeCriterion("light_reflectance_value", { min: 30, max: 45 }); // "light_reflectance_value:30..45"
83
- */
84
- export declare function specRangeCriterion(attributeId: string, bounds: {
85
- min?: number;
86
- max?: number;
87
- }): string;
88
- /**
89
- * An `attribute:value` criterion string for `bySpec` that filters by
90
- * certification PROGRAMME across all four certification buckets.
91
- *
92
- * The value may be a display name or alias ("GREENGUARD Gold", "LEED"), resolved
93
- * server-side to its canonical programme token, or a canonical token directly
94
- * (e.g. `greenguard_certificate`, `has_greenguard_gold_certification`).
95
- *
96
- * @example
97
- * // every brand's GREENGUARD-Gold materials
98
- * client.bySpec([certificationProgrammeCriterion("GREENGUARD Gold")]);
40
+ * client.search({ similarTo: { variantId: seed }, filters: [certificationProgramme("has_greenguard_gold_certification")] });
99
41
  */
100
- export declare function certificationProgrammeCriterion(programme: string): string;
42
+ export declare const certificationProgramme: (programme: string) => CertificationProgrammeFilter;
package/specifications.js CHANGED
@@ -1,24 +1,32 @@
1
1
  /**
2
- * Zero-dependency builders for the specification surface. Turn a plain-language
3
- * spec intent into a typed criterion the SDK's two spec operations accept:
4
- *
5
- * - `search({ filters })` takes {@link SpecFilter} objects — a spec gate layered
6
- * onto a ranked (colour / visual / lexical) search. Build them with
7
- * {@link specTerm}, {@link hasSpec}, and {@link certificationProgramme}.
8
- * - `bySpec(specs)` takes `attribute:value` strings — the value-anchored,
9
- * spec-only primitive. Build them with {@link specCriterion} and
10
- * {@link certificationProgrammeCriterion}.
2
+ * Zero-dependency builders for the specification surface. Turn a
3
+ * plain-language spec intent into a typed {@link SpecFilter} `search({
4
+ * filters })` accepts: hard token sets on the one search's index, run in the
5
+ * same query. Build them with {@link specTerm}, {@link hasSpec}, and
6
+ * {@link certificationProgramme}.
11
7
  *
12
8
  * The point of these helpers: Desk (and any spec-driven caller) never has to
13
- * remember that a certification programme lives under a VIRTUAL attribute, nor
14
- * hand-format the `attribute:value` string the `bySpec` route splits on its
15
- * first `:`.
9
+ * remember that a certification programme lives under a VIRTUAL attribute.
10
+ *
11
+ * A hard specification across every brand (formerly `bySpec`, built with
12
+ * `specCriterion`/`specRangeCriterion`) is now `list_variants`'s `filters`:
13
+ * `{field: attributeId, op: "in", values: [...]}` for a term,
14
+ * `{field: attributeId, op: "gte"/"lte"/etc, value}` for a number — a plain
15
+ * object literal needs no encoder (MG-2222).
16
+ */
17
+ import { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID } from "./spec-types.js";
18
+ /**
19
+ * A hard criterion excluding one canonical value.
20
+ *
21
+ * By default retains only variants with a KNOWN value (unstated does not
22
+ * pass). Pass `whenUnstated: "pass"` to admit unstated variants too — only a
23
+ * variant that STATES the excluded term is dropped.
16
24
  */
17
- import { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, } from "./spec-types.js";
18
- /** A hard criterion excluding one known canonical value while retaining only variants with known values. */
19
- export function excludeSpec(attributeId, excludesTerm) {
20
- return { attributeId, excludesTerm };
21
- }
25
+ export const excludeSpec = (attributeId, excludesTerm, whenUnstated) => ({
26
+ attributeId,
27
+ excludesTerm,
28
+ ...(whenUnstated === undefined ? {} : { whenUnstated }),
29
+ });
22
30
  /**
23
31
  * A term-equality criterion for `search({ filters })` — the attribute must
24
32
  * carry this canonical value.
@@ -27,9 +35,7 @@ export function excludeSpec(attributeId, excludesTerm) {
27
35
  * // "same fire class as the seed"
28
36
  * client.search({ similarTo: { variantId }, filters: [specTerm("fire_classifications", "astm_e84_class_a")] });
29
37
  */
30
- export function specTerm(attributeId, term) {
31
- return { attributeId, term };
32
- }
38
+ export const specTerm = (attributeId, term) => ({ attributeId, term });
33
39
  /**
34
40
  * A presence criterion for `search({ filters })` — the attribute must have ANY
35
41
  * accepted value.
@@ -38,81 +44,25 @@ export function specTerm(attributeId, term) {
38
44
  * // "…and it must have an EPD on record"
39
45
  * client.search({ similarTo: { variantId }, filters: [hasSpec("environmental_product_declaration")] });
40
46
  */
41
- export function hasSpec(attributeId) {
42
- return { attributeId, hasValue: true };
43
- }
47
+ export const hasSpec = (attributeId) => ({
48
+ attributeId,
49
+ hasValue: true,
50
+ });
44
51
  /**
45
52
  * A certification-programme criterion for `search({ filters })`, pinned to the
46
53
  * virtual attribute so a programme matches wherever it landed at ingest
47
54
  * (compliance / sustainability / material-health / VOC buckets).
48
55
  *
49
- * The value may be a display name or alias ("GREENGUARD Gold", "LEED") — the
50
- * server resolves it to its canonical programme token before matching — or a
51
- * canonical token directly (e.g. `greenguard_certificate`,
52
- * `has_greenguard_gold_certification`).
56
+ * The value is a canonical programme token (e.g. `greenguard_certificate`,
57
+ * `has_greenguard_gold_certification`). The one search matches tokens on its
58
+ * index and does not resolve display names, so a name such as
59
+ * "GREENGUARD Gold" is a 400 naming the term.
53
60
  *
54
61
  * @example
55
62
  * // "find a GREENGUARD-certified alternative"
56
- * client.search({ similarTo: { variantId: seed }, filters: [certificationProgramme("GREENGUARD Gold")] });
57
- */
58
- export function certificationProgramme(programme) {
59
- return { attributeId: CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, term: programme };
60
- }
61
- /**
62
- * An `attribute:value` criterion string for `bySpec`. The `bySpec` route splits
63
- * on the FIRST `:`, so a value may itself contain colons; the attribute id may
64
- * not.
65
- *
66
- * @example
67
- * client.bySpec([specCriterion("primary_material", "textile"), specCriterion("fire_classifications", "astm_e84_class_a")]);
68
- */
69
- export function specCriterion(attributeId, value) {
70
- return `${attributeId}:${value}`;
71
- }
72
- /**
73
- * An `attribute:min..max` RANGE criterion string for `bySpec`, for a
74
- * NUMBER-valued spec (`light_reflectance_value`, `nrc_rating`,
75
- * `slip_resistance_dcof`, …). Pass the result in `bySpec`'s `ranges` option.
76
- *
77
- * BOTH BOUNDS ARE INCLUSIVE — `{ min: 60 }` matches a value of exactly 60 —
78
- * because spec language is written that way ("LRV of 60 or more", "DCOF ≥ 0.42")
79
- * and because inclusive-both-ends means adjacent ranges overlap at the join
80
- * rather than leaving a gap that hides products.
81
- *
82
- * At least one bound is REQUIRED: a range with neither is a presence check, and
83
- * this throws rather than sending a criterion the server would have to refuse.
84
- * Discover which attributes take a range — and the span they actually occupy —
85
- * from `specificationFacets()`: those are the facets with `kind: "numeric"`.
86
- *
87
- * @example
88
- * // light paints, every brand at once
89
- * client.bySpec([], { ranges: [specRangeCriterion("light_reflectance_value", { min: 60 })] });
90
- * @example
91
- * // a mid-tone band
92
- * specRangeCriterion("light_reflectance_value", { min: 30, max: 45 }); // "light_reflectance_value:30..45"
93
- */
94
- export function specRangeCriterion(attributeId, bounds) {
95
- const { min, max } = bounds;
96
- if (min === undefined && max === undefined) {
97
- throw new Error(`specRangeCriterion("${attributeId}") needs a min, a max, or both — a range with neither would match every recorded value. Use hasSpec() for a presence check.`);
98
- }
99
- if (min !== undefined && max !== undefined && min > max) {
100
- throw new Error(`specRangeCriterion("${attributeId}") is inverted (min ${min} > max ${max}) and can only ever match nothing.`);
101
- }
102
- return `${attributeId}:${min ?? ""}..${max ?? ""}`;
103
- }
104
- /**
105
- * An `attribute:value` criterion string for `bySpec` that filters by
106
- * certification PROGRAMME across all four certification buckets.
107
- *
108
- * The value may be a display name or alias ("GREENGUARD Gold", "LEED"), resolved
109
- * server-side to its canonical programme token, or a canonical token directly
110
- * (e.g. `greenguard_certificate`, `has_greenguard_gold_certification`).
111
- *
112
- * @example
113
- * // every brand's GREENGUARD-Gold materials
114
- * client.bySpec([certificationProgrammeCriterion("GREENGUARD Gold")]);
63
+ * client.search({ similarTo: { variantId: seed }, filters: [certificationProgramme("has_greenguard_gold_certification")] });
115
64
  */
116
- export function certificationProgrammeCriterion(programme) {
117
- return specCriterion(CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, programme);
118
- }
65
+ export const certificationProgramme = (programme) => ({
66
+ attributeId: CERTIFICATION_PROGRAMME_ATTRIBUTE_ID,
67
+ term: programme,
68
+ });
package/sse.d.ts CHANGED
@@ -11,11 +11,11 @@
11
11
  * chunks are held in an internal buffer until their terminating blank line.
12
12
  */
13
13
  /** One dispatched SSE frame. `data` is the joined data lines (no trailing newline). */
14
- export interface SseFrame {
14
+ export type SseFrame = {
15
15
  id?: string;
16
16
  event?: string;
17
17
  data: string;
18
- }
18
+ };
19
19
  /**
20
20
  * A push-based SSE line assembler. Feed it decoded text with {@link push}; it
21
21
  * returns any frames completed by that text. Call {@link flush} once the stream
package/sse.js CHANGED
@@ -26,13 +26,15 @@ export class SseDecoder {
26
26
  const frames = [];
27
27
  for (;;) {
28
28
  const lineEnd = this.#nextLineEnd();
29
- if (lineEnd === null)
29
+ if (lineEnd === null) {
30
30
  break;
31
+ }
31
32
  const line = this.#buffer.slice(0, lineEnd.index);
32
33
  this.#buffer = this.#buffer.slice(lineEnd.nextIndex);
33
34
  const frame = this.#consumeLine(line);
34
- if (frame)
35
+ if (frame) {
35
36
  frames.push(frame);
37
+ }
36
38
  }
37
39
  return frames;
38
40
  }
@@ -45,8 +47,9 @@ export class SseDecoder {
45
47
  : this.#buffer;
46
48
  this.#buffer = "";
47
49
  const frame = this.#consumeLine(line);
48
- if (frame)
50
+ if (frame) {
49
51
  return [frame];
52
+ }
50
53
  }
51
54
  const frame = this.#dispatch();
52
55
  return frame ? [frame] : [];
@@ -55,11 +58,13 @@ export class SseDecoder {
55
58
  #nextLineEnd() {
56
59
  for (let i = 0; i < this.#buffer.length; i += 1) {
57
60
  const char = this.#buffer[i];
58
- if (char === "\n")
61
+ if (char === "\n") {
59
62
  return { index: i, nextIndex: i + 1 };
63
+ }
60
64
  if (char === "\r") {
61
- if (i === this.#buffer.length - 1)
65
+ if (i === this.#buffer.length - 1) {
62
66
  return null;
67
+ }
63
68
  return this.#buffer[i + 1] === "\n"
64
69
  ? { index: i, nextIndex: i + 2 }
65
70
  : { index: i, nextIndex: i + 1 };
@@ -68,15 +73,18 @@ export class SseDecoder {
68
73
  return null;
69
74
  }
70
75
  #consumeLine(line) {
71
- if (line.length === 0)
76
+ if (line.length === 0) {
72
77
  return this.#dispatch();
73
- if (line.startsWith(":"))
78
+ }
79
+ if (line.startsWith(":")) {
74
80
  return undefined;
81
+ }
75
82
  const colon = line.indexOf(":");
76
83
  const field = colon === -1 ? line : line.slice(0, colon);
77
84
  let value = colon === -1 ? "" : line.slice(colon + 1);
78
- if (value.startsWith(" "))
85
+ if (value.startsWith(" ")) {
79
86
  value = value.slice(1);
87
+ }
80
88
  if (field === "data") {
81
89
  this.#dataLines.push(value);
82
90
  this.#hasFields = true;
@@ -92,13 +100,16 @@ export class SseDecoder {
92
100
  return undefined;
93
101
  }
94
102
  #dispatch() {
95
- if (!this.#hasFields)
103
+ if (!this.#hasFields) {
96
104
  return undefined;
105
+ }
97
106
  const frame = { data: this.#dataLines.join("\n") };
98
- if (this.#event !== undefined)
107
+ if (this.#event !== undefined) {
99
108
  frame.event = this.#event;
100
- if (this.#id !== undefined)
109
+ }
110
+ if (this.#id !== undefined) {
101
111
  frame.id = this.#id;
112
+ }
102
113
  this.#dataLines = [];
103
114
  this.#event = undefined;
104
115
  this.#id = undefined;
@@ -117,28 +128,33 @@ export async function* readSseFrames(body, signal) {
117
128
  const sse = new SseDecoder();
118
129
  try {
119
130
  for (;;) {
120
- if (signal?.aborted)
131
+ if (signal?.aborted) {
121
132
  return;
133
+ }
122
134
  let result;
123
135
  try {
124
136
  result = await reader.read();
125
137
  }
126
138
  catch (error) {
127
- if (signal?.aborted)
139
+ if (signal?.aborted) {
128
140
  return;
141
+ }
129
142
  throw error;
130
143
  }
131
144
  if (result.done) {
132
- for (const frame of sse.push(decoder.decode()))
145
+ for (const frame of sse.push(decoder.decode())) {
133
146
  yield frame;
134
- for (const frame of sse.flush())
147
+ }
148
+ for (const frame of sse.flush()) {
135
149
  yield frame;
150
+ }
136
151
  return;
137
152
  }
138
153
  const text = decoder.decode(result.value, { stream: true });
139
154
  for (const frame of sse.push(text)) {
140
- if (signal?.aborted)
155
+ if (signal?.aborted) {
141
156
  return;
157
+ }
142
158
  yield frame;
143
159
  }
144
160
  }
@@ -2,40 +2,40 @@ import type { BySpecVerdict } from "./by-spec-types.js";
2
2
  import type { VariantId } from "./identifiers.js";
3
3
  import type { MaterialSuccessor } from "./material-types.js";
4
4
  export type SubstituteSignatureFamily = "textile" | "tile" | "coating" | "lighting_electrical" | "acoustic" | "surface" | "furniture" | "sanitaryware" | "fittings" | "architectural_hardware";
5
- export interface SubstituteSignatureCriterion {
5
+ export type SubstituteSignatureCriterion = {
6
6
  role: "primary_material" | "performance";
7
7
  attributeId: string;
8
8
  term: string;
9
- }
10
- export interface AvailableSubstituteSignature {
9
+ };
10
+ export type AvailableSubstituteSignature = {
11
11
  family: SubstituteSignatureFamily;
12
12
  form: string;
13
13
  criteria: [SubstituteSignatureCriterion, SubstituteSignatureCriterion];
14
- }
15
- export interface UnsupportedSubstituteSignature {
14
+ };
15
+ export type UnsupportedSubstituteSignature = {
16
16
  family: SubstituteSignatureFamily;
17
17
  form: string;
18
18
  reason: string;
19
- }
20
- export interface InsufficientSubstituteSignature {
19
+ };
20
+ export type InsufficientSubstituteSignature = {
21
21
  family: SubstituteSignatureFamily;
22
22
  form: string;
23
23
  missingRoles: ("primary_material" | "performance")[];
24
- }
25
- export interface FindSubstitutesOptions {
24
+ };
25
+ export type FindSubstitutesOptions = {
26
26
  excludeBrands?: string[];
27
27
  diversityBoost?: number;
28
28
  limit?: number;
29
29
  cursor?: string;
30
30
  includeSamplingArtifacts?: boolean;
31
31
  includeUnavailable?: boolean;
32
- }
33
- export interface SubstituteMatchedCriterion {
32
+ };
33
+ export type SubstituteMatchedCriterion = {
34
34
  attributeId: string;
35
35
  confidence: number | null;
36
36
  sourceBasis: string | null;
37
- }
38
- export interface SubstituteResultItem {
37
+ };
38
+ export type SubstituteResultItem = {
39
39
  variantId: VariantId;
40
40
  brandSlug: string;
41
41
  brand: string;
@@ -50,8 +50,8 @@ export interface SubstituteResultItem {
50
50
  diversityAdjustment: number;
51
51
  score: number;
52
52
  verdict: BySpecVerdict;
53
- }
54
- export interface AvailableSubstitutesResponse {
53
+ };
54
+ export type AvailableSubstitutesResponse = {
55
55
  status: "available";
56
56
  signatureUsed: AvailableSubstituteSignature;
57
57
  items: SubstituteResultItem[];
@@ -69,7 +69,7 @@ export interface AvailableSubstitutesResponse {
69
69
  poolTruncated: boolean;
70
70
  supersededBy: MaterialSuccessor | null;
71
71
  nextCursor?: string;
72
- }
72
+ };
73
73
  /**
74
74
  * MG-1686. The search read a bounded window of the matches and nothing in it
75
75
  * reached the page, while more matches existed past the window. It is not an
@@ -77,7 +77,7 @@ export interface AvailableSubstitutesResponse {
77
77
  * empty `items`. `reason` names what happened and the next move; follow
78
78
  * `nextCursor` when it is present.
79
79
  */
80
- export interface InconclusiveSubstitutesResponse {
80
+ export type InconclusiveSubstitutesResponse = {
81
81
  status: "inconclusive";
82
82
  signatureUsed: AvailableSubstituteSignature;
83
83
  items: [];
@@ -86,17 +86,17 @@ export interface InconclusiveSubstitutesResponse {
86
86
  reason: string;
87
87
  supersededBy: MaterialSuccessor | null;
88
88
  nextCursor?: string;
89
- }
90
- export interface UnsupportedSubstitutesResponse {
89
+ };
90
+ export type UnsupportedSubstitutesResponse = {
91
91
  status: "unsupported";
92
92
  signature: UnsupportedSubstituteSignature;
93
93
  items: [];
94
94
  supersededBy: MaterialSuccessor | null;
95
- }
96
- export interface InsufficientSubstitutesResponse {
95
+ };
96
+ export type InsufficientSubstitutesResponse = {
97
97
  status: "insufficient_signature";
98
98
  signature: InsufficientSubstituteSignature;
99
99
  items: [];
100
100
  supersededBy: MaterialSuccessor | null;
101
- }
101
+ };
102
102
  export type FindSubstitutesResponse = AvailableSubstitutesResponse | InconclusiveSubstitutesResponse | UnsupportedSubstitutesResponse | InsufficientSubstitutesResponse;
@@ -12,13 +12,12 @@
12
12
  * `mg.searchVocabulary()` covers attribute/value tokens. Suggestions are a page
13
13
  * of the best matches, never a census of matching entities.
14
14
  */
15
- import type { CorpusScope, CorpusScopeReceipt } from "./corpus-scope-types.js";
16
15
  /** Which kind of entity a suggestion is — and therefore what `refId` means. */
17
16
  export type SuggestKind = "product" | "brand" | "category";
18
17
  /** How the query met the suggestion's label. Strongest first. */
19
- export type SuggestMatch = "prefix" | "word" | "contains" | "fuzzy";
18
+ export type SuggestMatch = "prefix" | "word" | "fuzzy";
20
19
  /** One ranked typeahead suggestion, carrying the identity it resolves to. */
21
- export interface Suggestion {
20
+ export type Suggestion = {
22
21
  kind: SuggestKind;
23
22
  /** The entity's name as written, for display. */
24
23
  label: string;
@@ -36,27 +35,23 @@ export interface Suggestion {
36
35
  * Opaque, and null when none was picked — not a product without variants.
37
36
  */
38
37
  variantId: string | null;
39
- /** Variants behind this entity IN MATERIALGRAPH — a coverage figure. */
38
+ /** How many of this entity's variants the search index holds: a coverage figure. */
40
39
  variantCount: number;
41
- }
40
+ };
42
41
  /** The suggest response: the query as interpreted, plus the ranked suggestions. */
43
- export interface SuggestResponse {
44
- /** The normalised query the corpus was matched against. */
42
+ export type SuggestResponse = {
43
+ /** The typed words the search index was matched against. */
45
44
  query: string;
46
- /** Ranked best-match-first. Empty when nothing came close — a miss, not an error. */
45
+ /** Ranked best-match-first. Empty when nothing came close: a miss, not an error. */
47
46
  suggestions: Suggestion[];
48
- /** Present only when a narrowing governed corpus was applied. */
49
- corpusScope?: CorpusScopeReceipt;
50
- }
47
+ };
51
48
  /** Options for {@link MaterialGraphClient.suggest}. */
52
- export interface SuggestOptions {
49
+ export type SuggestOptions = {
53
50
  /** How many suggestions to return (1–20, default 8). */
54
51
  limit?: number;
55
52
  /** Restrict to these kinds. Omit for all of them. */
56
53
  kind?: SuggestKind | SuggestKind[];
57
- /** Governed corpus membership; absent means the whole graph. */
58
- corpusScope?: CorpusScope;
59
- }
54
+ };
60
55
  /**
61
56
  * Shape the query string for a suggest call.
62
57
  *
@@ -65,9 +60,8 @@ export interface SuggestOptions {
65
60
  * here rather than being sent as repeated `?kind=` pairs the route would ignore.
66
61
  * Undefined members are dropped by the transport.
67
62
  */
68
- export declare function suggestQuery(q: string, options?: SuggestOptions): {
63
+ export declare const suggestQuery: (q: string, options?: SuggestOptions) => {
69
64
  q: string;
70
65
  limit?: number;
71
66
  kind?: string;
72
- corpusScope?: CorpusScope;
73
67
  };
package/suggest-types.js CHANGED
@@ -20,9 +20,9 @@
20
20
  * here rather than being sent as repeated `?kind=` pairs the route would ignore.
21
21
  * Undefined members are dropped by the transport.
22
22
  */
23
- export function suggestQuery(q, options) {
23
+ export const suggestQuery = (q, options) => {
24
24
  const kind = Array.isArray(options?.kind)
25
25
  ? options.kind.join(",")
26
26
  : options?.kind;
27
- return { q, limit: options?.limit, kind, corpusScope: options?.corpusScope };
28
- }
27
+ return { kind, limit: options?.limit, q };
28
+ };
@@ -1,5 +1,5 @@
1
1
  /** Exact, source-path-grained status coverage for primary product typing. */
2
- export interface ProductTypeStatusCoverageCounts {
2
+ export type ProductTypeStatusCoverageCounts = {
3
3
  variants: number;
4
4
  accepted: number;
5
5
  proposed: number;
@@ -8,13 +8,13 @@ export interface ProductTypeStatusCoverageCounts {
8
8
  proposedUnknownConfidence: number;
9
9
  otherStatus: number;
10
10
  missingPrimary: number;
11
- }
12
- export interface ProductTypeStatusCoverageSourcePath extends ProductTypeStatusCoverageCounts {
11
+ };
12
+ export type ProductTypeStatusCoverageSourcePath = {
13
13
  /** Complete stored source path; null means the product retained no path. */
14
14
  sourcePath: string | null;
15
- }
15
+ } & ProductTypeStatusCoverageCounts;
16
16
  /** Current primary-assignment coverage, never an inferred acceptance decision. */
17
- export interface ProductTypeStatusCoverage {
17
+ export type ProductTypeStatusCoverage = {
18
18
  computedAt: string;
19
19
  basis: {
20
20
  count: "exact";
@@ -26,9 +26,9 @@ export interface ProductTypeStatusCoverage {
26
26
  };
27
27
  totals: ProductTypeStatusCoverageCounts;
28
28
  sourcePaths: ProductTypeStatusCoverageSourcePath[];
29
- }
30
- export interface ProductTypeCoverageOptions {
29
+ };
30
+ export type ProductTypeCoverageOptions = {
31
31
  [key: string]: number | undefined;
32
32
  /** Reporting cutoff in [0,1], default 0.85; it never accepts a proposal. */
33
33
  comparisonThreshold?: number;
34
- }
34
+ };