@instruments/materialgraph 0.7.1 → 0.9.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 +139 -0
- package/by-colour-types.js +1 -0
- package/client-config.d.ts +17 -0
- package/client-config.js +9 -0
- package/client.d.ts +35 -22
- package/client.js +46 -32
- package/composition-types.d.ts +31 -1
- package/index.d.ts +4 -1
- package/index.js +1 -1
- package/match-stream-types.d.ts +85 -1
- package/match-stream-types.js +8 -0
- package/match-stream.d.ts +1 -1
- package/match-types.d.ts +101 -0
- package/match-types.js +1 -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-events.d.ts +11 -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 +8 -0
- package/types.d.ts +83 -104
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,7 +15,9 @@ 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
|
|
18
|
+
export type * from "./match-types.js";
|
|
19
|
+
export type * from "./by-colour-types.js";
|
|
20
|
+
export { MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
|
|
19
21
|
export type * from "./match-stream-types.js";
|
|
20
22
|
export { CodesClient } from "./codes-client.js";
|
|
21
23
|
export type * from "./codes-types.js";
|
|
@@ -23,6 +25,7 @@ export { ColoursClient } from "./colours-client.js";
|
|
|
23
25
|
export type { ColoursTransport } from "./colours-client.js";
|
|
24
26
|
export type * from "./colour-aggregate-types.js";
|
|
25
27
|
export type * from "./palette-search-types.js";
|
|
28
|
+
export type * from "./association-types.js";
|
|
26
29
|
export type * from "./brand-types.js";
|
|
27
30
|
export type * from "./material-asset-types.js";
|
|
28
31
|
export type * from "./material-block-types.js";
|
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { VARY_AXES } from "./composition-types.js";
|
|
|
5
5
|
export { PROJECT_EVENT_KINDS } from "./project-types.js";
|
|
6
6
|
export { COMPOSITION_PHASE_EVENT_TYPES, COMPOSITION_PROGRAMME_EVENT_TYPES, COMPOSITION_REVIEW_CRITERIA_EVENT_TYPES, parseRunEvent, } from "./run-events.js";
|
|
7
7
|
export { MaterialGraphError } from "./errors.js";
|
|
8
|
-
export { MATCH_IMAGE_TYPES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
|
|
8
|
+
export { MATCH_IMAGE_TYPES, MATCH_OUTCOMES, MATCH_MATERIAL_FUNCTIONS, MATCH_STREAM_EVENT_TYPES, MATCH_SURFACE_STATUSES, MATCH_WORKFLOW_STEPS, } from "./match-stream-types.js";
|
|
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";
|
package/match-stream-types.d.ts
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* The value lists are exported so a consumer can build an exhaustive switch or a
|
|
16
16
|
* UI legend from the same source the validator uses.
|
|
17
17
|
*/
|
|
18
|
-
import type {
|
|
18
|
+
import type { SearchResultItem } from "./types.js";
|
|
19
|
+
import type { MatchCategoryInference, MatchColourReading } from "./match-types.js";
|
|
19
20
|
/** How the workflow classified the uploaded image. */
|
|
20
21
|
export declare const MATCH_IMAGE_TYPES: readonly ["swatch", "installation", "flatplan"];
|
|
21
22
|
export type MatchImageType = (typeof MATCH_IMAGE_TYPES)[number];
|
|
@@ -57,21 +58,99 @@ export interface MatchDetectedSurface {
|
|
|
57
58
|
* arrives repeatedly as the run progresses (`matching` → `complete` / `error`);
|
|
58
59
|
* render by replacing on id rather than appending.
|
|
59
60
|
*
|
|
61
|
+
* A `complete` surface can arrive TWICE: the first frame delivers its finished
|
|
62
|
+
* results as soon as they exist, and a second repeats them unchanged with the
|
|
63
|
+
* verifier's per-candidate verdicts attached (`senseCheck`).
|
|
64
|
+
* Replacing on id handles both; the results never change between them, so
|
|
65
|
+
* nothing a user is looking at moves when the second lands.
|
|
66
|
+
*
|
|
60
67
|
* `results` and `inferredCategories` are always present on a yielded event: the
|
|
61
68
|
* canonical schema defaults each to `[]`, and the reader fills them when the
|
|
62
69
|
* server omits them, so neither ever arrives as `undefined`.
|
|
63
70
|
*/
|
|
71
|
+
/**
|
|
72
|
+
* What a Match actually compared, so a consumer can tell "the catalogue holds
|
|
73
|
+
* nothing close" from "everything ranked badly" (MG-1031). Without it both
|
|
74
|
+
* arrive as an empty list and the difference is unrecoverable.
|
|
75
|
+
*
|
|
76
|
+
* UNITS: `qualityFloor` and `bestRejected` are absolute image-arm cosines in
|
|
77
|
+
* [0,1] — the same unit as each result's `confidence` — so they belong on one
|
|
78
|
+
* axis. `poolSize` and `droppedBelowFloor` are counts and belong on neither.
|
|
79
|
+
*/
|
|
80
|
+
export interface MatchComparison {
|
|
81
|
+
/** Candidates retrieved before the quality floor and product dedup. */
|
|
82
|
+
poolSize: number;
|
|
83
|
+
/** How many of those the quality floor rejected. */
|
|
84
|
+
droppedBelowFloor: number;
|
|
85
|
+
/** The floor they were held to, as an absolute image cosine in [0,1]. */
|
|
86
|
+
qualityFloor: number;
|
|
87
|
+
/**
|
|
88
|
+
* The closest REJECTED candidate, same unit as `qualityFloor`. Absent when
|
|
89
|
+
* nothing was rejected, or when the rejects carried no readable signal.
|
|
90
|
+
*/
|
|
91
|
+
bestRejected?: number;
|
|
92
|
+
}
|
|
64
93
|
export interface MatchSurfaceResult {
|
|
65
94
|
surface: MatchDetectedSurface;
|
|
66
95
|
status: MatchSurfaceStatus;
|
|
67
96
|
results: SearchResultItem[];
|
|
68
97
|
inferredCategories: MatchCategoryInference[];
|
|
98
|
+
/** What this surface compared against. Absent means the server did not report it. */
|
|
99
|
+
comparison?: MatchComparison;
|
|
100
|
+
/**
|
|
101
|
+
* The verifier's reading of each candidate, when it ran.
|
|
102
|
+
*
|
|
103
|
+
* ABSENT means the stage did not run — it is opt-out, and the swatch route
|
|
104
|
+
* never runs it — OR that it is still running, which `senseCheckPending`
|
|
105
|
+
* distinguishes. Neither is the same as every candidate abstaining, and a
|
|
106
|
+
* consumer must not conflate them.
|
|
107
|
+
*
|
|
108
|
+
* `abstained` is NOT a soft rejection: it means the candidate was not judged
|
|
109
|
+
* (no image, no answer, or the judge was unavailable). Never render an
|
|
110
|
+
* abstention as a negative signal about the material.
|
|
111
|
+
*/
|
|
112
|
+
senseCheck?: MatchSenseCheckCell[];
|
|
113
|
+
/**
|
|
114
|
+
* TRUE on the interim frame that delivers finished results while the verifier
|
|
115
|
+
* is still reading them. The verifier annotates; it never filters and never
|
|
116
|
+
* reorders, so this says "badges are coming", never "these results may
|
|
117
|
+
* change". Render the rows immediately.
|
|
118
|
+
*/
|
|
119
|
+
senseCheckPending?: boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Per-candidate colour readings against this surface's own crop, when the
|
|
122
|
+
* colour re-rank ran. `results` are already ordered by the blended score when
|
|
123
|
+
* this is present; this array is the receipt for that order.
|
|
124
|
+
*/
|
|
125
|
+
colour?: MatchColourReading[];
|
|
126
|
+
/** The segment's own extracted palette — what the colour stage matched against. */
|
|
127
|
+
segmentPalette?: Array<{
|
|
128
|
+
hex: string;
|
|
129
|
+
proportion: number;
|
|
130
|
+
}>;
|
|
69
131
|
/** Present only on `status: "error"` — why this one surface failed. */
|
|
70
132
|
error?: string;
|
|
71
133
|
}
|
|
134
|
+
/** The verifier's reading of one candidate, keyed back to its variant. */
|
|
135
|
+
export interface MatchSenseCheckCell {
|
|
136
|
+
variantId: string;
|
|
137
|
+
verdict: MatchSenseCheckVerdict;
|
|
138
|
+
reason: string;
|
|
139
|
+
}
|
|
140
|
+
export declare const MATCH_SENSE_CHECK_VERDICTS: readonly ["confirmed", "rejected", "abstained"];
|
|
141
|
+
export type MatchSenseCheckVerdict = (typeof MATCH_SENSE_CHECK_VERDICTS)[number];
|
|
72
142
|
/** The terminal Match workflow result — every surface in its final state. */
|
|
143
|
+
/**
|
|
144
|
+
* How a Match run ended. `no_surfaces` means the detector worked and found no
|
|
145
|
+
* material in the photo — a finding, not a failure. Branch on this rather than
|
|
146
|
+
* on an error message. Absent means `matched`.
|
|
147
|
+
*/
|
|
148
|
+
export declare const MATCH_OUTCOMES: readonly ["matched", "no_surfaces"];
|
|
149
|
+
export type MatchOutcome = (typeof MATCH_OUTCOMES)[number];
|
|
73
150
|
export interface MatchWorkflowResult {
|
|
74
151
|
imageType: MatchImageType;
|
|
152
|
+
/** How the run ended. Absent means `matched`. */
|
|
153
|
+
outcome?: MatchOutcome;
|
|
75
154
|
surfaces: MatchSurfaceResult[];
|
|
76
155
|
/** Present for swatch / single-surface runs that skip decompose. */
|
|
77
156
|
results?: SearchResultItem[];
|
|
@@ -82,6 +161,11 @@ export interface MatchWorkflowResult {
|
|
|
82
161
|
* "nothing above the floor". Do not fold `surfaces[]` to tell those apart.
|
|
83
162
|
*/
|
|
84
163
|
totals: MatchRunTotals;
|
|
164
|
+
/**
|
|
165
|
+
* What a SWATCH run compared against — a swatch detects no surfaces, so it has
|
|
166
|
+
* nowhere else to put this. A scene run reports per surface instead.
|
|
167
|
+
*/
|
|
168
|
+
comparison?: MatchComparison;
|
|
85
169
|
}
|
|
86
170
|
/** Progress narration for the phase the workflow just entered. */
|
|
87
171
|
export interface MatchStreamStepEvent {
|
package/match-stream-types.js
CHANGED
|
@@ -26,3 +26,11 @@ export const MATCH_STREAM_EVENT_TYPES = [
|
|
|
26
26
|
"complete",
|
|
27
27
|
"error",
|
|
28
28
|
];
|
|
29
|
+
export const MATCH_SENSE_CHECK_VERDICTS = ["confirmed", "rejected", "abstained"];
|
|
30
|
+
/** The terminal Match workflow result — every surface in its final state. */
|
|
31
|
+
/**
|
|
32
|
+
* How a Match run ended. `no_surfaces` means the detector worked and found no
|
|
33
|
+
* material in the photo — a finding, not a failure. Branch on this rather than
|
|
34
|
+
* on an error message. Absent means `matched`.
|
|
35
|
+
*/
|
|
36
|
+
export const MATCH_OUTCOMES = ["matched", "no_surfaces"];
|
package/match-stream.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { HttpTransport } from "./http-transport.js";
|
|
2
2
|
import { type MatchStreamEvent } from "./match-stream-types.js";
|
|
3
|
-
import type { MatchInput } from "./types.js";
|
|
3
|
+
import type { MatchInput } from "./match-types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Decode one NDJSON line into a validated {@link MatchStreamEvent}, raising a
|
|
6
6
|
* {@link MaterialGraphError} on anything the contract does not allow. Exported
|
package/match-types.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/match-types
|
|
3
|
+
* @description The buffered Material Match request and response, hand-mirrored
|
|
4
|
+
* from the server's Zod contracts.
|
|
5
|
+
*
|
|
6
|
+
* Split out of `types.ts` — which is at the repository's source-size limit —
|
|
7
|
+
* along its natural seam: everything a caller of `client.match()` needs, and
|
|
8
|
+
* nothing else. The STREAMING contracts live in `match-stream-types.ts`.
|
|
9
|
+
*/
|
|
10
|
+
import type { SearchFilter } from "./search-refinement-types.js";
|
|
11
|
+
import type { OpenEnum, PaletteSwatch, SearchResultItem } from "./types.js";
|
|
12
|
+
/** An inferred product-type category from the query image, with its boost. */
|
|
13
|
+
export interface MatchCategoryInference {
|
|
14
|
+
productTypeId: string;
|
|
15
|
+
displayName: string;
|
|
16
|
+
boost: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The Material Match response (non-streaming form).
|
|
20
|
+
*
|
|
21
|
+
* `poolSize` is the candidate pool the floor was applied to, NOT a corpus total
|
|
22
|
+
* and NOT "how many materials look like this". An empty `results` with
|
|
23
|
+
* `droppedBelowFloor > 0` means "candidates existed and none was good enough" —
|
|
24
|
+
* a different answer from `poolSize: 0`, which means the image found nothing to
|
|
25
|
+
* search against at all.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* One candidate's colour reading against the query crop. `measurable: false`
|
|
29
|
+
* means the material carries no palette on record — UNKNOWN, never "no colour"
|
|
30
|
+
* and never "the wrong colour".
|
|
31
|
+
*/
|
|
32
|
+
export interface MatchColourReading {
|
|
33
|
+
variantId: string;
|
|
34
|
+
colourDistance: number | null;
|
|
35
|
+
colourBand: string | null;
|
|
36
|
+
measurable: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface MatchResponse {
|
|
39
|
+
/** THIS answer, capped by `limit`. Not a total. */
|
|
40
|
+
results: SearchResultItem[];
|
|
41
|
+
inferredCategories: MatchCategoryInference[];
|
|
42
|
+
qualityFloor: number;
|
|
43
|
+
poolSize: number;
|
|
44
|
+
droppedBelowFloor: number;
|
|
45
|
+
droppedAsDuplicateProduct: number;
|
|
46
|
+
/**
|
|
47
|
+
* The closest candidate the quality floor REJECTED, in the same [0,1] unit as
|
|
48
|
+
* `qualityFloor`. This is what turns "no matches" into "the closest thing in
|
|
49
|
+
* the catalogue read 0.48 against a 0.55 bar" — the one number that separates
|
|
50
|
+
* an engine that failed from a corpus that does not hold the material. Absent
|
|
51
|
+
* when nothing was rejected; null when the rejects carried no readable signal.
|
|
52
|
+
*/
|
|
53
|
+
bestRejected?: number | null;
|
|
54
|
+
/** The maximum score achievable under the weights this query ran — `score`'s denominator. */
|
|
55
|
+
maxScore: number;
|
|
56
|
+
/**
|
|
57
|
+
* Per-candidate colour readings against the query crop, in `results` order.
|
|
58
|
+
* `null` means the colour stage DID NOT RUN (no image bytes, or it was turned
|
|
59
|
+
* off) — never "no colour".
|
|
60
|
+
*/
|
|
61
|
+
colour?: MatchColourReading[] | null;
|
|
62
|
+
/** The query crop's own extracted palette — what the colour stage compared against. */
|
|
63
|
+
segmentPalette?: PaletteSwatch[] | null;
|
|
64
|
+
note?: string;
|
|
65
|
+
}
|
|
66
|
+
/** The Material Match request body — exactly one of `imageBase64`, `imageUrl`, `vector`. */
|
|
67
|
+
export interface MatchInput {
|
|
68
|
+
imageBase64?: string;
|
|
69
|
+
imageUrl?: string;
|
|
70
|
+
vector?: string;
|
|
71
|
+
limit?: number;
|
|
72
|
+
qualityFloor?: number;
|
|
73
|
+
categoryTopK?: number;
|
|
74
|
+
categoryMinBoost?: number;
|
|
75
|
+
detectionLabel?: string;
|
|
76
|
+
/**
|
|
77
|
+
* The detector's fuller reading of the surface — a SENTENCE, where
|
|
78
|
+
* `detectionLabel` is a phrase. Fused WITH the image into ONE multimodal
|
|
79
|
+
* query vector and preferred over the label when both are present.
|
|
80
|
+
*
|
|
81
|
+
* Distinct from `detectionLabel`, which also buys the category scope: a
|
|
82
|
+
* request can narrow the scope by label and steer retrieval by description in
|
|
83
|
+
* the same call.
|
|
84
|
+
*/
|
|
85
|
+
detectionDescription?: string;
|
|
86
|
+
materialFunction?: string;
|
|
87
|
+
detectionCategory?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Opt-in: also return quality-floor rejects, flagged `belowFloor: true` and
|
|
90
|
+
* appended after the kept results. Absent/false = default behaviour;
|
|
91
|
+
* `droppedBelowFloor` is unchanged.
|
|
92
|
+
*/
|
|
93
|
+
includeBelowFloor?: boolean;
|
|
94
|
+
requestedType?: OpenEnum<"swatch" | "installation" | "flatplan">;
|
|
95
|
+
/** Hard spec gates forwarded verbatim to the inner search — term match or presence, each with an optional trust bar. */
|
|
96
|
+
filters?: SearchFilter[];
|
|
97
|
+
/** Soft criteria (rank-never-exclude). A miss demotes within the page but never removes a hit. */
|
|
98
|
+
preferences?: SearchFilter[];
|
|
99
|
+
/** Opt in to seed-relative verdict cells; inert unless the inner search carries a variant seed. */
|
|
100
|
+
verdicts?: boolean;
|
|
101
|
+
}
|
package/match-types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
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
|
+
}
|