@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
@@ -61,11 +61,11 @@ export type SlotPoolCriterion = {
61
61
  coverageNote?: string;
62
62
  };
63
63
  /** A colour cue for a slot. Colours rerank within the retrieved set; they never admit. */
64
- export interface SlotPoolColourCue {
64
+ export type SlotPoolColourCue = {
65
65
  /** `#rrggbb`. */
66
66
  hex: string;
67
67
  name?: string;
68
- }
68
+ };
69
69
  /**
70
70
  * What to do with a candidate the catalogue no longer lists. Neither value ever
71
71
  * marks such a candidate eligible — the policy decides only whether it is
@@ -73,7 +73,7 @@ export interface SlotPoolColourCue {
73
73
  */
74
74
  export type SlotPoolAvailabilityPolicy = "flag-unavailable" | "exclude-unavailable";
75
75
  /** One slot of work. Self-contained: nothing in it identifies a project. */
76
- export interface SlotPoolTask {
76
+ export type SlotPoolTask = {
77
77
  /**
78
78
  * YOUR key for this task, opaque to MaterialGraph and returned verbatim on the
79
79
  * matching pool. This is how you correlate 24 results; it is never parsed,
@@ -102,9 +102,9 @@ export interface SlotPoolTask {
102
102
  availability?: SlotPoolAvailabilityPolicy;
103
103
  /** Candidates returned for this task. Max 48, default 12. */
104
104
  limit?: number;
105
- }
105
+ };
106
106
  /** Body for `POST /api/v1/schemes/pools` ({@link MaterialGraphClient.slotPools}). */
107
- export interface SlotPoolsRequest {
107
+ export type SlotPoolsRequest = {
108
108
  /** Up to 24 tasks. Each is independent: one failing costs that one. */
109
109
  tasks: SlotPoolTask[];
110
110
  /**
@@ -112,11 +112,11 @@ export interface SlotPoolsRequest {
112
112
  * (default true). One bounded read — never one request per candidate.
113
113
  */
114
114
  coSpecification?: boolean;
115
- }
115
+ };
116
116
  /** The six live verdict states, plus the two legacy tokens older rows carry. */
117
117
  export type SlotPoolVerdictState = OpenEnum<"matched" | "deviated" | "failed" | "unverified" | "missing" | "not_evaluated">;
118
118
  /** One cell of a candidate's report card against one criterion. */
119
- export interface SlotPoolVerdictCell {
119
+ export type SlotPoolVerdictCell = {
120
120
  attributeId: string;
121
121
  state: SlotPoolVerdictState;
122
122
  strength: OpenEnum<"required" | "preferred">;
@@ -149,12 +149,12 @@ export interface SlotPoolVerdictCell {
149
149
  sourceBasis: string | null;
150
150
  trustGap: OpenEnum<"below_confidence" | "basis_unmet" | "proposed"> | null;
151
151
  citation?: VerdictCitation;
152
- }
152
+ };
153
153
  /** Why a candidate is labelled. An eligible candidate carries none of these. */
154
154
  export type SlotPoolFlag = OpenEnum<"below-floor" | "required-not-applied" | "discontinued" | "superseded" | "unverified-value">;
155
155
  export type SlotPoolAvailability = OpenEnum<"available" | "discontinued" | "superseded" | "unknown">;
156
156
  /** The declared successor of a withdrawn material, one hop only. */
157
- export interface SlotPoolSuccessor {
157
+ export type SlotPoolSuccessor = {
158
158
  variantId: VariantId;
159
159
  brandSlug: string;
160
160
  productId: string;
@@ -163,13 +163,13 @@ export interface SlotPoolSuccessor {
163
163
  variant: string;
164
164
  color: string | null;
165
165
  availability: SlotPoolAvailability;
166
- }
166
+ };
167
167
  /**
168
168
  * The features a composer scores on. Colours are EXTRACTED FROM PRODUCT IMAGERY
169
169
  * — visual likeness, never a declared colour specification. An empty `palette`
170
170
  * or `attributes` means nothing is on record, never that the material has none.
171
171
  */
172
- export interface SlotPoolCandidateFeatures {
172
+ export type SlotPoolCandidateFeatures = {
173
173
  colour: {
174
174
  dominantHex: string | null;
175
175
  hsl: {
@@ -201,8 +201,8 @@ export interface SlotPoolCandidateFeatures {
201
201
  term: string;
202
202
  }[];
203
203
  dimensions: Record<string, unknown>[] | null;
204
- }
205
- export interface SlotPoolCandidate {
204
+ };
205
+ export type SlotPoolCandidate = {
206
206
  variantId: VariantId;
207
207
  productId: string;
208
208
  brandSlug: string;
@@ -241,7 +241,7 @@ export interface SlotPoolCandidate {
241
241
  minConfidence: number | null;
242
242
  };
243
243
  features: SlotPoolCandidateFeatures;
244
- }
244
+ };
245
245
  /**
246
246
  * Why a pool is short. Four different facts, and none of them is "nothing in
247
247
  * the catalogue matches your brief".
@@ -268,7 +268,7 @@ export type SlotPoolShortfall = {
268
268
  tier: string;
269
269
  consideredCount: number;
270
270
  };
271
- export interface SlotPool {
271
+ export type SlotPool = {
272
272
  /** Your own key, verbatim. */
273
273
  taskKey: string;
274
274
  category: string | null;
@@ -305,14 +305,14 @@ export interface SlotPool {
305
305
  variantId: VariantId;
306
306
  } | null;
307
307
  warnings: string[];
308
- }
308
+ };
309
309
  /**
310
310
  * The sparse pairing graph among the returned candidates. Each unordered pair
311
311
  * appears ONCE and the relation is symmetric. An empty `edges` under a null
312
312
  * `datasetSessionId` means the dataset is absent, NOT that these materials are
313
313
  * never specified together.
314
314
  */
315
- export interface SlotPoolCoSpecification {
315
+ export type SlotPoolCoSpecification = {
316
316
  edges: {
317
317
  from: VariantId;
318
318
  to: VariantId;
@@ -326,9 +326,9 @@ export interface SlotPoolCoSpecification {
326
326
  window: string;
327
327
  signal: string;
328
328
  };
329
- }
329
+ };
330
330
  /** The `200` body from `POST /api/v1/schemes/pools`. */
331
- export interface SlotPoolsResponse {
331
+ export type SlotPoolsResponse = {
332
332
  versions: {
333
333
  contract: string;
334
334
  retrieval: string;
@@ -369,4 +369,4 @@ export interface SlotPoolsResponse {
369
369
  coSpecificationQueries: number;
370
370
  };
371
371
  warnings: string[];
372
- }
372
+ };
@@ -1,7 +1,7 @@
1
1
  import type { PostSourceMaterialCommentResult, SourceMaterialBatchDetail, SourceMaterialCommentThread } from "./run-types.js";
2
2
  /** Validate a batch-detail body, returning it typed, or throw explaining why. */
3
- export declare function checkSourceMaterialBatchDetail(value: unknown, batchId: string): SourceMaterialBatchDetail;
3
+ export declare const checkSourceMaterialBatchDetail: (value: unknown, batchId: string) => SourceMaterialBatchDetail;
4
4
  /** Validate a comment-thread body, returning it typed, or throw explaining why. */
5
- export declare function checkSourceMaterialCommentThread(value: unknown, sourceId: string): SourceMaterialCommentThread;
5
+ export declare const checkSourceMaterialCommentThread: (value: unknown, sourceId: string) => SourceMaterialCommentThread;
6
6
  /** Validate a posted-comment body, returning it typed, or throw explaining why. */
7
- export declare function checkPostSourceMaterialCommentResult(value: unknown, sourceId: string): PostSourceMaterialCommentResult;
7
+ export declare const checkPostSourceMaterialCommentResult: (value: unknown, sourceId: string) => PostSourceMaterialCommentResult;
@@ -48,23 +48,21 @@ const SOURCE_ROLES = [
48
48
  "inspiration_image",
49
49
  "unclassified",
50
50
  ];
51
- function detailFailure(batchId) {
52
- return (reason) => MaterialGraphError.unexpected(`GET /api/v1/source-material/${batchId} returned a malformed body: ${reason}`);
53
- }
54
- function checkAnalysis(value, what, fail) {
51
+ const detailFailure = (batchId) => (reason) => MaterialGraphError.unexpected(`GET /api/v1/source-material/${batchId} returned a malformed body: ${reason}`);
52
+ const checkAnalysis = (value, what, fail) => {
55
53
  const record = requireRecord(value, what, fail);
56
54
  // `model` and `analysedAt` ARE `.min(1)` canonically — fields this endpoint
57
55
  // introduces, where an empty value is meaningless and `model` already cannot
58
56
  // be written empty. Parity here is achieved by the schema being strict, never
59
57
  // by this mirror freelancing past it.
60
58
  return {
59
+ analysedAt: requireNonEmptyString(record.analysedAt, `${what}.analysedAt`, fail),
61
60
  kind: requireEnum(record.kind, ANALYSIS_KINDS, `${what}.kind`, fail),
62
61
  model: requireNonEmptyString(record.model, `${what}.model`, fail),
63
- status: requireEnum(record.status, ANALYSIS_STATUSES, `${what}.status`, fail),
64
62
  result: requireJsonRecord(record.result, `${what}.result`, fail),
65
- analysedAt: requireNonEmptyString(record.analysedAt, `${what}.analysedAt`, fail),
63
+ status: requireEnum(record.status, ANALYSIS_STATUSES, `${what}.status`, fail),
66
64
  };
67
- }
65
+ };
68
66
  /** `sourceMaterialCommentAuthorSchema`'s `attribution` members, verbatim. */
69
67
  const COMMENT_ATTRIBUTIONS = ["reported"];
70
68
  /** The canonical cap on both author fields: `.trim().min(1).max(160)`. */
@@ -84,27 +82,27 @@ const AUTHOR_FIELD_MAX = 160;
84
82
  * schema caps. A validator that is looser than the contract is a validator that
85
83
  * lets the two drift without anything failing.
86
84
  */
87
- function checkCommentBase(record, what, fail) {
85
+ const checkCommentBase = (record, what, fail) => {
88
86
  const author = requireRecord(record.author, `${what}.author`, fail);
89
87
  const recordedBy = requireRecord(record.recordedBy, `${what}.recordedBy`, fail);
90
88
  return {
91
- commentId: requireNonEmptyString(record.commentId, `${what}.commentId`, fail),
92
89
  author: {
93
- name: requireTrimmedBoundedString(author.name, `${what}.author.name`, AUTHOR_FIELD_MAX, fail),
94
- organisation: requireNullableTrimmedBoundedString(author.organisation, `${what}.author.organisation`, AUTHOR_FIELD_MAX, fail),
95
90
  // Closed here, matching the canonical `z.literal("reported")`, while the
96
91
  // published type is `OpenEnum` so a newer server value keeps
97
92
  // type-checking — the same split the analysis enums make.
98
93
  attribution: requireEnum(author.attribution, COMMENT_ATTRIBUTIONS, `${what}.author.attribution`, fail),
94
+ name: requireTrimmedBoundedString(author.name, `${what}.author.name`, AUTHOR_FIELD_MAX, fail),
95
+ organisation: requireNullableTrimmedBoundedString(author.organisation, `${what}.author.organisation`, AUTHOR_FIELD_MAX, fail),
99
96
  },
97
+ body: requireNonEmptyString(record.body, `${what}.body`, fail),
98
+ commentId: requireNonEmptyString(record.commentId, `${what}.commentId`, fail),
99
+ createdAt: requireNonEmptyString(record.createdAt, `${what}.createdAt`, fail),
100
100
  recordedBy: {
101
101
  principalId: requireNonEmptyString(recordedBy.principalId, `${what}.recordedBy.principalId`, fail),
102
102
  },
103
- body: requireNonEmptyString(record.body, `${what}.body`, fail),
104
- createdAt: requireNonEmptyString(record.createdAt, `${what}.createdAt`, fail),
105
103
  };
106
- }
107
- function checkComment(value, what, fail) {
104
+ };
105
+ const checkComment = (value, what, fail) => {
108
106
  const record = requireRecord(value, what, fail);
109
107
  // Same reasoning as `analyses`: no `.default([])` canonically, so an absent
110
108
  // `replies` is malformed rather than empty.
@@ -113,8 +111,8 @@ function checkComment(value, what, fail) {
113
111
  ...checkCommentBase(record, what, fail),
114
112
  replies: replies.map((reply, index) => checkCommentBase(requireRecord(reply, `${what}.replies[${index}]`, fail), `${what}.replies[${index}]`, fail)),
115
113
  };
116
- }
117
- function checkFile(value, what, fail) {
114
+ };
115
+ const checkFile = (value, what, fail) => {
118
116
  const record = requireRecord(value, what, fail);
119
117
  // NOT `requireDefaultedArray`: the schema has no `.default([])`, so an absent
120
118
  // `analyses` is a malformed body rather than an empty one. Keeping that
@@ -133,11 +131,7 @@ function checkFile(value, what, fail) {
133
131
  // refuse a response the server can legitimately produce, and tightening them
134
132
  // is a change to a contract this endpoint does not own.
135
133
  return {
136
- sourceId: requireString(record.sourceId, `${what}.sourceId`, fail),
137
- role: requireEnum(record.role, SOURCE_ROLES, `${what}.role`, fail),
138
- filename: requireString(record.filename, `${what}.filename`, fail),
139
- mediaType: requireString(record.mediaType, `${what}.mediaType`, fail),
140
- sha256: requireString(record.sha256, `${what}.sha256`, fail),
134
+ analyses: analyses.map((analysis, index) => checkAnalysis(analysis, `${what}.analyses[${index}]`, fail)),
141
135
  // `requireSafeInteger`, NOT `requireIntegerAtLeast(…, 0)`. Canonically these
142
136
  // are a bare `z.number().int()` on the INHERITED
143
137
  // `sourceMaterialFileReceiptSchema`, which carries no lower bound — so a
@@ -150,17 +144,21 @@ function checkFile(value, what, fail) {
150
144
  // fields is a canonical change to a schema shared with the upload path, and
151
145
  // belongs in its own ticket with this mirror following after.
152
146
  bytes: requireSafeInteger(record.bytes, `${what}.bytes`, fail),
147
+ comments: comments.map((comment, index) => checkComment(comment, `${what}.comments[${index}]`, fail)),
148
+ commentsTruncated,
149
+ filename: requireString(record.filename, `${what}.filename`, fail),
150
+ mediaType: requireString(record.mediaType, `${what}.mediaType`, fail),
153
151
  pages: record.pages === null
154
152
  ? null
155
153
  : requireSafeInteger(record.pages, `${what}.pages`, fail),
154
+ role: requireEnum(record.role, SOURCE_ROLES, `${what}.role`, fail),
155
+ sha256: requireString(record.sha256, `${what}.sha256`, fail),
156
+ sourceId: requireString(record.sourceId, `${what}.sourceId`, fail),
156
157
  url: requireString(record.url, `${what}.url`, fail),
157
- analyses: analyses.map((analysis, index) => checkAnalysis(analysis, `${what}.analyses[${index}]`, fail)),
158
- comments: comments.map((comment, index) => checkComment(comment, `${what}.comments[${index}]`, fail)),
159
- commentsTruncated,
160
158
  };
161
- }
159
+ };
162
160
  /** Validate a batch-detail body, returning it typed, or throw explaining why. */
163
- export function checkSourceMaterialBatchDetail(value, batchId) {
161
+ export const checkSourceMaterialBatchDetail = (value, batchId) => {
164
162
  const fail = detailFailure(batchId);
165
163
  const record = requireRecord(value, "body", fail);
166
164
  const sources = requireArray(record.sources, "body.sources", fail);
@@ -169,21 +167,19 @@ export function checkSourceMaterialBatchDetail(value, batchId) {
169
167
  createdAt: requireString(record.createdAt, "body.createdAt", fail),
170
168
  sources: sources.map((file, index) => checkFile(file, `body.sources[${index}]`, fail)),
171
169
  };
172
- }
173
- function commentsFailure(verb, sourceId) {
174
- return (reason) => MaterialGraphError.unexpected(`${verb} .../sources/${sourceId}/comments returned a malformed body: ${reason}`);
175
- }
170
+ };
171
+ const commentsFailure = (verb, sourceId) => (reason) => MaterialGraphError.unexpected(`${verb} .../sources/${sourceId}/comments returned a malformed body: ${reason}`);
176
172
  /** Validate a comment-thread body, returning it typed, or throw explaining why. */
177
- export function checkSourceMaterialCommentThread(value, sourceId) {
173
+ export const checkSourceMaterialCommentThread = (value, sourceId) => {
178
174
  const fail = commentsFailure("GET", sourceId);
179
175
  const record = requireRecord(value, "body", fail);
180
176
  const comments = requireArray(record.comments, "body.comments", fail);
181
177
  return {
182
- sourceId: requireString(record.sourceId, "body.sourceId", fail),
183
178
  comments: comments.map((comment, index) => checkComment(comment, `body.comments[${index}]`, fail)),
179
+ sourceId: requireString(record.sourceId, "body.sourceId", fail),
184
180
  truncated: requireBoolean(record.truncated, "body.truncated", fail),
185
181
  };
186
- }
182
+ };
187
183
  /** `storedSourceMaterialCommentSchema`'s discriminator members, verbatim. */
188
184
  const STORED_COMMENT_KINDS = ["root", "reply"];
189
185
  /**
@@ -195,7 +191,7 @@ const STORED_COMMENT_KINDS = ["root", "reply"];
195
191
  * defect this discriminated union was added to fix, and a mirror that did it
196
192
  * would put the lie back on the client side.
197
193
  */
198
- function checkStoredComment(value, what, fail) {
194
+ const checkStoredComment = (value, what, fail) => {
199
195
  const record = requireRecord(value, what, fail);
200
196
  const kind = requireEnum(record.kind, STORED_COMMENT_KINDS, `${what}.kind`, fail);
201
197
  if (kind === "reply") {
@@ -206,13 +202,13 @@ function checkStoredComment(value, what, fail) {
206
202
  };
207
203
  }
208
204
  return { kind: "root", ...checkComment(record, what, fail) };
209
- }
205
+ };
210
206
  /** Validate a posted-comment body, returning it typed, or throw explaining why. */
211
- export function checkPostSourceMaterialCommentResult(value, sourceId) {
207
+ export const checkPostSourceMaterialCommentResult = (value, sourceId) => {
212
208
  const fail = commentsFailure("POST", sourceId);
213
209
  const record = requireRecord(value, "body", fail);
214
210
  return {
215
- sourceId: requireString(record.sourceId, "body.sourceId", fail),
216
211
  comment: checkStoredComment(record.comment, "body.comment", fail),
212
+ sourceId: requireString(record.sourceId, "body.sourceId", fail),
217
213
  };
218
- }
214
+ };
@@ -1,9 +1,9 @@
1
- export interface SpecFacetValue {
1
+ export type SpecFacetValue = {
2
2
  value: string;
3
3
  variants: number;
4
4
  brands: number;
5
5
  label?: string;
6
- }
6
+ };
7
7
  /**
8
8
  * A NUMERIC facet's observed span and the coverage behind it.
9
9
  *
@@ -17,13 +17,13 @@ export interface SpecFacetValue {
17
17
  * `unparseableVariants` is the honesty companion: values recorded here that are
18
18
  * not numbers, which a range EXCLUDES rather than reading as zero.
19
19
  */
20
- export interface SpecFacetRange {
20
+ export type SpecFacetRange = {
21
21
  min: number;
22
22
  max: number;
23
23
  variants: number;
24
24
  unparseableVariants: number;
25
- }
26
- export interface SpecFacet {
25
+ };
26
+ export type SpecFacet = {
27
27
  attributeId: string;
28
28
  name: string;
29
29
  isArray: boolean;
@@ -39,15 +39,15 @@ export interface SpecFacet {
39
39
  /** Present ONLY on a `numeric` facet. */
40
40
  range?: SpecFacetRange;
41
41
  description?: string;
42
- }
43
- export interface SpecFacetsListResponse {
42
+ };
43
+ export type SpecFacetsListResponse = {
44
44
  mode: "facets";
45
45
  count: number;
46
46
  facets: SpecFacet[];
47
- }
48
- export interface SpecFacetsDistributionResponse {
47
+ };
48
+ export type SpecFacetsDistributionResponse = {
49
49
  mode: "distribution";
50
50
  attributeId: string;
51
51
  count: number;
52
52
  values: SpecFacetValue[];
53
- }
53
+ };
package/spec-types.d.ts CHANGED
@@ -60,15 +60,15 @@ export type CertificationProgrammeAttributeId = typeof CERTIFICATION_PROGRAMME_A
60
60
  * and `client.attributeValues()`, or resolve free text with
61
61
  * `client.resolveAttribute()`.
62
62
  */
63
- export interface SpecTermFilter {
63
+ export type SpecTermFilter = {
64
64
  attributeId: string;
65
65
  term: string;
66
- }
66
+ };
67
67
  /** A negative spec criterion; absence of a value remains unproven. */
68
- export interface SpecExclusionFilter {
68
+ export type SpecExclusionFilter = {
69
69
  attributeId: string;
70
70
  excludesTerm: string;
71
- }
71
+ };
72
72
  /**
73
73
  * A presence spec criterion: the attribute must have ANY accepted value —
74
74
  * "has an EPD on record", "has a measured slip figure at all". Not supported for
@@ -90,10 +90,10 @@ export type SpecPresenceFilter = {
90
90
  * virtual {@link CERTIFICATION_PROGRAMME_ATTRIBUTE_ID}. Structurally assignable
91
91
  * to {@link SpecFilter}, so it drops straight into `search({ filters })`.
92
92
  */
93
- export interface CertificationProgrammeFilter {
93
+ export type CertificationProgrammeFilter = {
94
94
  attributeId: CertificationProgrammeAttributeId;
95
95
  term: string;
96
- }
96
+ };
97
97
  /**
98
98
  * A hard, canonical-attribute spec criterion — either a term match or a
99
99
  * presence check. The union the search engine applies as a restriction BEFORE
@@ -1,22 +1,6 @@
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}.
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 `:`.
16
- */
17
- import { type CertificationProgrammeFilter, type SpecExclusionFilter, type SpecPresenceFilter, type SpecTermFilter } from "./spec-types.js";
1
+ import type { CertificationProgrammeFilter, SpecExclusionFilter, SpecPresenceFilter, SpecTermFilter } from "./spec-types.js";
18
2
  /** 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;
3
+ export declare const excludeSpec: (attributeId: string, excludesTerm: string) => SpecExclusionFilter;
20
4
  /**
21
5
  * A term-equality criterion for `search({ filters })` — the attribute must
22
6
  * carry this canonical value.
@@ -25,7 +9,7 @@ export declare function excludeSpec(attributeId: string, excludesTerm: string):
25
9
  * // "same fire class as the seed"
26
10
  * client.search({ similarTo: { variantId }, filters: [specTerm("fire_classifications", "astm_e84_class_a")] });
27
11
  */
28
- export declare function specTerm(attributeId: string, term: string): SpecTermFilter;
12
+ export declare const specTerm: (attributeId: string, term: string) => SpecTermFilter;
29
13
  /**
30
14
  * A presence criterion for `search({ filters })` — the attribute must have ANY
31
15
  * accepted value.
@@ -34,7 +18,7 @@ export declare function specTerm(attributeId: string, term: string): SpecTermFil
34
18
  * // "…and it must have an EPD on record"
35
19
  * client.search({ similarTo: { variantId }, filters: [hasSpec("environmental_product_declaration")] });
36
20
  */
37
- export declare function hasSpec(attributeId: string): SpecPresenceFilter;
21
+ export declare const hasSpec: (attributeId: string) => SpecPresenceFilter;
38
22
  /**
39
23
  * A certification-programme criterion for `search({ filters })`, pinned to the
40
24
  * virtual attribute so a programme matches wherever it landed at ingest
@@ -49,7 +33,7 @@ export declare function hasSpec(attributeId: string): SpecPresenceFilter;
49
33
  * // "find a GREENGUARD-certified alternative"
50
34
  * client.search({ similarTo: { variantId: seed }, filters: [certificationProgramme("GREENGUARD Gold")] });
51
35
  */
52
- export declare function certificationProgramme(programme: string): CertificationProgrammeFilter;
36
+ export declare const certificationProgramme: (programme: string) => CertificationProgrammeFilter;
53
37
  /**
54
38
  * An `attribute:value` criterion string for `bySpec`. The `bySpec` route splits
55
39
  * on the FIRST `:`, so a value may itself contain colons; the attribute id may
@@ -58,7 +42,7 @@ export declare function certificationProgramme(programme: string): Certification
58
42
  * @example
59
43
  * client.bySpec([specCriterion("primary_material", "textile"), specCriterion("fire_classifications", "astm_e84_class_a")]);
60
44
  */
61
- export declare function specCriterion(attributeId: string, value: string): string;
45
+ export declare const specCriterion: (attributeId: string, value: string) => string;
62
46
  /**
63
47
  * An `attribute:min..max` RANGE criterion string for `bySpec`, for a
64
48
  * NUMBER-valued spec (`light_reflectance_value`, `nrc_rating`,
@@ -81,10 +65,10 @@ export declare function specCriterion(attributeId: string, value: string): strin
81
65
  * // a mid-tone band
82
66
  * specRangeCriterion("light_reflectance_value", { min: 30, max: 45 }); // "light_reflectance_value:30..45"
83
67
  */
84
- export declare function specRangeCriterion(attributeId: string, bounds: {
68
+ export declare const specRangeCriterion: (attributeId: string, bounds: {
85
69
  min?: number;
86
70
  max?: number;
87
- }): string;
71
+ }) => string;
88
72
  /**
89
73
  * An `attribute:value` criterion string for `bySpec` that filters by
90
74
  * certification PROGRAMME across all four certification buckets.
@@ -97,4 +81,4 @@ export declare function specRangeCriterion(attributeId: string, bounds: {
97
81
  * // every brand's GREENGUARD-Gold materials
98
82
  * client.bySpec([certificationProgrammeCriterion("GREENGUARD Gold")]);
99
83
  */
100
- export declare function certificationProgrammeCriterion(programme: string): string;
84
+ export declare const certificationProgrammeCriterion: (programme: string) => string;
package/specifications.js CHANGED
@@ -14,11 +14,9 @@
14
14
  * hand-format the `attribute:value` string the `bySpec` route splits on its
15
15
  * first `:`.
16
16
  */
17
- import { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, } from "./spec-types.js";
17
+ import { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID } from "./spec-types.js";
18
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
- }
19
+ export const excludeSpec = (attributeId, excludesTerm) => ({ attributeId, excludesTerm });
22
20
  /**
23
21
  * A term-equality criterion for `search({ filters })` — the attribute must
24
22
  * carry this canonical value.
@@ -27,9 +25,7 @@ export function excludeSpec(attributeId, excludesTerm) {
27
25
  * // "same fire class as the seed"
28
26
  * client.search({ similarTo: { variantId }, filters: [specTerm("fire_classifications", "astm_e84_class_a")] });
29
27
  */
30
- export function specTerm(attributeId, term) {
31
- return { attributeId, term };
32
- }
28
+ export const specTerm = (attributeId, term) => ({ attributeId, term });
33
29
  /**
34
30
  * A presence criterion for `search({ filters })` — the attribute must have ANY
35
31
  * accepted value.
@@ -38,9 +34,10 @@ export function specTerm(attributeId, term) {
38
34
  * // "…and it must have an EPD on record"
39
35
  * client.search({ similarTo: { variantId }, filters: [hasSpec("environmental_product_declaration")] });
40
36
  */
41
- export function hasSpec(attributeId) {
42
- return { attributeId, hasValue: true };
43
- }
37
+ export const hasSpec = (attributeId) => ({
38
+ attributeId,
39
+ hasValue: true,
40
+ });
44
41
  /**
45
42
  * A certification-programme criterion for `search({ filters })`, pinned to the
46
43
  * virtual attribute so a programme matches wherever it landed at ingest
@@ -55,9 +52,10 @@ export function hasSpec(attributeId) {
55
52
  * // "find a GREENGUARD-certified alternative"
56
53
  * client.search({ similarTo: { variantId: seed }, filters: [certificationProgramme("GREENGUARD Gold")] });
57
54
  */
58
- export function certificationProgramme(programme) {
59
- return { attributeId: CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, term: programme };
60
- }
55
+ export const certificationProgramme = (programme) => ({
56
+ attributeId: CERTIFICATION_PROGRAMME_ATTRIBUTE_ID,
57
+ term: programme,
58
+ });
61
59
  /**
62
60
  * An `attribute:value` criterion string for `bySpec`. The `bySpec` route splits
63
61
  * on the FIRST `:`, so a value may itself contain colons; the attribute id may
@@ -66,9 +64,7 @@ export function certificationProgramme(programme) {
66
64
  * @example
67
65
  * client.bySpec([specCriterion("primary_material", "textile"), specCriterion("fire_classifications", "astm_e84_class_a")]);
68
66
  */
69
- export function specCriterion(attributeId, value) {
70
- return `${attributeId}:${value}`;
71
- }
67
+ export const specCriterion = (attributeId, value) => `${attributeId}:${value}`;
72
68
  /**
73
69
  * An `attribute:min..max` RANGE criterion string for `bySpec`, for a
74
70
  * NUMBER-valued spec (`light_reflectance_value`, `nrc_rating`,
@@ -91,7 +87,7 @@ export function specCriterion(attributeId, value) {
91
87
  * // a mid-tone band
92
88
  * specRangeCriterion("light_reflectance_value", { min: 30, max: 45 }); // "light_reflectance_value:30..45"
93
89
  */
94
- export function specRangeCriterion(attributeId, bounds) {
90
+ export const specRangeCriterion = (attributeId, bounds) => {
95
91
  const { min, max } = bounds;
96
92
  if (min === undefined && max === undefined) {
97
93
  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.`);
@@ -100,7 +96,7 @@ export function specRangeCriterion(attributeId, bounds) {
100
96
  throw new Error(`specRangeCriterion("${attributeId}") is inverted (min ${min} > max ${max}) and can only ever match nothing.`);
101
97
  }
102
98
  return `${attributeId}:${min ?? ""}..${max ?? ""}`;
103
- }
99
+ };
104
100
  /**
105
101
  * An `attribute:value` criterion string for `bySpec` that filters by
106
102
  * certification PROGRAMME across all four certification buckets.
@@ -113,6 +109,4 @@ export function specRangeCriterion(attributeId, bounds) {
113
109
  * // every brand's GREENGUARD-Gold materials
114
110
  * client.bySpec([certificationProgrammeCriterion("GREENGUARD Gold")]);
115
111
  */
116
- export function certificationProgrammeCriterion(programme) {
117
- return specCriterion(CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, programme);
118
- }
112
+ export const certificationProgrammeCriterion = (programme) => specCriterion(CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, programme);
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