@instruments/materialgraph 0.3.0 → 0.4.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/client-browse.d.ts +46 -0
- package/client-browse.js +42 -0
- package/client.d.ts +15 -5
- package/client.js +17 -22
- package/material-asset-types.d.ts +1 -1
- package/operations.d.ts +1 -1
- package/operations.js +1 -0
- package/package.json +1 -1
- package/suggest-types.d.ts +58 -0
- package/suggest-types.js +21 -0
- package/types.d.ts +1 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `browse` namespace's implementation — the paged colour-ordered walk of the
|
|
3
|
+
* corpus behind `client.browse(...)` and `client.browse.pages(...)`.
|
|
4
|
+
*
|
|
5
|
+
* Lifted out of `client.ts` for the repository's source-file size budget. These
|
|
6
|
+
* were already private implementations behind a public namespace, so nothing
|
|
7
|
+
* about the client's surface changes: `client.browse` is still a callable with a
|
|
8
|
+
* `.pages()` generator, and the class still owns the transport. What moved is
|
|
9
|
+
* the pagination LOOP, which is the only real logic here and the only part worth
|
|
10
|
+
* testing on its own.
|
|
11
|
+
*/
|
|
12
|
+
import type { BrowseParams, BrowseResponse } from "./types.js";
|
|
13
|
+
/** `client.browse(...)` — callable for one page, `.pages()` for the whole walk. */
|
|
14
|
+
export interface BrowseNamespace {
|
|
15
|
+
(params: BrowseParams, signal?: AbortSignal): Promise<BrowseResponse>;
|
|
16
|
+
pages(params: BrowseParams, signal?: AbortSignal): AsyncGenerator<BrowseResponse, void, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/** Fetch one page. The client supplies this, so the transport stays private. */
|
|
19
|
+
export type BrowsePageFetcher = (params: BrowseParams, signal?: AbortSignal) => Promise<BrowseResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* The query string for one browse page — the four params the route reads, named
|
|
22
|
+
* here so the client method and the pagination loop cannot disagree about them.
|
|
23
|
+
*/
|
|
24
|
+
export declare function browseQuery(params: BrowseParams): {
|
|
25
|
+
sort: BrowseParams["sort"];
|
|
26
|
+
cursor: BrowseParams["cursor"];
|
|
27
|
+
limit: BrowseParams["limit"];
|
|
28
|
+
types: BrowseParams["types"];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Walk every page from `params.cursor` onward.
|
|
32
|
+
*
|
|
33
|
+
* Stops on the first page that reports no next cursor OR comes back empty. Both
|
|
34
|
+
* conditions matter: a server that keeps handing out a cursor for an exhausted
|
|
35
|
+
* scan would otherwise spin here forever, and an infinite generator is a hang,
|
|
36
|
+
* not an error anyone can see.
|
|
37
|
+
*/
|
|
38
|
+
export declare function browsePages(fetchPage: BrowsePageFetcher, params: BrowseParams, signal?: AbortSignal): AsyncGenerator<BrowseResponse, void, unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* Build the callable-with-`.pages()` object the client exposes as `browse`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const page = await client.browse({ sort: "lightest" });
|
|
44
|
+
* for await (const page of client.browse.pages({ sort: "lightest" })) { … }
|
|
45
|
+
*/
|
|
46
|
+
export declare function createBrowseNamespace(fetchPage: BrowsePageFetcher): BrowseNamespace;
|
package/client-browse.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The query string for one browse page — the four params the route reads, named
|
|
3
|
+
* here so the client method and the pagination loop cannot disagree about them.
|
|
4
|
+
*/
|
|
5
|
+
export function browseQuery(params) {
|
|
6
|
+
return {
|
|
7
|
+
sort: params.sort,
|
|
8
|
+
cursor: params.cursor,
|
|
9
|
+
limit: params.limit,
|
|
10
|
+
types: params.types,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Walk every page from `params.cursor` onward.
|
|
15
|
+
*
|
|
16
|
+
* Stops on the first page that reports no next cursor OR comes back empty. Both
|
|
17
|
+
* conditions matter: a server that keeps handing out a cursor for an exhausted
|
|
18
|
+
* scan would otherwise spin here forever, and an infinite generator is a hang,
|
|
19
|
+
* not an error anyone can see.
|
|
20
|
+
*/
|
|
21
|
+
export async function* browsePages(fetchPage, params, signal) {
|
|
22
|
+
let cursor = params.cursor;
|
|
23
|
+
for (;;) {
|
|
24
|
+
const page = await fetchPage({ ...params, cursor }, signal);
|
|
25
|
+
yield page;
|
|
26
|
+
if (page.cursor === undefined || page.results.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
cursor = page.cursor;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build the callable-with-`.pages()` object the client exposes as `browse`.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const page = await client.browse({ sort: "lightest" });
|
|
36
|
+
* for await (const page of client.browse.pages({ sort: "lightest" })) { … }
|
|
37
|
+
*/
|
|
38
|
+
export function createBrowseNamespace(fetchPage) {
|
|
39
|
+
const browse = (params, signal) => fetchPage(params, signal);
|
|
40
|
+
browse.pages = (params, signal) => browsePages(fetchPage, params, signal);
|
|
41
|
+
return browse;
|
|
42
|
+
}
|
package/client.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type RateLimit } from "./errors.js";
|
|
2
|
+
import { type BrowseNamespace } from "./client-browse.js";
|
|
3
|
+
export type { BrowseNamespace } from "./client-browse.js";
|
|
2
4
|
import type { CapabilityManifestResponse, CreatePublicRunRequest, CreatePublicRunResponse, DrainRunEventsOptions, PublicRunResponse, ResumeRunOptions, RunEvent, SourceMaterialBatchDetail, SourceMaterialBatchReceipt, StreamRunEventsOptions, UploadSourceMaterialInput } from "./run-types.js";
|
|
3
5
|
import type { FinishScheduleResponse, GetRunScheduleOptions } from "./schedule-types.js";
|
|
4
6
|
import type { MatchStreamEvent } from "./match-stream-types.js";
|
|
@@ -11,7 +13,7 @@ import type { BrandCatalogListPage, BrandsOptions } from "./brand-types.js";
|
|
|
11
13
|
import type { MaterialAssetProjection } from "./material-asset-types.js";
|
|
12
14
|
import type { MaterialBlockProjection } from "./material-block-types.js";
|
|
13
15
|
import type { SchemaResource, SchemaResourceResponse } from "./schema-resource-types.js";
|
|
14
|
-
import type { ApplicableSpecsResponse, BrandOptions, BrandProfileResponse, ByColourParams, ByColourResponse,
|
|
16
|
+
import type { ApplicableSpecsResponse, BrandOptions, BrandProfileResponse, ByColourParams, ByColourResponse, BySpecOptions, BySpecResponse, ColourFacetsResponse, CoordinateInput, CoordinateResponse, DemandBatchInput, DemandBatchResponse, DemandParams, DemandResponse, ExtractPaletteInput, ExtractPaletteResponse, GlossaryTermResponse, MaterialResponse, MaterialsBatchDetailResponse, MaterialsBatchGetOptions, MaterialsBatchOptions, MaterialsBatchTileResponse, MatchInput, MatchResponse, PairingsOptions, PairingsResponse, ResolveAttributeOptions, ResolveAttributeResponse, ResolveAttributeValueOptions, ResolveAttributeValueResponse, ResolveColourResponse, SearchGetParams, SearchInput, SearchResponse, SiblingsResponse, SpecFacetsDistributionResponse, SpecFacetsListResponse, SuggestColourResponse, SuggestOptions, SuggestResponse, TaxonomyResponse, VocabularySearchOptions, VocabularySearchResponse, WhoamiResponse } from "./types.js";
|
|
15
17
|
export declare const DEFAULT_BASE_URL = "https://beta.materialgraph.com";
|
|
16
18
|
export declare const MAX_BATCH_IDS = 100;
|
|
17
19
|
export interface MaterialGraphClientOptions {
|
|
@@ -22,10 +24,6 @@ export interface MaterialGraphClientOptions {
|
|
|
22
24
|
/** Inject a custom `fetch` (tests, proxies). Defaults to the global `fetch`. */
|
|
23
25
|
fetch?: typeof fetch;
|
|
24
26
|
}
|
|
25
|
-
export interface BrowseNamespace {
|
|
26
|
-
(params: BrowseParams, signal?: AbortSignal): Promise<BrowseResponse>;
|
|
27
|
-
pages(params: BrowseParams, signal?: AbortSignal): AsyncGenerator<BrowseResponse, void, unknown>;
|
|
28
|
-
}
|
|
29
27
|
export declare class MaterialGraphClient {
|
|
30
28
|
#private;
|
|
31
29
|
readonly baseUrl: string;
|
|
@@ -130,6 +128,18 @@ export declare class MaterialGraphClient {
|
|
|
130
128
|
suggestColour(q: string, options?: {
|
|
131
129
|
limit?: number;
|
|
132
130
|
}, signal?: AbortSignal): Promise<SuggestColourResponse>;
|
|
131
|
+
/**
|
|
132
|
+
* Entity typeahead across products, brands and categories
|
|
133
|
+
* (GET `/api/v1/search/suggest`). Built for per-keystroke use: one indexed
|
|
134
|
+
* lookup, no embedding call and no model. Every suggestion carries the
|
|
135
|
+
* `refId` it resolves to — a product id, a brand slug, or a product-type key
|
|
136
|
+
* — so selecting one should navigate to that entity rather than re-running
|
|
137
|
+
* `label` as a search.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* const { suggestions } = await client.suggest("carr", { kind: "product" });
|
|
141
|
+
*/
|
|
142
|
+
suggest(q: string, options?: SuggestOptions, signal?: AbortSignal): Promise<SuggestResponse>;
|
|
133
143
|
/** Resolve a free-text spec phrase to canonical attribute ids (GET `/api/v1/catalog/attributes/resolve`). */
|
|
134
144
|
resolveAttribute(q: string, options?: ResolveAttributeOptions, signal?: AbortSignal): Promise<ResolveAttributeResponse>;
|
|
135
145
|
/** Resolve a value phrase against one canonical attribute's dictionary. */
|
package/client.js
CHANGED
|
@@ -2,6 +2,8 @@ import { MaterialGraphError } from "./errors.js";
|
|
|
2
2
|
import { HttpTransport } from "./http-transport.js";
|
|
3
3
|
import { findSdkOperation } from "./operations.js";
|
|
4
4
|
import { cancelRun, capabilities as capabilitiesRun, createRun, drainRunEvents, getRun, getRunSchedule, getSourceMaterialBatch as getSourceMaterialBatchCall, resumeRun, streamRunEvents, uploadSourceMaterial, } from "./runs.js";
|
|
5
|
+
import { browseQuery, createBrowseNamespace } from "./client-browse.js";
|
|
6
|
+
import { suggestQuery } from "./suggest-types.js";
|
|
5
7
|
import { matchStream as matchStreamCall } from "./match-stream.js";
|
|
6
8
|
import { appendProjectEvent as appendProjectEventCall, createProject as createProjectCall, getProject as getProjectCall, listProjects as listProjectsCall, } from "./projects.js";
|
|
7
9
|
import { CodesClient } from "./codes-client.js";
|
|
@@ -51,9 +53,7 @@ export class MaterialGraphClient {
|
|
|
51
53
|
fetch: options.fetch ?? globalThis.fetch,
|
|
52
54
|
});
|
|
53
55
|
this.baseUrl = this.#transport.baseUrl;
|
|
54
|
-
|
|
55
|
-
browse.pages = (params, signal) => this.#browsePages(params, signal);
|
|
56
|
-
this.browse = browse;
|
|
56
|
+
this.browse = createBrowseNamespace((params, signal) => this.#get("search_browse_by_colour", browseQuery(params), signal));
|
|
57
57
|
this.codes = new CodesClient({
|
|
58
58
|
get: (operationId, query, signal) => this.#get(operationId, query, signal),
|
|
59
59
|
post: (operationId, body, signal) => this.#post(operationId, body, signal),
|
|
@@ -173,25 +173,6 @@ export class MaterialGraphClient {
|
|
|
173
173
|
idKind: options?.idKind ?? "variantId",
|
|
174
174
|
}, signal);
|
|
175
175
|
}
|
|
176
|
-
// ── Browse (private impls behind the `browse` namespace) ─────────────────────
|
|
177
|
-
#browsePage(params, signal) {
|
|
178
|
-
return this.#get("search_browse_by_colour", {
|
|
179
|
-
sort: params.sort,
|
|
180
|
-
cursor: params.cursor,
|
|
181
|
-
limit: params.limit,
|
|
182
|
-
types: params.types,
|
|
183
|
-
}, signal);
|
|
184
|
-
}
|
|
185
|
-
async *#browsePages(params, signal) {
|
|
186
|
-
let cursor = params.cursor;
|
|
187
|
-
for (;;) {
|
|
188
|
-
const page = await this.#browsePage({ ...params, cursor }, signal);
|
|
189
|
-
yield page;
|
|
190
|
-
if (page.cursor === undefined || page.results.length === 0)
|
|
191
|
-
return;
|
|
192
|
-
cursor = page.cursor;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
176
|
// ── Colour helpers ───────────────────────────────────────────────────────────
|
|
196
177
|
/** The three canonical colour vocabularies with live counts (GET `/api/v1/colours/facets`). */
|
|
197
178
|
colourFacets(signal) {
|
|
@@ -205,6 +186,20 @@ export class MaterialGraphClient {
|
|
|
205
186
|
suggestColour(q, options, signal) {
|
|
206
187
|
return this.#get("suggest_colour_names", { q, limit: options?.limit }, signal);
|
|
207
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Entity typeahead across products, brands and categories
|
|
191
|
+
* (GET `/api/v1/search/suggest`). Built for per-keystroke use: one indexed
|
|
192
|
+
* lookup, no embedding call and no model. Every suggestion carries the
|
|
193
|
+
* `refId` it resolves to — a product id, a brand slug, or a product-type key
|
|
194
|
+
* — so selecting one should navigate to that entity rather than re-running
|
|
195
|
+
* `label` as a search.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* const { suggestions } = await client.suggest("carr", { kind: "product" });
|
|
199
|
+
*/
|
|
200
|
+
suggest(q, options, signal) {
|
|
201
|
+
return this.#get("search_suggest", suggestQuery(q, options), signal);
|
|
202
|
+
}
|
|
208
203
|
// ── Catalog ──────────────────────────────────────────────────────────────────
|
|
209
204
|
/** Resolve a free-text spec phrase to canonical attribute ids (GET `/api/v1/catalog/attributes/resolve`). */
|
|
210
205
|
resolveAttribute(q, options, signal) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenEnum } from "./types.js";
|
|
2
2
|
export type MaterialAssetVisualRole = OpenEnum<"grid" | "detail" | "scene" | "swatch" | "technical" | "unknown">;
|
|
3
|
-
export type MaterialAssetStatus = OpenEnum<"downloaded" | "linked_not_downloaded" | "failed">;
|
|
3
|
+
export type MaterialAssetStatus = OpenEnum<"downloaded" | "linked_not_downloaded" | "failed" | "retired_placeholder">;
|
|
4
4
|
export interface MaterialAssetProjectionImage {
|
|
5
5
|
key: string;
|
|
6
6
|
ordinal: number;
|
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 ["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 ["extractPalette", "POST", "/api/v1/search/palettes/extract", "extract_image_palette"], 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 ["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 ["extractPalette", "POST", "/api/v1/search/palettes/extract", "extract_image_palette"], 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"]];
|
|
3
3
|
export type SdkOperationId = (typeof OPERATION_DEFINITIONS)[number][3];
|
|
4
4
|
export type SdkOperation = Readonly<{
|
|
5
5
|
clientMethod: (typeof OPERATION_DEFINITIONS)[number][0];
|
package/operations.js
CHANGED
|
@@ -26,6 +26,7 @@ const OPERATION_DEFINITIONS = [
|
|
|
26
26
|
["colours.stats", "GET", "/api/v1/colours/stats", "get_colour_stats"],
|
|
27
27
|
["resolveColour", "GET", "/api/v1/search/colours/resolve", "resolve_colour_name"],
|
|
28
28
|
["suggestColour", "GET", "/api/v1/search/colours/suggest", "suggest_colour_names"],
|
|
29
|
+
["suggest", "GET", "/api/v1/search/suggest", "search_suggest"],
|
|
29
30
|
["resolveAttribute", "GET", "/api/v1/catalog/attributes/resolve", "catalog_resolve_attribute"],
|
|
30
31
|
[
|
|
31
32
|
"resolveAttributeValue",
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity typeahead (MG-654) — the hand-mirrored wire types for
|
|
3
|
+
* `GET /api/v1/search/suggest`, plus the one query-shaping rule the endpoint
|
|
4
|
+
* imposes.
|
|
5
|
+
*
|
|
6
|
+
* Split out of `types.ts` for the repository's source-file size budget, the same
|
|
7
|
+
* reason `catalog-discovery-types.ts` sits beside it; both are re-exported from
|
|
8
|
+
* `types.ts`, so importers see no difference.
|
|
9
|
+
*/
|
|
10
|
+
/** Which kind of entity a suggestion is — and therefore what `refId` means. */
|
|
11
|
+
export type SuggestKind = "product" | "brand" | "category";
|
|
12
|
+
/** How the query met the suggestion's label. Strongest first. */
|
|
13
|
+
export type SuggestMatch = "prefix" | "word" | "contains" | "fuzzy";
|
|
14
|
+
/** One ranked typeahead suggestion, carrying the identity it resolves to. */
|
|
15
|
+
export interface Suggestion {
|
|
16
|
+
kind: SuggestKind;
|
|
17
|
+
/** The entity's name as written, for display. */
|
|
18
|
+
label: string;
|
|
19
|
+
/**
|
|
20
|
+
* The resolvable identity: a product id, a brand slug, or a product-type key.
|
|
21
|
+
* Selecting a suggestion should navigate to this, not re-search `label`.
|
|
22
|
+
*/
|
|
23
|
+
refId: string;
|
|
24
|
+
match: SuggestMatch;
|
|
25
|
+
brandSlug: string | null;
|
|
26
|
+
brandName: string | null;
|
|
27
|
+
categoryKey: string | null;
|
|
28
|
+
/** A representative variant, so a client can open a material record directly. */
|
|
29
|
+
variantId: string | null;
|
|
30
|
+
variantCount: number;
|
|
31
|
+
}
|
|
32
|
+
/** The suggest response: the query as interpreted, plus the ranked suggestions. */
|
|
33
|
+
export interface SuggestResponse {
|
|
34
|
+
/** The normalised query the corpus was matched against. */
|
|
35
|
+
query: string;
|
|
36
|
+
/** Ranked best-match-first. Empty when nothing came close — a miss, not an error. */
|
|
37
|
+
suggestions: Suggestion[];
|
|
38
|
+
}
|
|
39
|
+
/** Options for {@link MaterialGraphClient.suggest}. */
|
|
40
|
+
export interface SuggestOptions {
|
|
41
|
+
/** How many suggestions to return (1–20, default 8). */
|
|
42
|
+
limit?: number;
|
|
43
|
+
/** Restrict to these kinds. Omit for all of them. */
|
|
44
|
+
kind?: SuggestKind | SuggestKind[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Shape the query string for a suggest call.
|
|
48
|
+
*
|
|
49
|
+
* The only non-obvious rule: `kind` is a COMMA LIST on the wire (`product,brand`),
|
|
50
|
+
* which is the house convention for multi-value v1 params, so an array is joined
|
|
51
|
+
* here rather than being sent as repeated `?kind=` pairs the route would ignore.
|
|
52
|
+
* Undefined members are dropped by the transport.
|
|
53
|
+
*/
|
|
54
|
+
export declare function suggestQuery(q: string, options?: SuggestOptions): {
|
|
55
|
+
q: string;
|
|
56
|
+
limit?: number;
|
|
57
|
+
kind?: string;
|
|
58
|
+
};
|
package/suggest-types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity typeahead (MG-654) — the hand-mirrored wire types for
|
|
3
|
+
* `GET /api/v1/search/suggest`, plus the one query-shaping rule the endpoint
|
|
4
|
+
* imposes.
|
|
5
|
+
*
|
|
6
|
+
* Split out of `types.ts` for the repository's source-file size budget, the same
|
|
7
|
+
* reason `catalog-discovery-types.ts` sits beside it; both are re-exported from
|
|
8
|
+
* `types.ts`, so importers see no difference.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Shape the query string for a suggest call.
|
|
12
|
+
*
|
|
13
|
+
* The only non-obvious rule: `kind` is a COMMA LIST on the wire (`product,brand`),
|
|
14
|
+
* which is the house convention for multi-value v1 params, so an array is joined
|
|
15
|
+
* here rather than being sent as repeated `?kind=` pairs the route would ignore.
|
|
16
|
+
* Undefined members are dropped by the transport.
|
|
17
|
+
*/
|
|
18
|
+
export function suggestQuery(q, options) {
|
|
19
|
+
const kind = Array.isArray(options?.kind) ? options.kind.join(",") : options?.kind;
|
|
20
|
+
return { q, limit: options?.limit, kind };
|
|
21
|
+
}
|
package/types.d.ts
CHANGED
|
@@ -363,6 +363,7 @@ export interface ResolveAttributeResponse {
|
|
|
363
363
|
candidates: AttributeCandidate[];
|
|
364
364
|
}
|
|
365
365
|
export type * from "./catalog-discovery-types.js";
|
|
366
|
+
export type * from "./suggest-types.js";
|
|
366
367
|
export type * from "./by-spec-types.js";
|
|
367
368
|
export interface WhoamiResponse {
|
|
368
369
|
principal: string;
|