@instruments/materialgraph 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/association-types.d.ts +38 -27
  2. package/associations-client.d.ts +4 -4
  3. package/associations-client.js +3 -10
  4. package/attribution-types.d.ts +4 -4
  5. package/brand-types.d.ts +14 -6
  6. package/brands-client.d.ts +7 -38
  7. package/brands-client.js +10 -40
  8. package/by-colour-types.d.ts +58 -31
  9. package/by-spec-types.d.ts +6 -73
  10. package/by-spec-types.js +7 -5
  11. package/catalog-discovery-types.d.ts +11 -26
  12. package/catalogue-client.d.ts +16 -35
  13. package/catalogue-client.js +32 -67
  14. package/catalogue-types.d.ts +44 -4
  15. package/categories-client.d.ts +63 -0
  16. package/categories-client.js +48 -0
  17. package/category-types.d.ts +114 -0
  18. package/citation-types.d.ts +4 -4
  19. package/client-config.d.ts +4 -6
  20. package/client-config.js +2 -4
  21. package/client-source-material-comments.d.ts +4 -4
  22. package/client-source-material-comments.js +4 -38
  23. package/client-vocabulary.d.ts +7 -9
  24. package/client-vocabulary.js +22 -30
  25. package/client.d.ts +110 -244
  26. package/client.js +217 -387
  27. package/codes-client.d.ts +2 -2
  28. package/codes-client.js +8 -8
  29. package/codes-types.d.ts +55 -34
  30. package/colour-aggregate-types.d.ts +24 -24
  31. package/colours-client.d.ts +6 -11
  32. package/colours-client.js +11 -19
  33. package/coordinate-client.d.ts +2 -2
  34. package/coordinate-client.js +1 -13
  35. package/corpus-scope-types.d.ts +3 -3
  36. package/corpus-scope-types.js +1 -25
  37. package/demand-batch-types.d.ts +18 -18
  38. package/demand-types.d.ts +24 -24
  39. package/errors.d.ts +13 -13
  40. package/errors.js +54 -52
  41. package/http-transport.d.ts +13 -21
  42. package/http-transport.js +31 -28
  43. package/identify-types.d.ts +54 -44
  44. package/identify-types.js +5 -3
  45. package/index.d.ts +11 -27
  46. package/index.js +4 -6
  47. package/list-variant-facets-types.d.ts +60 -0
  48. package/list-variants-types.d.ts +142 -0
  49. package/list-variants-types.js +12 -0
  50. package/match-stream-types.d.ts +45 -32
  51. package/match-stream-types.js +2 -0
  52. package/match-stream.d.ts +2 -2
  53. package/match-stream.js +67 -49
  54. package/match-types.d.ts +32 -8
  55. package/material-asset-types.d.ts +89 -69
  56. package/material-block-types.d.ts +8 -6
  57. package/material-composition-client.d.ts +21 -0
  58. package/material-composition-client.js +13 -0
  59. package/material-composition-types.d.ts +403 -0
  60. package/material-query-plan-types.d.ts +61 -145
  61. package/material-resources-client.d.ts +12 -10
  62. package/material-resources-client.js +27 -22
  63. package/material-types.d.ts +16 -24
  64. package/ndjson.js +16 -8
  65. package/operations.d.ts +6 -6
  66. package/operations.js +29 -156
  67. package/package.json +5 -1
  68. package/palette-search-types.d.ts +87 -52
  69. package/query-understanding-types.d.ts +65 -40
  70. package/resolve-client.d.ts +8 -12
  71. package/resolve-client.js +9 -13
  72. package/resolve-colour-types.d.ts +8 -8
  73. package/resolve-types.d.ts +10 -10
  74. package/response-schemas.d.ts +20 -0
  75. package/response-schemas.generated.d.ts +5 -0
  76. package/response-schemas.generated.js +160 -0
  77. package/response-schemas.js +113 -0
  78. package/run-types.d.ts +64 -145
  79. package/runs.d.ts +9 -58
  80. package/runs.js +60 -149
  81. package/samplize-catalogue-types.d.ts +18 -18
  82. package/samplize-colorvec.d.ts +20 -20
  83. package/samplize-colorvec.js +66 -42
  84. package/schema-resource-types.d.ts +52 -39
  85. package/schema-resource-types.js +5 -5
  86. package/search-card-types.d.ts +26 -4
  87. package/search-index-plan-types.d.ts +70 -0
  88. package/search-refinement-types.d.ts +10 -40
  89. package/search-refinement-types.js +1 -0
  90. package/search-request-types.d.ts +121 -204
  91. package/search-response-receipt-types.d.ts +13 -253
  92. package/search-response-types.d.ts +2 -2
  93. package/search-result-validation.d.ts +3 -19
  94. package/search-result-validation.js +42 -183
  95. package/source-material-validation.d.ts +3 -3
  96. package/source-material-validation.js +35 -39
  97. package/spec-facet-types.d.ts +11 -16
  98. package/spec-types.d.ts +23 -16
  99. package/spec-types.js +8 -7
  100. package/specifications.d.ts +14 -72
  101. package/specifications.js +39 -89
  102. package/sse.d.ts +2 -2
  103. package/sse.js +32 -16
  104. package/substitute-types.d.ts +22 -22
  105. package/suggest-types.d.ts +11 -17
  106. package/suggest-types.js +3 -3
  107. package/taxonomy-coverage-types.d.ts +8 -8
  108. package/types.d.ts +202 -405
  109. package/validation.d.ts +26 -26
  110. package/validation.js +97 -92
  111. package/webmcp.d.ts +3 -3
  112. package/webmcp.generated.js +10 -93
  113. package/brand-most-sampled-types.d.ts +0 -33
  114. package/browse-types.d.ts +0 -236
  115. package/client-browse.d.ts +0 -78
  116. package/client-browse.js +0 -72
  117. package/client-exploration.d.ts +0 -9
  118. package/client-exploration.js +0 -7
  119. package/compare-types.d.ts +0 -89
  120. package/composition-client.d.ts +0 -33
  121. package/composition-client.js +0 -27
  122. package/composition-types.d.ts +0 -455
  123. package/composition-types.js +0 -10
  124. package/correction-types.d.ts +0 -88
  125. package/exploration-types.d.ts +0 -118
  126. package/exploration-types.js +0 -1
  127. package/fan-deck-types.d.ts +0 -42
  128. package/fan-deck-types.js +0 -9
  129. package/match-rejection-types.d.ts +0 -43
  130. package/match-rejection-types.js +0 -7
  131. package/palette-completion-types.d.ts +0 -115
  132. package/palette-completion-types.js +0 -1
  133. package/project-types.d.ts +0 -79
  134. package/project-types.js +0 -9
  135. package/projects.d.ts +0 -13
  136. package/projects.js +0 -46
  137. package/render-assets-types.d.ts +0 -65
  138. package/render-assets-types.js +0 -1
  139. package/run-events.d.ts +0 -106
  140. package/run-events.js +0 -32
  141. package/schedule-reference-types.d.ts +0 -46
  142. package/schedule-reference-types.js +0 -1
  143. package/schedule-references-client.d.ts +0 -14
  144. package/schedule-references-client.js +0 -26
  145. package/schedule-types.d.ts +0 -261
  146. package/schedule-types.js +0 -1
  147. package/search-collapse-types.d.ts +0 -69
  148. package/search-collapse-types.js +0 -1
  149. package/search-mood-types.d.ts +0 -6
  150. package/search-mood-types.js +0 -1
  151. package/search-window-types.d.ts +0 -25
  152. package/search-window-types.js +0 -1
  153. package/slot-pool-types.d.ts +0 -372
  154. package/slot-pool-types.js +0 -1
  155. /package/{brand-most-sampled-types.js → category-types.js} +0 -0
  156. /package/{browse-types.js → list-variant-facets-types.js} +0 -0
  157. /package/{compare-types.js → material-composition-types.js} +0 -0
  158. /package/{correction-types.js → search-index-plan-types.js} +0 -0
@@ -3,43 +3,54 @@ export const SAMPLIZE_COLORVEC_RANKING_VERSION = "solid-colorvec-cosine-v2";
3
3
  export const SAMPLIZE_COLORVEC_EMBEDDING_VERSION = EMBEDDING_VERSION;
4
4
  const decodeVector = (encoded) => {
5
5
  const bytes = Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0));
6
- if (bytes.length !== EMBEDDING_VECTOR_SIZE * 4)
6
+ if (bytes.length !== EMBEDDING_VECTOR_SIZE * 4) {
7
7
  throw new Error("Invalid colour vector size.");
8
+ }
8
9
  const view = new DataView(bytes.buffer);
9
10
  return Array.from({ length: EMBEDDING_VECTOR_SIZE }, (_, i) => view.getFloat32(i * 4, true));
10
11
  };
11
12
  const facets = ["brand", "family", "lightness", "intensity"];
12
13
  const identityOrder = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
13
14
  export const samplizeSolidColorVector = (hex) => {
14
- if (!/^#[0-9a-f]{6}$/i.test(hex))
15
+ if (!/^#[0-9a-f]{6}$/i.test(hex)) {
15
16
  throw new Error("A six-digit published colour is required.");
17
+ }
16
18
  return paletteToEmbedding([{ hex, proportion: 1 }], { validateOklab: true });
17
19
  };
18
20
  /** Canonical constraints are shared by full-cache similarity and constrained text retrieval. */
19
- export function selectSamplizeEligiblePaints(paints, input) {
21
+ export const selectSamplizeEligiblePaints = (paints, input) => {
20
22
  const reference = input.reference
21
23
  ? paints.find((p) => p.variantId === input.reference)
22
24
  : undefined;
23
- if (input.reference && !reference)
25
+ if (input.reference && !reference) {
24
26
  throw new Error("The reference is absent from this catalogue version.");
25
- const low = input.lightnessMin ?? 0, high = input.lightnessMax ?? 1;
26
- const cool = input.temperatureMin ?? -0.4, warm = input.temperatureMax ?? 0.4;
27
+ }
28
+ const low = input.lightnessMin ?? 0;
29
+ const high = input.lightnessMax ?? 1;
30
+ const cool = input.temperatureMin ?? -0.4;
31
+ const warm = input.temperatureMax ?? 0.4;
27
32
  if (![low, high, cool, warm].every(Number.isFinite) ||
28
33
  low > high ||
29
- cool > warm)
34
+ cool > warm) {
30
35
  throw new Error("Appearance ranges must be finite and ordered.");
36
+ }
31
37
  const candidates = paints.filter((p) => {
32
- if (!reference)
38
+ if (!reference) {
33
39
  return true;
34
- if (p.variantId === reference.variantId)
40
+ }
41
+ if (p.variantId === reference.variantId) {
35
42
  return false;
36
- if (input.direction === "lighter")
43
+ }
44
+ if (input.direction === "lighter") {
37
45
  return p.oklab.L > reference.oklab.L;
38
- if (input.direction === "darker")
46
+ }
47
+ if (input.direction === "darker") {
39
48
  return p.oklab.L < reference.oklab.L;
40
- if (input.direction === "muted")
49
+ }
50
+ if (input.direction === "muted") {
41
51
  return (Math.hypot(p.oklab.a, p.oklab.b) <
42
52
  Math.hypot(reference.oklab.a, reference.oklab.b));
53
+ }
43
54
  return true;
44
55
  });
45
56
  const matches = (p, omit) => p.oklab.L >= low &&
@@ -50,25 +61,30 @@ export function selectSamplizeEligiblePaints(paints, input) {
50
61
  const counts = {
51
62
  brand: {},
52
63
  family: {},
53
- lightness: {},
54
64
  intensity: {},
65
+ lightness: {},
55
66
  };
56
- for (const p of candidates)
57
- for (const f of facets)
58
- if (matches(p, f))
67
+ for (const p of candidates) {
68
+ for (const f of facets) {
69
+ if (matches(p, f)) {
59
70
  counts[f][p[f]] = (counts[f][p[f]] ?? 0) + 1;
71
+ }
72
+ }
73
+ }
60
74
  const eligible = candidates.filter((p) => matches(p));
61
- return { reference, eligible, counts };
62
- }
75
+ return { counts, eligible, reference };
76
+ };
63
77
  /** Official portable MG ranking over its complete versioned sampling-channel projection. */
64
- export function createSamplizeColorVecIndex(cache) {
78
+ export const createSamplizeColorVecIndex = (cache) => {
65
79
  if (cache.embeddingVersion !== EMBEDDING_VERSION ||
66
- cache.rankingVersion !== SAMPLIZE_COLORVEC_RANKING_VERSION)
80
+ cache.rankingVersion !== SAMPLIZE_COLORVEC_RANKING_VERSION) {
67
81
  throw new Error("The colour cache uses an incompatible embedding or ranking version. Refresh it before searching.");
82
+ }
68
83
  if (!cache.sourceVersion ||
69
84
  !cache.dictionaryVersion ||
70
- !Number.isFinite(Date.parse(cache.generatedAt)))
85
+ !Number.isFinite(Date.parse(cache.generatedAt))) {
71
86
  throw new Error("The colour cache is missing its provenance.");
87
+ }
72
88
  const paints = cache.paints.map((p) => ({
73
89
  ...p,
74
90
  vector: typeof p.vector === "string" ? decodeVector(p.vector) : p.vector,
@@ -78,8 +94,9 @@ export function createSamplizeColorVecIndex(cache) {
78
94
  if (identities.has(paint.variantId) ||
79
95
  paint.vector.length !== EMBEDDING_VECTOR_SIZE ||
80
96
  !paint.vector.every(Number.isFinite) ||
81
- ![paint.oklab.L, paint.oklab.a, paint.oklab.b].every(Number.isFinite))
97
+ ![paint.oklab.L, paint.oklab.a, paint.oklab.b].every(Number.isFinite)) {
82
98
  throw new Error("The colour cache contains invalid or duplicate paint records.");
99
+ }
83
100
  identities.add(paint.variantId);
84
101
  }
85
102
  const vectors = new Map();
@@ -88,8 +105,9 @@ export function createSamplizeColorVecIndex(cache) {
88
105
  let value = vectors.get(key);
89
106
  if (!value) {
90
107
  value = samplizeSolidColorVector(hex);
91
- if (vectors.size >= 512)
108
+ if (vectors.size >= 512) {
92
109
  vectors.delete(vectors.keys().next().value);
110
+ }
93
111
  vectors.set(key, value);
94
112
  }
95
113
  return value;
@@ -97,36 +115,42 @@ export function createSamplizeColorVecIndex(cache) {
97
115
  return {
98
116
  search(input) {
99
117
  const limit = input.limit ?? 48;
100
- if (!Number.isInteger(limit) || limit < 1 || limit > 100)
118
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
101
119
  throw new Error("Choose between 1 and 100 suggestions.");
120
+ }
102
121
  const { reference, eligible, counts } = selectSamplizeEligiblePaints(paints, input);
103
122
  const palette = (input.palette?.length
104
123
  ? input.palette
105
124
  : [{ hex: input.hex ?? reference?.hex ?? "", proportion: 1 }])
106
125
  .map((p) => ({ ...p, hex: p.hex.toLowerCase() }))
107
- .sort((a, b) => b.proportion - a.proportion || identityOrder(a.hex, b.hex));
126
+ .toSorted((a, b) => b.proportion - a.proportion || identityOrder(a.hex, b.hex));
108
127
  if (palette.length > 12 ||
109
128
  palette.some((p) => !Number.isFinite(p.proportion) ||
110
129
  p.proportion <= 0 ||
111
- p.proportion > 1))
130
+ p.proportion > 1)) {
112
131
  throw new Error("Supply up to twelve positive image colour shares.");
132
+ }
113
133
  const total = palette.reduce((sum, p) => sum + p.proportion, 0);
114
134
  const buckets = palette.map((p, position) => ({
115
135
  ...p,
136
+ paints: [],
116
137
  position,
117
- vector: vectorFor(p.hex),
118
138
  quota: Math.floor((limit * p.proportion) / total),
119
139
  remainder: ((limit * p.proportion) / total) % 1,
120
- paints: [],
140
+ vector: vectorFor(p.hex),
121
141
  }));
122
142
  let remaining = limit - buckets.reduce((sum, p) => sum + p.quota, 0);
123
- for (const p of [...buckets].sort((a, b) => b.remainder - a.remainder || a.position - b.position))
124
- if (remaining-- > 0)
143
+ for (const p of [...buckets].toSorted((a, b) => b.remainder - a.remainder || a.position - b.position)) {
144
+ if (remaining-- > 0) {
125
145
  p.quota++;
146
+ }
147
+ }
126
148
  for (const paint of eligible) {
127
- let best = buckets[0], score = embeddingCosineSimilarity(paint.vector, best.vector);
149
+ let best = buckets[0];
150
+ let score = embeddingCosineSimilarity(paint.vector, best.vector);
128
151
  for (let i = 1; i < buckets.length; i++) {
129
- const candidate = buckets[i], next = embeddingCosineSimilarity(paint.vector, candidate.vector);
152
+ const candidate = buckets[i];
153
+ const next = embeddingCosineSimilarity(paint.vector, candidate.vector);
130
154
  if (next > score) {
131
155
  best = candidate;
132
156
  score = next;
@@ -135,33 +159,33 @@ export function createSamplizeColorVecIndex(cache) {
135
159
  best.paints.push({ id: paint.variantId, score });
136
160
  }
137
161
  const groups = buckets
138
- .sort((a, b) => b.proportion - a.proportion || a.position - b.position)
162
+ .toSorted((a, b) => b.proportion - a.proportion || a.position - b.position)
139
163
  .map((p) => {
140
164
  const ids = p.paints
141
- .sort((a, b) => b.score - a.score || identityOrder(a.id, b.id))
165
+ .toSorted((a, b) => b.score - a.score || identityOrder(a.id, b.id))
142
166
  .slice(0, p.quota)
143
167
  .map((paint) => paint.id);
144
168
  return {
145
169
  hex: p.hex,
170
+ ids,
146
171
  proportion: p.proportion,
147
172
  quota: p.quota,
148
- ids,
149
173
  shortfall: p.quota - ids.length,
150
174
  };
151
175
  });
152
176
  const ids = groups.flatMap((p) => p.ids);
153
177
  return {
154
- ids,
155
- groups,
156
- limited: eligible.length > ids.length,
157
- eligibleCount: eligible.length,
178
+ countBasis: "complete-catalogue",
158
179
  counts,
159
- sourceVersion: cache.sourceVersion,
160
180
  dictionaryVersion: cache.dictionaryVersion,
181
+ eligibleCount: eligible.length,
161
182
  embeddingVersion: cache.embeddingVersion,
183
+ groups,
184
+ ids,
185
+ limited: eligible.length > ids.length,
162
186
  rankingVersion: cache.rankingVersion,
163
- countBasis: "complete-catalogue",
187
+ sourceVersion: cache.sourceVersion,
164
188
  };
165
189
  },
166
190
  };
167
- }
191
+ };
@@ -8,40 +8,46 @@ export type SchemaResource = "blocks" | "attributes" | "verticals" | "productTyp
8
8
  * it must cover cannot drift apart.
9
9
  */
10
10
  export declare const SCHEMA_RESOURCE_OPERATION_IDS: {
11
- readonly blocks: "list_schema_blocks";
12
11
  readonly attributes: "list_schema_attributes";
13
- readonly verticals: "list_schema_verticals";
12
+ readonly blocks: "list_schema_blocks";
13
+ readonly mappings: "list_schema_mappings";
14
+ readonly productTypeTemplates: "list_schema_product_type_templates";
14
15
  readonly productTypes: "list_schema_product_types";
16
+ readonly sourceRequirements: "list_schema_source_requirements";
15
17
  readonly units: "list_schema_units";
16
18
  readonly valueDictionaries: "list_schema_value_dictionaries";
17
- readonly sourceRequirements: "list_schema_source_requirements";
18
- readonly productTypeTemplates: "list_schema_product_type_templates";
19
- readonly mappings: "list_schema_mappings";
19
+ readonly verticals: "list_schema_verticals";
20
20
  };
21
21
  export type SchemaResourceRequest = SchemaResource;
22
- export interface SchemaLifecycle {
22
+ export type SchemaLifecycle = {
23
23
  status: OpenEnum<"draft" | "active" | "deprecated">;
24
24
  introducedIn: string;
25
25
  deprecatedIn?: string;
26
26
  supersededBy?: string;
27
- }
28
- export interface SchemaExternalMapping {
27
+ };
28
+ export type SchemaExternalMapping = {
29
29
  target: OpenEnum<"schema_org" | "ifc_pset" | "bsdd" | "iso_23387" | "eclass" | "gs1_gdm" | "gdsn" | "etim" | "uniclass">;
30
30
  targetPath: string;
31
31
  mappingType: OpenEnum<"direct" | "transform" | "derived" | "classification" | "semantic">;
32
+ /**
33
+ * SKOS mapping strength, read from the MaterialGraph side. Only `exact`
34
+ * licenses substituting one concept for the other.
35
+ */
36
+ matchStrength?: SchemaMatchStrength;
32
37
  notes?: string;
33
- }
34
- export interface SchemaBlockItem {
38
+ };
39
+ export type SchemaMatchStrength = OpenEnum<"exact" | "close" | "broad" | "narrow" | "related">;
40
+ export type SchemaBlockItem = {
35
41
  id: string;
36
42
  semanticId: string;
37
43
  lifecycle: SchemaLifecycle;
38
44
  name: string;
39
45
  description: string;
40
46
  attributeIds: string[];
41
- }
42
- export type KnownSchemaQuantityKind = "length" | "area" | "volume" | "mass" | "time" | "temperature" | "currency" | "ratio" | "density" | "coverage" | "emissions" | "force" | "power" | "voltage" | "current" | "frequency" | "luminous_flux" | "color_temperature" | "count" | "unitless";
47
+ };
48
+ export type KnownSchemaQuantityKind = "length" | "area" | "volume" | "mass" | "time" | "temperature" | "currency" | "ratio" | "density" | "coverage" | "emissions" | "force" | "thermal_conductivity" | "power" | "voltage" | "current" | "frequency" | "luminous_flux" | "color_temperature" | "count" | "unitless";
43
49
  export type SchemaQuantityKind = OpenEnum<KnownSchemaQuantityKind>;
44
- export interface SchemaAttributeItem {
50
+ export type SchemaAttributeItem = {
45
51
  id: string;
46
52
  semanticId: string;
47
53
  lifecycle: SchemaLifecycle;
@@ -58,14 +64,14 @@ export interface SchemaAttributeItem {
58
64
  comparable: boolean;
59
65
  usedInBlocks: string[];
60
66
  enumValues: string[] | null;
61
- }
62
- export interface SchemaVerticalItem {
67
+ };
68
+ export type SchemaVerticalItem = {
63
69
  id: string;
64
70
  displayName: string;
65
71
  description: string;
66
- }
72
+ };
67
73
  export type SchemaApplicability = OpenEnum<"required" | "recommended" | "optional" | "unusual">;
68
- export interface SchemaProductTypeBlock {
74
+ export type SchemaProductTypeBlock = {
69
75
  blockId: string;
70
76
  applicability: SchemaApplicability;
71
77
  requiredAttributes?: string[];
@@ -74,19 +80,21 @@ export interface SchemaProductTypeBlock {
74
80
  completenessWeight?: number;
75
81
  notes?: string;
76
82
  optional?: boolean;
77
- }
78
- export interface SchemaProductTypeItem {
83
+ };
84
+ export type SchemaProductTypeItem = {
79
85
  id: string;
80
86
  name: string;
81
87
  description?: string;
88
+ /** Display names this type carried before a rename, kept so they still find it. */
89
+ formerNames?: string[];
82
90
  verticalId: string;
83
91
  parentProductTypeGroupId?: string;
84
92
  blocks: SchemaProductTypeBlock[];
85
93
  productTypeSpecificAttributes?: string[];
86
94
  semanticId: string;
87
95
  lifecycle: SchemaLifecycle;
88
- }
89
- export interface SchemaUnitItem {
96
+ };
97
+ export type SchemaUnitItem = {
90
98
  id: string;
91
99
  name: string;
92
100
  symbol: string;
@@ -97,10 +105,14 @@ export interface SchemaUnitItem {
97
105
  offset?: number;
98
106
  };
99
107
  notes?: string;
108
+ /** UN/CEFACT Rec 20 common code (schema.org `unitCode`); absent when Rec 20 has none. */
109
+ uncefactCode?: string;
110
+ /** QUDT unit IRI, where exactly one QUDT unit matches. */
111
+ qudtUnit?: string;
100
112
  semanticId: string;
101
113
  lifecycle: SchemaLifecycle;
102
- }
103
- export interface SchemaValueDictionaryTerm {
114
+ };
115
+ export type SchemaValueDictionaryTerm = {
104
116
  id: string;
105
117
  label: string;
106
118
  aliases?: string[];
@@ -108,20 +120,20 @@ export interface SchemaValueDictionaryTerm {
108
120
  externalMappings?: SchemaExternalMapping[];
109
121
  semanticId: string;
110
122
  lifecycle: SchemaLifecycle;
111
- }
112
- export interface SchemaValueDictionaryItem {
123
+ };
124
+ export type SchemaValueDictionaryItem = {
113
125
  id: string;
114
126
  name: string;
115
127
  description: string;
116
128
  terms: SchemaValueDictionaryTerm[];
117
129
  semanticId: string;
118
130
  lifecycle: SchemaLifecycle;
119
- }
131
+ };
120
132
  export type KnownSchemaSourceType = "manufacturer_page" | "technical_data_sheet" | "safety_data_sheet" | "test_report" | "certificate" | "image" | "commerce_page" | "catalog_pdf" | "derived_analysis";
121
133
  export type SchemaSourceType = OpenEnum<KnownSchemaSourceType>;
122
134
  export type KnownSchemaSourceMethod = "manual_review" | "agent_extract" | "pdf_extract" | "image_analysis" | "html_scrape" | "structured_feed" | "calculation";
123
135
  export type SchemaSourceMethod = OpenEnum<KnownSchemaSourceMethod>;
124
- export interface SchemaSourceRequirementItem {
136
+ export type SchemaSourceRequirementItem = {
125
137
  id: string;
126
138
  name: string;
127
139
  description: string;
@@ -130,11 +142,11 @@ export interface SchemaSourceRequirementItem {
130
142
  minConfidence: number;
131
143
  reviewRequired: boolean;
132
144
  freshnessDays?: number;
133
- sourceBasis?: OpenEnum<"declared" | "derived" | "declared">;
145
+ sourceBasis?: OpenEnum<"declared" | "derived">;
134
146
  semanticId: string;
135
147
  lifecycle: SchemaLifecycle;
136
- }
137
- export interface SchemaProductTypeTemplateBlock {
148
+ };
149
+ export type SchemaProductTypeTemplateBlock = {
138
150
  blockId: string;
139
151
  applicability: SchemaApplicability;
140
152
  requiredAttributes?: string[];
@@ -142,8 +154,8 @@ export interface SchemaProductTypeTemplateBlock {
142
154
  sourceRequirementId?: string;
143
155
  completenessWeight?: number;
144
156
  notes?: string;
145
- }
146
- export interface SchemaProductTypeTemplateItem {
157
+ };
158
+ export type SchemaProductTypeTemplateItem = {
147
159
  id: string;
148
160
  name: string;
149
161
  productTypeId: string;
@@ -152,17 +164,18 @@ export interface SchemaProductTypeTemplateItem {
152
164
  notes?: string;
153
165
  semanticId: string;
154
166
  lifecycle: SchemaLifecycle;
155
- }
156
- export interface SchemaMappingItem {
167
+ };
168
+ export type SchemaMappingItem = {
157
169
  target: SchemaExternalMapping["target"];
158
170
  subjectKind?: OpenEnum<"attribute" | "block" | "product_type" | "template" | "unit" | "value_dictionary" | "value_dictionary_term">;
159
171
  subjectId?: string;
160
172
  canonicalPath: string;
161
173
  targetPath: string;
162
174
  mappingType: SchemaExternalMapping["mappingType"];
175
+ matchStrength?: SchemaMatchStrength;
163
176
  notes?: string;
164
- }
165
- export interface SchemaResourceItemMap {
177
+ };
178
+ export type SchemaResourceItemMap = {
166
179
  blocks: SchemaBlockItem;
167
180
  attributes: SchemaAttributeItem;
168
181
  verticals: SchemaVerticalItem;
@@ -172,10 +185,10 @@ export interface SchemaResourceItemMap {
172
185
  sourceRequirements: SchemaSourceRequirementItem;
173
186
  productTypeTemplates: SchemaProductTypeTemplateItem;
174
187
  mappings: SchemaMappingItem;
175
- }
176
- export interface SchemaResourceResponse<K extends SchemaResource = SchemaResource> {
188
+ };
189
+ export type SchemaResourceResponse<K extends SchemaResource = SchemaResource> = {
177
190
  kind: K;
178
191
  schemaVersion: string;
179
192
  items: SchemaResourceItemMap[K][];
180
193
  totalCount: number;
181
- }
194
+ };
@@ -5,13 +5,13 @@
5
5
  * it must cover cannot drift apart.
6
6
  */
7
7
  export const SCHEMA_RESOURCE_OPERATION_IDS = {
8
- blocks: "list_schema_blocks",
9
8
  attributes: "list_schema_attributes",
10
- verticals: "list_schema_verticals",
9
+ blocks: "list_schema_blocks",
10
+ mappings: "list_schema_mappings",
11
+ productTypeTemplates: "list_schema_product_type_templates",
11
12
  productTypes: "list_schema_product_types",
13
+ sourceRequirements: "list_schema_source_requirements",
12
14
  units: "list_schema_units",
13
15
  valueDictionaries: "list_schema_value_dictionaries",
14
- sourceRequirements: "list_schema_source_requirements",
15
- productTypeTemplates: "list_schema_product_type_templates",
16
- mappings: "list_schema_mappings",
16
+ verticals: "list_schema_verticals",
17
17
  };
@@ -19,7 +19,7 @@ import type { OpenEnum, SearchData, SearchResponse } from "./types.js";
19
19
  * `variantId` at `view: "full"` or via `material()` before claiming anything the
20
20
  * card does not carry.
21
21
  */
22
- export interface SearchCardItem {
22
+ export type SearchCardItem = {
23
23
  /** Accepted sampleability fact. Absent means unknown, never false. */
24
24
  sampleable?: boolean;
25
25
  /** Opaque — round-trip verbatim. */
@@ -31,6 +31,19 @@ export interface SearchCardItem {
31
31
  name: string;
32
32
  variantName: string | null;
33
33
  imageUrl: string | null;
34
+ /**
35
+ * SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Key a
36
+ * cache or dedupe on it rather than the URL. ABSENT means no hash is on
37
+ * record, never that there is no image.
38
+ */
39
+ imageSha256?: string;
40
+ /**
41
+ * How many eligible variants the row's product has, the same set
42
+ * `listVariants` pages, so a follow-up list returns this many: the card's
43
+ * "12 colourways". ABSENT means the product is unknown or has no eligible
44
+ * variant.
45
+ */
46
+ variantCount?: number;
34
47
  /**
35
48
  * The manufacturer's own item code, the same key the full item carries.
36
49
  * Reach for it when two cards read alike: `name` is the PRODUCT name, and a
@@ -54,11 +67,20 @@ export interface SearchCardItem {
54
67
  * attribute rather than a list of candidates.
55
68
  */
56
69
  attributes?: Record<string, string | string[] | null>;
57
- }
70
+ };
58
71
  /** The `view:"card"` response form — the lean grid projection of {@link SearchResponse}. */
59
- export interface SearchCardResponse extends Omit<SearchResponse, "data"> {
72
+ export type SearchCardResponse = {
60
73
  data: Omit<SearchData, "view" | "results"> & {
61
74
  view: OpenEnum<"card">;
62
75
  results: SearchCardItem[];
63
76
  };
64
- }
77
+ } & Omit<SearchResponse, "data">;
78
+ /**
79
+ * The request forms the server answers with {@link SearchCardResponse}:
80
+ * `view: "card"`, or `intent: "typeahead"`, which forces the card view.
81
+ */
82
+ export type CardProjectionRequest = {
83
+ view: "card";
84
+ } | {
85
+ intent: "typeahead";
86
+ };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @module search-index-plan-types
3
+ * @description The plan the one search ran on, as `/search` reports it under
4
+ * `explain.plan` (ADR 0031). Mirrors `searchIndexPlanReceiptSchema` in
5
+ * `@materialgraph/products/search-index/plan-schema`; `key-parity.test.ts`
6
+ * holds the two to the same fields.
7
+ */
8
+ import type { CorpusScope } from "./corpus-scope-types.js";
9
+ /** One attribute the plan wants: its terms, or any value when `presence`. */
10
+ export type SearchIndexPlanWant = {
11
+ attributeId: string;
12
+ /** Share of the category's materials stating the attribute, 0 to 1. */
13
+ fill: number;
14
+ /** The words it was read from, or `"(filter)"` for a caller's filter. */
15
+ phrase: string;
16
+ /** Any stated value satisfies it; `terms` is then empty. */
17
+ presence?: true;
18
+ /** A hard want removes rows; a soft one only counts toward the order. */
19
+ strength: "hard" | "soft";
20
+ terms: string[];
21
+ };
22
+ /**
23
+ * The query's plan: the category, makers, wanted and excluded attribute terms,
24
+ * the colour, the words left for text, and the caller's corpus scope.
25
+ */
26
+ export type SearchIndexPlan = {
27
+ brands: {
28
+ ids: string[];
29
+ names: string[];
30
+ phrase: string;
31
+ } | null;
32
+ category: {
33
+ label: string;
34
+ phrase: string;
35
+ productTypeIds: string[];
36
+ } | null;
37
+ colour: {
38
+ family12: string[];
39
+ familyId: string;
40
+ hex: string;
41
+ oklab: [number, number, number];
42
+ phrase: string;
43
+ } | null;
44
+ /** Present only when the caller sent a scope narrower than the whole graph. */
45
+ corpusScope?: Exclude<CorpusScope, "all">;
46
+ excludeBrands: string[];
47
+ excludes: {
48
+ attributeId: string;
49
+ phrase: string;
50
+ term: string;
51
+ }[];
52
+ /** Words the reading did not place, left for the text match. */
53
+ leftover: string[];
54
+ normalised: string;
55
+ softAlone: boolean;
56
+ vendorColourNames: string[];
57
+ wants: SearchIndexPlanWant[];
58
+ };
59
+ /**
60
+ * Which reading a search ran on (`version`, `source`), whether it came from
61
+ * the cache, the plan itself, and its signature, so two runs of one request
62
+ * can be compared plan for plan.
63
+ */
64
+ export type SearchPlanReceipt = {
65
+ cached: boolean;
66
+ plan: SearchIndexPlan;
67
+ signature: string;
68
+ source: "dictionary" | "jev";
69
+ version: string;
70
+ };
@@ -1,5 +1,4 @@
1
- /** Types for structured refinements returned by MaterialGraph search. */
2
- import type { SearchInput } from "./types.js";
1
+ /** The spec-filter vocabulary MaterialGraph's filter and preference inputs share. */
3
2
  /**
4
3
  * A hard canonical-attribute filter accepted by the search engine — a term match
5
4
  * (`{ attributeId, term }`), a presence check (`{ attributeId, hasValue: true }`)
@@ -23,7 +22,7 @@ import type { SearchInput } from "./types.js";
23
22
  * of this object — without it, "no GREENGUARD results" reads as "nobody is
24
23
  * certified" when it means "nobody is certified TO THIS EVIDENTIAL STANDARD".
25
24
  */
26
- export interface SearchFilterTrust {
25
+ export type SearchFilterTrust = {
27
26
  /** Confidence floor, 0–1. A value below it is excluded, not marked failed. */
28
27
  minConfidence?: number;
29
28
  /**
@@ -45,7 +44,7 @@ export interface SearchFilterTrust {
45
44
  sourceBasis?: "catalog_feed" | "declared" | "derived";
46
45
  /** Fold the attribute's own registry confidence requirement in, server-side. */
47
46
  meetsRequirement?: true;
48
- }
47
+ };
49
48
  /**
50
49
  * One HARD criterion. Applied as a restriction BEFORE ranking, so a filtered
51
50
  * search's empty result means "nothing on record satisfies this", never "nothing
@@ -57,10 +56,16 @@ export type SearchFilter = {
57
56
  term: string;
58
57
  trust?: SearchFilterTrust;
59
58
  } | {
60
- /** Known effective values are required, and this term must be absent. */
61
59
  attributeId: string;
62
60
  excludesTerm: string;
63
61
  trust?: SearchFilterTrust;
62
+ /**
63
+ * What an UNKNOWN effective value does. Absent or `"drop"` (default)
64
+ * requires a known effective value — a variant that never states the
65
+ * attribute does not pass. `"pass"` admits it — a variant only fails by
66
+ * STATING the excluded term.
67
+ */
68
+ whenUnstated?: "drop" | "pass";
64
69
  }
65
70
  /**
66
71
  * TERM SET — the attribute must equal any ONE of these. OR within the entry;
@@ -96,38 +101,3 @@ export type SearchFilter = {
96
101
  max?: number;
97
102
  trust?: SearchFilterTrust;
98
103
  };
99
- /** One structured refinement returned with a search response. */
100
- export interface SearchSuggestion {
101
- label: string;
102
- /** Complete replacement request, not a partial patch. */
103
- request: SearchInput;
104
- }
105
- /** One reading a {@link SearchDisambiguation} offers. */
106
- export interface SearchInterpretation {
107
- id: string;
108
- label: string;
109
- kind: string;
110
- /** True for the reading that ran; all false means the engine chose none. */
111
- isDefault: boolean;
112
- /** The colour this reading resolved to, when the ambiguity was a colour one. */
113
- hex?: string;
114
- /** Complete replacement request, not a partial patch. */
115
- request: SearchInput;
116
- }
117
- /** The governed ambiguity classes emitted by MaterialGraph search. */
118
- export type SearchDisambiguationKind = "compliance-phrase" | "colour-material" | "paint-colour" | "paint-identity";
119
- /**
120
- * The server saying a query had multiple defensible readings.
121
- *
122
- * The reading that ran is flagged `isDefault`; every reading is false when the
123
- * engine deliberately chose none. Each carries a complete executable request,
124
- * so choosing a reading is a re-issue rather than a patch. Ignoring this block does not
125
- * make the ambiguity go away — it makes it invisible to the person who asked.
126
- */
127
- export interface SearchDisambiguation {
128
- /** Compliance, colour-material, paint-colour, or paint-identity ambiguity. */
129
- kind: SearchDisambiguationKind;
130
- /** The ambiguous term or phrase. */
131
- term: string;
132
- interpretations: SearchInterpretation[];
133
- }
@@ -1 +1,2 @@
1
+ /** The spec-filter vocabulary MaterialGraph's filter and preference inputs share. */
1
2
  export {};