@instruments/materialgraph 0.7.0 → 0.8.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/association-types.d.ts +92 -0
- package/association-types.js +1 -0
- package/associations-client.d.ts +51 -0
- package/associations-client.js +40 -0
- package/by-colour-types.d.ts +119 -0
- package/by-colour-types.js +1 -0
- package/by-spec-types.d.ts +45 -0
- package/catalog-discovery-types.d.ts +30 -14
- package/client-config.d.ts +17 -0
- package/client-config.js +9 -0
- package/client.d.ts +38 -23
- package/client.js +50 -33
- package/composition-types.d.ts +31 -1
- package/index.d.ts +2 -0
- package/material-types.d.ts +8 -0
- package/operations.d.ts +7 -1
- package/operations.js +16 -0
- package/package.json +1 -1
- package/resolve-client.d.ts +71 -0
- package/resolve-client.js +51 -0
- package/resolve-types.d.ts +102 -0
- package/resolve-types.js +17 -0
- package/run-types.d.ts +25 -0
- package/runs.d.ts +15 -1
- package/runs.js +24 -0
- package/schema-resource-types.d.ts +17 -14
- package/schema-resource-types.js +17 -1
- package/search-result-validation.js +3 -0
- package/types.d.ts +42 -54
package/client.js
CHANGED
|
@@ -1,33 +1,20 @@
|
|
|
1
1
|
import { MaterialGraphError } from "./errors.js";
|
|
2
2
|
import { HttpTransport } from "./http-transport.js";
|
|
3
|
-
|
|
4
|
-
import {
|
|
3
|
+
// Aliased to `operation` — the local name every call site here already used.
|
|
4
|
+
import { resolveOperation as operation } from "./operations.js";
|
|
5
|
+
import { cancelRun, capabilities as capabilitiesRun, createRun, drainRunEvents, getRun, getRunSchedule, getSourceMaterialBatch as getSourceMaterialBatchCall, listRuns, resumeRun, streamRunEvents, uploadSourceMaterial, } from "./runs.js";
|
|
6
|
+
import { DEFAULT_BASE_URL, MAX_BATCH_IDS } from "./client-config.js";
|
|
7
|
+
// Re-exported whole so `index.ts` and every existing importer keep their path.
|
|
8
|
+
export * from "./client-config.js";
|
|
5
9
|
import { browseQuery, createBrowseNamespace } from "./client-browse.js";
|
|
6
10
|
import { suggestQuery } from "./suggest-types.js";
|
|
7
11
|
import { matchStream as matchStreamCall } from "./match-stream.js";
|
|
8
12
|
import { appendProjectEvent as appendProjectEventCall, createProject as createProjectCall, getProject as getProjectCall, listProjects as listProjectsCall, } from "./projects.js";
|
|
9
13
|
import { CodesClient } from "./codes-client.js";
|
|
10
14
|
import { ColoursClient } from "./colours-client.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
blocks: "list_schema_blocks",
|
|
15
|
-
attributes: "list_schema_attributes",
|
|
16
|
-
verticals: "list_schema_verticals",
|
|
17
|
-
productTypes: "list_schema_product_types",
|
|
18
|
-
units: "list_schema_units",
|
|
19
|
-
valueDictionaries: "list_schema_value_dictionaries",
|
|
20
|
-
sourceRequirements: "list_schema_source_requirements",
|
|
21
|
-
productTypeTemplates: "list_schema_product_type_templates",
|
|
22
|
-
mappings: "list_schema_mappings",
|
|
23
|
-
};
|
|
24
|
-
function operation(operationId) {
|
|
25
|
-
const match = findSdkOperation(operationId);
|
|
26
|
-
if (!match) {
|
|
27
|
-
throw MaterialGraphError.unexpected(`Unknown SDK operation: ${operationId}`);
|
|
28
|
-
}
|
|
29
|
-
return match;
|
|
30
|
-
}
|
|
15
|
+
import { resolvePhrasesRequest, searchVocabularyRequest } from "./resolve-client.js";
|
|
16
|
+
import { declaredFinishes, declaredProducts } from "./associations-client.js";
|
|
17
|
+
import { SCHEMA_RESOURCE_OPERATION_IDS } from "./schema-resource-types.js";
|
|
31
18
|
/**
|
|
32
19
|
* The MaterialGraph client — every lens on the graph, on one object.
|
|
33
20
|
*
|
|
@@ -41,18 +28,25 @@ function operation(operationId) {
|
|
|
41
28
|
* | "which materials, from anyone, meet this hard spec?" | {@link MaterialGraphClient.bySpec} |
|
|
42
29
|
* | "what's near this colour / this palette / this gradient?" | {@link MaterialGraphClient.byColour}, `colours.palette()`, `colours.gradient()` |
|
|
43
30
|
* | "what goes with THIS material?" | {@link MaterialGraphClient.pairings}, {@link MaterialGraphClient.siblings}, {@link MaterialGraphClient.coordinate} |
|
|
31
|
+
* | "what does the manufacturer say is AVAILABLE on this?" | {@link MaterialGraphClient.associatedFinishes}, {@link MaterialGraphClient.associatedProducts} |
|
|
44
32
|
* | "how much is this specified?" | {@link MaterialGraphClient.demand}, {@link MaterialGraphClient.demandBatch} |
|
|
45
33
|
* | "is this allowed in an A-2 corridor?" | `codes.*` |
|
|
46
34
|
* | "what can I even ask for?" | {@link MaterialGraphClient.specificationFacets}, {@link MaterialGraphClient.attributeValues}, {@link MaterialGraphClient.taxonomy}, {@link MaterialGraphClient.colourFacets}, {@link MaterialGraphClient.glossary} |
|
|
35
|
+
* | "I have words — what do they mean in YOUR vocabulary?" | {@link MaterialGraphClient.resolve} |
|
|
47
36
|
* | "do the whole job for me, async" | {@link MaterialGraphClient.createRun} + `mg:compose` |
|
|
48
37
|
*
|
|
49
|
-
*
|
|
38
|
+
* Three structural rules that fall out of that table:
|
|
50
39
|
* - **Colour is a separate lens.** {@link MaterialGraphClient.search} matches
|
|
51
40
|
* WORDS. A colour word in `text` finds materials whose text mentions it, not
|
|
52
41
|
* materials that look it. Route visual intent to the colour lenses.
|
|
53
42
|
* - **Relationships hang off a material, not off a query.** You cannot ask "what
|
|
54
43
|
* pairs with beige oak"; you resolve a material first, then ask what pairs
|
|
55
44
|
* with THAT `variantId`.
|
|
45
|
+
* - **Declared is not inferred.** `associatedFinishes()` /
|
|
46
|
+
* `associatedProducts()` return compatibility the MANUFACTURER stated;
|
|
47
|
+
* `pairings()` returns companionship the graph INFERRED. The response shapes
|
|
48
|
+
* share no field, on purpose — render them as separate sections and never
|
|
49
|
+
* concatenate them.
|
|
56
50
|
*
|
|
57
51
|
* And three reading rules that apply to every lens: ids are opaque (see
|
|
58
52
|
* `./identifiers.ts`), absent is not false, and a page is not a corpus.
|
|
@@ -208,6 +202,8 @@ export class MaterialGraphClient {
|
|
|
208
202
|
* {@link MaterialGraphClient.browse} to walk by lightness/vividness, and
|
|
209
203
|
* {@link MaterialGraphClient.search} when colour is one signal among many.
|
|
210
204
|
* Report matches as visual likeness, never a stated colour specification.
|
|
205
|
+
* `family` gates the answer to ONE colorscope colour family when nearness
|
|
206
|
+
* alone crosses a hue boundary; a gated page can be shorter than `limit`.
|
|
211
207
|
*/
|
|
212
208
|
byColour(params, signal) {
|
|
213
209
|
return this.#get("search_by_colour", {
|
|
@@ -217,6 +213,7 @@ export class MaterialGraphClient {
|
|
|
217
213
|
a: params.a,
|
|
218
214
|
b: params.b,
|
|
219
215
|
category: params.category,
|
|
216
|
+
family: params.family,
|
|
220
217
|
limit: params.limit,
|
|
221
218
|
}, signal);
|
|
222
219
|
}
|
|
@@ -298,6 +295,14 @@ export class MaterialGraphClient {
|
|
|
298
295
|
variantId,
|
|
299
296
|
});
|
|
300
297
|
}
|
|
298
|
+
/** "What finishes does the manufacturer declare for THIS product?" — {@link declaredFinishes}. */
|
|
299
|
+
associatedFinishes(variantId, options, signal) {
|
|
300
|
+
return declaredFinishes(this.#transport, variantId, options, signal);
|
|
301
|
+
}
|
|
302
|
+
/** "What products does the manufacturer declare THIS finish for?" — {@link declaredProducts}. */
|
|
303
|
+
associatedProducts(variantId, options, signal) {
|
|
304
|
+
return declaredProducts(this.#transport, variantId, options, signal);
|
|
305
|
+
}
|
|
301
306
|
materials(ids, options, signal) {
|
|
302
307
|
if (ids.length > MAX_BATCH_IDS) {
|
|
303
308
|
throw MaterialGraphError.unexpected(`MaterialGraphClient.materials(): at most ${MAX_BATCH_IDS} ids per call, received ${ids.length}. Split into multiple batches.`);
|
|
@@ -379,16 +384,13 @@ export class MaterialGraphClient {
|
|
|
379
384
|
resolveAttributeValue(attributeId, query, options, signal) {
|
|
380
385
|
return this.#get("catalog_resolve_value", { q: query, limit: options?.limit }, signal, { attributeId });
|
|
381
386
|
}
|
|
382
|
-
/**
|
|
383
|
-
* THE QUESTION: "is 'FloorScore' an attribute or a value, and what is it called
|
|
384
|
-
* here?" The catch-all when you do not know which half of an `attribute:value`
|
|
385
|
-
* pair a phrase belongs to. Instead use
|
|
386
|
-
* {@link MaterialGraphClient.resolveAttribute} /
|
|
387
|
-
* {@link MaterialGraphClient.resolveAttributeValue} once you do, and
|
|
388
|
-
* {@link MaterialGraphClient.glossary} to EXPLAIN a term rather than find it.
|
|
389
|
-
*/
|
|
387
|
+
/** "Is this phrase an attribute or a value?" — see {@link searchVocabularyRequest}. */
|
|
390
388
|
searchVocabulary(query, options, signal) {
|
|
391
|
-
return this.#
|
|
389
|
+
return searchVocabularyRequest(this.#transport, query, options, signal);
|
|
390
|
+
}
|
|
391
|
+
/** "I have words — what do they mean in YOUR vocabulary?" — see {@link resolvePhrasesRequest}. */
|
|
392
|
+
resolve(phrases, signal) {
|
|
393
|
+
return resolvePhrasesRequest(this.#transport, phrases, signal);
|
|
392
394
|
}
|
|
393
395
|
/**
|
|
394
396
|
* THE QUESTION: "which materials, from ANYONE, are ASTM E84 Class A AND
|
|
@@ -398,7 +400,10 @@ export class MaterialGraphClient {
|
|
|
398
400
|
* Instead use `search({ filters })` when the spec merely GATES a ranked
|
|
399
401
|
* question, `codes.advisory()` when the real question is what a space demands,
|
|
400
402
|
* and {@link MaterialGraphClient.specificationFacets} first if you do not know
|
|
401
|
-
* the canonical tokens
|
|
403
|
+
* the canonical tokens. Guessing one no longer returns a silently empty
|
|
404
|
+
* answer: an unresolvable criterion means the query NEVER RAN, and the
|
|
405
|
+
* response says so — read {@link BySpecResponse.unresolvedCriteria} before
|
|
406
|
+
* treating an empty `matches` as "nothing qualifies".
|
|
402
407
|
*
|
|
403
408
|
* A PAGE, NOT A CORPUS, unusually so: `totalMatches` is the size of the
|
|
404
409
|
* returned sample under `limit`, not a corpus count. See {@link BySpecResponse}.
|
|
@@ -642,6 +647,18 @@ export class MaterialGraphClient {
|
|
|
642
647
|
run(runId, signal) {
|
|
643
648
|
return getRun(this.#transport, runId, signal);
|
|
644
649
|
}
|
|
650
|
+
/**
|
|
651
|
+
* THE QUESTION: "which Runs are mine?" — your own Runs, newest first, paged
|
|
652
|
+
* (GET `/api/v1/runs`). This is how a client that lost a Run id finds its work
|
|
653
|
+
* again: `{ status: "suspended" }` returns the Runs still waiting on an
|
|
654
|
+
* answer, whose ids you can then feed to {@link MaterialGraphClient.resumeRun}.
|
|
655
|
+
*
|
|
656
|
+
* Only your own Runs are ever returned. Page by following `nextCursor` until
|
|
657
|
+
* it is ABSENT — a full page is not the signal to stop.
|
|
658
|
+
*/
|
|
659
|
+
listRuns(options) {
|
|
660
|
+
return listRuns(this.#transport, options);
|
|
661
|
+
}
|
|
645
662
|
/**
|
|
646
663
|
* Export a completed compose Run's scheme as a finish schedule — one row per
|
|
647
664
|
* slot, every attribute value carrying its source and verification state
|
package/composition-types.d.ts
CHANGED
|
@@ -245,10 +245,28 @@ export interface PaletteDirection {
|
|
|
245
245
|
colours: BriefColourCue[];
|
|
246
246
|
sourceRefs: CompositionSourceRef[];
|
|
247
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* WHERE a slot's `category` came from (MG-954, extended MG-978): `resolved` —
|
|
250
|
+
* derived from the slot's own words against the catalog's category vectors;
|
|
251
|
+
* `resolved-coverage` — the words ended in a close race and the runner-up won it
|
|
252
|
+
* because the text winner held no value for one of the slot's required
|
|
253
|
+
* attributes; `model` — the interpreter's own draw stood because nothing
|
|
254
|
+
* resolved; `none` — neither produced one, so the slot has NO category and
|
|
255
|
+
* retrieval cannot gate it; `corrected` — a designer set it with a
|
|
256
|
+
* `set-slot-category` correction. Widened with {@link OpenEnum} so a newer
|
|
257
|
+
* server term still type-checks.
|
|
258
|
+
*/
|
|
259
|
+
export type SlotCategorySource = OpenEnum<"resolved" | "resolved-coverage" | "model" | "none" | "corrected">;
|
|
248
260
|
/**
|
|
249
261
|
* Suspend payload for the compose `review-programme` step: the FULL programme
|
|
250
262
|
* picture — every space and slot tagged with its provenance — so the card can
|
|
251
263
|
* show the whole thing and highlight what was inferred.
|
|
264
|
+
*
|
|
265
|
+
* Each slot also discloses the catalog `category` it will shop in and the
|
|
266
|
+
* `categorySource` that won it (MG-954). Both are OPTIONAL and additive: an
|
|
267
|
+
* ABSENT `category` means the slot has none — not that it has an empty one — and
|
|
268
|
+
* a slot in that state cannot be gated at retrieval, so it is skipped there with
|
|
269
|
+
* a counted shortfall unless a `set-slot-category` correction supplies one.
|
|
252
270
|
*/
|
|
253
271
|
export interface ReviewProgrammeSuspendPayload {
|
|
254
272
|
spaces: Array<{
|
|
@@ -262,12 +280,20 @@ export interface ReviewProgrammeSuspendPayload {
|
|
|
262
280
|
name: string;
|
|
263
281
|
spaceId?: string;
|
|
264
282
|
element?: SlotElement;
|
|
283
|
+
category?: string;
|
|
284
|
+
categorySource?: SlotCategorySource;
|
|
265
285
|
provenance: ProgrammeProvenance;
|
|
266
286
|
}>;
|
|
267
287
|
}
|
|
268
288
|
/**
|
|
269
289
|
* Resume grammar for the `review-programme` step: drop a slot, drop a space
|
|
270
|
-
* (cascade-dropping its slots), or
|
|
290
|
+
* (cascade-dropping its slots), rename a space, or set a slot's category.
|
|
291
|
+
*
|
|
292
|
+
* `set-slot-category` (MG-954) is an action INSIDE this same corrections array;
|
|
293
|
+
* its `category` must be one of the server's catalog category GROUP names (the
|
|
294
|
+
* same vocabulary the payload's `category` is drawn from) or the resume is
|
|
295
|
+
* refused. An empty `corrections` array stays legal however the step came to
|
|
296
|
+
* suspend — the suspension discloses, it does not coerce.
|
|
271
297
|
*/
|
|
272
298
|
export interface ReviewProgrammeResumeData {
|
|
273
299
|
corrections: Array<{
|
|
@@ -280,6 +306,10 @@ export interface ReviewProgrammeResumeData {
|
|
|
280
306
|
action: "rename-space";
|
|
281
307
|
spaceId: string;
|
|
282
308
|
name: string;
|
|
309
|
+
} | {
|
|
310
|
+
action: "set-slot-category";
|
|
311
|
+
slotId: string;
|
|
312
|
+
category: string;
|
|
283
313
|
}>;
|
|
284
314
|
}
|
|
285
315
|
/**
|
package/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type * from "./run-events.js";
|
|
|
15
15
|
export { MaterialGraphError } from "./errors.js";
|
|
16
16
|
export type { MaterialGraphErrorInit, MaterialGraphErrorKind, MaterialGraphRequestMetadata, ProblemDetail, RateLimit, SanitizedErrorValue, SanitizedIssue, SimpleErrorBody, } from "./errors.js";
|
|
17
17
|
export type * from "./types.js";
|
|
18
|
+
export type * from "./by-colour-types.js";
|
|
18
19
|
export { MATCH_IMAGE_TYPES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
|
|
19
20
|
export type * from "./match-stream-types.js";
|
|
20
21
|
export { CodesClient } from "./codes-client.js";
|
|
@@ -23,6 +24,7 @@ export { ColoursClient } from "./colours-client.js";
|
|
|
23
24
|
export type { ColoursTransport } from "./colours-client.js";
|
|
24
25
|
export type * from "./colour-aggregate-types.js";
|
|
25
26
|
export type * from "./palette-search-types.js";
|
|
27
|
+
export type * from "./association-types.js";
|
|
26
28
|
export type * from "./brand-types.js";
|
|
27
29
|
export type * from "./material-asset-types.js";
|
|
28
30
|
export type * from "./material-block-types.js";
|
package/material-types.d.ts
CHANGED
|
@@ -67,6 +67,14 @@ export interface MaterialTile {
|
|
|
67
67
|
category: string | null;
|
|
68
68
|
colour: MaterialColour;
|
|
69
69
|
availability: MaterialAvailability;
|
|
70
|
+
/**
|
|
71
|
+
* The accepted Colour Name attribute — the colourway's true name where
|
|
72
|
+
* `variantName` collapsed to the product's (MG-940: 83.7% of visible
|
|
73
|
+
* colourway families name every variant after the product, e.g. all 10 CF
|
|
74
|
+
* Stinson "Drift" colourways share `variantName: "Drift"`). Absent means
|
|
75
|
+
* the attribute is absent — never render a missing key as "unnamed".
|
|
76
|
+
*/
|
|
77
|
+
colourName?: string;
|
|
70
78
|
}
|
|
71
79
|
/**
|
|
72
80
|
* A canonical attribute/term pair carried on a detail record.
|
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 ["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 ["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 ["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 ["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];
|
|
@@ -10,6 +10,12 @@ export type SdkOperation = Readonly<{
|
|
|
10
10
|
export declare const SDK_OPERATIONS: readonly SdkOperation[];
|
|
11
11
|
/** Look up a registered operation by its OpenAPI `operationId`. */
|
|
12
12
|
export declare function findSdkOperation(operationId: SdkOperationId): SdkOperation | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Look up a registered operation, or throw. The lookup every caller that holds
|
|
15
|
+
* a literal `operationId` wants — lived as a private copy in `client.ts` and
|
|
16
|
+
* `projects.ts` before the association lens would have made it a third.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveOperation(operationId: SdkOperationId): SdkOperation;
|
|
13
19
|
/** Substitute `{param}` path placeholders with percent-encoded values. */
|
|
14
20
|
export declare function operationPath(sdkOperation: SdkOperation, pathParams?: Readonly<Record<string, string>>): string;
|
|
15
21
|
export {};
|
package/operations.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MaterialGraphError } from "./errors.js";
|
|
1
2
|
export const MATERIALGRAPH_API_VERSION = "0.7.0";
|
|
2
3
|
const OPERATION_DEFINITIONS = [
|
|
3
4
|
["search", "POST", "/api/v1/search", "search_materials_post"],
|
|
@@ -18,6 +19,8 @@ const OPERATION_DEFINITIONS = [
|
|
|
18
19
|
["schema", "GET", "/api/v1/schema/product-type-templates", "list_schema_product_type_templates"],
|
|
19
20
|
["schema", "GET", "/api/v1/schema/mappings", "list_schema_mappings"],
|
|
20
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"],
|
|
21
24
|
["materials", "POST", "/api/v1/materials/batch", "get_materials_batch_post"],
|
|
22
25
|
["materialsCached", "GET", "/api/v1/materials/batch", "get_materials_batch_get"],
|
|
23
26
|
["browse", "GET", "/api/v1/search/browse", "search_browse_by_colour"],
|
|
@@ -35,6 +38,7 @@ const OPERATION_DEFINITIONS = [
|
|
|
35
38
|
"catalog_resolve_value",
|
|
36
39
|
],
|
|
37
40
|
["searchVocabulary", "GET", "/api/v1/catalog/vocabulary/search", "catalog_vocabulary_search"],
|
|
41
|
+
["resolve", "POST", "/api/v1/resolve", "resolve_phrases"],
|
|
38
42
|
["bySpec", "GET", "/api/v1/search/specifications", "catalog_by_spec"],
|
|
39
43
|
["taxonomy", "GET", "/api/v1/taxonomy/categories", "get_category_taxonomy"],
|
|
40
44
|
["whoami", "GET", "/api/v1/whoami", "whoami"],
|
|
@@ -58,6 +62,7 @@ const OPERATION_DEFINITIONS = [
|
|
|
58
62
|
["sourceMaterialBatch", "GET", "/api/v1/source-material/{batchId}", "get_source_material_batch"],
|
|
59
63
|
["capabilities", "GET", "/api/v1/capabilities", "list_public_capabilities"],
|
|
60
64
|
["createRun", "POST", "/api/v1/runs", "create_public_run"],
|
|
65
|
+
["listRuns", "GET", "/api/v1/runs", "list_public_runs"],
|
|
61
66
|
["run", "GET", "/api/v1/runs/{runId}", "get_public_run"],
|
|
62
67
|
["runSchedule", "GET", "/api/v1/runs/{runId}/schedule", "get_run_finish_schedule"],
|
|
63
68
|
["streamRunEvents", "GET", "/api/v1/runs/{runId}/events", "list_public_run_events"],
|
|
@@ -78,6 +83,17 @@ export const SDK_OPERATIONS = Object.freeze(OPERATION_DEFINITIONS.map(([clientMe
|
|
|
78
83
|
export function findSdkOperation(operationId) {
|
|
79
84
|
return SDK_OPERATIONS.find((candidate) => candidate.operationId === operationId);
|
|
80
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Look up a registered operation, or throw. The lookup every caller that holds
|
|
88
|
+
* a literal `operationId` wants — lived as a private copy in `client.ts` and
|
|
89
|
+
* `projects.ts` before the association lens would have made it a third.
|
|
90
|
+
*/
|
|
91
|
+
export function resolveOperation(operationId) {
|
|
92
|
+
const match = findSdkOperation(operationId);
|
|
93
|
+
if (!match)
|
|
94
|
+
throw MaterialGraphError.unexpected(`Unknown SDK operation: ${operationId}`);
|
|
95
|
+
return match;
|
|
96
|
+
}
|
|
81
97
|
/** Substitute `{param}` path placeholders with percent-encoded values. */
|
|
82
98
|
export function operationPath(sdkOperation, pathParams = {}) {
|
|
83
99
|
return Object.entries(pathParams).reduce((path, [name, value]) => path.replace(`{${name}}`, encodeURIComponent(value)), sdkOperation.path);
|
package/package.json
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The VOCABULARY lens — words in, canonical tokens out. The two requests that
|
|
3
|
+
* answer "what is this phrase CALLED here?" rather than "what materials match
|
|
4
|
+
* it?", lifted out of the client facade so the facade stays a facade and the
|
|
5
|
+
* hover documentation has room to say what a caller actually needs.
|
|
6
|
+
*
|
|
7
|
+
* Standalone functions over the shared {@link HttpTransport}, not a namespace:
|
|
8
|
+
* `mg.resolve()` and `mg.searchVocabulary()` are flat methods on the public API
|
|
9
|
+
* and stay that way — `MaterialGraphClient` keeps a one-line delegating method
|
|
10
|
+
* for each, so nothing about the published surface moves. Same shape as
|
|
11
|
+
* `associations-client.ts`; auth, rate-limit accounting and error shaping stay
|
|
12
|
+
* in the one transport.
|
|
13
|
+
*
|
|
14
|
+
* ROUTING INTO AND OUT OF THIS LENS. It is the lens you reach for INSTEAD OF
|
|
15
|
+
* keeping a hand-written table of your users' words mapped onto this API's
|
|
16
|
+
* tokens: that table is a copy of a registry you do not own, and it drifts
|
|
17
|
+
* silently the moment the registry moves.
|
|
18
|
+
* - The whole phrase, any vocabulary → {@link resolvePhrasesRequest}. Batched,
|
|
19
|
+
* deterministic, and it says so out loud when a word means nothing here.
|
|
20
|
+
* - You already know it is an attribute, or a value under a known attribute →
|
|
21
|
+
* `mg.resolveAttribute()` / `mg.resolveAttributeValue()`.
|
|
22
|
+
* - You want to EXPLAIN a token you already hold → `mg.glossary(term)`.
|
|
23
|
+
* - You want to complete a name as someone types → `mg.suggest()`.
|
|
24
|
+
* - You want MATERIALS → `mg.search()`. This lens never returns one.
|
|
25
|
+
*/
|
|
26
|
+
import type { HttpTransport } from "./http-transport.js";
|
|
27
|
+
import type { ResolveResponse } from "./resolve-types.js";
|
|
28
|
+
import type { VocabularySearchOptions, VocabularySearchResponse } from "./types.js";
|
|
29
|
+
/**
|
|
30
|
+
* THE QUESTION: "I have words — what do they mean in YOUR vocabulary?" Send up
|
|
31
|
+
* to 50 phrases as your users typed them; each comes back with every canonical
|
|
32
|
+
* token MaterialGraph knows it as — brand, exact paint, colour family, category,
|
|
33
|
+
* attribute, value — best first, in request order. Backs `mg.resolve()`.
|
|
34
|
+
*
|
|
35
|
+
* A phrase can legitimately mean several things at once ("sage" is two vendor
|
|
36
|
+
* paints AND a colour family), so each entry carries a LIST of readings rather
|
|
37
|
+
* than a winner, and `kind` says which vocabulary each came from.
|
|
38
|
+
*
|
|
39
|
+
* Three rules worth reading before you spend a result:
|
|
40
|
+
* - **`unresolved` is stated, not inferred.** A phrase this vocabulary has no
|
|
41
|
+
* word for returns `resolved: []` AND `unresolved: true`, so you can tell an
|
|
42
|
+
* absent word from a dropped one. Absent is not false: it is a statement about
|
|
43
|
+
* this vocabulary, never about the material world.
|
|
44
|
+
* - **Ids are opaque.** Hand them back verbatim (see `./identifiers.ts`);
|
|
45
|
+
* `colour` and `attribute_value` ids arrive namespaced by their dictionary,
|
|
46
|
+
* because a term id is unique only within one.
|
|
47
|
+
* - **`rung` says how it matched** — `exact`, `alias`, or `lexical`. There is no
|
|
48
|
+
* semantic rung: every tier that would cost an embedding round-trip is off,
|
|
49
|
+
* which is what keeps this millisecond-class. A phrase only a semantic match
|
|
50
|
+
* could have caught comes back unresolved rather than slow.
|
|
51
|
+
*
|
|
52
|
+
* Deterministic — the same batch resolves to the same bytes every time. Instead
|
|
53
|
+
* use `mg.search()` when you want materials rather than words, `mg.suggest()` to
|
|
54
|
+
* complete a name as someone types, and `mg.glossary()` to EXPLAIN a token you
|
|
55
|
+
* have already resolved.
|
|
56
|
+
*
|
|
57
|
+
* @param phrases 1-50 phrases, each 1-200 characters. Sent as-is; each is
|
|
58
|
+
* resolved independently, so one meaningless phrase never spoils the batch.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolvePhrasesRequest(transport: HttpTransport, phrases: string[], signal?: AbortSignal): Promise<ResolveResponse>;
|
|
61
|
+
/**
|
|
62
|
+
* THE QUESTION: "is 'FloorScore' an attribute or a value, and what is it called
|
|
63
|
+
* here?" The catch-all for ONE phrase when you do not know which half of an
|
|
64
|
+
* `attribute:value` pair it belongs to. Backs `mg.searchVocabulary()`.
|
|
65
|
+
*
|
|
66
|
+
* Instead use `mg.resolveAttribute()` / `mg.resolveAttributeValue()` once you do
|
|
67
|
+
* know, {@link resolvePhrasesRequest} when you have SEVERAL phrases or the
|
|
68
|
+
* phrase might name a brand, paint, colour or category rather than a spec, and
|
|
69
|
+
* `mg.glossary()` to EXPLAIN a term rather than find it.
|
|
70
|
+
*/
|
|
71
|
+
export declare function searchVocabularyRequest(transport: HttpTransport, query: string, options?: VocabularySearchOptions, signal?: AbortSignal): Promise<VocabularySearchResponse>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { resolveOperation } from "./operations.js";
|
|
2
|
+
/**
|
|
3
|
+
* THE QUESTION: "I have words — what do they mean in YOUR vocabulary?" Send up
|
|
4
|
+
* to 50 phrases as your users typed them; each comes back with every canonical
|
|
5
|
+
* token MaterialGraph knows it as — brand, exact paint, colour family, category,
|
|
6
|
+
* attribute, value — best first, in request order. Backs `mg.resolve()`.
|
|
7
|
+
*
|
|
8
|
+
* A phrase can legitimately mean several things at once ("sage" is two vendor
|
|
9
|
+
* paints AND a colour family), so each entry carries a LIST of readings rather
|
|
10
|
+
* than a winner, and `kind` says which vocabulary each came from.
|
|
11
|
+
*
|
|
12
|
+
* Three rules worth reading before you spend a result:
|
|
13
|
+
* - **`unresolved` is stated, not inferred.** A phrase this vocabulary has no
|
|
14
|
+
* word for returns `resolved: []` AND `unresolved: true`, so you can tell an
|
|
15
|
+
* absent word from a dropped one. Absent is not false: it is a statement about
|
|
16
|
+
* this vocabulary, never about the material world.
|
|
17
|
+
* - **Ids are opaque.** Hand them back verbatim (see `./identifiers.ts`);
|
|
18
|
+
* `colour` and `attribute_value` ids arrive namespaced by their dictionary,
|
|
19
|
+
* because a term id is unique only within one.
|
|
20
|
+
* - **`rung` says how it matched** — `exact`, `alias`, or `lexical`. There is no
|
|
21
|
+
* semantic rung: every tier that would cost an embedding round-trip is off,
|
|
22
|
+
* which is what keeps this millisecond-class. A phrase only a semantic match
|
|
23
|
+
* could have caught comes back unresolved rather than slow.
|
|
24
|
+
*
|
|
25
|
+
* Deterministic — the same batch resolves to the same bytes every time. Instead
|
|
26
|
+
* use `mg.search()` when you want materials rather than words, `mg.suggest()` to
|
|
27
|
+
* complete a name as someone types, and `mg.glossary()` to EXPLAIN a token you
|
|
28
|
+
* have already resolved.
|
|
29
|
+
*
|
|
30
|
+
* @param phrases 1-50 phrases, each 1-200 characters. Sent as-is; each is
|
|
31
|
+
* resolved independently, so one meaningless phrase never spoils the batch.
|
|
32
|
+
*/
|
|
33
|
+
export function resolvePhrasesRequest(transport, phrases, signal) {
|
|
34
|
+
return transport.requestJson(resolveOperation("resolve_phrases"), {
|
|
35
|
+
body: { phrases },
|
|
36
|
+
signal,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* THE QUESTION: "is 'FloorScore' an attribute or a value, and what is it called
|
|
41
|
+
* here?" The catch-all for ONE phrase when you do not know which half of an
|
|
42
|
+
* `attribute:value` pair it belongs to. Backs `mg.searchVocabulary()`.
|
|
43
|
+
*
|
|
44
|
+
* Instead use `mg.resolveAttribute()` / `mg.resolveAttributeValue()` once you do
|
|
45
|
+
* know, {@link resolvePhrasesRequest} when you have SEVERAL phrases or the
|
|
46
|
+
* phrase might name a brand, paint, colour or category rather than a spec, and
|
|
47
|
+
* `mg.glossary()` to EXPLAIN a term rather than find it.
|
|
48
|
+
*/
|
|
49
|
+
export function searchVocabularyRequest(transport, query, options, signal) {
|
|
50
|
+
return transport.requestJson(resolveOperation("catalog_vocabulary_search"), { query: { q: query, limit: options?.limit, kind: options?.kind }, signal });
|
|
51
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary lens (MG-913) — the hand-mirrored wire types for
|
|
3
|
+
* `POST /api/v1/resolve`.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `types.ts` for the repository's source-file size budget, the same
|
|
6
|
+
* reason `suggest-types.ts` sits beside it; both are re-exported from `types.ts`,
|
|
7
|
+
* so importers see no difference.
|
|
8
|
+
*
|
|
9
|
+
* THE LENS: it turns WORDS into vocabulary, never into materials.
|
|
10
|
+
* `mg.search()` answers "I want materials" and `mg.answer` questions want prose;
|
|
11
|
+
* this answers "what do these words mean in your vocabulary?" — the question you
|
|
12
|
+
* ask BEFORE you spend a token on a filter, a facet or a brand slug. It is the
|
|
13
|
+
* reason you should not keep a hand-written table mapping your users' words onto
|
|
14
|
+
* this API's tokens: that table is a copy of a registry you do not own, and it
|
|
15
|
+
* drifts silently the moment the registry moves.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Which controlled vocabulary a reading came from — and therefore what `id`
|
|
19
|
+
* means and where you can spend it.
|
|
20
|
+
*
|
|
21
|
+
* - `brand` — a brand slug, for `mg.brand()` or a brand filter.
|
|
22
|
+
* - `paint_identity` — one exact vendor paint (a library colour), by its vendor
|
|
23
|
+
* code where the library has one.
|
|
24
|
+
* - `colour` — a canonical colour-family term, namespaced (`colour_family.green`).
|
|
25
|
+
* - `category` — a product-category taxonomy node key.
|
|
26
|
+
* - `attribute` — a registry attribute id: the LEFT half of an `attribute:value`
|
|
27
|
+
* pair, for `mg.bySpec()` or `search({ filters })`.
|
|
28
|
+
* - `attribute_value` — a value-dictionary term, namespaced (`ms_sheen.matte`):
|
|
29
|
+
* the RIGHT half.
|
|
30
|
+
*/
|
|
31
|
+
export type ResolutionKind = "brand" | "paint_identity" | "colour" | "category" | "attribute" | "attribute_value";
|
|
32
|
+
/**
|
|
33
|
+
* How the phrase matched, strongest first. `exact` — it IS the canonical token;
|
|
34
|
+
* `alias` — it IS a recorded alternative name for it; `lexical` — it resembles
|
|
35
|
+
* one closely enough to clear the resolver's own confidence floor.
|
|
36
|
+
*
|
|
37
|
+
* There is deliberately no `semantic` rung on this lens. Every tier that would
|
|
38
|
+
* cost an embedding round-trip is switched off, which is what keeps resolution
|
|
39
|
+
* millisecond-class; a phrase only a semantic match could have caught comes back
|
|
40
|
+
* unresolved rather than slow.
|
|
41
|
+
*/
|
|
42
|
+
export type ResolutionRung = "exact" | "alias" | "lexical";
|
|
43
|
+
/** One thing a phrase turned out to mean. */
|
|
44
|
+
export interface ResolvedMeaning {
|
|
45
|
+
kind: ResolutionKind;
|
|
46
|
+
/**
|
|
47
|
+
* The canonical token. OPAQUE — hand it back verbatim, never parse, tidy or
|
|
48
|
+
* construct one. The single thing worth knowing about the SHAPE: a
|
|
49
|
+
* value-dictionary term id is unique only within its dictionary, so `colour`
|
|
50
|
+
* and `attribute_value` ids arrive namespaced as `<dictionaryId>.<termId>`.
|
|
51
|
+
*/
|
|
52
|
+
id: string;
|
|
53
|
+
/** The canonical display term — what to show a human, not what to send back. */
|
|
54
|
+
term: string;
|
|
55
|
+
rung: ResolutionRung;
|
|
56
|
+
/**
|
|
57
|
+
* The resolver's own confidence in [0,1], present only when the underlying
|
|
58
|
+
* resolver produces one. Its ABSENCE is meaningful rather than missing data:
|
|
59
|
+
* the rung is then the whole statement, because an exact paint identity is an
|
|
60
|
+
* equality and not a score.
|
|
61
|
+
*/
|
|
62
|
+
confidence?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Present only when the resolver reported a runner-up. A small `gap` means the
|
|
65
|
+
* answer was nearly something else; when the resolver refused to break the tie,
|
|
66
|
+
* every tied reading is listed and `gap` is 0.
|
|
67
|
+
*/
|
|
68
|
+
ambiguity?: {
|
|
69
|
+
gap: number;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** What one phrase resolved to — including, explicitly, nothing. */
|
|
73
|
+
export interface PhraseResolution {
|
|
74
|
+
/** The phrase exactly as you sent it, so you can rejoin the batch by value. */
|
|
75
|
+
phrase: string;
|
|
76
|
+
/**
|
|
77
|
+
* The phrase in the one normalised form the resolvers fold to — the same
|
|
78
|
+
* `normalise` stage a search query passes through. Empty when the phrase was
|
|
79
|
+
* all punctuation.
|
|
80
|
+
*/
|
|
81
|
+
normalised: string;
|
|
82
|
+
/**
|
|
83
|
+
* Everything the phrase means here, best first. A phrase can legitimately mean
|
|
84
|
+
* several things at once ("sage" is two vendor paints AND a colour family), so
|
|
85
|
+
* this is a list rather than a winner.
|
|
86
|
+
*/
|
|
87
|
+
resolved: ResolvedMeaning[];
|
|
88
|
+
/**
|
|
89
|
+
* TRUE when nothing resolved. Read this rather than inferring it from
|
|
90
|
+
* `resolved.length`: the redundancy is deliberate, because a consumer that
|
|
91
|
+
* cannot SEE what failed to resolve cannot tell a word this vocabulary does
|
|
92
|
+
* not have from a word something quietly dropped. Absent is not false — an
|
|
93
|
+
* unresolved phrase is a statement about this vocabulary, never about the
|
|
94
|
+
* material world.
|
|
95
|
+
*/
|
|
96
|
+
unresolved: boolean;
|
|
97
|
+
}
|
|
98
|
+
/** The resolve response: one entry per phrase, in the order you sent them. */
|
|
99
|
+
export interface ResolveResponse {
|
|
100
|
+
/** One per phrase, in request order — never reordered, never deduplicated. */
|
|
101
|
+
resolutions: PhraseResolution[];
|
|
102
|
+
}
|
package/resolve-types.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary lens (MG-913) — the hand-mirrored wire types for
|
|
3
|
+
* `POST /api/v1/resolve`.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `types.ts` for the repository's source-file size budget, the same
|
|
6
|
+
* reason `suggest-types.ts` sits beside it; both are re-exported from `types.ts`,
|
|
7
|
+
* so importers see no difference.
|
|
8
|
+
*
|
|
9
|
+
* THE LENS: it turns WORDS into vocabulary, never into materials.
|
|
10
|
+
* `mg.search()` answers "I want materials" and `mg.answer` questions want prose;
|
|
11
|
+
* this answers "what do these words mean in your vocabulary?" — the question you
|
|
12
|
+
* ask BEFORE you spend a token on a filter, a facet or a brand slug. It is the
|
|
13
|
+
* reason you should not keep a hand-written table mapping your users' words onto
|
|
14
|
+
* this API's tokens: that table is a copy of a registry you do not own, and it
|
|
15
|
+
* drifts silently the moment the registry moves.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
package/run-types.d.ts
CHANGED
|
@@ -233,6 +233,31 @@ export interface CreatePublicRunResponse {
|
|
|
233
233
|
export interface PublicRunResponse {
|
|
234
234
|
run: PublicRun;
|
|
235
235
|
}
|
|
236
|
+
/** Query for `GET /api/v1/runs` ({@link MaterialGraphClient.listRuns}). */
|
|
237
|
+
export interface ListRunsOptions {
|
|
238
|
+
/**
|
|
239
|
+
* Return only Runs in this status. `"suspended"` is the recovery question:
|
|
240
|
+
* which of my Runs is still waiting on an answer?
|
|
241
|
+
*/
|
|
242
|
+
status?: PublicRunStatus;
|
|
243
|
+
/** Page size, 1–100. Defaults to 20 server-side. */
|
|
244
|
+
limit?: number;
|
|
245
|
+
/**
|
|
246
|
+
* The previous page's {@link PublicRunListResponse.nextCursor}, round-tripped
|
|
247
|
+
* VERBATIM. It is opaque — never parse or construct one.
|
|
248
|
+
*/
|
|
249
|
+
cursor?: string;
|
|
250
|
+
signal?: AbortSignal;
|
|
251
|
+
}
|
|
252
|
+
/** The `GET /api/v1/runs` response envelope — one page, newest first. */
|
|
253
|
+
export interface PublicRunListResponse {
|
|
254
|
+
runs: PublicRun[];
|
|
255
|
+
/**
|
|
256
|
+
* Pass as {@link ListRunsOptions.cursor} for the next page. ABSENT — not
|
|
257
|
+
* empty-string, not null — once the last page has been served.
|
|
258
|
+
*/
|
|
259
|
+
nextCursor?: string;
|
|
260
|
+
}
|
|
236
261
|
/** Body for `POST /api/v1/runs/{runId}/resume`. */
|
|
237
262
|
export interface ResumePublicRunRequest {
|
|
238
263
|
/** The resume payload, validated against the suspended step's resume schema. */
|