@instruments/materialgraph 0.10.0 → 0.11.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/browse-types.d.ts +147 -0
- package/browse-types.js +1 -0
- package/by-colour-types.d.ts +56 -0
- package/client-browse.d.ts +13 -3
- package/client-browse.js +12 -2
- package/client-exploration.d.ts +9 -0
- package/client-exploration.js +7 -0
- package/client-source-material-comments.d.ts +51 -0
- package/client-source-material-comments.js +40 -0
- package/client.d.ts +28 -22
- package/client.js +33 -24
- package/colour-aggregate-types.d.ts +58 -0
- package/colours-client.d.ts +8 -2
- package/colours-client.js +15 -2
- package/composition-client.d.ts +33 -0
- package/composition-client.js +27 -0
- package/composition-types.d.ts +46 -0
- package/coordinate-client.d.ts +23 -0
- package/coordinate-client.js +25 -0
- package/exploration-types.d.ts +110 -0
- package/exploration-types.js +1 -0
- package/fan-deck-types.d.ts +4 -1
- package/index.d.ts +4 -1
- package/operations.d.ts +1 -1
- package/operations.js +25 -0
- package/package.json +1 -1
- package/palette-search-types.d.ts +31 -0
- package/run-types.d.ts +132 -0
- package/runs.d.ts +35 -1
- package/runs.js +61 -1
- package/schedule-types.d.ts +128 -0
- package/schema-resource-types.d.ts +1 -1
- package/search-refinement-types.d.ts +28 -1
- package/search-request-types.d.ts +172 -0
- package/search-request-types.js +1 -0
- package/slot-pool-types.d.ts +370 -0
- package/slot-pool-types.js +1 -0
- package/source-material-validation.d.ts +5 -1
- package/source-material-validation.js +111 -4
- package/types.d.ts +149 -199
- package/validation.d.ts +12 -0
- package/validation.js +23 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire types for the browse lane — GET `/api/v1/search/browse`.
|
|
3
|
+
*
|
|
4
|
+
* The SDK's one genuinely cursor-paginated surface, and the only lane with no
|
|
5
|
+
* query, no relevance and no ranking: the corpus in a stated order. That is what
|
|
6
|
+
* a category listing or a brand fan deck actually needs, and it is why `count`
|
|
7
|
+
* matters here more than anywhere else — a listing that cannot state its own
|
|
8
|
+
* size has to either walk every page or report a page size as a total.
|
|
9
|
+
*
|
|
10
|
+
* Lifted out of `types.ts` for the repository's source-file size budget when the
|
|
11
|
+
* lane gained its non-colour sorts and its feed count (MG-1483 / MG-1542).
|
|
12
|
+
* Nothing about the client's surface changed: `index.ts` re-exports these
|
|
13
|
+
* exactly as before.
|
|
14
|
+
*/
|
|
15
|
+
import type { ByColourSwatch } from "./by-colour-types.js";
|
|
16
|
+
import type { Cursor, ProductId, VariantId } from "./identifiers.js";
|
|
17
|
+
import type { CountedTotal, OpenEnum } from "./types.js";
|
|
18
|
+
/** One item from the pure colour-scalar browse. */
|
|
19
|
+
export interface BrowseResultItem {
|
|
20
|
+
/** Opaque — round-trip verbatim. */
|
|
21
|
+
variantId: VariantId;
|
|
22
|
+
brand: string;
|
|
23
|
+
product: string;
|
|
24
|
+
brandSlug: string | null;
|
|
25
|
+
productId: ProductId | null;
|
|
26
|
+
color: string | null;
|
|
27
|
+
variantName: string | null;
|
|
28
|
+
imageUrl: string | null;
|
|
29
|
+
scalars: {
|
|
30
|
+
l: number | null;
|
|
31
|
+
chroma: number | null;
|
|
32
|
+
vibrancy: number | null;
|
|
33
|
+
};
|
|
34
|
+
retired?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The row's own image palette — the FULL stored palette of the SAME image
|
|
37
|
+
* `imageUrl` serves, uncapped and in stored order, each swatch with `oklab`
|
|
38
|
+
* (see {@link ByColourSwatch}), so a card can render, sort or group colours
|
|
39
|
+
* without a second call. A one-swatch palette means the extractor found one
|
|
40
|
+
* colour (solid-colour materials are genuinely monochrome), not that the list
|
|
41
|
+
* was trimmed. ABSENT when no palette is on record for that image: absent
|
|
42
|
+
* means unknown, NOT that the material has no colours. These swatches come
|
|
43
|
+
* from product imagery, not from the manufacturer.
|
|
44
|
+
*/
|
|
45
|
+
palette?: ByColourSwatch[];
|
|
46
|
+
}
|
|
47
|
+
/** The browse orders. `name` (A→Z) is the default; `recent` is newest first. */
|
|
48
|
+
export type BrowseSort = OpenEnum<"name" | "recent" | "light" | "dark" | "vivid" | "muted" | "colourful">;
|
|
49
|
+
/**
|
|
50
|
+
* The browse feed's total — how many materials the browse DESCRIBES, which is
|
|
51
|
+
* never `results.length`.
|
|
52
|
+
*
|
|
53
|
+
* Uncapped, unlike {@link SearchCounts}: `basis:"exact"` is the true figure
|
|
54
|
+
* whatever its size, and `basis:"lowerBound"` means the count query timed out
|
|
55
|
+
* and the value is a floor. Counted over the SAME filters the page was drawn
|
|
56
|
+
* from, so a `types=`, `brands=` or `corpusScope=` narrowed browse reports the
|
|
57
|
+
* narrowed total — you will never get a whole-graph number beside a filtered
|
|
58
|
+
* page.
|
|
59
|
+
*/
|
|
60
|
+
export interface BrowseCounts {
|
|
61
|
+
variants: CountedTotal;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A single page of the browse — the SDK's one genuinely cursor-paginated
|
|
65
|
+
* surface. `results.length` is this page. Ask for `count: true` and `counts`
|
|
66
|
+
* states the total; without it the browse states no total at all, and a corpus
|
|
67
|
+
* claim can only come from walking every page (`client.browse.pages(...)` does
|
|
68
|
+
* the loop).
|
|
69
|
+
*/
|
|
70
|
+
export interface BrowseResponse {
|
|
71
|
+
/** THIS PAGE. */
|
|
72
|
+
results: BrowseResultItem[];
|
|
73
|
+
/** Opaque keyset for the next page. Absent = the walk is finished. */
|
|
74
|
+
cursor?: Cursor;
|
|
75
|
+
/**
|
|
76
|
+
* The order this page was built in — echoed, because `sort` is optional and
|
|
77
|
+
* defaulted, so a caller that omitted it need not know the server's default
|
|
78
|
+
* to label its own listing.
|
|
79
|
+
*/
|
|
80
|
+
sort: BrowseSort;
|
|
81
|
+
/**
|
|
82
|
+
* The total, present ONLY when `count: true` was passed. Absent means it was
|
|
83
|
+
* not asked for — never that the set is empty.
|
|
84
|
+
*/
|
|
85
|
+
counts?: BrowseCounts;
|
|
86
|
+
/**
|
|
87
|
+
* The corpus this page was drawn from — present ONLY when the request
|
|
88
|
+
* narrowed it. ABSENT means the whole graph: every material MaterialGraph
|
|
89
|
+
* knows, orderable or not.
|
|
90
|
+
*/
|
|
91
|
+
corpusScope?: {
|
|
92
|
+
scope: OpenEnum<"all" | "materialBankOrderable">;
|
|
93
|
+
/** What the scope admits, in one sentence, for a human reader. */
|
|
94
|
+
description: string;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** Params for the pure colour `search/browse` surface. */
|
|
98
|
+
export interface BrowseParams {
|
|
99
|
+
/**
|
|
100
|
+
* OPTIONAL. Defaults to `name` (A→Z); `recent` is newest first.
|
|
101
|
+
*
|
|
102
|
+
* The five colour ramps (`light`/`dark`/`vivid`/`muted`/`colourful`) order by
|
|
103
|
+
* an EXTRACTED colour scalar and therefore see only colour-extracted
|
|
104
|
+
* materials — a genuinely smaller set than `name` and `recent` walk. That is
|
|
105
|
+
* not a bug to route around; ask for `count` and each sort reports the size of
|
|
106
|
+
* the set it actually describes.
|
|
107
|
+
*/
|
|
108
|
+
sort?: BrowseSort;
|
|
109
|
+
/**
|
|
110
|
+
* The previous page's `cursor`, verbatim. Opaque keyset state — not an offset.
|
|
111
|
+
* Changing `sort`, `limit`, `types`, `brands` or `corpusScope` invalidates it.
|
|
112
|
+
*/
|
|
113
|
+
cursor?: Cursor;
|
|
114
|
+
/** Page size. */
|
|
115
|
+
limit?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Return `counts.variants` — the total size of the set this browse walks,
|
|
118
|
+
* counted over the same filters the page came from.
|
|
119
|
+
*
|
|
120
|
+
* Opt-in, because it is a second query. A category listing that cannot state
|
|
121
|
+
* how many things it is listing has to either walk every page or report the
|
|
122
|
+
* page size as a total; this is the third option.
|
|
123
|
+
*/
|
|
124
|
+
count?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Comma-separated taxonomy keys to restrict the browse to, at EITHER tier of
|
|
127
|
+
* `/api/v1/taxonomy/categories`. A GROUP key (`tile_surfaces`) expands to
|
|
128
|
+
* every product type under it, a TYPE key (`ceramic_porcelain_tile`) stands
|
|
129
|
+
* for itself, and a mixed list is their deduplicated union. A key in neither
|
|
130
|
+
* tier is a 400 listing the valid keys — never an empty page.
|
|
131
|
+
*/
|
|
132
|
+
types?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Comma-separated brand slugs (`farrow-ball`) or display names
|
|
135
|
+
* (`Farrow & Ball`), case-insensitive. One brand plus a colour `sort` is that
|
|
136
|
+
* brand's fan deck. An unknown brand is a 400 naming it, never an empty page.
|
|
137
|
+
*/
|
|
138
|
+
brands?: string;
|
|
139
|
+
/**
|
|
140
|
+
* Which corpus to walk. ABSENT means the whole graph — every material
|
|
141
|
+
* MaterialGraph knows, orderable or not. `materialBankOrderable` restricts to
|
|
142
|
+
* materials carrying a Material Bank identity, applied inside the scan, so a
|
|
143
|
+
* scoped page is still a full page and `cursor` still means another eligible
|
|
144
|
+
* row exists.
|
|
145
|
+
*/
|
|
146
|
+
corpusScope?: OpenEnum<"all" | "materialBankOrderable">;
|
|
147
|
+
}
|
package/browse-types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/by-colour-types.d.ts
CHANGED
|
@@ -106,6 +106,44 @@ export interface ColourCollapse {
|
|
|
106
106
|
/** Rows dropped for resolving to a better-ranked row's stored photograph. */
|
|
107
107
|
droppedBySharedImage: number;
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Receipt naming which retrieval lane answered, and the colours it actually ran
|
|
111
|
+
* on. The live endpoint always sends it.
|
|
112
|
+
*
|
|
113
|
+
* Two lanes answer two different questions. A ONE-COLOUR query is a CONTAINMENT
|
|
114
|
+
* question — which materials hold a swatch near this colour — and is answered as
|
|
115
|
+
* a bounded OKLab ball over stored palette swatches. A multi-colour query is a
|
|
116
|
+
* SIMILARITY question — which palettes as a whole resemble this palette — and is
|
|
117
|
+
* answered by nearest-neighbour over the palette embedding. The two rank on
|
|
118
|
+
* different geometries, so `colourDistance` on a match means a different thing
|
|
119
|
+
* in each and is NOT comparable across them.
|
|
120
|
+
*/
|
|
121
|
+
export interface ColourLaneReceipt {
|
|
122
|
+
/** Which lane answered. Widened so a new server lane still type-checks. */
|
|
123
|
+
lane: OpenEnum<"containment" | "palette">;
|
|
124
|
+
/** Why this lane, in one sentence, for a human reader. */
|
|
125
|
+
reason: string;
|
|
126
|
+
/**
|
|
127
|
+
* How the page was ordered. `representative` — the containment default —
|
|
128
|
+
* draws the page in the contained set's own proportions of solid and
|
|
129
|
+
* multi-swatch materials, nearest-first within each, because ordering
|
|
130
|
+
* containment by proximity alone returns a page of solid-colour materials.
|
|
131
|
+
*/
|
|
132
|
+
order: OpenEnum<"representative" | "nearest" | "similarity">;
|
|
133
|
+
/**
|
|
134
|
+
* The colours the search ACTUALLY ran on, after minor-proportion accents were
|
|
135
|
+
* dropped. Compare against `query.colours`: a difference means the search that
|
|
136
|
+
* ran is not the search you asked for.
|
|
137
|
+
*/
|
|
138
|
+
effectiveColours: string[];
|
|
139
|
+
/**
|
|
140
|
+
* Colours removed from your query for carrying a proportion below the accent
|
|
141
|
+
* threshold. EMPTY is the normal case. Non-empty and those colours were absent
|
|
142
|
+
* from retrieval entirely — they did not merely rank low, so an empty-looking
|
|
143
|
+
* result is not evidence that nothing holds them.
|
|
144
|
+
*/
|
|
145
|
+
droppedColours: string[];
|
|
146
|
+
}
|
|
109
147
|
/** The `search/colours` response. */
|
|
110
148
|
export interface ByColourResponse {
|
|
111
149
|
query: {
|
|
@@ -135,6 +173,24 @@ export interface ByColourResponse {
|
|
|
135
173
|
* overfetch allowed, and this says so in counts rather than adjectives.
|
|
136
174
|
*/
|
|
137
175
|
collapse?: ColourCollapse;
|
|
176
|
+
/**
|
|
177
|
+
* Which retrieval lane answered and the colours it ran on. The live endpoint
|
|
178
|
+
* always sends it; optional here only so responses captured before the lane
|
|
179
|
+
* split still type-check.
|
|
180
|
+
*/
|
|
181
|
+
lane?: ColourLaneReceipt;
|
|
182
|
+
/**
|
|
183
|
+
* The corpus this page was drawn from — present ONLY when the request
|
|
184
|
+
* narrowed it. ABSENT means the whole graph: every material MaterialGraph
|
|
185
|
+
* knows, orderable or not. Under a scope the `familyGate` and `collapse` pool
|
|
186
|
+
* counts describe the SCOPED corpus too, because the scope was applied inside
|
|
187
|
+
* retrieval rather than over the page it produced.
|
|
188
|
+
*/
|
|
189
|
+
corpusScope?: {
|
|
190
|
+
scope: OpenEnum<"all" | "materialBankOrderable">;
|
|
191
|
+
/** What the scope admits, in one sentence, for a human reader. */
|
|
192
|
+
description: string;
|
|
193
|
+
};
|
|
138
194
|
}
|
|
139
195
|
/** Params for `search/colours`. */
|
|
140
196
|
export interface ByColourParams {
|
package/client-browse.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* the pagination LOOP, which is the only real logic here and the only part worth
|
|
10
10
|
* testing on its own.
|
|
11
11
|
*/
|
|
12
|
-
import type { BrowseParams, BrowseResponse } from "./types.js";
|
|
12
|
+
import type { BrowseParams, BrowseResponse } from "./browse-types.js";
|
|
13
13
|
/**
|
|
14
14
|
* `client.browse(...)` — callable for ONE PAGE, `.pages()` for the whole walk.
|
|
15
15
|
*
|
|
@@ -24,14 +24,24 @@ export interface BrowseNamespace {
|
|
|
24
24
|
/** Fetch one page. The client supplies this, so the transport stays private. */
|
|
25
25
|
export type BrowsePageFetcher = (params: BrowseParams, signal?: AbortSignal) => Promise<BrowseResponse>;
|
|
26
26
|
/**
|
|
27
|
-
* The query string for one browse page —
|
|
28
|
-
*
|
|
27
|
+
* The query string for one browse page — EVERY param the route reads, named here
|
|
28
|
+
* so the client method and the pagination loop cannot disagree about them.
|
|
29
|
+
*
|
|
30
|
+
* "Every" is load-bearing. This is an allow-list wrapper, and an allow-list
|
|
31
|
+
* wrapper that rebuilds a query from named fields is precisely the shape that
|
|
32
|
+
* silently drops a param the server already honours: `brands` shipped on the
|
|
33
|
+
* route and never reached it from here, so the fan deck was unreachable through
|
|
34
|
+
* the published client while the server had supported it all along. When the
|
|
35
|
+
* route gains a param, it gains a line HERE too, or it is not shipped.
|
|
29
36
|
*/
|
|
30
37
|
export declare function browseQuery(params: BrowseParams): {
|
|
31
38
|
sort: BrowseParams["sort"];
|
|
32
39
|
cursor: BrowseParams["cursor"];
|
|
33
40
|
limit: BrowseParams["limit"];
|
|
41
|
+
count: BrowseParams["count"];
|
|
34
42
|
types: BrowseParams["types"];
|
|
43
|
+
brands: BrowseParams["brands"];
|
|
44
|
+
corpusScope: BrowseParams["corpusScope"];
|
|
35
45
|
};
|
|
36
46
|
/**
|
|
37
47
|
* Walk every page from `params.cursor` onward.
|
package/client-browse.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The query string for one browse page —
|
|
3
|
-
*
|
|
2
|
+
* The query string for one browse page — EVERY param the route reads, named here
|
|
3
|
+
* so the client method and the pagination loop cannot disagree about them.
|
|
4
|
+
*
|
|
5
|
+
* "Every" is load-bearing. This is an allow-list wrapper, and an allow-list
|
|
6
|
+
* wrapper that rebuilds a query from named fields is precisely the shape that
|
|
7
|
+
* silently drops a param the server already honours: `brands` shipped on the
|
|
8
|
+
* route and never reached it from here, so the fan deck was unreachable through
|
|
9
|
+
* the published client while the server had supported it all along. When the
|
|
10
|
+
* route gains a param, it gains a line HERE too, or it is not shipped.
|
|
4
11
|
*/
|
|
5
12
|
export function browseQuery(params) {
|
|
6
13
|
return {
|
|
7
14
|
sort: params.sort,
|
|
8
15
|
cursor: params.cursor,
|
|
9
16
|
limit: params.limit,
|
|
17
|
+
count: params.count,
|
|
10
18
|
types: params.types,
|
|
19
|
+
brands: params.brands,
|
|
20
|
+
corpusScope: params.corpusScope,
|
|
11
21
|
};
|
|
12
22
|
}
|
|
13
23
|
/**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CandidateReadInput, CandidateReadResponse, GraphOperatorEvidence } from "./exploration-types.js";
|
|
2
|
+
import type { HttpTransport } from "./http-transport.js";
|
|
3
|
+
import type { VariantId } from "./identifiers.js";
|
|
4
|
+
/** Discovery and traversal share one namespace so availability precedes use. */
|
|
5
|
+
export interface ExplorationNamespace {
|
|
6
|
+
operators(variantId: VariantId, signal?: AbortSignal): Promise<GraphOperatorEvidence>;
|
|
7
|
+
candidates(variantId: VariantId, input: CandidateReadInput, signal?: AbortSignal): Promise<CandidateReadResponse>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createExplorationNamespace(transport: HttpTransport): ExplorationNamespace;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { resolveOperation } from "./operations.js";
|
|
2
|
+
export function createExplorationNamespace(transport) {
|
|
3
|
+
return {
|
|
4
|
+
operators: (variantId, signal) => transport.requestJson(resolveOperation("list_material_operators"), { pathParams: { variantId }, signal }),
|
|
5
|
+
candidates: (variantId, input, signal) => transport.requestJson(resolveOperation("read_material_candidates"), { body: input, pathParams: { variantId }, signal }),
|
|
6
|
+
};
|
|
7
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-file comment surface, namespaced as `mg.sourceMaterialComments` — the
|
|
3
|
+
* argument people leave on one uploaded file (MG-1345).
|
|
4
|
+
*
|
|
5
|
+
* A namespace rather than two more flat methods on an already-large facade,
|
|
6
|
+
* following `mg.codes` and `mg.colours`: reading a thread and adding to it are
|
|
7
|
+
* one family, they share a `(batchId, sourceId)` referent, and neither makes
|
|
8
|
+
* sense without the other. The namespace holds no transport of its own — the
|
|
9
|
+
* client hands it the shared one, so auth, rate-limit accounting and error
|
|
10
|
+
* shaping stay in one place.
|
|
11
|
+
*
|
|
12
|
+
* TWO RULES A CONSUMER MUST NOT GET WRONG.
|
|
13
|
+
*
|
|
14
|
+
* **The author name is REPORTED, never verified.** Every comment carries
|
|
15
|
+
* `author.attribution: "reported"` — a name somebody typed — plus `recordedBy`,
|
|
16
|
+
* the authenticated principal that actually wrote the row. Render "recorded as
|
|
17
|
+
* from Ruth Fielding", never "Ruth Fielding said". The API takes a machine key,
|
|
18
|
+
* and the person whose argument a remark carries is usually not the person at
|
|
19
|
+
* the keyboard; presenting the one as the other is the failure this field
|
|
20
|
+
* exists to prevent.
|
|
21
|
+
*
|
|
22
|
+
* **A reply is not a root.** {@link SourceMaterialCommentsNamespace.post}
|
|
23
|
+
* returns a result discriminated on `kind`: switch on it rather than reaching
|
|
24
|
+
* for `replies`, which a `reply` does not have. Threads are one level deep and
|
|
25
|
+
* the database enforces it, so a reply can never grow replies of its own.
|
|
26
|
+
*
|
|
27
|
+
* ROUTING OUT OF THIS NAMESPACE. `mg.sourceMaterialBatch(batchId)` already
|
|
28
|
+
* inlines every file's thread, so opening a batch is ONE call — do not loop this
|
|
29
|
+
* namespace over a batch's files to rebuild what that read returns. Reach for
|
|
30
|
+
* `list` when you are watching a single file.
|
|
31
|
+
*/
|
|
32
|
+
import { HttpTransport } from "./http-transport.js";
|
|
33
|
+
import type { PostSourceMaterialCommentInput, PostSourceMaterialCommentResult, SourceMaterialCommentThread } from "./run-types.js";
|
|
34
|
+
export interface SourceMaterialCommentsNamespace {
|
|
35
|
+
/**
|
|
36
|
+
* One file's thread, oldest root first, each root carrying its replies.
|
|
37
|
+
* `comments` is always an array; `truncated` says whether you are holding the
|
|
38
|
+
* whole thread. A file that is not in that batch, or a batch you do not own,
|
|
39
|
+
* raises the same 404 as a file that never existed.
|
|
40
|
+
*/
|
|
41
|
+
list(batchId: string, sourceId: string, signal?: AbortSignal): Promise<SourceMaterialCommentThread>;
|
|
42
|
+
/**
|
|
43
|
+
* Add one remark. Pass `parentCommentId` to answer a ROOT comment on the same
|
|
44
|
+
* file; nesting deeper is a 400. Pass `idempotencyKey` so a retry after a
|
|
45
|
+
* network timeout returns the comment you already posted rather than a
|
|
46
|
+
* permanent duplicate.
|
|
47
|
+
*/
|
|
48
|
+
post(batchId: string, sourceId: string, input: PostSourceMaterialCommentInput, signal?: AbortSignal): Promise<PostSourceMaterialCommentResult>;
|
|
49
|
+
}
|
|
50
|
+
/** Bind the comment operations to the client's shared transport. */
|
|
51
|
+
export declare function createSourceMaterialCommentsNamespace(transport: HttpTransport): SourceMaterialCommentsNamespace;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-file comment surface, namespaced as `mg.sourceMaterialComments` — the
|
|
3
|
+
* argument people leave on one uploaded file (MG-1345).
|
|
4
|
+
*
|
|
5
|
+
* A namespace rather than two more flat methods on an already-large facade,
|
|
6
|
+
* following `mg.codes` and `mg.colours`: reading a thread and adding to it are
|
|
7
|
+
* one family, they share a `(batchId, sourceId)` referent, and neither makes
|
|
8
|
+
* sense without the other. The namespace holds no transport of its own — the
|
|
9
|
+
* client hands it the shared one, so auth, rate-limit accounting and error
|
|
10
|
+
* shaping stay in one place.
|
|
11
|
+
*
|
|
12
|
+
* TWO RULES A CONSUMER MUST NOT GET WRONG.
|
|
13
|
+
*
|
|
14
|
+
* **The author name is REPORTED, never verified.** Every comment carries
|
|
15
|
+
* `author.attribution: "reported"` — a name somebody typed — plus `recordedBy`,
|
|
16
|
+
* the authenticated principal that actually wrote the row. Render "recorded as
|
|
17
|
+
* from Ruth Fielding", never "Ruth Fielding said". The API takes a machine key,
|
|
18
|
+
* and the person whose argument a remark carries is usually not the person at
|
|
19
|
+
* the keyboard; presenting the one as the other is the failure this field
|
|
20
|
+
* exists to prevent.
|
|
21
|
+
*
|
|
22
|
+
* **A reply is not a root.** {@link SourceMaterialCommentsNamespace.post}
|
|
23
|
+
* returns a result discriminated on `kind`: switch on it rather than reaching
|
|
24
|
+
* for `replies`, which a `reply` does not have. Threads are one level deep and
|
|
25
|
+
* the database enforces it, so a reply can never grow replies of its own.
|
|
26
|
+
*
|
|
27
|
+
* ROUTING OUT OF THIS NAMESPACE. `mg.sourceMaterialBatch(batchId)` already
|
|
28
|
+
* inlines every file's thread, so opening a batch is ONE call — do not loop this
|
|
29
|
+
* namespace over a batch's files to rebuild what that read returns. Reach for
|
|
30
|
+
* `list` when you are watching a single file.
|
|
31
|
+
*/
|
|
32
|
+
import { HttpTransport } from "./http-transport.js";
|
|
33
|
+
import { listSourceMaterialComments, postSourceMaterialComment, } from "./runs.js";
|
|
34
|
+
/** Bind the comment operations to the client's shared transport. */
|
|
35
|
+
export function createSourceMaterialCommentsNamespace(transport) {
|
|
36
|
+
return {
|
|
37
|
+
list: (batchId, sourceId, signal) => listSourceMaterialComments(transport, batchId, sourceId, signal),
|
|
38
|
+
post: (batchId, sourceId, input, signal) => postSourceMaterialComment(transport, batchId, sourceId, input, signal),
|
|
39
|
+
};
|
|
40
|
+
}
|
package/client.d.ts
CHANGED
|
@@ -2,7 +2,11 @@ import type { MaterialGraphClientOptions } from "./client-config.js";
|
|
|
2
2
|
import { type RateLimit } from "./errors.js";
|
|
3
3
|
export * from "./client-config.js";
|
|
4
4
|
import { type BrowseNamespace } from "./client-browse.js";
|
|
5
|
+
import { type ExplorationNamespace } from "./client-exploration.js";
|
|
5
6
|
export type { BrowseNamespace } from "./client-browse.js";
|
|
7
|
+
export type { ExplorationNamespace } from "./client-exploration.js";
|
|
8
|
+
import { type SourceMaterialCommentsNamespace } from "./client-source-material-comments.js";
|
|
9
|
+
export type { SourceMaterialCommentsNamespace } from "./client-source-material-comments.js";
|
|
6
10
|
import type { AssociatedOptions } from "./association-types.js";
|
|
7
11
|
import type { BrandCatalogListPage, BrandsOptions } from "./brand-types.js";
|
|
8
12
|
import type { ByColourParams, ByColourResponse } from "./by-colour-types.js";
|
|
@@ -20,6 +24,7 @@ import { resolvePhrasesRequest as resolvePhrases } from "./resolve-client.js";
|
|
|
20
24
|
import type { CapabilityManifestResponse, CreatePublicRunRequest, CreatePublicRunResponse, DrainRunEventsOptions, ListRunsOptions, PublicRunListResponse, PublicRunResponse, ResumeRunOptions, RunEvent, SourceMaterialBatchDetail, SourceMaterialBatchReceipt, StreamRunEventsOptions, UploadSourceMaterialInput } from "./run-types.js";
|
|
21
25
|
import type { FinishScheduleResponse, GetRunScheduleOptions } from "./schedule-types.js";
|
|
22
26
|
import type { SchemaResource, SchemaResourceResponse } from "./schema-resource-types.js";
|
|
27
|
+
import type { SlotPoolsRequest, SlotPoolsResponse } from "./slot-pool-types.js";
|
|
23
28
|
import type { ApplicableSpecsResponse, BrandOptions, BrandProfileResponse, BySpecOptions, BySpecResponse, ColourFacetsResponse, CoordinateInput, CoordinateResponse, DemandBatchInput, DemandBatchResponse, DemandParams, DemandResponse, ExtractPaletteInput, ExtractPaletteResponse, GlossaryTermResponse, MaterialResponse, MaterialsBatchDetailResponse, MaterialsBatchGetOptions, MaterialsBatchOptions, MaterialsBatchTileResponse, PairingsOptions, PairingsResponse, ResolveAttributeOptions, ResolveAttributeResponse, ResolveAttributeValueOptions, ResolveAttributeValueResponse, ResolveColourResponse, SearchGetParams, SearchInput, SearchResponse, SiblingsResponse, SpecFacetsDistributionResponse, SpecFacetsListResponse, SuggestColourResponse, SuggestOptions, SuggestResponse, TaxonomyResponse, VocabularySearchOptions, WhoamiResponse } from "./types.js";
|
|
24
29
|
/**
|
|
25
30
|
* The MaterialGraph client — every lens on the graph, on one object.
|
|
@@ -61,14 +66,21 @@ export declare class MaterialGraphClient {
|
|
|
61
66
|
#private;
|
|
62
67
|
readonly baseUrl: string;
|
|
63
68
|
/**
|
|
64
|
-
* THE QUESTION: "show me everything
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
69
|
+
* THE QUESTION: "show me everything in this category / this brand, in a plain
|
|
70
|
+
* order." No query, no relevance, no ranking. `browse(params)` is one page;
|
|
71
|
+
* `browse.pages(params)` walks them all.
|
|
72
|
+
*
|
|
73
|
+
* `sort` is optional (`name` A→Z by default, `recent` for newest first, plus
|
|
74
|
+
* the five colour ramps), `types`/`brands`/`corpusScope` narrow it, and
|
|
75
|
+
* `count: true` returns the total so a listing can say how many things it is
|
|
76
|
+
* listing without walking every page. `results.length` remains a PAGE.
|
|
68
77
|
*
|
|
69
78
|
* Instead use {@link MaterialGraphClient.byColour} for materials NEAR a colour,
|
|
70
79
|
* {@link MaterialGraphClient.search} when there is anything to rank against,
|
|
71
80
|
* and `colours.profiles()` for a category's palette rather than its members.
|
|
81
|
+
*
|
|
82
|
+
* @example A category listing that can state its own size
|
|
83
|
+
* const page = await client.browse({ types: "tile_surfaces", count: true });
|
|
72
84
|
*/
|
|
73
85
|
readonly browse: BrowseNamespace;
|
|
74
86
|
/**
|
|
@@ -94,6 +106,14 @@ export declare class MaterialGraphClient {
|
|
|
94
106
|
* likeness, never a declared colour specification.
|
|
95
107
|
*/
|
|
96
108
|
readonly colours: ColoursClient;
|
|
109
|
+
/** Discover honest graph questions, then traverse one explicit operator. */
|
|
110
|
+
readonly exploration: ExplorationNamespace;
|
|
111
|
+
/**
|
|
112
|
+
* THE QUESTION: "what did people say about this uploaded file, and record what
|
|
113
|
+
* they said." Names on these remarks are REPORTED, never verified — see
|
|
114
|
+
* {@link SourceMaterialCommentsNamespace}.
|
|
115
|
+
*/
|
|
116
|
+
readonly sourceMaterialComments: SourceMaterialCommentsNamespace;
|
|
97
117
|
constructor(options: MaterialGraphClientOptions);
|
|
98
118
|
get lastRateLimit(): RateLimit | null;
|
|
99
119
|
/**
|
|
@@ -364,17 +384,7 @@ export declare class MaterialGraphClient {
|
|
|
364
384
|
* and `mg:admin` unlocks extra evidence fields.
|
|
365
385
|
*/
|
|
366
386
|
whoami(signal?: AbortSignal): Promise<WhoamiResponse>;
|
|
367
|
-
/**
|
|
368
|
-
* THE QUESTION: "here is my whole scheme so far — what completes it?" The
|
|
369
|
-
* multi-seed form of {@link MaterialGraphClient.pairings}: lift is summed across
|
|
370
|
-
* seeds, so a companion suiting one pick ranks below one suiting several.
|
|
371
|
-
* Instead use `pairings` for a single material and `colours.palette()` when the
|
|
372
|
-
* scheme is COLOURS rather than materials. Check `unresolved` before presenting.
|
|
373
|
-
*
|
|
374
|
-
* Coordinate a palette of already-chosen materials (POST
|
|
375
|
-
* `/api/v1/pairings/coordinate`). Returns demand-lift-ranked companions with
|
|
376
|
-
* colour swatches and an annotate-only `colourFit` (never reorders in v1).
|
|
377
|
-
*/
|
|
387
|
+
/** What completes a scheme already part-chosen. See {@link coordinateCall}. */
|
|
378
388
|
coordinate(input: CoordinateInput, signal?: AbortSignal): Promise<CoordinateResponse>;
|
|
379
389
|
/**
|
|
380
390
|
* THE QUESTION: "how much is this material actually specified, and what gets
|
|
@@ -553,14 +563,10 @@ export declare class MaterialGraphClient {
|
|
|
553
563
|
* Poll {@link MaterialGraphClient.run} for the terminal state.
|
|
554
564
|
*/
|
|
555
565
|
cancelRun(runId: RunId, signal?: AbortSignal): Promise<PublicRunResponse>;
|
|
556
|
-
/**
|
|
557
|
-
* Derive an "option B" scheme from a succeeded compose Run along one
|
|
558
|
-
* constraint axis (POST `/api/v1/schemes/vary`). Deterministic and
|
|
559
|
-
* synchronous — the response IS the hydrated scheme (no Run envelope), stamped
|
|
560
|
-
* with axis + source provenance whose `notes` are the variation's receipts.
|
|
561
|
-
* Requires the `mg:read` scope.
|
|
562
|
-
*/
|
|
566
|
+
/** Option B from a composed Run, along one axis. See {@link varySchemeCall}. */
|
|
563
567
|
varyScheme(body: VarySchemesRequest, signal?: AbortSignal): Promise<VarySchemesResponse>;
|
|
568
|
+
/** Ranked candidate pools for up to 24 slots. See {@link slotPoolsCall}. */
|
|
569
|
+
slotPools(body: SlotPoolsRequest, signal?: AbortSignal): Promise<SlotPoolsResponse>;
|
|
564
570
|
/**
|
|
565
571
|
* Stream ordered Run events as an async iterator (GET
|
|
566
572
|
* `/api/v1/runs/{runId}/events`, SSE). Iterates until the stream ends or the
|
package/client.js
CHANGED
|
@@ -7,10 +7,14 @@ import { cancelRun, capabilities as capabilitiesRun, createRun, drainRunEvents,
|
|
|
7
7
|
// Re-exported whole so `index.ts` and every existing importer keep their path.
|
|
8
8
|
export * from "./client-config.js";
|
|
9
9
|
import { browseQuery, createBrowseNamespace, } from "./client-browse.js";
|
|
10
|
+
import { createExplorationNamespace, } from "./client-exploration.js";
|
|
11
|
+
import { createSourceMaterialCommentsNamespace, } from "./client-source-material-comments.js";
|
|
10
12
|
import { declaredFinishes, declaredProducts } from "./associations-client.js";
|
|
11
13
|
import { brandColourDeck, brandProfile, listBrands } from "./brands-client.js";
|
|
12
14
|
import { CodesClient } from "./codes-client.js";
|
|
13
15
|
import { ColoursClient } from "./colours-client.js";
|
|
16
|
+
import { slotPools as slotPoolsCall, varyScheme as varySchemeCall, } from "./composition-client.js";
|
|
17
|
+
import { coordinate as coordinateCall } from "./coordinate-client.js";
|
|
14
18
|
import { matchStream as matchStreamCall } from "./match-stream.js";
|
|
15
19
|
import { appendProjectEvent as appendProjectEventCall, createProject as createProjectCall, getProject as getProjectCall, listProjects as listProjectsCall, } from "./projects.js";
|
|
16
20
|
import { resolvePhrasesRequest as resolvePhrases, searchVocabularyRequest, } from "./resolve-client.js";
|
|
@@ -55,14 +59,21 @@ import { suggestQuery } from "./suggest-types.js";
|
|
|
55
59
|
export class MaterialGraphClient {
|
|
56
60
|
baseUrl;
|
|
57
61
|
/**
|
|
58
|
-
* THE QUESTION: "show me everything
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
+
* THE QUESTION: "show me everything in this category / this brand, in a plain
|
|
63
|
+
* order." No query, no relevance, no ranking. `browse(params)` is one page;
|
|
64
|
+
* `browse.pages(params)` walks them all.
|
|
65
|
+
*
|
|
66
|
+
* `sort` is optional (`name` A→Z by default, `recent` for newest first, plus
|
|
67
|
+
* the five colour ramps), `types`/`brands`/`corpusScope` narrow it, and
|
|
68
|
+
* `count: true` returns the total so a listing can say how many things it is
|
|
69
|
+
* listing without walking every page. `results.length` remains a PAGE.
|
|
62
70
|
*
|
|
63
71
|
* Instead use {@link MaterialGraphClient.byColour} for materials NEAR a colour,
|
|
64
72
|
* {@link MaterialGraphClient.search} when there is anything to rank against,
|
|
65
73
|
* and `colours.profiles()` for a category's palette rather than its members.
|
|
74
|
+
*
|
|
75
|
+
* @example A category listing that can state its own size
|
|
76
|
+
* const page = await client.browse({ types: "tile_surfaces", count: true });
|
|
66
77
|
*/
|
|
67
78
|
browse;
|
|
68
79
|
/**
|
|
@@ -88,6 +99,14 @@ export class MaterialGraphClient {
|
|
|
88
99
|
* likeness, never a declared colour specification.
|
|
89
100
|
*/
|
|
90
101
|
colours;
|
|
102
|
+
/** Discover honest graph questions, then traverse one explicit operator. */
|
|
103
|
+
exploration;
|
|
104
|
+
/**
|
|
105
|
+
* THE QUESTION: "what did people say about this uploaded file, and record what
|
|
106
|
+
* they said." Names on these remarks are REPORTED, never verified — see
|
|
107
|
+
* {@link SourceMaterialCommentsNamespace}.
|
|
108
|
+
*/
|
|
109
|
+
sourceMaterialComments;
|
|
91
110
|
#transport;
|
|
92
111
|
constructor(options) {
|
|
93
112
|
if (!options.apiKey) {
|
|
@@ -108,6 +127,8 @@ export class MaterialGraphClient {
|
|
|
108
127
|
get: (operationId, query, signal) => this.#get(operationId, query, signal),
|
|
109
128
|
post: (operationId, body, signal) => this.#post(operationId, body, signal),
|
|
110
129
|
});
|
|
130
|
+
this.exploration = createExplorationNamespace(this.#transport);
|
|
131
|
+
this.sourceMaterialComments = createSourceMaterialCommentsNamespace(this.#transport);
|
|
111
132
|
}
|
|
112
133
|
get lastRateLimit() {
|
|
113
134
|
return this.#transport.lastRateLimit;
|
|
@@ -452,19 +473,9 @@ export class MaterialGraphClient {
|
|
|
452
473
|
return this.#get("whoami", undefined, signal);
|
|
453
474
|
}
|
|
454
475
|
// ── Pairings / demand ────────────────────────────────────────────────────────
|
|
455
|
-
/**
|
|
456
|
-
* THE QUESTION: "here is my whole scheme so far — what completes it?" The
|
|
457
|
-
* multi-seed form of {@link MaterialGraphClient.pairings}: lift is summed across
|
|
458
|
-
* seeds, so a companion suiting one pick ranks below one suiting several.
|
|
459
|
-
* Instead use `pairings` for a single material and `colours.palette()` when the
|
|
460
|
-
* scheme is COLOURS rather than materials. Check `unresolved` before presenting.
|
|
461
|
-
*
|
|
462
|
-
* Coordinate a palette of already-chosen materials (POST
|
|
463
|
-
* `/api/v1/pairings/coordinate`). Returns demand-lift-ranked companions with
|
|
464
|
-
* colour swatches and an annotate-only `colourFit` (never reorders in v1).
|
|
465
|
-
*/
|
|
476
|
+
/** What completes a scheme already part-chosen. See {@link coordinateCall}. */
|
|
466
477
|
coordinate(input, signal) {
|
|
467
|
-
return this.#
|
|
478
|
+
return coordinateCall(this.#transport, input, signal);
|
|
468
479
|
}
|
|
469
480
|
/**
|
|
470
481
|
* THE QUESTION: "how much is this material actually specified, and what gets
|
|
@@ -690,15 +701,13 @@ export class MaterialGraphClient {
|
|
|
690
701
|
cancelRun(runId, signal) {
|
|
691
702
|
return cancelRun(this.#transport, runId, signal);
|
|
692
703
|
}
|
|
693
|
-
/**
|
|
694
|
-
* Derive an "option B" scheme from a succeeded compose Run along one
|
|
695
|
-
* constraint axis (POST `/api/v1/schemes/vary`). Deterministic and
|
|
696
|
-
* synchronous — the response IS the hydrated scheme (no Run envelope), stamped
|
|
697
|
-
* with axis + source provenance whose `notes` are the variation's receipts.
|
|
698
|
-
* Requires the `mg:read` scope.
|
|
699
|
-
*/
|
|
704
|
+
/** Option B from a composed Run, along one axis. See {@link varySchemeCall}. */
|
|
700
705
|
varyScheme(body, signal) {
|
|
701
|
-
return this.#
|
|
706
|
+
return varySchemeCall(this.#transport, body, signal);
|
|
707
|
+
}
|
|
708
|
+
/** Ranked candidate pools for up to 24 slots. See {@link slotPoolsCall}. */
|
|
709
|
+
slotPools(body, signal) {
|
|
710
|
+
return slotPoolsCall(this.#transport, body, signal);
|
|
702
711
|
}
|
|
703
712
|
/**
|
|
704
713
|
* Stream ordered Run events as an async iterator (GET
|