@instruments/materialgraph 0.24.0 → 0.26.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 (124) hide show
  1. package/association-types.d.ts +20 -20
  2. package/associations-client.d.ts +4 -4
  3. package/associations-client.js +3 -10
  4. package/attribution-types.d.ts +3 -3
  5. package/brand-most-sampled-types.d.ts +4 -4
  6. package/brand-types.d.ts +6 -6
  7. package/brands-client.d.ts +4 -4
  8. package/brands-client.js +9 -13
  9. package/browse-types.d.ts +8 -8
  10. package/by-colour-types.d.ts +18 -18
  11. package/by-spec-types.d.ts +14 -14
  12. package/catalog-discovery-types.d.ts +14 -14
  13. package/catalogue-client.d.ts +4 -4
  14. package/catalogue-client.js +38 -37
  15. package/catalogue-types.d.ts +4 -4
  16. package/citation-types.d.ts +4 -4
  17. package/client-browse.d.ts +4 -4
  18. package/client-browse.js +24 -25
  19. package/client-config.d.ts +2 -2
  20. package/client-exploration.d.ts +3 -3
  21. package/client-exploration.js +4 -6
  22. package/client-source-material-comments.d.ts +4 -4
  23. package/client-source-material-comments.js +4 -38
  24. package/client-vocabulary.d.ts +8 -8
  25. package/client-vocabulary.js +20 -30
  26. package/client.d.ts +11 -45
  27. package/client.js +143 -188
  28. package/codes-client.d.ts +2 -2
  29. package/codes-client.js +8 -8
  30. package/codes-types.d.ts +34 -34
  31. package/colour-aggregate-types.d.ts +24 -24
  32. package/colours-client.d.ts +2 -2
  33. package/colours-client.js +15 -15
  34. package/compare-types.d.ts +10 -10
  35. package/composition-client.d.ts +3 -3
  36. package/composition-client.js +8 -7
  37. package/composition-types.d.ts +12 -12
  38. package/coordinate-client.d.ts +2 -2
  39. package/coordinate-client.js +1 -13
  40. package/corpus-scope-types.d.ts +3 -3
  41. package/corpus-scope-types.js +1 -25
  42. package/correction-types.d.ts +10 -10
  43. package/demand-batch-types.d.ts +18 -18
  44. package/demand-types.d.ts +24 -24
  45. package/errors.d.ts +12 -12
  46. package/errors.js +53 -52
  47. package/exploration-types.d.ts +29 -22
  48. package/fan-deck-types.d.ts +6 -6
  49. package/http-transport.d.ts +13 -21
  50. package/http-transport.js +31 -28
  51. package/identify-types.d.ts +10 -10
  52. package/index.d.ts +0 -6
  53. package/index.js +0 -2
  54. package/match-rejection-types.d.ts +6 -6
  55. package/match-stream-types.d.ts +32 -32
  56. package/match-stream.d.ts +2 -2
  57. package/match-stream.js +55 -41
  58. package/match-types.d.ts +8 -8
  59. package/material-asset-types.d.ts +26 -26
  60. package/material-block-types.d.ts +6 -6
  61. package/material-query-plan-types.d.ts +26 -26
  62. package/material-resources-client.d.ts +5 -5
  63. package/material-resources-client.js +10 -20
  64. package/material-types.d.ts +12 -12
  65. package/ndjson.js +16 -8
  66. package/operations.d.ts +6 -6
  67. package/operations.js +9 -39
  68. package/package.json +2 -2
  69. package/palette-completion-types.d.ts +22 -22
  70. package/palette-search-types.d.ts +28 -28
  71. package/query-understanding-types.d.ts +43 -36
  72. package/render-assets-types.d.ts +8 -8
  73. package/resolve-client.d.ts +2 -2
  74. package/resolve-client.js +4 -6
  75. package/resolve-colour-types.d.ts +22 -6
  76. package/resolve-types.d.ts +10 -10
  77. package/run-types.d.ts +70 -70
  78. package/runs.d.ts +13 -26
  79. package/runs.js +77 -89
  80. package/samplize-catalogue-types.d.ts +18 -18
  81. package/samplize-colorvec.d.ts +20 -20
  82. package/samplize-colorvec.js +66 -42
  83. package/schema-resource-types.d.ts +38 -38
  84. package/schema-resource-types.js +5 -5
  85. package/search-card-types.d.ts +14 -5
  86. package/search-collapse-types.d.ts +4 -4
  87. package/search-mood-types.d.ts +2 -2
  88. package/search-refinement-types.d.ts +8 -8
  89. package/search-request-types.d.ts +6 -6
  90. package/search-response-receipt-types.d.ts +135 -34
  91. package/search-response-types.d.ts +2 -2
  92. package/search-result-validation.d.ts +3 -3
  93. package/search-result-validation.js +53 -36
  94. package/search-window-types.d.ts +2 -2
  95. package/slot-pool-types.d.ts +20 -20
  96. package/source-material-validation.d.ts +3 -3
  97. package/source-material-validation.js +35 -39
  98. package/spec-facet-types.d.ts +10 -10
  99. package/spec-types.d.ts +6 -6
  100. package/specifications.d.ts +9 -25
  101. package/specifications.js +15 -21
  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 +7 -7
  106. package/suggest-types.js +3 -3
  107. package/taxonomy-coverage-types.d.ts +8 -8
  108. package/types.d.ts +119 -119
  109. package/validation.d.ts +26 -26
  110. package/validation.js +97 -92
  111. package/webmcp.d.ts +2 -2
  112. package/webmcp.generated.js +94 -87
  113. package/project-types.d.ts +0 -79
  114. package/project-types.js +0 -9
  115. package/projects.d.ts +0 -13
  116. package/projects.js +0 -46
  117. package/run-events.d.ts +0 -106
  118. package/run-events.js +0 -32
  119. package/schedule-reference-types.d.ts +0 -46
  120. package/schedule-reference-types.js +0 -1
  121. package/schedule-references-client.d.ts +0 -14
  122. package/schedule-references-client.js +0 -26
  123. package/schedule-types.d.ts +0 -261
  124. package/schedule-types.js +0 -1
@@ -42,14 +42,14 @@ export type MatchSurfaceStatus = (typeof MATCH_SURFACE_STATUSES)[number];
42
42
  export declare const MATCH_STREAM_EVENT_TYPES: readonly ["step", "classified", "surfaces", "surface", "heartbeat", "complete", "error"];
43
43
  export type MatchStreamEventType = (typeof MATCH_STREAM_EVENT_TYPES)[number];
44
44
  /** Where a surface sits in the image, in Gemini-style 0–1000 image space. */
45
- export interface MatchBoundingBox {
45
+ export type MatchBoundingBox = {
46
46
  x0: number;
47
47
  y0: number;
48
48
  x1: number;
49
49
  y1: number;
50
- }
50
+ };
51
51
  /** One surface the decompose step found in the image. */
52
- export interface MatchDetectedSurface {
52
+ export type MatchDetectedSurface = {
53
53
  id: string;
54
54
  label: string;
55
55
  materialFunction: MatchMaterialFunction;
@@ -61,7 +61,7 @@ export interface MatchDetectedSurface {
61
61
  boundingBox: MatchBoundingBox;
62
62
  /** JPEG data-URI crop used for Match retrieval — the thumbnail to show. */
63
63
  cropDataUri?: string;
64
- }
64
+ };
65
65
  /**
66
66
  * One surface's matching state and its ranked results. The same `surface.id`
67
67
  * arrives repeatedly as the run progresses (`matching` → `complete` / `error`);
@@ -86,7 +86,7 @@ export interface MatchDetectedSurface {
86
86
  * [0,1] — the same unit as each result's `confidence` — so they belong on one
87
87
  * axis. `poolSize` and `droppedBelowFloor` are counts and belong on neither.
88
88
  */
89
- export interface MatchComparison {
89
+ export type MatchComparison = {
90
90
  /** Candidates retrieved before the quality floor and product dedup. */
91
91
  poolSize: number;
92
92
  /** How many of those the quality floor rejected. */
@@ -98,8 +98,8 @@ export interface MatchComparison {
98
98
  * nothing was rejected, or when the rejects carried no readable signal.
99
99
  */
100
100
  bestRejected?: number;
101
- }
102
- export interface MatchSurfaceResult {
101
+ };
102
+ export type MatchSurfaceResult = {
103
103
  surface: MatchDetectedSurface;
104
104
  status: MatchSurfaceStatus;
105
105
  results: SearchResultItem[];
@@ -150,10 +150,10 @@ export interface MatchSurfaceResult {
150
150
  */
151
151
  colour?: MatchColourReading[];
152
152
  /** The segment's own extracted palette — what the colour stage matched against. */
153
- segmentPalette?: Array<{
153
+ segmentPalette?: {
154
154
  hex: string;
155
155
  proportion: number;
156
- }>;
156
+ }[];
157
157
  /**
158
158
  * One sentence of provenance a consumer may render verbatim, when the server
159
159
  * sent one — e.g. the `colour_fallback` explanation carrying the refused
@@ -162,13 +162,13 @@ export interface MatchSurfaceResult {
162
162
  note?: string;
163
163
  /** Present only on `status: "error"` — why this one surface failed. */
164
164
  error?: string;
165
- }
165
+ };
166
166
  /** The verifier's reading of one candidate, keyed back to its variant. */
167
- export interface MatchSenseCheckCell {
167
+ export type MatchSenseCheckCell = {
168
168
  variantId: string;
169
169
  verdict: MatchSenseCheckVerdict;
170
170
  reason: string;
171
- }
171
+ };
172
172
  export declare const MATCH_SENSE_CHECK_VERDICTS: readonly ["confirmed", "rejected", "abstained"];
173
173
  export type MatchSenseCheckVerdict = (typeof MATCH_SENSE_CHECK_VERDICTS)[number];
174
174
  /** The terminal Match workflow result — every surface in its final state. */
@@ -179,7 +179,7 @@ export type MatchSenseCheckVerdict = (typeof MATCH_SENSE_CHECK_VERDICTS)[number]
179
179
  */
180
180
  export declare const MATCH_OUTCOMES: readonly ["matched", "no_surfaces"];
181
181
  export type MatchOutcome = (typeof MATCH_OUTCOMES)[number];
182
- export interface MatchWorkflowResult {
182
+ export type MatchWorkflowResult = {
183
183
  /**
184
184
  * Result attribution (MG-1131) — `responseId` (the same value as the run's
185
185
  * `X-Request-Id` header), `basis: "match"`, and `issuedAt`. Every item in
@@ -214,10 +214,10 @@ export interface MatchWorkflowResult {
214
214
  */
215
215
  paletteMatches?: {
216
216
  results: SearchResultItem[];
217
- palette: Array<{
217
+ palette: {
218
218
  hex: string;
219
219
  proportion: number;
220
- }>;
220
+ }[];
221
221
  note: string;
222
222
  };
223
223
  /**
@@ -225,23 +225,23 @@ export interface MatchWorkflowResult {
225
225
  * nowhere else to put this. A scene run reports per surface instead.
226
226
  */
227
227
  comparison?: MatchComparison;
228
- }
228
+ };
229
229
  /** Progress narration for the phase the workflow just entered. */
230
- export interface MatchStreamStepEvent {
230
+ export type MatchStreamStepEvent = {
231
231
  type: "step";
232
232
  step: MatchWorkflowStep;
233
233
  message: string;
234
- }
234
+ };
235
235
  /** The image type the classify step settled on. */
236
- export interface MatchStreamClassifiedEvent {
236
+ export type MatchStreamClassifiedEvent = {
237
237
  type: "classified";
238
238
  imageType: MatchImageType;
239
- }
239
+ };
240
240
  /** Every surface the decompose step found, before any of them has matched. */
241
- export interface MatchStreamSurfacesEvent {
241
+ export type MatchStreamSurfacesEvent = {
242
242
  type: "surfaces";
243
243
  surfaces: MatchDetectedSurface[];
244
- }
244
+ };
245
245
  /**
246
246
  * The run's tally at the moment a `surface` event was emitted, so a consumer
247
247
  * reads the server's arithmetic rather than reimplementing it.
@@ -252,7 +252,7 @@ export interface MatchStreamSurfacesEvent {
252
252
  * `matchesSoFar`. `surfacesResolved === surfacesDetected` is therefore the
253
253
  * correct "the run is done" test, and never stalls at 3/4 on a failure.
254
254
  */
255
- export interface MatchRunTotals {
255
+ export type MatchRunTotals = {
256
256
  /** Surfaces the decompose step found. The denominator; fixed for the run. */
257
257
  surfacesDetected: number;
258
258
  /** Surfaces that reached a terminal state — `complete` OR `error`. */
@@ -261,14 +261,14 @@ export interface MatchRunTotals {
261
261
  surfacesFailed: number;
262
262
  /** Result items accumulated across every surface resolved so far. */
263
263
  matchesSoFar: number;
264
- }
264
+ };
265
265
  /** One surface's state changed — the frame that makes Match progressive. */
266
- export interface MatchStreamSurfaceEvent {
266
+ export type MatchStreamSurfaceEvent = {
267
267
  type: "surface";
268
268
  surface: MatchSurfaceResult;
269
269
  /** The run's tally as of this frame. Always present on a `surface` event. */
270
270
  totals: MatchRunTotals;
271
- }
271
+ };
272
272
  /**
273
273
  * CONNECTION LIVENESS ONLY — never progress. Proxies and load balancers kill
274
274
  * idle connections, so the server sends this when the stream has been quiet, and
@@ -276,18 +276,18 @@ export interface MatchStreamSurfaceEvent {
276
276
  * consumer should treat it as a state change: do not advance a step, reset a
277
277
  * no-progress watchdog, or count it towards anything.
278
278
  */
279
- export interface MatchStreamHeartbeatEvent {
279
+ export type MatchStreamHeartbeatEvent = {
280
280
  type: "heartbeat";
281
- }
281
+ };
282
282
  /** Terminal: the whole run finished and carries its assembled result. */
283
- export interface MatchStreamCompleteEvent {
283
+ export type MatchStreamCompleteEvent = {
284
284
  type: "complete";
285
285
  result: MatchWorkflowResult;
286
- }
286
+ };
287
287
  /** Terminal: the run failed as a whole (a single surface failing is not this). */
288
- export interface MatchStreamErrorEvent {
288
+ export type MatchStreamErrorEvent = {
289
289
  type: "error";
290
290
  message: string;
291
- }
291
+ };
292
292
  /** One frame of the Match progress stream, discriminated by `type`. */
293
293
  export type MatchStreamEvent = MatchStreamStepEvent | MatchStreamClassifiedEvent | MatchStreamSurfacesEvent | MatchStreamSurfaceEvent | MatchStreamHeartbeatEvent | MatchStreamCompleteEvent | MatchStreamErrorEvent;
package/match-stream.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { HttpTransport } from "./http-transport.js";
2
- import { type MatchStreamEvent } from "./match-stream-types.js";
2
+ import type { MatchStreamEvent } from "./match-stream-types.js";
3
3
  import type { MatchInput } from "./match-types.js";
4
4
  /**
5
5
  * Decode one NDJSON line into a validated {@link MatchStreamEvent}, raising a
@@ -7,7 +7,7 @@ import type { MatchInput } from "./match-types.js";
7
7
  * for `contract-parity.test.ts`, which re-checks it against the real Zod schema;
8
8
  * it is not part of the published surface.
9
9
  */
10
- export declare function decodeMatchStreamEvent(line: string): MatchStreamEvent;
10
+ export declare const decodeMatchStreamEvent: (line: string) => MatchStreamEvent;
11
11
  /**
12
12
  * Stream Match progress as an async iterator. Iterates until the run reaches a
13
13
  * `complete` or an `error` event, and raises if the connection ends before one
package/match-stream.js CHANGED
@@ -57,7 +57,7 @@
57
57
  import { MaterialGraphError } from "./errors.js";
58
58
  import { MATCH_IMAGE_TYPES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
59
59
  import { readNdjsonLines } from "./ndjson.js";
60
- import { findSdkOperation, } from "./operations.js";
60
+ import { findSdkOperation } from "./operations.js";
61
61
  import { checkSearchResultItems } from "./search-result-validation.js";
62
62
  import { requireArray, requireBoundedNumber, requireDefaultedArray, requireEnum, requireIntegerAtLeast, requireNumber, requireOptionalString, requireRecord, requireString, } from "./validation.js";
63
63
  /** The NDJSON media type the Match route negotiates the scene workflow on. */
@@ -70,34 +70,37 @@ const BOUNDING_BOX_CORNERS = Object.freeze([
70
70
  "x1",
71
71
  "y1",
72
72
  ]);
73
- function operation(operationId) {
73
+ const operation = (operationId) => {
74
74
  const found = findSdkOperation(operationId);
75
- if (!found)
75
+ if (!found) {
76
76
  throw MaterialGraphError.unexpected(`Unknown SDK operation: ${operationId}`);
77
+ }
77
78
  return found;
78
- }
79
+ };
79
80
  /**
80
81
  * The failure shape every check in this module raises: one message naming the
81
82
  * offending path and quoting a bounded slice of the frame.
82
83
  */
83
- function frameFailure(line) {
84
+ const frameFailure = (line) => {
84
85
  const preview = line.length > MAX_FRAME_PREVIEW
85
86
  ? `${line.slice(0, MAX_FRAME_PREVIEW)}…`
86
87
  : line;
87
88
  return (reason) => MaterialGraphError.unexpected(`MaterialGraph match stream sent a malformed NDJSON frame: ${reason}. Frame: ${preview}`);
88
- }
89
+ };
89
90
  /** Check one `MatchCategoryInference` item. */
90
- function checkCategoryInference(value, what, fail) {
91
+ const checkCategoryInference = (value, what, fail) => {
91
92
  const record = requireRecord(value, what, fail);
92
93
  requireString(record.productTypeId, `${what}.productTypeId`, fail);
93
94
  requireString(record.displayName, `${what}.displayName`, fail);
94
95
  requireNumber(record.boost, `${what}.boost`, fail);
95
- }
96
- function checkCategoryInferences(items, what, fail) {
97
- items.forEach((item, index) => checkCategoryInference(item, `${what}[${index}]`, fail));
98
- }
96
+ };
97
+ const checkCategoryInferences = (items, what, fail) => {
98
+ items.forEach((item, index) => {
99
+ checkCategoryInference(item, `${what}[${index}]`, fail);
100
+ });
101
+ };
99
102
  /** Check one detected surface — identity, function, confidence, and its box. */
100
- function checkDetectedSurface(value, what, fail) {
103
+ const checkDetectedSurface = (value, what, fail) => {
101
104
  const record = requireRecord(value, what, fail);
102
105
  requireString(record.id, `${what}.id`, fail);
103
106
  requireString(record.label, `${what}.label`, fail);
@@ -110,12 +113,12 @@ function checkDetectedSurface(value, what, fail) {
110
113
  for (const corner of BOUNDING_BOX_CORNERS) {
111
114
  requireNumber(box[corner], `${what}.boundingBox.${corner}`, fail);
112
115
  }
113
- }
116
+ };
114
117
  /**
115
118
  * Check one surface's matching state and fill the canonical `.default([])`
116
119
  * arrays, so a consumer never meets `undefined` where the type promises an array.
117
120
  */
118
- function readSurfaceResult(value, what, fail) {
121
+ const readSurfaceResult = (value, what, fail) => {
119
122
  const record = requireRecord(value, what, fail);
120
123
  checkDetectedSurface(record.surface, `${what}.surface`, fail);
121
124
  requireEnum(record.status, MATCH_SURFACE_STATUSES, `${what}.status`, fail);
@@ -124,8 +127,8 @@ function readSurfaceResult(value, what, fail) {
124
127
  checkSearchResultItems(results, `${what}.results`, fail);
125
128
  const inferredCategories = requireDefaultedArray(record.inferredCategories, `${what}.inferredCategories`, fail);
126
129
  checkCategoryInferences(inferredCategories, `${what}.inferredCategories`, fail);
127
- return { ...record, results, inferredCategories };
128
- }
130
+ return { ...record, inferredCategories, results };
131
+ };
129
132
  /**
130
133
  * `matchRunTotalsSchema` — four non-negative integers plus the TWO cross-field
131
134
  * invariants its `.superRefine()` enforces. Relational rather than field-wise,
@@ -135,7 +138,7 @@ function readSurfaceResult(value, what, fail) {
135
138
  * `matchesSoFar` is deliberately unbounded against the surface counts — one
136
139
  * surface can carry many results and another none, so no ratio is principled.
137
140
  */
138
- function checkRunTotals(value, what, fail) {
141
+ const checkRunTotals = (value, what, fail) => {
139
142
  const record = requireRecord(value, what, fail);
140
143
  const detected = requireIntegerAtLeast(record.surfacesDetected, `${what}.surfacesDetected`, fail, 0);
141
144
  const resolved = requireIntegerAtLeast(record.surfacesResolved, `${what}.surfacesResolved`, fail, 0);
@@ -149,9 +152,9 @@ function checkRunTotals(value, what, fail) {
149
152
  if (resolved > detected) {
150
153
  throw fail(`${what}.surfacesResolved (${resolved}) exceeds ${what}.surfacesDetected (${detected}) — a run cannot resolve more surfaces than it found`);
151
154
  }
152
- }
155
+ };
153
156
  /** Check the terminal workflow result — image type, surfaces, optional roll-ups. */
154
- function readWorkflowResult(value, what, fail) {
157
+ const readWorkflowResult = (value, what, fail) => {
155
158
  const record = requireRecord(value, what, fail);
156
159
  requireEnum(record.imageType, MATCH_IMAGE_TYPES, `${what}.imageType`, fail);
157
160
  const surfaces = requireArray(record.surfaces, `${what}.surfaces`, fail).map((surface, index) => readSurfaceResult(surface, `${what}.surfaces[${index}]`, fail));
@@ -164,26 +167,30 @@ function readWorkflowResult(value, what, fail) {
164
167
  checkCategoryInferences(requireArray(record.inferredCategories, `${what}.inferredCategories`, fail), `${what}.inferredCategories`, fail);
165
168
  }
166
169
  return { ...record, surfaces };
167
- }
170
+ };
168
171
  /**
169
172
  * Validate one frame against the canonical contract and apply the schema's
170
173
  * `.default([])` fills, returning the event as a plain record. Unknown keys ride
171
174
  * through untouched — see the pass-through note in the module header.
172
175
  */
173
- function readFrame(value, fail) {
176
+ const readFrame = (value, fail) => {
174
177
  const record = requireRecord(value, "the frame", fail);
175
178
  const type = requireString(record.type, "`type`", fail);
176
179
  switch (type) {
177
- case "step":
180
+ case "step": {
178
181
  requireEnum(record.step, MATCH_WORKFLOW_STEPS, "`step`", fail);
179
182
  requireString(record.message, "`message`", fail);
180
183
  return record;
181
- case "classified":
184
+ }
185
+ case "classified": {
182
186
  requireEnum(record.imageType, MATCH_IMAGE_TYPES, "`imageType`", fail);
183
187
  return record;
188
+ }
184
189
  case "surfaces": {
185
190
  const surfaces = requireArray(record.surfaces, "`surfaces`", fail);
186
- surfaces.forEach((surface, index) => checkDetectedSurface(surface, `surfaces[${index}]`, fail));
191
+ surfaces.forEach((surface, index) => {
192
+ checkDetectedSurface(surface, `surfaces[${index}]`, fail);
193
+ });
187
194
  return record;
188
195
  }
189
196
  case "surface": {
@@ -193,37 +200,41 @@ function readFrame(value, fail) {
193
200
  checkRunTotals(record.totals, "`totals`", fail);
194
201
  return { ...record, surface };
195
202
  }
196
- case "heartbeat":
203
+ case "heartbeat": {
197
204
  // Payload-free by contract — there is nothing else to check.
198
205
  return record;
199
- case "complete":
206
+ }
207
+ case "complete": {
200
208
  return {
201
209
  ...record,
202
210
  result: readWorkflowResult(record.result, "`result`", fail),
203
211
  };
204
- case "error":
212
+ }
213
+ case "error": {
205
214
  requireString(record.message, "`message`", fail);
206
215
  return record;
207
- default:
216
+ }
217
+ default: {
208
218
  throw fail(`\`type\` is not a known Match stream event (${type})`);
219
+ }
209
220
  }
210
- }
221
+ };
211
222
  /**
212
223
  * The single narrowing boundary of this module. {@link readFrame} has already
213
224
  * proven every field the union's shape depends on; re-checking the discriminant
214
225
  * here keeps the assertion from being vacuous.
215
226
  */
216
- function assertMatchStreamEvent(frame, fail) {
227
+ const assertMatchStreamEvent = (frame, fail) => {
217
228
  const record = requireRecord(frame, "the frame", fail);
218
229
  requireEnum(record.type, MATCH_STREAM_EVENT_TYPES, "`type`", fail);
219
- }
230
+ };
220
231
  /**
221
232
  * Decode one NDJSON line into a validated {@link MatchStreamEvent}, raising a
222
233
  * {@link MaterialGraphError} on anything the contract does not allow. Exported
223
234
  * for `contract-parity.test.ts`, which re-checks it against the real Zod schema;
224
235
  * it is not part of the published surface.
225
236
  */
226
- export function decodeMatchStreamEvent(line) {
237
+ export const decodeMatchStreamEvent = (line) => {
227
238
  const fail = frameFailure(line);
228
239
  let parsed;
229
240
  try {
@@ -235,10 +246,8 @@ export function decodeMatchStreamEvent(line) {
235
246
  const frame = readFrame(parsed, fail);
236
247
  assertMatchStreamEvent(frame, fail);
237
248
  return frame;
238
- }
239
- function isTerminal(event) {
240
- return event.type === "complete" || event.type === "error";
241
- }
249
+ };
250
+ const isTerminal = (event) => event.type === "complete" || event.type === "error";
242
251
  /**
243
252
  * Stream Match progress as an async iterator. Iterates until the run reaches a
244
253
  * `complete` or an `error` event, and raises if the connection ends before one
@@ -251,33 +260,38 @@ function isTerminal(event) {
251
260
  * it cancelled, so the truncated-stream error is not raised for it.
252
261
  */
253
262
  export async function* matchStream(transport, input, signal) {
254
- if (signal?.aborted === true)
263
+ if (signal?.aborted === true) {
255
264
  return;
265
+ }
256
266
  // Our own controller, so abandoning the iterator cancels the request too.
257
267
  const controller = new AbortController();
258
- const forwardAbort = () => controller.abort();
268
+ const forwardAbort = () => {
269
+ controller.abort();
270
+ };
259
271
  signal?.addEventListener("abort", forwardAbort, { once: true });
260
272
  try {
261
273
  let body;
262
274
  try {
263
275
  body = await transport.openStream(operation("match_material"), {
276
+ accept: MATCH_STREAM_ACCEPT,
264
277
  body: input,
265
278
  signal: controller.signal,
266
- accept: MATCH_STREAM_ACCEPT,
267
279
  subject: "match stream",
268
280
  });
269
281
  }
270
282
  catch (error) {
271
283
  // Cancelled before the response headers landed — the caller's own stop.
272
- if (controller.signal.aborted)
284
+ if (controller.signal.aborted) {
273
285
  return;
286
+ }
274
287
  throw error;
275
288
  }
276
289
  for await (const line of readNdjsonLines(body, controller.signal)) {
277
290
  const event = decodeMatchStreamEvent(line);
278
291
  yield event;
279
- if (isTerminal(event))
292
+ if (isTerminal(event)) {
280
293
  return;
294
+ }
281
295
  }
282
296
  if (!controller.signal.aborted) {
283
297
  throw MaterialGraphError.unexpected("MaterialGraph match stream ended without a `complete` or `error` event — the connection was truncated");
package/match-types.d.ts CHANGED
@@ -12,11 +12,11 @@ import type { CorpusScope } from "./corpus-scope-types.js";
12
12
  import type { SearchFilter } from "./search-refinement-types.js";
13
13
  import type { OpenEnum, PaletteSwatch, SearchResultItem } from "./types.js";
14
14
  /** An inferred product-type category from the query image, with its boost. */
15
- export interface MatchCategoryInference {
15
+ export type MatchCategoryInference = {
16
16
  productTypeId: string;
17
17
  displayName: string;
18
18
  boost: number;
19
- }
19
+ };
20
20
  /**
21
21
  * The Material Match response (non-streaming form).
22
22
  *
@@ -31,13 +31,13 @@ export interface MatchCategoryInference {
31
31
  * means the material carries no palette on record — UNKNOWN, never "no colour"
32
32
  * and never "the wrong colour".
33
33
  */
34
- export interface MatchColourReading {
34
+ export type MatchColourReading = {
35
35
  variantId: string;
36
36
  colourDistance: number | null;
37
37
  colourBand: string | null;
38
38
  measurable: boolean;
39
- }
40
- export interface MatchResponse {
39
+ };
40
+ export type MatchResponse = {
41
41
  /**
42
42
  * Result attribution (MG-1131). `basis` is always `"match"` here — this route
43
43
  * has no `mode`, so this is the field that lets a Match outcome be grouped
@@ -73,9 +73,9 @@ export interface MatchResponse {
73
73
  /** The query crop's own extracted palette — what the colour stage compared against. */
74
74
  segmentPalette?: PaletteSwatch[] | null;
75
75
  note?: string;
76
- }
76
+ };
77
77
  /** The Material Match request body — exactly one of `imageBase64`, `imageUrl`, `vector`. */
78
- export interface MatchInput {
78
+ export type MatchInput = {
79
79
  imageBase64?: string;
80
80
  imageUrl?: string;
81
81
  vector?: string;
@@ -111,4 +111,4 @@ export interface MatchInput {
111
111
  preferences?: SearchFilter[];
112
112
  /** Opt in to seed-relative verdict cells; inert unless the inner search carries a variant seed. */
113
113
  verdicts?: boolean;
114
- }
114
+ };
@@ -18,7 +18,7 @@ export type MaterialAssetVisualRole = OpenEnum<"grid" | "detail" | "scene" | "sw
18
18
  * - `retired_placeholder` — a stand-in for a withdrawn asset.
19
19
  */
20
20
  export type MaterialAssetStatus = OpenEnum<"downloaded" | "linked_not_downloaded" | "failed" | "retired_placeholder">;
21
- export interface MaterialAssetProjectionImage {
21
+ export type MaterialAssetProjectionImage = {
22
22
  key: string;
23
23
  ordinal: number;
24
24
  proxyPath: string;
@@ -28,8 +28,8 @@ export interface MaterialAssetProjectionImage {
28
28
  fileExtension: string | null;
29
29
  filename: string | null;
30
30
  byteSize: number | null;
31
- }
32
- export interface MaterialAssetProjectionDownload {
31
+ };
32
+ export type MaterialAssetProjectionDownload = {
33
33
  ordinal: number;
34
34
  url: string;
35
35
  label: string | null;
@@ -38,20 +38,20 @@ export interface MaterialAssetProjectionDownload {
38
38
  contentType: string | null;
39
39
  fileExtension: string | null;
40
40
  filename: string | null;
41
- }
41
+ };
42
42
  export type MaterialDocumentStatus = OpenEnum<"downloaded" | "linked_not_downloaded" | "unavailable_source" | "dead_link" | "failed_ingest">;
43
43
  export type MaterialDocumentCoverageState = OpenEnum<"available" | "none_declared" | "not_ingested" | "unavailable_source" | "dead_link" | "failed_ingest">;
44
- export interface MaterialDocumentScope {
44
+ export type MaterialDocumentScope = {
45
45
  kind: "product" | "variant";
46
46
  id: string;
47
- }
48
- export interface MaterialDocumentSource {
47
+ };
48
+ export type MaterialDocumentSource = {
49
49
  /** Opaque, public identifier for one source collection; never a PIM/DAM path. */
50
50
  id: string;
51
51
  authority: string;
52
52
  revision: string;
53
- }
54
- export interface MaterialDocumentProjectionItem {
53
+ };
54
+ export type MaterialDocumentProjectionItem = {
55
55
  id: string;
56
56
  scope: MaterialDocumentScope & {
57
57
  inherited: boolean;
@@ -61,12 +61,12 @@ export interface MaterialDocumentProjectionItem {
61
61
  /** True only for a Product declaration or this exact requested Variant. */
62
62
  appliesToRequestedVariant: boolean;
63
63
  /** Every exact source-grain declaration collapsed into this URL identity. */
64
- declarations: Array<{
64
+ declarations: {
65
65
  scope: MaterialDocumentScope;
66
66
  source: MaterialDocumentSource;
67
67
  status: MaterialDocumentStatus;
68
68
  readable: boolean;
69
- }>;
69
+ }[];
70
70
  documentType: string | null;
71
71
  originalName: string;
72
72
  status: MaterialDocumentStatus;
@@ -75,46 +75,46 @@ export interface MaterialDocumentProjectionItem {
75
75
  contentType: string | null;
76
76
  fileExtension: string | null;
77
77
  source: MaterialDocumentSource;
78
- }
79
- export interface MaterialDocumentCoverageSource {
78
+ };
79
+ export type MaterialDocumentCoverageSource = {
80
80
  scope: MaterialDocumentScope;
81
81
  state: MaterialDocumentCoverageState;
82
82
  exact: boolean;
83
83
  declaredCount: number | null;
84
84
  readableCount: number;
85
85
  source: MaterialDocumentSource;
86
- }
87
- export interface MaterialDocumentCoverage {
86
+ };
87
+ export type MaterialDocumentCoverage = {
88
88
  productUnion: MaterialDocumentCoverageSummary;
89
89
  requestedVariant: MaterialDocumentCoverageSummary;
90
90
  sources: MaterialDocumentCoverageSource[];
91
- }
92
- export interface MaterialDocumentCoverageSummary {
91
+ };
92
+ export type MaterialDocumentCoverageSummary = {
93
93
  state: MaterialDocumentCoverageState;
94
94
  exact: boolean;
95
95
  declaredCount: number | null;
96
96
  readableCount: number;
97
- }
98
- export interface MaterialDocumentPageOptions {
97
+ };
98
+ export type MaterialDocumentPageOptions = {
99
99
  cursor?: string;
100
100
  limit?: number;
101
- }
102
- export interface MaterialDocumentPage {
101
+ };
102
+ export type MaterialDocumentPage = {
103
103
  variantId: VariantId;
104
104
  documents: MaterialDocumentProjectionItem[];
105
105
  coverage: MaterialDocumentCoverage;
106
106
  totalDocuments: number;
107
107
  nextCursor: string | null;
108
- }
108
+ };
109
109
  /** Tallies over what this projection returned — never a claim about the brand's own library. */
110
- export interface MaterialAssetProjectionSummary {
110
+ export type MaterialAssetProjectionSummary = {
111
111
  imageCount: number;
112
112
  downloadCount: number;
113
113
  documentCount: number;
114
114
  readableDocumentCount: number;
115
115
  downloadedImageCount: number;
116
- }
117
- export interface MaterialAssetProjection {
116
+ };
117
+ export type MaterialAssetProjection = {
118
118
  /** Opaque — echoed from the request. */
119
119
  variantId: VariantId;
120
120
  images: MaterialAssetProjectionImage[];
@@ -122,4 +122,4 @@ export interface MaterialAssetProjection {
122
122
  documents: MaterialDocumentProjectionItem[];
123
123
  documentCoverage: MaterialDocumentCoverage;
124
124
  summary: MaterialAssetProjectionSummary;
125
- }
125
+ };
@@ -45,7 +45,7 @@ export type MaterialBlockFieldValue = string | number | boolean | unknown[] | Re
45
45
  * `status: "verified"` is a real negative you may publish; the same `false`
46
46
  * under `missing` is a placeholder for an unanswered question.
47
47
  */
48
- export interface MaterialBlockProjectionField {
48
+ export type MaterialBlockProjectionField = {
49
49
  /** Canonical vocabulary, not an opaque id — the same token `bySpec` accepts. */
50
50
  attributeId: string;
51
51
  label: string;
@@ -56,21 +56,21 @@ export interface MaterialBlockProjectionField {
56
56
  sourceBasis?: string;
57
57
  /** Claim confidence supplied by the graph; absence means no confidence was emitted. */
58
58
  confidence?: number;
59
- }
60
- export interface MaterialBlockProjectionItem {
59
+ };
60
+ export type MaterialBlockProjectionItem = {
61
61
  canonicalBlockId: string;
62
62
  canonicalBlockName: string;
63
63
  status: MaterialBlockStatus;
64
64
  fields: MaterialBlockProjectionField[];
65
65
  /** The work queue: attributes with `status: "missing"`. UNKNOWN, never "none". */
66
66
  missingAttributeIds: string[];
67
- }
67
+ };
68
68
  /**
69
69
  * Every canonical block for one material, each field carrying whether it is
70
70
  * determined. The whole surface, not a page — there is no cursor here.
71
71
  */
72
- export interface MaterialBlockProjection {
72
+ export type MaterialBlockProjection = {
73
73
  /** Opaque — echoed from the request. */
74
74
  variantId: VariantId;
75
75
  blocks: MaterialBlockProjectionItem[];
76
- }
76
+ };