@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
@@ -7,7 +7,7 @@
7
7
  * limit, in the same per-lens shape as `brands-client` / `codes-client` /
8
8
  * `colours-client`. Behaviour is unchanged.
9
9
  */
10
- import { HttpTransport } from "./http-transport.js";
10
+ import type { HttpTransport } from "./http-transport.js";
11
11
  import type { CoordinateInput, CoordinateResponse } from "./types.js";
12
12
  /**
13
13
  * THE QUESTION: "here is my whole scheme so far — what completes it?" The
@@ -20,4 +20,4 @@ import type { CoordinateInput, CoordinateResponse } from "./types.js";
20
20
  * scheme is COLOURS rather than materials. Check `unresolved` before presenting:
21
21
  * a reference that resolved to nothing is named there, not dropped.
22
22
  */
23
- export declare function coordinate(transport: HttpTransport, input: CoordinateInput, signal?: AbortSignal): Promise<CoordinateResponse>;
23
+ export declare const coordinate: (transport: HttpTransport, input: CoordinateInput, signal?: AbortSignal) => Promise<CoordinateResponse>;
@@ -1,13 +1,3 @@
1
- /**
2
- * The COORDINATION lens: given several materials already chosen, what completes
3
- * them. A thin wrapper over the shared {@link HttpTransport};
4
- * `MaterialGraphClient.coordinate` delegates here.
5
- *
6
- * Extracted from `client.ts`, which sits above the repository's source-size
7
- * limit, in the same per-lens shape as `brands-client` / `codes-client` /
8
- * `colours-client`. Behaviour is unchanged.
9
- */
10
- import { HttpTransport } from "./http-transport.js";
11
1
  import { resolveOperation } from "./operations.js";
12
2
  /**
13
3
  * THE QUESTION: "here is my whole scheme so far — what completes it?" The
@@ -20,6 +10,4 @@ import { resolveOperation } from "./operations.js";
20
10
  * scheme is COLOURS rather than materials. Check `unresolved` before presenting:
21
11
  * a reference that resolved to nothing is named there, not dropped.
22
12
  */
23
- export function coordinate(transport, input, signal) {
24
- return transport.requestJson(resolveOperation("coordinate_materials"), { body: input, signal });
25
- }
13
+ export const coordinate = async (transport, input, signal) => await transport.requestJson(resolveOperation("coordinate_materials"), { body: input, signal });
@@ -22,7 +22,7 @@
22
22
  * and this build does not, so a new scope is not a compile error in a client
23
23
  * that simply has not been republished yet.
24
24
  */
25
- import { type OpenEnum } from "./types.js";
25
+ import type { OpenEnum } from "./types.js";
26
26
  /**
27
27
  * Every corpus a caller may ask for.
28
28
  *
@@ -50,8 +50,8 @@ export type CorpusScope = OpenEnum<"samplizeCatalogue" | "all" | "designShopOrde
50
50
  * the counts: a short page under a scope is a small SCOPED corpus, never a
51
51
  * truncated one.
52
52
  */
53
- export interface CorpusScopeReceipt {
53
+ export type CorpusScopeReceipt = {
54
54
  scope: CorpusScope;
55
55
  /** What the scope admits, in one sentence, for a human reader. */
56
56
  description: string;
57
- }
57
+ };
@@ -1,25 +1 @@
1
- /**
2
- * The corpus scope vocabulary, declared ONCE for the whole client.
3
- *
4
- * ── Why this file exists ──
5
- * Until MG-1168 the union was spelled inline at six places across the SDK, and
6
- * five of them had gone stale: `designShopOrderable` shipped in MG-1144 and
7
- * reached only the search request type, so a TypeScript consumer could send the
8
- * scope to `/search` and not to `/browse` — against a server that had accepted
9
- * it on both since the day it landed. The narrowed RECEIPT types were worse
10
- * than the request ones, because a caller could not even name the scope it got
11
- * back.
12
- *
13
- * That is the third hop of the reachability checklist failing quietly: server
14
- * correct, published client unable to reach the surface. One alias means the
15
- * next member is one edit here rather than six edits nobody is reminded to
16
- * make. `corpus-scope-parity.test.ts` in `apps/web/config` fails if this file
17
- * falls behind `CORPUS_SCOPES`.
18
- *
19
- * ── Why `OpenEnum` ──
20
- * The server may add a scope before a consumer upgrades. `OpenEnum` keeps the
21
- * known members as autocomplete while still accepting a string the server knows
22
- * and this build does not, so a new scope is not a compile error in a client
23
- * that simply has not been republished yet.
24
- */
25
- import {} from "./types.js";
1
+ export {};
@@ -27,20 +27,20 @@ export type CorrectionTarget = {
27
27
  url: string;
28
28
  };
29
29
  /** Caller-supplied evidence is not an independently verified graph reading. */
30
- export interface CorrectionEvidence {
30
+ export type CorrectionEvidence = {
31
31
  state: "known" | "unknown" | "conflicting" | "not_applicable";
32
32
  value?: CorrectionJson;
33
33
  sourceUrl?: string;
34
34
  note?: string;
35
- }
36
- export interface CreateCorrectionInput {
35
+ };
36
+ export type CreateCorrectionInput = {
37
37
  target: CorrectionTarget;
38
38
  pageEvidence: CorrectionEvidence;
39
39
  graphEvidence: CorrectionEvidence;
40
40
  proposedChange: CorrectionJson;
41
41
  rationale: string;
42
- }
43
- export interface Correction {
42
+ };
43
+ export type Correction = {
44
44
  id: string;
45
45
  submission: CreateCorrectionInput;
46
46
  status: "submitted" | "in_review" | "resolved" | "withdrawn";
@@ -48,8 +48,8 @@ export interface Correction {
48
48
  createdAt: string;
49
49
  updatedAt: string;
50
50
  acceptedTruthChanged: false;
51
- }
52
- export interface CorrectionResponse {
51
+ };
52
+ export type CorrectionResponse = {
53
53
  data: Correction;
54
54
  meta: {
55
55
  operationId: "corrections.create";
@@ -65,8 +65,8 @@ export interface CorrectionResponse {
65
65
  self: string;
66
66
  };
67
67
  warnings: never[];
68
- }
69
- export interface CorrectionsListResponse {
68
+ };
69
+ export type CorrectionsListResponse = {
70
70
  data: Correction[];
71
71
  meta: {
72
72
  operationId: "corrections.list";
@@ -85,4 +85,4 @@ export interface CorrectionsListResponse {
85
85
  next: string | null;
86
86
  };
87
87
  warnings: never[];
88
- }
88
+ };
@@ -18,35 +18,35 @@ import type { DemandMomentum, DemandQuarter, DemandSignal, OpenEnum } from "./ty
18
18
  * Body for `POST /api/v1/demand/batch` — enrich 1–48 already-selected candidate
19
19
  * ids with their real specification demand, in input order and cardinality.
20
20
  */
21
- export interface DemandBatchInput {
21
+ export type DemandBatchInput = {
22
22
  /** 1–48 canonical variant ids. Order AND cardinality are preserved — duplicates are echoed, never collapsed. */
23
23
  variantIds: VariantId[];
24
24
  /** The behavioural signal to read demand from. Defaults to `sampled` (order co-occurrence) server-side. */
25
25
  signal?: DemandSignal;
26
26
  /** Optional declared context (e.g. `{ projectType: "hospitality" }`) — echoed for provenance, never used to rank or filter. */
27
27
  context?: Record<string, string>;
28
- }
28
+ };
29
29
  /** Headline population behind the metric — this variant's own counts. */
30
- export interface DemandBatchPopulation {
30
+ export type DemandBatchPopulation = {
31
31
  specCount: number;
32
32
  projectCount: number;
33
33
  customerCount: number;
34
- }
34
+ };
35
35
  /** The consideration→specification funnel (project-grain; `exclusionRate` is annotate-only). */
36
- export interface DemandBatchFunnel {
36
+ export type DemandBatchFunnel = {
37
37
  consideredProjects: number;
38
38
  specifiedProjects: number;
39
39
  excludedCount: number;
40
40
  exclusionRate: number;
41
- }
41
+ };
42
42
  /** Per-result guardrail status — present on `internal` (`mg:admin`) results only. */
43
- export interface DemandBatchEvidence {
43
+ export type DemandBatchEvidence = {
44
44
  belowPrivacyFloor: boolean;
45
45
  belowQualityFloor: boolean;
46
46
  suppressedForPublic: boolean;
47
- }
47
+ };
48
48
  /** A variant that carries a usable demand signal. */
49
- export interface DemandBatchAvailableResult {
49
+ export type DemandBatchAvailableResult = {
50
50
  variantId: VariantId;
51
51
  state: "available";
52
52
  population: DemandBatchPopulation;
@@ -57,28 +57,28 @@ export interface DemandBatchAvailableResult {
57
57
  funnel: DemandBatchFunnel | null;
58
58
  /** Exact guardrail evidence for `internal` callers; null for public. */
59
59
  evidence: DemandBatchEvidence | null;
60
- }
60
+ };
61
61
  /**
62
62
  * A variant with a stats row that is below the public quality floor. We HAVE a
63
63
  * reading and are declining to publish it — not a claim that nobody specifies it.
64
64
  */
65
- export interface DemandBatchInsufficientResult {
65
+ export type DemandBatchInsufficientResult = {
66
66
  variantId: VariantId;
67
67
  state: "insufficient_data";
68
- }
68
+ };
69
69
  /**
70
70
  * A variant with no stats — indistinguishable from a privacy-suppressed one for
71
71
  * public callers, and therefore never reportable as "nobody specifies this".
72
72
  */
73
- export interface DemandBatchNoSignalResult {
73
+ export type DemandBatchNoSignalResult = {
74
74
  variantId: VariantId;
75
75
  state: "no_signal";
76
- }
76
+ };
77
77
  /** A requested id that resolves to no real variant. */
78
- export interface DemandBatchUnknownResult {
78
+ export type DemandBatchUnknownResult = {
79
79
  variantId: VariantId;
80
80
  state: "unknown_variant";
81
- }
81
+ };
82
82
  /**
83
83
  * One discriminated result per input id, in input order and cardinality.
84
84
  *
@@ -88,7 +88,7 @@ export interface DemandBatchUnknownResult {
88
88
  */
89
89
  export type DemandBatchResult = DemandBatchAvailableResult | DemandBatchInsufficientResult | DemandBatchNoSignalResult | DemandBatchUnknownResult;
90
90
  /** The `POST /api/v1/demand/batch` envelope. */
91
- export interface DemandBatchResponse {
91
+ export type DemandBatchResponse = {
92
92
  /** The completed ingestion-session id these counts were mined in (the dataset generation). */
93
93
  generationId: string;
94
94
  metric: "specification_demand";
@@ -115,4 +115,4 @@ export interface DemandBatchResponse {
115
115
  /** The echoed declared context, or null when none was supplied. */
116
116
  context: Record<string, string> | null;
117
117
  results: DemandBatchResult[];
118
- }
118
+ };
package/demand-types.d.ts CHANGED
@@ -15,7 +15,7 @@
15
15
  import type { ProductId, VariantId } from "./identifiers.js";
16
16
  import type { CompanionDemand, DemandMomentum, DemandQuarter, OpenEnum } from "./types.js";
17
17
  /** A resolved seed material (identity block shared by the demand reads). */
18
- export interface DemandSeed {
18
+ export type DemandSeed = {
19
19
  /** Opaque — round-trip verbatim. */
20
20
  variantId: VariantId;
21
21
  brand: string;
@@ -25,16 +25,16 @@ export interface DemandSeed {
25
25
  imageUrl: string | null;
26
26
  brandSlug: string;
27
27
  productId: ProductId;
28
- }
28
+ };
29
29
  /** Headline demand stats for a seed: counts, quarterly series, momentum. */
30
- export interface MaterialDemandStats {
30
+ export type MaterialDemandStats = {
31
31
  specCount: number;
32
32
  projectCount: number;
33
33
  customerCount: number;
34
34
  /** Sparse — a quarter with no activity is ABSENT, not a zero row. */
35
35
  byQuarter: DemandQuarter[];
36
36
  momentum: DemandMomentum;
37
- }
37
+ };
38
38
  /**
39
39
  * `getMaterialDemand` result, passed through verbatim by the `/demand` route.
40
40
  *
@@ -42,14 +42,14 @@ export interface MaterialDemandStats {
42
42
  * the publication floor. It is never a reading of zero, and never licenses
43
43
  * "nobody specifies this".
44
44
  */
45
- export interface MaterialDemandResult {
45
+ export type MaterialDemandResult = {
46
46
  found: boolean;
47
47
  query: string;
48
48
  seed: DemandSeed | null;
49
49
  /** The only window v1 serves. Activity outside it is unread, not absent. */
50
50
  window: "trailing_36mo";
51
51
  demand: MaterialDemandStats | null;
52
- }
52
+ };
53
53
  /**
54
54
  * `getCoSpecifiedMaterials` result, passed through verbatim. The `companions`
55
55
  * list (materials specified alongside the seed) is included but left loosely
@@ -59,7 +59,7 @@ export interface MaterialDemandResult {
59
59
  * phrase matched several materials and `seedAlternatives` holds them — pick one
60
60
  * and re-ask by `variantId` rather than treating the first as the answer.
61
61
  */
62
- export interface CoSpecifiedResult {
62
+ export type CoSpecifiedResult = {
63
63
  found: boolean;
64
64
  resolution: OpenEnum<"resolved" | "ambiguous" | "not_found">;
65
65
  query: string;
@@ -67,25 +67,25 @@ export interface CoSpecifiedResult {
67
67
  seedCategory: string | null;
68
68
  seedAlternatives: DemandSeed[];
69
69
  companions?: unknown[];
70
- }
70
+ };
71
71
  /** The `/api/v1/demand` envelope — both domain reads side by side, verbatim. */
72
- export interface DemandResponse {
72
+ export type DemandResponse = {
73
73
  query: string;
74
74
  demand: MaterialDemandResult;
75
75
  cospec: CoSpecifiedResult;
76
- }
76
+ };
77
77
  /** Seed a demand read by EXACTLY ONE of `variantId` or `material`. */
78
- export interface DemandParams {
78
+ export type DemandParams = {
79
79
  /** An exact variant id. Opaque — pass through verbatim. */
80
80
  variantId?: VariantId;
81
81
  /** Free text ("Brand Product Colour"), resolved server-side. May be ambiguous. */
82
82
  material?: string;
83
- }
84
- export interface CoordinateSeed extends DemandSeed {
83
+ };
84
+ export type CoordinateSeed = {
85
85
  /** The input reference this seed resolved from. */
86
86
  resolvedFrom: string;
87
- }
88
- export interface CoordinateCompanion {
87
+ } & DemandSeed;
88
+ export type CoordinateCompanion = {
89
89
  /** Opaque — round-trip verbatim. */
90
90
  variantId: VariantId;
91
91
  brand: string;
@@ -118,37 +118,37 @@ export interface CoordinateCompanion {
118
118
  totalLift: number;
119
119
  liftLabel: string;
120
120
  seedMatchCount: number;
121
- seedContributions: Array<{
121
+ seedContributions: {
122
122
  seedVariantId: VariantId;
123
123
  lift: number;
124
- }>;
124
+ }[];
125
125
  demand: CompanionDemand | null;
126
- swatches: Array<{
126
+ swatches: {
127
127
  hex: string;
128
128
  proportion: number;
129
- }>;
129
+ }[];
130
130
  /** Annotate-only appearance similarity — never reorders companions in v1. */
131
131
  colourFit: number | null;
132
- }
132
+ };
133
133
  /**
134
134
  * The `POST /api/v1/pairings/coordinate` envelope. `unresolved` lists the input
135
135
  * references that matched nothing — read it before presenting `companions` as
136
136
  * "what goes with your palette", because a companion set derived from two of
137
137
  * four seeds is a different claim.
138
138
  */
139
- export interface CoordinateResponse {
139
+ export type CoordinateResponse = {
140
140
  seeds: CoordinateSeed[];
141
141
  /** Input references that resolved to no material. Never silently dropped. */
142
142
  unresolved: string[];
143
143
  window: "trailing_36mo";
144
144
  companions: CoordinateCompanion[];
145
- }
145
+ };
146
146
  /** Body for `POST /api/v1/pairings/coordinate`. */
147
- export interface CoordinateInput {
147
+ export type CoordinateInput = {
148
148
  /** Free-text material references, resolved server-side; misses land in `unresolved`. */
149
149
  materials?: string[];
150
150
  /** Exact variant ids. Opaque — pass through verbatim. */
151
151
  variantIds?: VariantId[];
152
152
  projectType?: string;
153
153
  limit?: number;
154
- }
154
+ };
package/errors.d.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  export type MaterialGraphErrorKind = "problem" | "simple" | "network" | "timeout" | "aborted" | "rate_limited" | "unexpected";
3
3
  export type SanitizedErrorValue = null | boolean | number | string | SanitizedErrorValue[] | SanitizedIssue;
4
4
  /** A bounded, recursively sanitized validation-issue record. */
5
- export interface SanitizedIssue {
5
+ export type SanitizedIssue = {
6
6
  [key: string]: SanitizedErrorValue;
7
- }
7
+ };
8
8
  /** Normalized RFC 7807 body. Unknown response fields are intentionally discarded. */
9
9
  export interface ProblemDetail {
10
10
  type: string;
@@ -25,22 +25,22 @@ export interface ProblemDetail {
25
25
  readonly [extension: string]: unknown;
26
26
  }
27
27
  /** Normalized residual `{ error }` body. Unknown response fields are discarded. */
28
- export interface SimpleErrorBody {
28
+ export type SimpleErrorBody = {
29
29
  error: string;
30
30
  issues?: SanitizedIssue[];
31
- }
31
+ };
32
32
  /** Parsed `X-RateLimit-*` / `Retry-After` headers. `null` means absent. */
33
- export interface RateLimit {
33
+ export type RateLimit = {
34
34
  limit: number | null;
35
35
  remaining: number | null;
36
36
  reset: number | null;
37
37
  retryAfter: number | null;
38
- }
39
- export interface MaterialGraphRequestMetadata {
38
+ };
39
+ export type MaterialGraphRequestMetadata = {
40
40
  method: string;
41
41
  origin: string;
42
42
  path: string;
43
- }
43
+ };
44
44
  export interface MaterialGraphErrorInit {
45
45
  kind: MaterialGraphErrorKind;
46
46
  status?: number;
@@ -55,18 +55,18 @@ export interface MaterialGraphErrorInit {
55
55
  /** Accepted for compatibility but deliberately never retained on the public error. */
56
56
  cause?: unknown;
57
57
  }
58
- interface ResponseErrorInput extends MaterialGraphRequestMetadata {
58
+ type ResponseErrorInput = {
59
59
  status: number;
60
60
  body: unknown;
61
61
  responseText: string;
62
62
  rateLimit: RateLimit | null;
63
63
  apiKey: string;
64
64
  queryValues: readonly string[];
65
- }
66
- interface TransportErrorInput extends MaterialGraphRequestMetadata {
65
+ } & MaterialGraphRequestMetadata;
66
+ type TransportErrorInput = {
67
67
  cause: unknown;
68
68
  callerSignal?: AbortSignal;
69
- }
69
+ } & MaterialGraphRequestMetadata;
70
70
  /**
71
71
  * MaterialGraph's documented problem EXTENSION members — the only non-standard
72
72
  * keys this client retains.
package/errors.js CHANGED
@@ -43,38 +43,36 @@ const PROBLEM_EXTENSION_KEYS = new Set(MATERIALGRAPH_PROBLEM_EXTENSIONS);
43
43
  const MAX_UNEXPECTED_TEXT = 768;
44
44
  const MAX_EXTENSION_DEPTH = 8;
45
45
  const MAX_EXTENSION_ITEMS = 100;
46
- const MAX_EXTENSION_STRING = 1_024;
47
- function isRecord(value) {
48
- return typeof value === "object" && value !== null;
49
- }
50
- function redact(text, secrets) {
51
- return secrets.reduce((sanitized, secret) => {
52
- if (secret.length === 0)
53
- return sanitized;
54
- return sanitized.split(secret).join("[REDACTED]");
55
- }, text);
56
- }
57
- function safeString(text, secrets) {
58
- return redact(text, secrets).slice(0, MAX_EXTENSION_STRING);
59
- }
60
- function secretVariants(apiKey, queryValues) {
61
- return [
62
- apiKey,
63
- ...queryValues,
64
- ...queryValues.map(encodeURIComponent),
65
- ...queryValues.map((value) => new URLSearchParams([["value", value]]).toString().slice("value=".length)),
66
- ];
67
- }
68
- function requestMetadata(input) {
69
- return { method: input.method, origin: input.origin, path: input.path };
70
- }
46
+ const MAX_EXTENSION_STRING = 1024;
47
+ const isRecord = (value) => typeof value === "object" && value !== null;
48
+ const redact = (text, secrets) => secrets.reduce((sanitized, secret) => {
49
+ if (secret.length === 0) {
50
+ return sanitized;
51
+ }
52
+ return sanitized.split(secret).join("[REDACTED]");
53
+ }, text);
54
+ const safeString = (text, secrets) => redact(text, secrets).slice(0, MAX_EXTENSION_STRING);
55
+ const secretVariants = (apiKey, queryValues) => [
56
+ apiKey,
57
+ ...queryValues,
58
+ ...queryValues.map(encodeURIComponent),
59
+ ...queryValues.map((value) => new URLSearchParams([["value", value]]).toString().slice("value=".length)),
60
+ ];
61
+ const requestMetadata = (input) => ({
62
+ method: input.method,
63
+ origin: input.origin,
64
+ path: input.path,
65
+ });
71
66
  function sanitizeValue(value, secrets, depth = 0) {
72
- if (depth >= MAX_EXTENSION_DEPTH)
67
+ if (depth >= MAX_EXTENSION_DEPTH) {
73
68
  return undefined;
74
- if (value === null || typeof value === "boolean")
69
+ }
70
+ if (value === null || typeof value === "boolean") {
75
71
  return value;
76
- if (typeof value === "number")
72
+ }
73
+ if (typeof value === "number") {
77
74
  return Number.isFinite(value) ? value : undefined;
75
+ }
78
76
  if (typeof value === "string") {
79
77
  return safeString(value, secrets);
80
78
  }
@@ -84,8 +82,9 @@ function sanitizeValue(value, secrets, depth = 0) {
84
82
  .map((item) => sanitizeValue(item, secrets, depth + 1))
85
83
  .filter((item) => item !== undefined);
86
84
  }
87
- if (!isRecord(value))
85
+ if (!isRecord(value)) {
88
86
  return undefined;
87
+ }
89
88
  return sanitizeRecord(value, secrets, depth);
90
89
  }
91
90
  function sanitizeRecord(value, secrets, depth) {
@@ -99,15 +98,16 @@ function sanitizeRecord(value, secrets, depth) {
99
98
  });
100
99
  return Object.fromEntries(entries);
101
100
  }
102
- function sanitizeIssues(value, secrets) {
103
- if (!Array.isArray(value))
101
+ const sanitizeIssues = (value, secrets) => {
102
+ if (!Array.isArray(value)) {
104
103
  return undefined;
104
+ }
105
105
  return value
106
106
  .slice(0, MAX_EXTENSION_ITEMS)
107
107
  .filter((issue) => isRecord(issue) && !Array.isArray(issue))
108
108
  .map((issue) => sanitizeRecord(issue, secrets, 0));
109
- }
110
- function sanitizeSuggestions(value, secrets) {
109
+ };
110
+ const sanitizeSuggestions = (value, secrets) => {
111
111
  if (!Array.isArray(value) ||
112
112
  value.some((suggestion) => typeof suggestion !== "string")) {
113
113
  return undefined;
@@ -115,8 +115,8 @@ function sanitizeSuggestions(value, secrets) {
115
115
  return value
116
116
  .slice(0, MAX_EXTENSION_ITEMS)
117
117
  .map((suggestion) => safeString(suggestion, secrets));
118
- }
119
- function normalizeProblem(body, secrets) {
118
+ };
119
+ const normalizeProblem = (body, secrets) => {
120
120
  if (!isRecord(body) ||
121
121
  typeof body.type !== "string" ||
122
122
  typeof body.title !== "string" ||
@@ -150,24 +150,25 @@ function normalizeProblem(body, secrets) {
150
150
  : {}),
151
151
  ...(issues === undefined ? {} : { issues }),
152
152
  };
153
- }
154
- function normalizeSimple(body, secrets) {
155
- if (!isRecord(body) || typeof body.error !== "string")
153
+ };
154
+ const normalizeSimple = (body, secrets) => {
155
+ if (!isRecord(body) || typeof body.error !== "string") {
156
156
  return undefined;
157
+ }
157
158
  const issues = sanitizeIssues(body.issues, secrets);
158
159
  return {
159
160
  error: safeString(body.error, secrets),
160
161
  ...(issues === undefined ? {} : { issues }),
161
162
  };
162
- }
163
- function unexpectedMessage(status, responseText, secrets) {
163
+ };
164
+ const unexpectedMessage = (status, responseText, secrets) => {
164
165
  const sanitized = redact(responseText, secrets)
165
166
  .trim()
166
167
  .slice(0, MAX_UNEXPECTED_TEXT);
167
168
  return sanitized.length > 0
168
169
  ? `MaterialGraph request failed with HTTP ${status}: ${sanitized}`
169
170
  : `MaterialGraph request failed with HTTP ${status}`;
170
- }
171
+ };
171
172
  /** The one error class thrown by all SDK transport and HTTP failures. */
172
173
  export class MaterialGraphError extends Error {
173
174
  kind;
@@ -237,42 +238,42 @@ export class MaterialGraphError extends Error {
237
238
  simple?.error ??
238
239
  "MaterialGraph rate limit exceeded (429)", {
239
240
  ...metadata,
240
- status: input.status,
241
- rateLimit: input.rateLimit,
242
241
  kind: "rate_limited",
243
- retriable: false,
244
- traceId: problem?.trace_id,
245
242
  problem,
243
+ rateLimit: input.rateLimit,
244
+ retriable: false,
246
245
  simple,
246
+ status: input.status,
247
+ traceId: problem?.trace_id,
247
248
  });
248
249
  }
249
250
  if (problem !== undefined) {
250
251
  return new MaterialGraphError(problem.detail || problem.title, {
251
252
  ...metadata,
252
- status: input.status,
253
- rateLimit: input.rateLimit,
254
253
  kind: "problem",
254
+ problem,
255
+ rateLimit: input.rateLimit,
255
256
  retriable: retriable || problem.is_retriable,
257
+ status: input.status,
256
258
  traceId: problem.trace_id,
257
- problem,
258
259
  });
259
260
  }
260
261
  if (simple !== undefined) {
261
262
  return new MaterialGraphError(simple.error, {
262
263
  ...metadata,
263
- status: input.status,
264
- rateLimit: input.rateLimit,
265
264
  kind: "simple",
265
+ rateLimit: input.rateLimit,
266
266
  retriable,
267
267
  simple,
268
+ status: input.status,
268
269
  });
269
270
  }
270
271
  return new MaterialGraphError(unexpectedMessage(input.status, input.responseText, secrets), {
271
272
  ...metadata,
272
273
  kind: "unexpected",
273
- status: input.status,
274
- retriable,
275
274
  rateLimit: input.rateLimit,
275
+ retriable,
276
+ status: input.status,
276
277
  });
277
278
  }
278
279
  }