@instruments/materialgraph 0.9.1 → 0.10.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.
package/http-transport.js CHANGED
@@ -19,7 +19,10 @@ function parseRateLimit(headers) {
19
19
  const remaining = parseIntOrNull(headers.get("x-ratelimit-remaining"));
20
20
  const reset = parseIntOrNull(headers.get("x-ratelimit-reset"));
21
21
  const retryAfter = parseIntOrNull(headers.get("retry-after"));
22
- if (limit === null && remaining === null && reset === null && retryAfter === null) {
22
+ if (limit === null &&
23
+ remaining === null &&
24
+ reset === null &&
25
+ retryAfter === null) {
23
26
  return null;
24
27
  }
25
28
  return { limit, remaining, reset, retryAfter };
@@ -39,7 +42,11 @@ export class HttpTransport {
39
42
  }
40
43
  /** The bearer + JSON `Accept` headers, plus any per-request additions. */
41
44
  authHeaders(extra) {
42
- return { Authorization: `Bearer ${this.apiKey}`, Accept: "application/json", ...extra };
45
+ return {
46
+ Authorization: `Bearer ${this.apiKey}`,
47
+ Accept: "application/json",
48
+ ...extra,
49
+ };
43
50
  }
44
51
  buildUrl(path, query) {
45
52
  const url = new URL(`${this.baseUrl}${path}`);
@@ -83,7 +90,11 @@ export class HttpTransport {
83
90
  });
84
91
  }
85
92
  catch (cause) {
86
- throw MaterialGraphError.fromTransport({ ...metadata, cause, callerSignal: input.signal });
93
+ throw MaterialGraphError.fromTransport({
94
+ ...metadata,
95
+ cause,
96
+ callerSignal: input.signal,
97
+ });
87
98
  }
88
99
  const rateLimit = parseRateLimit(response.headers);
89
100
  this.#lastRateLimit = rateLimit;
@@ -92,7 +103,11 @@ export class HttpTransport {
92
103
  text = await response.text();
93
104
  }
94
105
  catch (cause) {
95
- throw MaterialGraphError.fromTransport({ ...metadata, cause, callerSignal: input.signal });
106
+ throw MaterialGraphError.fromTransport({
107
+ ...metadata,
108
+ cause,
109
+ callerSignal: input.signal,
110
+ });
96
111
  }
97
112
  let parsed;
98
113
  if (text.length > 0) {
@@ -147,7 +162,11 @@ export class HttpTransport {
147
162
  });
148
163
  }
149
164
  catch (cause) {
150
- throw MaterialGraphError.fromTransport({ ...metadata, cause, callerSignal: options.signal });
165
+ throw MaterialGraphError.fromTransport({
166
+ ...metadata,
167
+ cause,
168
+ callerSignal: options.signal,
169
+ });
151
170
  }
152
171
  const rateLimit = parseRateLimit(response.headers);
153
172
  this.#lastRateLimit = rateLimit;
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { MaterialGraphClient, DEFAULT_BASE_URL, MAX_BATCH_IDS } from "./client.js";
1
+ export { MaterialGraphClient, DEFAULT_BASE_URL, MAX_BATCH_IDS, } from "./client.js";
2
2
  export type { MaterialGraphClientOptions, BrowseNamespace } from "./client.js";
3
3
  export { MATERIALGRAPH_API_VERSION, SDK_OPERATIONS } from "./operations.js";
4
4
  export type { SdkOperation, SdkOperationId } from "./operations.js";
@@ -27,10 +27,11 @@ export type * from "./colour-aggregate-types.js";
27
27
  export type * from "./palette-search-types.js";
28
28
  export type * from "./association-types.js";
29
29
  export type * from "./brand-types.js";
30
+ export type * from "./fan-deck-types.js";
30
31
  export type * from "./material-asset-types.js";
31
32
  export type * from "./material-block-types.js";
32
33
  export type * from "./schema-resource-types.js";
33
34
  export type * from "./search-refinement-types.js";
34
35
  export { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID } from "./spec-types.js";
35
36
  export type * from "./spec-types.js";
36
- export { certificationProgramme, certificationProgrammeCriterion, hasSpec, specCriterion, specTerm, } from "./specifications.js";
37
+ export { certificationProgramme, certificationProgrammeCriterion, hasSpec, specCriterion, specRangeCriterion, specTerm, } from "./specifications.js";
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { MaterialGraphClient, DEFAULT_BASE_URL, MAX_BATCH_IDS } from "./client.js";
1
+ export { MaterialGraphClient, DEFAULT_BASE_URL, MAX_BATCH_IDS, } from "./client.js";
2
2
  export { MATERIALGRAPH_API_VERSION, SDK_OPERATIONS } from "./operations.js";
3
3
  export { TERMINAL_RUN_EVENT_TYPES } from "./run-types.js";
4
4
  export { VARY_AXES } from "./composition-types.js";
@@ -9,4 +9,4 @@ export { MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STRE
9
9
  export { CodesClient } from "./codes-client.js";
10
10
  export { ColoursClient } from "./colours-client.js";
11
11
  export { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID } from "./spec-types.js";
12
- export { certificationProgramme, certificationProgrammeCriterion, hasSpec, specCriterion, specTerm, } from "./specifications.js";
12
+ export { certificationProgramme, certificationProgrammeCriterion, hasSpec, specCriterion, specRangeCriterion, specTerm, } from "./specifications.js";
@@ -1,3 +1,4 @@
1
+ import type { MatchCategoryInference, MatchColourReading } from "./match-types.js";
1
2
  /**
2
3
  * The Material Match PROGRESS-STREAM contracts — the wire vocabulary of
3
4
  * {@link MaterialGraphClient.matchStream} (`POST /api/v1/search/match` under
@@ -16,7 +17,6 @@
16
17
  * UI legend from the same source the validator uses.
17
18
  */
18
19
  import type { SearchResultItem } from "./types.js";
19
- import type { MatchCategoryInference, MatchColourReading } from "./match-types.js";
20
20
  /** How the workflow classified the uploaded image. */
21
21
  export declare const MATCH_IMAGE_TYPES: readonly ["swatch", "installation", "flatplan"];
22
22
  export type MatchImageType = (typeof MATCH_IMAGE_TYPES)[number];
@@ -1,5 +1,9 @@
1
1
  /** How the workflow classified the uploaded image. */
2
- export const MATCH_IMAGE_TYPES = ["swatch", "installation", "flatplan"];
2
+ export const MATCH_IMAGE_TYPES = [
3
+ "swatch",
4
+ "installation",
5
+ "flatplan",
6
+ ];
3
7
  /** What a detected surface is FOR — the element the material would serve. */
4
8
  export const MATCH_MATERIAL_FUNCTIONS = [
5
9
  "flooring",
@@ -13,7 +17,12 @@ export const MATCH_MATERIAL_FUNCTIONS = [
13
17
  "sample",
14
18
  ];
15
19
  /** The workflow's coarse progress phase, narrated by a `step` event. */
16
- export const MATCH_WORKFLOW_STEPS = ["classifying", "decomposing", "matching", "complete"];
20
+ export const MATCH_WORKFLOW_STEPS = [
21
+ "classifying",
22
+ "decomposing",
23
+ "matching",
24
+ "complete",
25
+ ];
17
26
  /**
18
27
  * Where one surface stands in the run.
19
28
  *
@@ -40,7 +49,11 @@ export const MATCH_STREAM_EVENT_TYPES = [
40
49
  "complete",
41
50
  "error",
42
51
  ];
43
- export const MATCH_SENSE_CHECK_VERDICTS = ["confirmed", "rejected", "abstained"];
52
+ export const MATCH_SENSE_CHECK_VERDICTS = [
53
+ "confirmed",
54
+ "rejected",
55
+ "abstained",
56
+ ];
44
57
  /** The terminal Match workflow result — every surface in its final state. */
45
58
  /**
46
59
  * How a Match run ended. `no_surfaces` means the detector worked and found no
package/match-stream.js CHANGED
@@ -55,16 +55,21 @@
55
55
  * invariants.
56
56
  */
57
57
  import { MaterialGraphError } from "./errors.js";
58
- import { findSdkOperation } from "./operations.js";
59
58
  import { MATCH_IMAGE_TYPES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
60
59
  import { readNdjsonLines } from "./ndjson.js";
60
+ import { findSdkOperation, } from "./operations.js";
61
61
  import { checkSearchResultItems } from "./search-result-validation.js";
62
62
  import { requireArray, requireBoundedNumber, requireDefaultedArray, requireEnum, requireIntegerAtLeast, requireNumber, requireOptionalString, requireRecord, requireString, } from "./validation.js";
63
63
  /** The NDJSON media type the Match route negotiates the scene workflow on. */
64
64
  const MATCH_STREAM_ACCEPT = "application/x-ndjson";
65
65
  /** How much of an offending frame a diagnostic quotes (crops can be megabytes). */
66
66
  const MAX_FRAME_PREVIEW = 200;
67
- const BOUNDING_BOX_CORNERS = Object.freeze(["x0", "y0", "x1", "y1"]);
67
+ const BOUNDING_BOX_CORNERS = Object.freeze([
68
+ "x0",
69
+ "y0",
70
+ "x1",
71
+ "y1",
72
+ ]);
68
73
  function operation(operationId) {
69
74
  const found = findSdkOperation(operationId);
70
75
  if (!found)
@@ -76,7 +81,9 @@ function operation(operationId) {
76
81
  * offending path and quoting a bounded slice of the frame.
77
82
  */
78
83
  function frameFailure(line) {
79
- const preview = line.length > MAX_FRAME_PREVIEW ? `${line.slice(0, MAX_FRAME_PREVIEW)}…` : line;
84
+ const preview = line.length > MAX_FRAME_PREVIEW
85
+ ? `${line.slice(0, MAX_FRAME_PREVIEW)}…`
86
+ : line;
80
87
  return (reason) => MaterialGraphError.unexpected(`MaterialGraph match stream sent a malformed NDJSON frame: ${reason}. Frame: ${preview}`);
81
88
  }
82
89
  /** Check one `MatchCategoryInference` item. */
@@ -190,7 +197,10 @@ function readFrame(value, fail) {
190
197
  // Payload-free by contract — there is nothing else to check.
191
198
  return record;
192
199
  case "complete":
193
- return { ...record, result: readWorkflowResult(record.result, "`result`", fail) };
200
+ return {
201
+ ...record,
202
+ result: readWorkflowResult(record.result, "`result`", fail),
203
+ };
194
204
  case "error":
195
205
  requireString(record.message, "`message`", fail);
196
206
  return record;
@@ -1,3 +1,4 @@
1
+ import type { ProductId, VariantId } from "./identifiers.js";
1
2
  /**
2
3
  * Hand-mirrored wire types for the material projections — the grid-card tile,
3
4
  * the detail record, and the availability/successor block they carry.
@@ -22,7 +23,6 @@
22
23
  * that says which.
23
24
  */
24
25
  import type { ImageSource, MaterialColour, OpenEnum, PaletteSwatch } from "./types.js";
25
- import type { ProductId, VariantId } from "./identifiers.js";
26
26
  /**
27
27
  * Whether a material can still be bought.
28
28
  *
package/operations.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare const MATERIALGRAPH_API_VERSION = "0.7.0";
2
- declare const OPERATION_DEFINITIONS: readonly [readonly ["search", "POST", "/api/v1/search", "search_materials_post"], readonly ["searchGet", "GET", "/api/v1/search", "search_materials_get"], readonly ["match", "POST", "/api/v1/search/match", "match_material"], readonly ["byColour", "GET", "/api/v1/search/colours", "search_by_colour"], readonly ["material", "GET", "/api/v1/materials/{variantId}", "get_material"], readonly ["siblings", "GET", "/api/v1/materials/{variantId}/siblings", "get_material_siblings"], readonly ["materialBlocks", "GET", "/api/v1/materials/{variantId}/blocks", "list_material_blocks"], readonly ["materialAssets", "GET", "/api/v1/materials/{variantId}/assets", "list_material_assets"], readonly ["schema", "GET", "/api/v1/schema/blocks", "list_schema_blocks"], readonly ["schema", "GET", "/api/v1/schema/attributes", "list_schema_attributes"], readonly ["schema", "GET", "/api/v1/schema/verticals", "list_schema_verticals"], readonly ["schema", "GET", "/api/v1/schema/product-types", "list_schema_product_types"], readonly ["schema", "GET", "/api/v1/schema/units", "list_schema_units"], readonly ["schema", "GET", "/api/v1/schema/value-dictionaries", "list_schema_value_dictionaries"], readonly ["schema", "GET", "/api/v1/schema/source-requirements", "list_schema_source_requirements"], readonly ["schema", "GET", "/api/v1/schema/product-type-templates", "list_schema_product_type_templates"], readonly ["schema", "GET", "/api/v1/schema/mappings", "list_schema_mappings"], readonly ["pairings", "GET", "/api/v1/materials/{variantId}/pairings", "get_material_pairings"], readonly ["associatedFinishes", "GET", "/api/v1/associated/finishes", "list_associated_finishes"], readonly ["associatedProducts", "GET", "/api/v1/associated/products", "list_associated_products"], readonly ["materials", "POST", "/api/v1/materials/batch", "get_materials_batch_post"], readonly ["materialsCached", "GET", "/api/v1/materials/batch", "get_materials_batch_get"], readonly ["browse", "GET", "/api/v1/search/browse", "search_browse_by_colour"], readonly ["colourFacets", "GET", "/api/v1/colours/facets", "get_colour_facets"], readonly ["colours.profiles", "GET", "/api/v1/colours/profiles", "get_category_colour_profiles"], readonly ["colours.stats", "GET", "/api/v1/colours/stats", "get_colour_stats"], readonly ["resolveColour", "GET", "/api/v1/search/colours/resolve", "resolve_colour_name"], readonly ["suggestColour", "GET", "/api/v1/search/colours/suggest", "suggest_colour_names"], readonly ["suggest", "GET", "/api/v1/search/suggest", "search_suggest"], readonly ["resolveAttribute", "GET", "/api/v1/catalog/attributes/resolve", "catalog_resolve_attribute"], readonly ["resolveAttributeValue", "GET", "/api/v1/catalog/attributes/{attributeId}/values/resolve", "catalog_resolve_value"], readonly ["searchVocabulary", "GET", "/api/v1/catalog/vocabulary/search", "catalog_vocabulary_search"], readonly ["resolve", "POST", "/api/v1/resolve", "resolve_phrases"], readonly ["bySpec", "GET", "/api/v1/search/specifications", "catalog_by_spec"], readonly ["taxonomy", "GET", "/api/v1/taxonomy/categories", "get_category_taxonomy"], readonly ["whoami", "GET", "/api/v1/whoami", "whoami"], readonly ["coordinate", "POST", "/api/v1/pairings/coordinate", "coordinate_materials"], readonly ["demand", "GET", "/api/v1/demand", "get_material_demand"], readonly ["colours.palette", "POST", "/api/v1/search/palettes", "search_by_palette"], readonly ["extractPalette", "POST", "/api/v1/search/palettes/extract", "extract_image_palette"], readonly ["colours.gradient", "POST", "/api/v1/search/gradients", "search_by_gradient"], readonly ["specificationFacets", "GET", "/api/v1/catalog/specifications/facets", "list_spec_facets"], readonly ["attributeValues", "GET", "/api/v1/catalog/attributes/{attributeId}/values", "list_attribute_values"], readonly ["applicableSpecs", "GET", "/api/v1/taxonomy/categories/{key}/specs", "get_applicable_specs"], readonly ["glossary", "GET", "/api/v1/glossary/{term}", "explain_material_term"], readonly ["brands", "GET", "/api/v1/brands", "list_brands"], readonly ["brand", "GET", "/api/v1/brands/{brandSlug}", "get_brand_profile"], readonly ["uploadSourceMaterial", "POST", "/api/v1/source-material", "upload_source_material"], readonly ["sourceMaterialBatch", "GET", "/api/v1/source-material/{batchId}", "get_source_material_batch"], readonly ["capabilities", "GET", "/api/v1/capabilities", "list_public_capabilities"], readonly ["createRun", "POST", "/api/v1/runs", "create_public_run"], readonly ["listRuns", "GET", "/api/v1/runs", "list_public_runs"], readonly ["run", "GET", "/api/v1/runs/{runId}", "get_public_run"], readonly ["runSchedule", "GET", "/api/v1/runs/{runId}/schedule", "get_run_finish_schedule"], readonly ["streamRunEvents", "GET", "/api/v1/runs/{runId}/events", "list_public_run_events"], readonly ["resumeRun", "POST", "/api/v1/runs/{runId}/resume", "resume_public_run"], readonly ["cancelRun", "POST", "/api/v1/runs/{runId}/cancel", "cancel_public_run"], readonly ["varyScheme", "POST", "/api/v1/schemes/vary", "vary_schemes"], readonly ["createProject", "POST", "/api/v1/projects", "create_box_project"], readonly ["listProjects", "GET", "/api/v1/projects", "list_box_projects"], readonly ["getProject", "GET", "/api/v1/projects/{projectId}", "get_box_project"], readonly ["appendProjectEvent", "POST", "/api/v1/projects/{projectId}/events", "append_box_project_event"], readonly ["demandBatch", "POST", "/api/v1/demand/batch", "get_demand_batch"], readonly ["codeAdvisory", "POST", "/api/v1/codes/advisory", "resolveCodeAdvisory"], readonly ["codes.context", "GET", "/api/v1/codes/context", "list_code_context"], readonly ["codes.requirements", "GET", "/api/v1/codes/requirements", "list_code_requirements"]];
2
+ declare const OPERATION_DEFINITIONS: readonly [readonly ["search", "POST", "/api/v1/search", "search_materials_post"], readonly ["searchGet", "GET", "/api/v1/search", "search_materials_get"], readonly ["match", "POST", "/api/v1/search/match", "match_material"], readonly ["byColour", "GET", "/api/v1/search/colours", "search_by_colour"], readonly ["material", "GET", "/api/v1/materials/{variantId}", "get_material"], readonly ["siblings", "GET", "/api/v1/materials/{variantId}/siblings", "get_material_siblings"], readonly ["materialBlocks", "GET", "/api/v1/materials/{variantId}/blocks", "list_material_blocks"], readonly ["materialAssets", "GET", "/api/v1/materials/{variantId}/assets", "list_material_assets"], readonly ["schema", "GET", "/api/v1/schema/blocks", "list_schema_blocks"], readonly ["schema", "GET", "/api/v1/schema/attributes", "list_schema_attributes"], readonly ["schema", "GET", "/api/v1/schema/verticals", "list_schema_verticals"], readonly ["schema", "GET", "/api/v1/schema/product-types", "list_schema_product_types"], readonly ["schema", "GET", "/api/v1/schema/units", "list_schema_units"], readonly ["schema", "GET", "/api/v1/schema/value-dictionaries", "list_schema_value_dictionaries"], readonly ["schema", "GET", "/api/v1/schema/source-requirements", "list_schema_source_requirements"], readonly ["schema", "GET", "/api/v1/schema/product-type-templates", "list_schema_product_type_templates"], readonly ["schema", "GET", "/api/v1/schema/mappings", "list_schema_mappings"], readonly ["pairings", "GET", "/api/v1/materials/{variantId}/pairings", "get_material_pairings"], readonly ["associatedFinishes", "GET", "/api/v1/associated/finishes", "list_associated_finishes"], readonly ["associatedProducts", "GET", "/api/v1/associated/products", "list_associated_products"], readonly ["materials", "POST", "/api/v1/materials/batch", "get_materials_batch_post"], readonly ["materialsCached", "GET", "/api/v1/materials/batch", "get_materials_batch_get"], readonly ["browse", "GET", "/api/v1/search/browse", "search_browse_by_colour"], readonly ["colourFacets", "GET", "/api/v1/colours/facets", "get_colour_facets"], readonly ["colours.profiles", "GET", "/api/v1/colours/profiles", "get_category_colour_profiles"], readonly ["colours.stats", "GET", "/api/v1/colours/stats", "get_colour_stats"], readonly ["resolveColour", "GET", "/api/v1/search/colours/resolve", "resolve_colour_name"], readonly ["suggestColour", "GET", "/api/v1/search/colours/suggest", "suggest_colour_names"], readonly ["suggest", "GET", "/api/v1/search/suggest", "search_suggest"], readonly ["resolveAttribute", "GET", "/api/v1/catalog/attributes/resolve", "catalog_resolve_attribute"], readonly ["resolveAttributeValue", "GET", "/api/v1/catalog/attributes/{attributeId}/values/resolve", "catalog_resolve_value"], readonly ["searchVocabulary", "GET", "/api/v1/catalog/vocabulary/search", "catalog_vocabulary_search"], readonly ["resolve", "POST", "/api/v1/resolve", "resolve_phrases"], readonly ["bySpec", "GET", "/api/v1/search/specifications", "catalog_by_spec"], readonly ["taxonomy", "GET", "/api/v1/taxonomy/categories", "get_category_taxonomy"], readonly ["whoami", "GET", "/api/v1/whoami", "whoami"], readonly ["coordinate", "POST", "/api/v1/pairings/coordinate", "coordinate_materials"], readonly ["demand", "GET", "/api/v1/demand", "get_material_demand"], readonly ["colours.palette", "POST", "/api/v1/search/palettes", "search_by_palette"], readonly ["extractPalette", "POST", "/api/v1/search/palettes/extract", "extract_image_palette"], readonly ["colours.gradient", "POST", "/api/v1/search/gradients", "search_by_gradient"], readonly ["specificationFacets", "GET", "/api/v1/catalog/specifications/facets", "list_spec_facets"], readonly ["attributeValues", "GET", "/api/v1/catalog/attributes/{attributeId}/values", "list_attribute_values"], readonly ["applicableSpecs", "GET", "/api/v1/taxonomy/categories/{key}/specs", "get_applicable_specs"], readonly ["glossary", "GET", "/api/v1/glossary/{term}", "explain_material_term"], readonly ["brands", "GET", "/api/v1/brands", "list_brands"], readonly ["brand", "GET", "/api/v1/brands/{brandSlug}", "get_brand_profile"], readonly ["brandColourDeck", "GET", "/api/v1/brands/{brandSlug}/colours", "brand_colour_deck"], readonly ["uploadSourceMaterial", "POST", "/api/v1/source-material", "upload_source_material"], readonly ["sourceMaterialBatch", "GET", "/api/v1/source-material/{batchId}", "get_source_material_batch"], readonly ["capabilities", "GET", "/api/v1/capabilities", "list_public_capabilities"], readonly ["createRun", "POST", "/api/v1/runs", "create_public_run"], readonly ["listRuns", "GET", "/api/v1/runs", "list_public_runs"], readonly ["run", "GET", "/api/v1/runs/{runId}", "get_public_run"], readonly ["runSchedule", "GET", "/api/v1/runs/{runId}/schedule", "get_run_finish_schedule"], readonly ["streamRunEvents", "GET", "/api/v1/runs/{runId}/events", "list_public_run_events"], readonly ["resumeRun", "POST", "/api/v1/runs/{runId}/resume", "resume_public_run"], readonly ["cancelRun", "POST", "/api/v1/runs/{runId}/cancel", "cancel_public_run"], readonly ["varyScheme", "POST", "/api/v1/schemes/vary", "vary_schemes"], readonly ["createProject", "POST", "/api/v1/projects", "create_box_project"], readonly ["listProjects", "GET", "/api/v1/projects", "list_box_projects"], readonly ["getProject", "GET", "/api/v1/projects/{projectId}", "get_box_project"], readonly ["appendProjectEvent", "POST", "/api/v1/projects/{projectId}/events", "append_box_project_event"], readonly ["demandBatch", "POST", "/api/v1/demand/batch", "get_demand_batch"], readonly ["codeAdvisory", "POST", "/api/v1/codes/advisory", "resolveCodeAdvisory"], readonly ["codes.context", "GET", "/api/v1/codes/context", "list_code_context"], readonly ["codes.requirements", "GET", "/api/v1/codes/requirements", "list_code_requirements"]];
3
3
  export type SdkOperationId = (typeof OPERATION_DEFINITIONS)[number][3];
4
4
  export type SdkOperation = Readonly<{
5
5
  clientMethod: (typeof OPERATION_DEFINITIONS)[number][0];
package/operations.js CHANGED
@@ -6,38 +6,118 @@ const OPERATION_DEFINITIONS = [
6
6
  ["match", "POST", "/api/v1/search/match", "match_material"],
7
7
  ["byColour", "GET", "/api/v1/search/colours", "search_by_colour"],
8
8
  ["material", "GET", "/api/v1/materials/{variantId}", "get_material"],
9
- ["siblings", "GET", "/api/v1/materials/{variantId}/siblings", "get_material_siblings"],
10
- ["materialBlocks", "GET", "/api/v1/materials/{variantId}/blocks", "list_material_blocks"],
11
- ["materialAssets", "GET", "/api/v1/materials/{variantId}/assets", "list_material_assets"],
9
+ [
10
+ "siblings",
11
+ "GET",
12
+ "/api/v1/materials/{variantId}/siblings",
13
+ "get_material_siblings",
14
+ ],
15
+ [
16
+ "materialBlocks",
17
+ "GET",
18
+ "/api/v1/materials/{variantId}/blocks",
19
+ "list_material_blocks",
20
+ ],
21
+ [
22
+ "materialAssets",
23
+ "GET",
24
+ "/api/v1/materials/{variantId}/assets",
25
+ "list_material_assets",
26
+ ],
12
27
  ["schema", "GET", "/api/v1/schema/blocks", "list_schema_blocks"],
13
28
  ["schema", "GET", "/api/v1/schema/attributes", "list_schema_attributes"],
14
29
  ["schema", "GET", "/api/v1/schema/verticals", "list_schema_verticals"],
15
- ["schema", "GET", "/api/v1/schema/product-types", "list_schema_product_types"],
30
+ [
31
+ "schema",
32
+ "GET",
33
+ "/api/v1/schema/product-types",
34
+ "list_schema_product_types",
35
+ ],
16
36
  ["schema", "GET", "/api/v1/schema/units", "list_schema_units"],
17
- ["schema", "GET", "/api/v1/schema/value-dictionaries", "list_schema_value_dictionaries"],
18
- ["schema", "GET", "/api/v1/schema/source-requirements", "list_schema_source_requirements"],
19
- ["schema", "GET", "/api/v1/schema/product-type-templates", "list_schema_product_type_templates"],
37
+ [
38
+ "schema",
39
+ "GET",
40
+ "/api/v1/schema/value-dictionaries",
41
+ "list_schema_value_dictionaries",
42
+ ],
43
+ [
44
+ "schema",
45
+ "GET",
46
+ "/api/v1/schema/source-requirements",
47
+ "list_schema_source_requirements",
48
+ ],
49
+ [
50
+ "schema",
51
+ "GET",
52
+ "/api/v1/schema/product-type-templates",
53
+ "list_schema_product_type_templates",
54
+ ],
20
55
  ["schema", "GET", "/api/v1/schema/mappings", "list_schema_mappings"],
21
- ["pairings", "GET", "/api/v1/materials/{variantId}/pairings", "get_material_pairings"],
22
- ["associatedFinishes", "GET", "/api/v1/associated/finishes", "list_associated_finishes"],
23
- ["associatedProducts", "GET", "/api/v1/associated/products", "list_associated_products"],
56
+ [
57
+ "pairings",
58
+ "GET",
59
+ "/api/v1/materials/{variantId}/pairings",
60
+ "get_material_pairings",
61
+ ],
62
+ [
63
+ "associatedFinishes",
64
+ "GET",
65
+ "/api/v1/associated/finishes",
66
+ "list_associated_finishes",
67
+ ],
68
+ [
69
+ "associatedProducts",
70
+ "GET",
71
+ "/api/v1/associated/products",
72
+ "list_associated_products",
73
+ ],
24
74
  ["materials", "POST", "/api/v1/materials/batch", "get_materials_batch_post"],
25
- ["materialsCached", "GET", "/api/v1/materials/batch", "get_materials_batch_get"],
75
+ [
76
+ "materialsCached",
77
+ "GET",
78
+ "/api/v1/materials/batch",
79
+ "get_materials_batch_get",
80
+ ],
26
81
  ["browse", "GET", "/api/v1/search/browse", "search_browse_by_colour"],
27
82
  ["colourFacets", "GET", "/api/v1/colours/facets", "get_colour_facets"],
28
- ["colours.profiles", "GET", "/api/v1/colours/profiles", "get_category_colour_profiles"],
83
+ [
84
+ "colours.profiles",
85
+ "GET",
86
+ "/api/v1/colours/profiles",
87
+ "get_category_colour_profiles",
88
+ ],
29
89
  ["colours.stats", "GET", "/api/v1/colours/stats", "get_colour_stats"],
30
- ["resolveColour", "GET", "/api/v1/search/colours/resolve", "resolve_colour_name"],
31
- ["suggestColour", "GET", "/api/v1/search/colours/suggest", "suggest_colour_names"],
90
+ [
91
+ "resolveColour",
92
+ "GET",
93
+ "/api/v1/search/colours/resolve",
94
+ "resolve_colour_name",
95
+ ],
96
+ [
97
+ "suggestColour",
98
+ "GET",
99
+ "/api/v1/search/colours/suggest",
100
+ "suggest_colour_names",
101
+ ],
32
102
  ["suggest", "GET", "/api/v1/search/suggest", "search_suggest"],
33
- ["resolveAttribute", "GET", "/api/v1/catalog/attributes/resolve", "catalog_resolve_attribute"],
103
+ [
104
+ "resolveAttribute",
105
+ "GET",
106
+ "/api/v1/catalog/attributes/resolve",
107
+ "catalog_resolve_attribute",
108
+ ],
34
109
  [
35
110
  "resolveAttributeValue",
36
111
  "GET",
37
112
  "/api/v1/catalog/attributes/{attributeId}/values/resolve",
38
113
  "catalog_resolve_value",
39
114
  ],
40
- ["searchVocabulary", "GET", "/api/v1/catalog/vocabulary/search", "catalog_vocabulary_search"],
115
+ [
116
+ "searchVocabulary",
117
+ "GET",
118
+ "/api/v1/catalog/vocabulary/search",
119
+ "catalog_vocabulary_search",
120
+ ],
41
121
  ["resolve", "POST", "/api/v1/resolve", "resolve_phrases"],
42
122
  ["bySpec", "GET", "/api/v1/search/specifications", "catalog_by_spec"],
43
123
  ["taxonomy", "GET", "/api/v1/taxonomy/categories", "get_category_taxonomy"],
@@ -45,38 +125,94 @@ const OPERATION_DEFINITIONS = [
45
125
  ["coordinate", "POST", "/api/v1/pairings/coordinate", "coordinate_materials"],
46
126
  ["demand", "GET", "/api/v1/demand", "get_material_demand"],
47
127
  ["colours.palette", "POST", "/api/v1/search/palettes", "search_by_palette"],
48
- ["extractPalette", "POST", "/api/v1/search/palettes/extract", "extract_image_palette"],
49
- ["colours.gradient", "POST", "/api/v1/search/gradients", "search_by_gradient"],
50
- ["specificationFacets", "GET", "/api/v1/catalog/specifications/facets", "list_spec_facets"],
128
+ [
129
+ "extractPalette",
130
+ "POST",
131
+ "/api/v1/search/palettes/extract",
132
+ "extract_image_palette",
133
+ ],
134
+ [
135
+ "colours.gradient",
136
+ "POST",
137
+ "/api/v1/search/gradients",
138
+ "search_by_gradient",
139
+ ],
140
+ [
141
+ "specificationFacets",
142
+ "GET",
143
+ "/api/v1/catalog/specifications/facets",
144
+ "list_spec_facets",
145
+ ],
51
146
  [
52
147
  "attributeValues",
53
148
  "GET",
54
149
  "/api/v1/catalog/attributes/{attributeId}/values",
55
150
  "list_attribute_values",
56
151
  ],
57
- ["applicableSpecs", "GET", "/api/v1/taxonomy/categories/{key}/specs", "get_applicable_specs"],
152
+ [
153
+ "applicableSpecs",
154
+ "GET",
155
+ "/api/v1/taxonomy/categories/{key}/specs",
156
+ "get_applicable_specs",
157
+ ],
58
158
  ["glossary", "GET", "/api/v1/glossary/{term}", "explain_material_term"],
59
159
  ["brands", "GET", "/api/v1/brands", "list_brands"],
60
160
  ["brand", "GET", "/api/v1/brands/{brandSlug}", "get_brand_profile"],
61
- ["uploadSourceMaterial", "POST", "/api/v1/source-material", "upload_source_material"],
62
- ["sourceMaterialBatch", "GET", "/api/v1/source-material/{batchId}", "get_source_material_batch"],
161
+ [
162
+ "brandColourDeck",
163
+ "GET",
164
+ "/api/v1/brands/{brandSlug}/colours",
165
+ "brand_colour_deck",
166
+ ],
167
+ [
168
+ "uploadSourceMaterial",
169
+ "POST",
170
+ "/api/v1/source-material",
171
+ "upload_source_material",
172
+ ],
173
+ [
174
+ "sourceMaterialBatch",
175
+ "GET",
176
+ "/api/v1/source-material/{batchId}",
177
+ "get_source_material_batch",
178
+ ],
63
179
  ["capabilities", "GET", "/api/v1/capabilities", "list_public_capabilities"],
64
180
  ["createRun", "POST", "/api/v1/runs", "create_public_run"],
65
181
  ["listRuns", "GET", "/api/v1/runs", "list_public_runs"],
66
182
  ["run", "GET", "/api/v1/runs/{runId}", "get_public_run"],
67
- ["runSchedule", "GET", "/api/v1/runs/{runId}/schedule", "get_run_finish_schedule"],
68
- ["streamRunEvents", "GET", "/api/v1/runs/{runId}/events", "list_public_run_events"],
183
+ [
184
+ "runSchedule",
185
+ "GET",
186
+ "/api/v1/runs/{runId}/schedule",
187
+ "get_run_finish_schedule",
188
+ ],
189
+ [
190
+ "streamRunEvents",
191
+ "GET",
192
+ "/api/v1/runs/{runId}/events",
193
+ "list_public_run_events",
194
+ ],
69
195
  ["resumeRun", "POST", "/api/v1/runs/{runId}/resume", "resume_public_run"],
70
196
  ["cancelRun", "POST", "/api/v1/runs/{runId}/cancel", "cancel_public_run"],
71
197
  ["varyScheme", "POST", "/api/v1/schemes/vary", "vary_schemes"],
72
198
  ["createProject", "POST", "/api/v1/projects", "create_box_project"],
73
199
  ["listProjects", "GET", "/api/v1/projects", "list_box_projects"],
74
200
  ["getProject", "GET", "/api/v1/projects/{projectId}", "get_box_project"],
75
- ["appendProjectEvent", "POST", "/api/v1/projects/{projectId}/events", "append_box_project_event"],
201
+ [
202
+ "appendProjectEvent",
203
+ "POST",
204
+ "/api/v1/projects/{projectId}/events",
205
+ "append_box_project_event",
206
+ ],
76
207
  ["demandBatch", "POST", "/api/v1/demand/batch", "get_demand_batch"],
77
208
  ["codeAdvisory", "POST", "/api/v1/codes/advisory", "resolveCodeAdvisory"],
78
209
  ["codes.context", "GET", "/api/v1/codes/context", "list_code_context"],
79
- ["codes.requirements", "GET", "/api/v1/codes/requirements", "list_code_requirements"],
210
+ [
211
+ "codes.requirements",
212
+ "GET",
213
+ "/api/v1/codes/requirements",
214
+ "list_code_requirements",
215
+ ],
80
216
  ];
81
217
  export const SDK_OPERATIONS = Object.freeze(OPERATION_DEFINITIONS.map(([clientMethod, method, path, operationId]) => Object.freeze({ clientMethod, method, path, operationId })));
82
218
  /** Look up a registered operation by its OpenAPI `operationId`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instruments/materialgraph",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -24,13 +24,19 @@
24
24
  * - You want MATERIALS → `mg.search()`. This lens never returns one.
25
25
  */
26
26
  import type { HttpTransport } from "./http-transport.js";
27
- import type { ResolveResponse } from "./resolve-types.js";
27
+ import type { ResolvePhrasesScope, ResolveResponse } from "./resolve-types.js";
28
28
  import type { VocabularySearchOptions, VocabularySearchResponse } from "./types.js";
29
29
  /**
30
30
  * THE QUESTION: "I have words — what do they mean in YOUR vocabulary?" Send up
31
31
  * to 50 phrases as your users typed them; each comes back with every canonical
32
32
  * token MaterialGraph knows it as — brand, exact paint, colour family, category,
33
- * attribute, value — best first, in request order. Backs `mg.resolve()`.
33
+ * attribute, value, and the two code axes (jurisdiction, occupancy group) — best
34
+ * first, in request order. Backs `mg.resolve()`.
35
+ *
36
+ * The code axes read out of a sentence: "a maximum security prison in Kansas"
37
+ * returns `us-ks` and `I-3`, the pair `mg.codeAdvisory()` is keyed on. They are
38
+ * half a context, not a whole one — that call also wants a space type and a
39
+ * sprinklered flag, and validates the combination before it answers.
34
40
  *
35
41
  * A phrase can legitimately mean several things at once ("sage" is two vendor
36
42
  * paints AND a colour family), so each entry carries a LIST of readings rather
@@ -54,10 +60,23 @@ import type { VocabularySearchOptions, VocabularySearchResponse } from "./types.
54
60
  * complete a name as someone types, and `mg.glossary()` to EXPLAIN a token you
55
61
  * have already resolved.
56
62
  *
63
+ * - **Every reading says what stands behind it.** `coverage.variants` is how
64
+ * many variants carry it corpus-wide, and `0` is a measured answer rather
65
+ * than missing data — a word this vocabulary knows and the catalogue holds
66
+ * nothing under. That is the case you would otherwise discover only by making
67
+ * a second call, on a hot path, where a second call gets skipped. An ABSENT
68
+ * `coverage` means it could not be determined; never read it as none.
69
+ *
70
+ * Pass `category` when you are grounding these words for a SLOT, and read
71
+ * `coverage.inCategory`: a corpus-wide count is not a promise the reading is
72
+ * reachable inside a given category, and that conflation is what turns a
73
+ * top-ranked suggestion into an unsatisfiable requirement.
74
+ *
57
75
  * @param phrases 1-50 phrases, each 1-200 characters. Sent as-is; each is
58
76
  * resolved independently, so one meaningless phrase never spoils the batch.
77
+ * @param options `category` to scope the coverage answer, and an `AbortSignal`.
59
78
  */
60
- export declare function resolvePhrasesRequest(transport: HttpTransport, phrases: string[], signal?: AbortSignal): Promise<ResolveResponse>;
79
+ export declare function resolvePhrasesRequest(transport: HttpTransport, phrases: string[], scope?: ResolvePhrasesScope): Promise<ResolveResponse>;
61
80
  /**
62
81
  * THE QUESTION: "is 'FloorScore' an attribute or a value, and what is it called
63
82
  * here?" The catch-all for ONE phrase when you do not know which half of an
package/resolve-client.js CHANGED
@@ -3,7 +3,13 @@ import { resolveOperation } from "./operations.js";
3
3
  * THE QUESTION: "I have words — what do they mean in YOUR vocabulary?" Send up
4
4
  * to 50 phrases as your users typed them; each comes back with every canonical
5
5
  * token MaterialGraph knows it as — brand, exact paint, colour family, category,
6
- * attribute, value — best first, in request order. Backs `mg.resolve()`.
6
+ * attribute, value, and the two code axes (jurisdiction, occupancy group) — best
7
+ * first, in request order. Backs `mg.resolve()`.
8
+ *
9
+ * The code axes read out of a sentence: "a maximum security prison in Kansas"
10
+ * returns `us-ks` and `I-3`, the pair `mg.codeAdvisory()` is keyed on. They are
11
+ * half a context, not a whole one — that call also wants a space type and a
12
+ * sprinklered flag, and validates the combination before it answers.
7
13
  *
8
14
  * A phrase can legitimately mean several things at once ("sage" is two vendor
9
15
  * paints AND a colour family), so each entry carries a LIST of readings rather
@@ -27,13 +33,34 @@ import { resolveOperation } from "./operations.js";
27
33
  * complete a name as someone types, and `mg.glossary()` to EXPLAIN a token you
28
34
  * have already resolved.
29
35
  *
36
+ * - **Every reading says what stands behind it.** `coverage.variants` is how
37
+ * many variants carry it corpus-wide, and `0` is a measured answer rather
38
+ * than missing data — a word this vocabulary knows and the catalogue holds
39
+ * nothing under. That is the case you would otherwise discover only by making
40
+ * a second call, on a hot path, where a second call gets skipped. An ABSENT
41
+ * `coverage` means it could not be determined; never read it as none.
42
+ *
43
+ * Pass `category` when you are grounding these words for a SLOT, and read
44
+ * `coverage.inCategory`: a corpus-wide count is not a promise the reading is
45
+ * reachable inside a given category, and that conflation is what turns a
46
+ * top-ranked suggestion into an unsatisfiable requirement.
47
+ *
30
48
  * @param phrases 1-50 phrases, each 1-200 characters. Sent as-is; each is
31
49
  * resolved independently, so one meaningless phrase never spoils the batch.
50
+ * @param options `category` to scope the coverage answer, and an `AbortSignal`.
32
51
  */
33
- export function resolvePhrasesRequest(transport, phrases, signal) {
52
+ export function resolvePhrasesRequest(transport, phrases, scope) {
53
+ // A bare signal is what this took before `category` existed; keep accepting it
54
+ // so no published call site had to change to gain coverage.
55
+ const options = scope instanceof AbortSignal ? { signal: scope } : (scope ?? {});
34
56
  return transport.requestJson(resolveOperation("resolve_phrases"), {
35
- body: { phrases },
36
- signal,
57
+ body: {
58
+ phrases,
59
+ ...(options.category === undefined
60
+ ? {}
61
+ : { category: options.category }),
62
+ },
63
+ signal: options.signal,
37
64
  });
38
65
  }
39
66
  /**