@snowcone-app/canvas 0.36.7 → 0.37.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/ERROR_CONTRACT.md +137 -0
- package/dist/{EditorCanvasImpl-BeeY09cA.js → EditorCanvasImpl-BRdFWZA5.js} +2 -2
- package/dist/{EditorCanvasImpl-BeeY09cA.js.map → EditorCanvasImpl-BRdFWZA5.js.map} +1 -1
- package/dist/FontAnalyzer-CEYA_6fY.js.map +1 -1
- package/dist/api/embed.d.ts +3 -0
- package/dist/components/embed-realtime/validateEmbed.d.ts +13 -0
- package/dist/design/bundle-config.d.ts +127 -0
- package/dist/design/product-config.d.ts +3 -0
- package/dist/embed-CLz3CTcX.js +1799 -0
- package/dist/embed-CLz3CTcX.js.map +1 -0
- package/dist/embed.mjs +50 -45
- package/dist/errors/editorError.d.ts +28 -1
- package/example/package.json +1 -1
- package/package.json +3 -3
- package/dist/embed-D9n0deJ3.js +0 -1588
- package/dist/embed-D9n0deJ3.js.map +0 -1
package/dist/api/embed.d.ts
CHANGED
|
@@ -51,6 +51,9 @@ export { validateEmbed, collectEmbedIssues } from '../components/embed-realtime/
|
|
|
51
51
|
export type { ValidateEmbedInput, EmbedIssue } from '../components/embed-realtime/validateEmbed.js';
|
|
52
52
|
export { productToRenderConfig } from '../design/product-config.js';
|
|
53
53
|
export type { ProductRenderConfig, ProductRenderConfigOptions } from '../design/product-config.js';
|
|
54
|
+
export { bundleToRenderConfig, isBundleProduct, bundleVariantToken, splitRoleKey } from '../design/bundle-config.js';
|
|
55
|
+
export type { BundleRenderConfig, BundleRenderConfigOptions, BundleRoleConfig, BundlePlacementConfig, BundleVariantChoice, CatalogBundleProduct, CatalogBundleBlock, CatalogBundleMember, CatalogBundleAlternative, } from '../design/bundle-config.js';
|
|
56
|
+
export { isBundleRenderProduct } from '../components/embed-realtime/validateEmbed.js';
|
|
54
57
|
export { design, DesignBuilder, isLayerToken, isColorToken } from '../design/design-builder.js';
|
|
55
58
|
export type { Anchor, ShapeKind, DesignArtboard, StateArtboard, FromStateOptions, AnyDesign, LayerKind, LayerToken, ColorToken, } from '../design/design-builder.js';
|
|
56
59
|
export { useEditor } from '../contexts/EditorContext.js';
|
|
@@ -34,6 +34,16 @@ export interface EmbedIssue {
|
|
|
34
34
|
/** Two layers share a name — name-bound hooks bind the FIRST match,
|
|
35
35
|
* so a control may edit the wrong layer. */
|
|
36
36
|
| 'duplicate-layer-names'
|
|
37
|
+
/** BUNDLE session (ADR-0099): a design artboard is a bare label
|
|
38
|
+
* (`"Front"`) instead of a role-scoped key (`"top.front"`), or a bare
|
|
39
|
+
* `variantId` is set — the server refuses both
|
|
40
|
+
* (`E_BUNDLE_ROLE_REQUIRED`): two members can both have a "Front". */
|
|
41
|
+
| 'bundle-role-required'
|
|
42
|
+
/** BUNDLE session (ADR-0099): a role has no entry in
|
|
43
|
+
* `product.variants` — the server keys the render on the per-role
|
|
44
|
+
* variant set, so every role needs one (`bundleToRenderConfig` fills
|
|
45
|
+
* defaults; hand-written configs must too). */
|
|
46
|
+
| 'bundle-variant-required'
|
|
37
47
|
/** Runtime (not mount-time): a render has been in flight past
|
|
38
48
|
* `SLOW_RENDER_HINT_MS` with no mockup and no error — the silent-hang
|
|
39
49
|
* class. The render may still arrive; this is a heads-up. */
|
|
@@ -49,6 +59,9 @@ export interface EmbedIssue {
|
|
|
49
59
|
* which entries are auto-filled colors, but without a variant none are.
|
|
50
60
|
*/
|
|
51
61
|
export declare function requiredPlacementLabels(product: RenderProduct): string[];
|
|
62
|
+
/** True when the product is wired as a BUNDLE session (ADR-0099): it
|
|
63
|
+
* carries per-role `picks` and/or `variants`. */
|
|
64
|
+
export declare function isBundleRenderProduct(product: RenderProduct): boolean;
|
|
52
65
|
/** Find every wiring problem. Pure — no logging, no throwing. */
|
|
53
66
|
export declare function collectEmbedIssues({ shop, product, design, hasGrant }: ValidateEmbedInput): EmbedIssue[];
|
|
54
67
|
/** Legacy advisory API: log everything, never throw. (`placement-mismatch`
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { CatalogProduct, RenderProduct } from '@snowcone-app/sdk';
|
|
2
|
+
/** The `bundle` block of a catalog product (ADR-0099). */
|
|
3
|
+
export type CatalogBundleBlock = NonNullable<CatalogProduct['bundle']>;
|
|
4
|
+
/** One slot of a bundle. */
|
|
5
|
+
export type CatalogBundleMember = CatalogBundleBlock['members'][number];
|
|
6
|
+
/** One alternative product of a slot. */
|
|
7
|
+
export type CatalogBundleAlternative = CatalogBundleMember['products'][number];
|
|
8
|
+
/** A catalog product that IS a bundle — `bundle.members` is present and non-empty. */
|
|
9
|
+
export type CatalogBundleProduct = CatalogProduct & {
|
|
10
|
+
bundle: CatalogBundleBlock;
|
|
11
|
+
};
|
|
12
|
+
/** True when the catalog product carries a non-empty `bundle` block. */
|
|
13
|
+
export declare function isBundleProduct(product: CatalogProduct): product is CatalogBundleProduct;
|
|
14
|
+
export interface BundleRenderConfigOptions {
|
|
15
|
+
/** Which alternative fills each slot, `role → member product code`.
|
|
16
|
+
* Omitted roles take the slot's first alternative. Unknown roles throw
|
|
17
|
+
* `E_BUNDLE_ROLE_NOT_FOUND`; a product outside the slot throws
|
|
18
|
+
* `E_BUNDLE_PICK_NOT_FOUND` (both list the valid values). */
|
|
19
|
+
picks?: Record<string, string>;
|
|
20
|
+
/** The variant per slot, `role → gvid`. Omitted roles take the picked
|
|
21
|
+
* alternative's `defaultGvid` (else its first variant). A gvid outside the
|
|
22
|
+
* alternative's variant list throws `E_BUNDLE_VARIANT_NOT_FOUND`. */
|
|
23
|
+
variants?: Record<string, string>;
|
|
24
|
+
/** Role-scoped placement KEY to edit first (e.g. `"top.front"`). Defaults
|
|
25
|
+
* to the first renderable placement of the picked alternatives. A bare
|
|
26
|
+
* label (`"Front"`) throws `E_BUNDLE_ROLE_REQUIRED`; an unknown key throws
|
|
27
|
+
* `E_PRODUCT_NOT_RENDERABLE` — both list the valid keys. */
|
|
28
|
+
placement?: string;
|
|
29
|
+
/** Render width passthrough (`product.width`). */
|
|
30
|
+
width?: number;
|
|
31
|
+
}
|
|
32
|
+
/** Geometry of one role-scoped placement of the picked alternatives. */
|
|
33
|
+
export interface BundlePlacementConfig {
|
|
34
|
+
/** The role-scoped wire key — the artboard NAME and the `renderState`
|
|
35
|
+
* placement on a bundle (`"top.front"`). */
|
|
36
|
+
key: string;
|
|
37
|
+
role: string;
|
|
38
|
+
/** The member's own placement label (`"Front"`) — display only, never an
|
|
39
|
+
* identity on a bundle. */
|
|
40
|
+
label: string;
|
|
41
|
+
/** The member product this placement belongs to (the slot's pick). */
|
|
42
|
+
memberProductId: string;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
aspectRatio: number;
|
|
46
|
+
}
|
|
47
|
+
/** One selectable variant of a slot's picked alternative. */
|
|
48
|
+
export interface BundleVariantChoice {
|
|
49
|
+
gvid: string;
|
|
50
|
+
/** Human label from the alternative's `options.combinations` row (e.g.
|
|
51
|
+
* `"Size M"`); falls back to the gvid when the row is unknown. */
|
|
52
|
+
label: string;
|
|
53
|
+
}
|
|
54
|
+
/** One slot of the bundle, resolved for the current picks + variants. */
|
|
55
|
+
export interface BundleRoleConfig {
|
|
56
|
+
role: string;
|
|
57
|
+
required: boolean;
|
|
58
|
+
/** The alternatives' product codes, in catalog order (first = default). */
|
|
59
|
+
alternatives: string[];
|
|
60
|
+
/** The alternative currently filling the slot. */
|
|
61
|
+
pick: string;
|
|
62
|
+
/** The variant the slot renders (`variants[role]`). */
|
|
63
|
+
variantId: string;
|
|
64
|
+
/** Every variant the picked alternative accepts for `variants[role]`. */
|
|
65
|
+
variantChoices: BundleVariantChoice[];
|
|
66
|
+
/** The slot's renderable placements for the pick, in catalog order. */
|
|
67
|
+
placements: BundlePlacementConfig[];
|
|
68
|
+
}
|
|
69
|
+
export interface BundleRenderConfig {
|
|
70
|
+
/** Discriminant — a bundle config is never confusable with a
|
|
71
|
+
* `ProductRenderConfig`. */
|
|
72
|
+
kind: 'bundle';
|
|
73
|
+
/** Ready for `<Editor.Root product={…}>`: `picks` + `variants` set,
|
|
74
|
+
* `variantId` absent, `placements` / `requiredPlacements` carry the
|
|
75
|
+
* role-scoped KEYS (the placement names the server demands). */
|
|
76
|
+
product: RenderProduct;
|
|
77
|
+
/** The resolved pick per role — every role present. */
|
|
78
|
+
picks: Record<string, string>;
|
|
79
|
+
/** The resolved variant per role — every role present. */
|
|
80
|
+
variants: Record<string, string>;
|
|
81
|
+
/** `role:renderGvid,…` sorted by role — the bundle scene identity the
|
|
82
|
+
* catalog publishes as a bundle mockup's `gvids` entry and the server keys
|
|
83
|
+
* the composite on. */
|
|
84
|
+
variantToken: string;
|
|
85
|
+
/** Every slot, resolved. */
|
|
86
|
+
roles: BundleRoleConfig[];
|
|
87
|
+
/** The placement being edited first — seed `design({ name: key, width, height })`. */
|
|
88
|
+
placement: BundlePlacementConfig;
|
|
89
|
+
/** Every renderable placement of the picked alternatives, in catalog order. */
|
|
90
|
+
placements: BundlePlacementConfig[];
|
|
91
|
+
/** `placements.map(p => p.key)` — the artboard names / renderState placements. */
|
|
92
|
+
placementKeys: string[];
|
|
93
|
+
/** The bundle's roles in catalog order. */
|
|
94
|
+
roleNames: string[];
|
|
95
|
+
/** First scene that photographs the picked alternatives — the default
|
|
96
|
+
* `<Editor.Preview mockupId>`. */
|
|
97
|
+
primaryMockupId: string;
|
|
98
|
+
}
|
|
99
|
+
/** `role:renderGvid,…` sorted by role — deterministic, matches the box and the catalog. */
|
|
100
|
+
export declare function bundleVariantToken(variantByRole: Record<string, string>): string;
|
|
101
|
+
/** Split a role-scoped key (`"top.front"`) into `{ role, key }`; `null` when it carries no role. */
|
|
102
|
+
export declare function splitRoleKey(name: string): {
|
|
103
|
+
role: string;
|
|
104
|
+
key: string;
|
|
105
|
+
} | null;
|
|
106
|
+
/**
|
|
107
|
+
* Derive the full bundle embed wiring from one `getProduct()` payload.
|
|
108
|
+
*
|
|
109
|
+
* ```ts
|
|
110
|
+
* const config = bundleToRenderConfig(await getProduct('V9NNNH'), { width: 2000 });
|
|
111
|
+
* const seed = design({ name: config.placement.key, ...config.placement })
|
|
112
|
+
* .image(artworkUrl, { anchor: 'center' }); // ONE artboard → broadcast to every member
|
|
113
|
+
*
|
|
114
|
+
* <Editor.Root shop={SHOP} product={config.product} design={seed} grantUrl="/api/realtime-grant">
|
|
115
|
+
*
|
|
116
|
+
* // A pick or variant change is a NEW config: rebuild and pass the new product.
|
|
117
|
+
* const next = bundleToRenderConfig(product, { picks: { top: 'TANKXA' }, variants: config.variants });
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @throws EditorError `E_NOT_A_BUNDLE` — the product has no `bundle` block.
|
|
121
|
+
* @throws EditorError `E_BUNDLE_ROLE_NOT_FOUND` — `picks` / `variants` name an unknown role.
|
|
122
|
+
* @throws EditorError `E_BUNDLE_PICK_NOT_FOUND` — a pick is not one of the slot's alternatives.
|
|
123
|
+
* @throws EditorError `E_BUNDLE_VARIANT_NOT_FOUND` — a variant is not one of the pick's gvids, or the pick has none.
|
|
124
|
+
* @throws EditorError `E_BUNDLE_ROLE_REQUIRED` — `options.placement` is a bare label, not `<role>.<key>`.
|
|
125
|
+
* @throws EditorError `E_PRODUCT_NOT_RENDERABLE` — no renderable placement / scene, or an unknown placement key.
|
|
126
|
+
*/
|
|
127
|
+
export declare function bundleToRenderConfig(catalogProduct: CatalogProduct, options?: BundleRenderConfigOptions): BundleRenderConfig;
|
|
@@ -54,5 +54,8 @@ export interface ProductRenderConfig {
|
|
|
54
54
|
* @throws EditorError `E_PRODUCT_NOT_RENDERABLE` when the product has no
|
|
55
55
|
* renderable image placement, no mockup scenes, or `options.placement`
|
|
56
56
|
* names a placement that doesn't exist (`data.validNames` lists the real ones).
|
|
57
|
+
* @throws EditorError `E_BUNDLE_CONFIG_REQUIRED` when the product is a BUNDLE
|
|
58
|
+
* (ADR-0099: a `bundle` block) — it has no single variantId and role-scoped
|
|
59
|
+
* placements, so this adapter cannot describe it; use `bundleToRenderConfig()`.
|
|
57
60
|
*/
|
|
58
61
|
export declare function productToRenderConfig(catalogProduct: CatalogProduct, options?: ProductRenderConfigOptions): ProductRenderConfig;
|