@snowcone-app/sdk 0.1.14 → 0.1.15

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/README.md CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  **JavaScript/TypeScript SDK for product mockups and print-on-demand**
4
4
 
5
- Merch provides a simple SDK for fetching product data and generating real-time merchandise mockups. Use it to visualize artwork on t-shirts, posters, mugs, and more.
5
+ A small, isomorphic SDK for fetching product data and building real-time
6
+ merchandise mockup URLs. Use it to visualize artwork on t-shirts, posters, mugs,
7
+ and more — in the browser or on the server.
8
+
9
+ 📖 **Full documentation: [developers.snowcone.app/sdk](https://developers.snowcone.app/sdk)**
6
10
 
7
11
  ## Installation
8
12
 
@@ -33,9 +37,9 @@ const url = getMockupUrl('hoodie-black', {
33
37
  // <img src={url} />
34
38
  ```
35
39
 
36
- > The `key` is your **publishable** token — public and safe to expose (like
37
- > Cloudinary's cloud name). It defaults to your `shop.id`. See the security
38
- > ladder below if you want to lock things down.
40
+ > The `shop` ID is your **publishable** token — public and safe to expose (like
41
+ > Cloudinary's cloud name). It defaults to your `shop.id`. See [Public or
42
+ > signed](#public-or-signed) below if you want to lock things down.
39
43
 
40
44
  ## Core Functions
41
45
 
@@ -94,7 +98,7 @@ const url = getMockupUrl(productCode: string, opts: {
94
98
  asset?: string; // Single default-placement image (get-started shorthand)
95
99
  design?: Design; // Multi-placement: { [placementKey]: Fill } — takes precedence over `asset`
96
100
  options?: Record<string, string>; // Variant picks: { size: "m" } → opt.size=m
97
- secret?: string; // Optional: per-shop secret → appends an L3 &signature (server only)
101
+ secret?: string; // Optional: per-shop secret → appends a signed &signature (server only)
98
102
  base?: string; // Optional: override the host (default img.snowcone.app)
99
103
  width?: number; // Optional: display width
100
104
  view?: string; // Optional: camera view / mockup scene (alias: `mockup`)
@@ -140,18 +144,16 @@ const cap = getMockupUrl('RQNU68', {
140
144
  > accepted (it builds the same URL as `getMockupUrl(productCode, { asset, … })`).
141
145
  > Prefer the code-first form above for new code.
142
146
 
143
- ### Security ladder
147
+ ### Public or signed
144
148
 
145
- The default is open and frictionless; climb only as far as you need:
149
+ The default is open and frictionless. There's one decision to make up front:
146
150
 
147
- | Level | Control | Effect |
148
- |---|---|---|
149
- | **L0** (default) | none | public token, any domain, any asset |
150
- | **L1** | domain allowlist | token only renders from your domains |
151
- | **L2** | asset allowlist | restrict which asset sources composite |
152
- | **L3** | signed URLs | URL must carry a valid `&s` (HMAC of a per-shop secret) |
151
+ - **Public** the Shop ID alone, safe to expose. Lock it to your **asset
152
+ origins** so a stolen ID can only re-render your own catalog.
153
+ - **Signed** your server appends an `&signature` (HMAC of a per-shop secret),
154
+ so only you can mint valid URLs. The secret stays server-side.
153
155
 
154
- For **L3**, pass `secret` (server-side only) and `getMockupUrl` appends the
156
+ To sign, pass `secret` (server-side only) and `getMockupUrl` appends the
155
157
  verified `&signature`:
156
158
 
157
159
  ```typescript
@@ -163,6 +165,8 @@ const url = getMockupUrl('hoodie-black', {
163
165
  });
164
166
  ```
165
167
 
168
+ See [Public or signed](https://developers.snowcone.app/get-started) for the full picture.
169
+
166
170
  ### React Hooks (Optional)
167
171
 
168
172
  For React applications, use the React-specific exports:
@@ -211,14 +215,14 @@ See: [@snowcone-app/ui on npm](https://www.npmjs.com/package/@snowcone-app/ui)
211
215
 
212
216
  ## Examples
213
217
 
214
- - [Next.js Example](https://github.com/snowcone-app/ui-components/tree/main/examples/next-ecommerce)
215
- - [Basic Product Display](https://github.com/snowcone-app/ui-components/tree/main/examples/next-ecommerce/app/demos)
218
+ - [Getting started](https://developers.snowcone.app/get-started)
219
+ - [Mockup URLs reference](https://developers.snowcone.app/mockups)
220
+ - [Live playground](https://developers.snowcone.app/playground)
216
221
 
217
222
  ## Support
218
223
 
219
- - **Issues:** [GitHub Issues](https://github.com/snowcone-app/ui-components/issues)
220
- - **Discussions:** [GitHub Discussions](https://github.com/snowcone-app/ui-components/discussions)
221
- - **Docs:** [developers.snowcone.app](https://developers.snowcone.app)
224
+ - **Docs:** [developers.snowcone.app/sdk](https://developers.snowcone.app/sdk)
225
+ - **Issues:** [GitHub Issues](https://github.com/snowcone-app/snowcone-monorepo/issues)
222
226
 
223
227
  ## License
224
228
 
@@ -1,6 +1,9 @@
1
+ // src/realtime/constants.ts
2
+ var REALTIME_WS_URL = "wss://cdn.snowcone.app/realtime";
3
+
1
4
  // src/realtime/websocket.ts
2
5
  var RealtimeMockupService = class {
3
- constructor(wsUrl = "wss://WS_URL_NOT_CONFIGURED.invalid/realtime") {
6
+ constructor(wsUrl = REALTIME_WS_URL) {
4
7
  this.wsUrl = wsUrl;
5
8
  }
6
9
  ws = null;
@@ -649,5 +652,6 @@ ${versionToSend}
649
652
  };
650
653
 
651
654
  export {
655
+ REALTIME_WS_URL,
652
656
  RealtimeMockupService
653
657
  };
package/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  DEFAULT_ARTWORK_URL: () => DEFAULT_ARTWORK_URL,
39
39
  DEFAULT_ASPECT_RATIO: () => DEFAULT_ASPECT_RATIO,
40
40
  DEFAULT_COLOR: () => DEFAULT_COLOR,
41
+ DEFAULT_GRANT_BASE: () => DEFAULT_GRANT_BASE,
41
42
  DEFAULT_MOCKUP_BASE: () => DEFAULT_MOCKUP_BASE,
42
43
  DEFAULT_PLACEMENT_DIMENSIONS: () => DEFAULT_PLACEMENT_DIMENSIONS,
43
44
  Elements: () => Elements,
@@ -51,7 +52,9 @@ __export(index_exports, {
51
52
  ProductLoader: () => ProductLoader,
52
53
  ProductProps: () => ProductProps,
53
54
  PropertyManager: () => PropertyManager,
55
+ REALTIME_WS_URL: () => REALTIME_WS_URL,
54
56
  RealtimeMockupService: () => RealtimeMockupService,
57
+ RenderSession: () => RenderSession,
55
58
  StandardComponents: () => StandardComponents,
56
59
  StandardEvents: () => StandardEvents,
57
60
  StateManager: () => StateManager,
@@ -95,6 +98,7 @@ __export(index_exports, {
95
98
  describeProductPrice: () => describeProductPrice,
96
99
  describeProductTitle: () => describeProductTitle,
97
100
  extractProductId: () => extractProductId,
101
+ fetchRealtimeGrant: () => fetchRealtimeGrant,
98
102
  filterImagePlacements: () => filterImagePlacements,
99
103
  findBestCombination: () => findBestCombination,
100
104
  findClosestSnapPoint: () => findClosestSnapPoint,
@@ -118,6 +122,7 @@ __export(index_exports, {
118
122
  isValidAlignment: () => isValidAlignment,
119
123
  isValidTileCount: () => isValidTileCount,
120
124
  listProducts: () => listProducts,
125
+ mintRealtimeGrant: () => mintRealtimeGrant,
121
126
  mockupUrl: () => mockupUrl,
122
127
  normalizeChoice: () => normalizeChoice,
123
128
  prepareOptionRenderData: () => prepareOptionRenderData,
@@ -4797,9 +4802,12 @@ function createSvelteComponent(descriptor, svelte) {
4797
4802
  };
4798
4803
  }
4799
4804
 
4805
+ // src/realtime/constants.ts
4806
+ var REALTIME_WS_URL = "wss://cdn.snowcone.app/realtime";
4807
+
4800
4808
  // src/realtime/websocket.ts
4801
4809
  var RealtimeMockupService = class {
4802
- constructor(wsUrl = "wss://WS_URL_NOT_CONFIGURED.invalid/realtime") {
4810
+ constructor(wsUrl = REALTIME_WS_URL) {
4803
4811
  this.wsUrl = wsUrl;
4804
4812
  }
4805
4813
  ws = null;
@@ -5447,6 +5455,154 @@ ${versionToSend}
5447
5455
  }
5448
5456
  };
5449
5457
 
5458
+ // src/realtime/grant.ts
5459
+ var DEFAULT_GRANT_BASE = "https://api.snowcone.app";
5460
+ async function mintRealtimeGrant(opts) {
5461
+ const f = opts.fetch ?? globalThis.fetch;
5462
+ const res = await f(`${opts.base ?? DEFAULT_GRANT_BASE}/realtime/grant`, {
5463
+ method: "POST",
5464
+ headers: {
5465
+ "Content-Type": "application/json",
5466
+ Authorization: `Bearer ${opts.apiKey}`
5467
+ },
5468
+ body: JSON.stringify({ shop: opts.shop })
5469
+ });
5470
+ if (!res.ok) {
5471
+ const detail = await res.text().catch(() => "");
5472
+ throw new Error(`realtime grant failed: ${res.status}${detail ? ` ${detail}` : ""}`);
5473
+ }
5474
+ return await res.json();
5475
+ }
5476
+ async function fetchRealtimeGrant(grantUrl, shop, fetchImpl) {
5477
+ const f = fetchImpl ?? globalThis.fetch;
5478
+ const res = await f(grantUrl, {
5479
+ method: "POST",
5480
+ headers: { "Content-Type": "application/json" },
5481
+ body: JSON.stringify({ shop })
5482
+ });
5483
+ if (!res.ok) throw new Error(`realtime grant failed: ${res.status}`);
5484
+ return await res.json();
5485
+ }
5486
+
5487
+ // src/realtime/session.ts
5488
+ var RenderSession = class {
5489
+ svc;
5490
+ opts;
5491
+ product;
5492
+ mockupCb = null;
5493
+ errorCb = null;
5494
+ ready = null;
5495
+ constructor(opts) {
5496
+ if (!opts.shop) throw new Error("RenderSession: `shop` is required");
5497
+ if (!opts.getToken && !opts.grantUrl) {
5498
+ throw new Error("RenderSession: provide `grantUrl` or `getToken` to authorize the session");
5499
+ }
5500
+ this.opts = opts;
5501
+ this.product = opts.product ?? null;
5502
+ this.svc = new RealtimeMockupService(opts.wsUrl ?? REALTIME_WS_URL);
5503
+ const getToken = opts.getToken ?? (() => fetchRealtimeGrant(opts.grantUrl, opts.shop, opts.fetch));
5504
+ this.svc.setTokenProvider(getToken);
5505
+ }
5506
+ /** Register a callback fired whenever rendered mockup URLs update. */
5507
+ onMockups(cb) {
5508
+ this.mockupCb = cb;
5509
+ return this;
5510
+ }
5511
+ /** Register an error callback (server/transport errors). */
5512
+ onError(cb) {
5513
+ this.errorCb = cb;
5514
+ return this;
5515
+ }
5516
+ /** Set or update the product. Sends config immediately if already connected. */
5517
+ setProduct(product) {
5518
+ this.product = product;
5519
+ this.svc.sendConfig(this.toConfig(product));
5520
+ }
5521
+ /**
5522
+ * Connect, authorize, and configure. Resolves once the session is ready to
5523
+ * accept {@link RenderSession.renderState}. Idempotent.
5524
+ */
5525
+ connect() {
5526
+ if (this.ready) return this.ready;
5527
+ if (!this.product) {
5528
+ return Promise.reject(
5529
+ new Error("RenderSession: set a product (via options.product or setProduct) before connect()")
5530
+ );
5531
+ }
5532
+ const product = this.product;
5533
+ this.ready = new Promise((resolve, reject) => {
5534
+ let settled = false;
5535
+ this.svc.setCallbacks({
5536
+ onConnected: () => {
5537
+ this.svc.sendConfig(this.toConfig(product));
5538
+ },
5539
+ onConfigReceived: () => {
5540
+ if (!settled) {
5541
+ settled = true;
5542
+ resolve();
5543
+ }
5544
+ },
5545
+ onMockupRendered: () => {
5546
+ this.mockupCb?.(this.svc.getState().mockupResults);
5547
+ },
5548
+ onAllMockupsRendered: (results) => {
5549
+ this.mockupCb?.(results);
5550
+ },
5551
+ onError: (error) => {
5552
+ this.errorCb?.(error);
5553
+ if (!settled) {
5554
+ settled = true;
5555
+ reject(new Error(error));
5556
+ }
5557
+ }
5558
+ });
5559
+ this.svc.sendConfig(this.toConfig(product));
5560
+ this.svc.connect();
5561
+ });
5562
+ return this.ready;
5563
+ }
5564
+ /**
5565
+ * Render a canvas state for a placement. The server rasterizes it and fetches
5566
+ * the assets referenced inside — no pixels are uploaded. Results arrive via
5567
+ * {@link RenderSession.onMockups}. Safe to call repeatedly (e.g. on every
5568
+ * canvas edit); pass `throttleMs` to debounce during live dragging.
5569
+ */
5570
+ async renderState(placement, state, throttleMs = 0) {
5571
+ await this.connect();
5572
+ this.svc.sendCanvasState(placement, state, this.product?.mockupIds.length ?? 1, throttleMs);
5573
+ }
5574
+ /** Update only the mockup ids to render (reuses the current state). */
5575
+ updateMockupIds(mockupIds) {
5576
+ if (this.product) this.product = { ...this.product, mockupIds };
5577
+ this.svc.updateMockupIds(mockupIds);
5578
+ }
5579
+ /** Current rendered results. */
5580
+ getMockups() {
5581
+ return this.svc.getState().mockupResults;
5582
+ }
5583
+ /** Close the WebSocket and stop auto-renew. */
5584
+ close() {
5585
+ this.svc.disconnect();
5586
+ this.ready = null;
5587
+ }
5588
+ /** Escape hatch: the underlying low-level service. */
5589
+ get service() {
5590
+ return this.svc;
5591
+ }
5592
+ toConfig(product) {
5593
+ return {
5594
+ productId: product.productId,
5595
+ mockupIds: product.mockupIds,
5596
+ // shop comes from the grant token server-side; sent for completeness.
5597
+ shop: this.opts.shop,
5598
+ // WebSocketConfig requires these; the server treats empty variant as "none".
5599
+ variantId: product.variantId ?? "",
5600
+ width: product.width ?? 1e3,
5601
+ ...product.placementSettings ? { placementSettings: product.placementSettings } : {}
5602
+ };
5603
+ }
5604
+ };
5605
+
5450
5606
  // src/index.ts
5451
5607
  function getFetcher(config) {
5452
5608
  return config?.fetcher || globalThis.fetch.bind(globalThis);
@@ -5534,6 +5690,7 @@ function createClient(config) {
5534
5690
  DEFAULT_ARTWORK_URL,
5535
5691
  DEFAULT_ASPECT_RATIO,
5536
5692
  DEFAULT_COLOR,
5693
+ DEFAULT_GRANT_BASE,
5537
5694
  DEFAULT_MOCKUP_BASE,
5538
5695
  DEFAULT_PLACEMENT_DIMENSIONS,
5539
5696
  Elements,
@@ -5547,7 +5704,9 @@ function createClient(config) {
5547
5704
  ProductLoader,
5548
5705
  ProductProps,
5549
5706
  PropertyManager,
5707
+ REALTIME_WS_URL,
5550
5708
  RealtimeMockupService,
5709
+ RenderSession,
5551
5710
  StandardComponents,
5552
5711
  StandardEvents,
5553
5712
  StateManager,
@@ -5591,6 +5750,7 @@ function createClient(config) {
5591
5750
  describeProductPrice,
5592
5751
  describeProductTitle,
5593
5752
  extractProductId,
5753
+ fetchRealtimeGrant,
5594
5754
  filterImagePlacements,
5595
5755
  findBestCombination,
5596
5756
  findClosestSnapPoint,
@@ -5614,6 +5774,7 @@ function createClient(config) {
5614
5774
  isValidAlignment,
5615
5775
  isValidTileCount,
5616
5776
  listProducts,
5777
+ mintRealtimeGrant,
5617
5778
  mockupUrl,
5618
5779
  normalizeChoice,
5619
5780
  prepareOptionRenderData,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { createDevFetcher } from './dev-fetcher.cjs';
2
2
  import { PublicDesign, PublicFill, PublicOptions } from '@snowcone-app/mockup-url';
3
- import { O as OptionAttribute, a as OptionSelection, C as Combination, F as FrameworkAdapter, b as ComponentProps, c as ComponentDescriptor, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, g as FrameworkUtilities } from './websocket-Dum3OooZ.cjs';
4
- export { A as AdapterRegistry, M as MockupResult, P as ProductComponentContext, R as RealtimeMockupCallbacks, h as RealtimeMockupService, i as RealtimeMockupState, j as RenderResult, W as WebSocketConfig, k as WebSocketMessage, l as adapterRegistry, m as computeDisabledChoices, n as createComponent, o as defineComponent, p as deriveDefaultSelection, q as findBestCombination, r as getPricePreview, s as isOptionAvailable, t as resolveBestCombination } from './websocket-Dum3OooZ.cjs';
3
+ import { O as OptionAttribute, a as OptionSelection, C as Combination, F as FrameworkAdapter, b as ComponentProps, c as ComponentDescriptor, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, g as FrameworkUtilities, P as PlacementSettings, M as MockupResult, R as RealtimeMockupService } from './websocket-BQH1HYJp.cjs';
4
+ export { A as AdapterRegistry, h as ProductComponentContext, i as RealtimeMockupCallbacks, j as RealtimeMockupState, k as RenderResult, W as WebSocketConfig, l as WebSocketMessage, m as adapterRegistry, n as computeDisabledChoices, o as createComponent, p as defineComponent, q as deriveDefaultSelection, r as findBestCombination, s as getPricePreview, t as isOptionAvailable, u as resolveBestCombination } from './websocket-BQH1HYJp.cjs';
5
5
 
6
6
  interface CatalogProduct$2 {
7
7
  id: string;
@@ -2481,6 +2481,169 @@ declare class SvelteAdapter implements FrameworkAdapter<ComponentProps> {
2481
2481
  */
2482
2482
  declare function createSvelteComponent(descriptor: ComponentDescriptor, svelte: any): any;
2483
2483
 
2484
+ /**
2485
+ * Production realtime render WebSocket endpoint (the rendercenter edge).
2486
+ *
2487
+ * This is the value to connect to for server-side canvas rendering — open
2488
+ * `${REALTIME_WS_URL}?token=<grant>`. Replaces the old un-discoverable
2489
+ * `wss://WS_URL_NOT_CONFIGURED.invalid/realtime` placeholder so a 3rd party
2490
+ * can find the endpoint from the package alone (ADR-0079, Phase 2).
2491
+ */
2492
+ declare const REALTIME_WS_URL = "wss://cdn.snowcone.app/realtime";
2493
+
2494
+ /**
2495
+ * Realtime grant helpers (ADR-0079, Phase 2).
2496
+ *
2497
+ * A realtime render session is authorized by a short-lived (60s) grant token.
2498
+ * There are two ways to obtain one, mirroring Stripe's pk_/sk_ split:
2499
+ *
2500
+ * - {@link mintRealtimeGrant} — SERVER-SIDE, with a secret API key (sk_).
2501
+ * - {@link fetchRealtimeGrant} — BROWSER, from your own proxy endpoint.
2502
+ *
2503
+ * The browser then opens `${REALTIME_WS_URL}?token=<token>` (RenderSession does
2504
+ * this for you).
2505
+ */
2506
+ /** A short-lived realtime session grant. */
2507
+ interface RealtimeGrant {
2508
+ /** Opaque session token to put on the WS URL as `?token=`. */
2509
+ token: string;
2510
+ /** Expiry, epoch seconds. Renew before this (RenderSession auto-renews). */
2511
+ expiresAt: number;
2512
+ }
2513
+ /** Default backend base URL hosting `POST /realtime/grant`. */
2514
+ declare const DEFAULT_GRANT_BASE = "https://api.snowcone.app";
2515
+ /**
2516
+ * SERVER-SIDE: mint a realtime grant with a secret API key (sk_). Call this
2517
+ * from YOUR backend — never the browser; the API key must stay secret. The key
2518
+ * needs the `mockups:realtime` (or `mockups`) scope and its organization must
2519
+ * own the target `shop`. Returns a 60s grant your browser code opens the WS
2520
+ * with (hand it down via your own endpoint + {@link fetchRealtimeGrant}).
2521
+ *
2522
+ * @example
2523
+ * // your backend route: POST /api/realtime/grant
2524
+ * const grant = await mintRealtimeGrant({ apiKey: process.env.SNOWCONE_API_KEY!, shop });
2525
+ * return Response.json(grant);
2526
+ */
2527
+ declare function mintRealtimeGrant(opts: {
2528
+ /** Secret API key (sk_) with the `mockups:realtime` or `mockups` scope. */
2529
+ apiKey: string;
2530
+ /** Target shop id (= shop.id). Must belong to the key's organization. */
2531
+ shop: string;
2532
+ /** Backend base URL. Defaults to {@link DEFAULT_GRANT_BASE}. */
2533
+ base?: string;
2534
+ /** Override fetch (e.g. in tests / non-global-fetch runtimes). */
2535
+ fetch?: typeof fetch;
2536
+ }): Promise<RealtimeGrant>;
2537
+ /**
2538
+ * BROWSER: fetch a grant from your own proxy endpoint, which calls
2539
+ * {@link mintRealtimeGrant} server-side (so the secret key never reaches the
2540
+ * browser). The proxy receives `POST { shop }` and returns `{ token, expiresAt }`.
2541
+ * This is the default token provider {@link RenderSession} uses when given a
2542
+ * `grantUrl`.
2543
+ */
2544
+ declare function fetchRealtimeGrant(grantUrl: string, shop: string, fetchImpl?: typeof fetch): Promise<RealtimeGrant>;
2545
+
2546
+ /**
2547
+ * RenderSession — a high-level facade over {@link RealtimeMockupService} for the
2548
+ * server-side canvas render flow (ADR-0079, Phase 2).
2549
+ *
2550
+ * It hides the connect → grant → config → renew → canvas_state choreography so a
2551
+ * 3rd party can do what the www PDP does in a few calls, without holding the
2552
+ * artwork bytes or rendering each placement client-side:
2553
+ *
2554
+ * @example
2555
+ * const session = new RenderSession({
2556
+ * shop: 'YOUR_SHOP_ID',
2557
+ * grantUrl: '/api/realtime/grant', // your proxy → mintRealtimeGrant (server)
2558
+ * product: { productId: 'BEEB77', mockupIds: ['front'] },
2559
+ * });
2560
+ * session.onMockups((results) => { img.src = results[0].imageUrl; });
2561
+ * await session.connect();
2562
+ * session.renderState('Front', serializeStateForServer(canvasState));
2563
+ *
2564
+ * For the low-level escape hatch, use {@link RealtimeMockupService} directly.
2565
+ */
2566
+
2567
+ /**
2568
+ * The server-render canvas state — the JSON produced by `serializeStateForServer()`
2569
+ * in `@snowcone-app/canvas` (its `ServerRenderRequest`). Typed structurally here
2570
+ * so the SDK stays dependency-free; if you have `@snowcone-app/canvas`, its
2571
+ * `ServerRenderRequest` is assignable to this. `schemaVersion` is the wire
2572
+ * contract version (`CANVAS_STATE_SCHEMA_VERSION`); a missing value is treated
2573
+ * as `1` by the renderer.
2574
+ */
2575
+ interface RenderState {
2576
+ schemaVersion?: number;
2577
+ artboards?: Array<Record<string, unknown>>;
2578
+ elements?: Array<Record<string, unknown>>;
2579
+ [key: string]: unknown;
2580
+ }
2581
+ /** Product the session renders against (Snowcone catalog ids). */
2582
+ interface RenderProduct {
2583
+ productId: string;
2584
+ mockupIds: string[];
2585
+ /** Optional variant (gvid). Omit if the product has no variant axis. */
2586
+ variantId?: string;
2587
+ /** Render width in px (default 1000). */
2588
+ width?: number;
2589
+ /** Per-placement settings (tiling, scale mode). */
2590
+ placementSettings?: Record<string, PlacementSettings>;
2591
+ }
2592
+ interface RenderSessionOptions {
2593
+ /** Publishable shop id (= shop.id, like Stripe pk_). */
2594
+ shop: string;
2595
+ /** Product config. Can also be set later via {@link RenderSession.setProduct}. */
2596
+ product?: RenderProduct;
2597
+ /** Realtime WS endpoint. Defaults to {@link REALTIME_WS_URL}. */
2598
+ wsUrl?: string;
2599
+ /**
2600
+ * How to authorize the session. Provide exactly one:
2601
+ * - `grantUrl`: your endpoint that returns `{ token, expiresAt }` for
2602
+ * `POST { shop }` (recommended — a same-origin proxy to `mintRealtimeGrant`).
2603
+ * - `getToken`: full control over fetching the grant.
2604
+ */
2605
+ grantUrl?: string;
2606
+ getToken?: () => Promise<RealtimeGrant>;
2607
+ /** Override fetch (used with `grantUrl`). */
2608
+ fetch?: typeof fetch;
2609
+ }
2610
+ declare class RenderSession {
2611
+ private readonly svc;
2612
+ private readonly opts;
2613
+ private product;
2614
+ private mockupCb;
2615
+ private errorCb;
2616
+ private ready;
2617
+ constructor(opts: RenderSessionOptions);
2618
+ /** Register a callback fired whenever rendered mockup URLs update. */
2619
+ onMockups(cb: (results: MockupResult[]) => void): this;
2620
+ /** Register an error callback (server/transport errors). */
2621
+ onError(cb: (error: string) => void): this;
2622
+ /** Set or update the product. Sends config immediately if already connected. */
2623
+ setProduct(product: RenderProduct): void;
2624
+ /**
2625
+ * Connect, authorize, and configure. Resolves once the session is ready to
2626
+ * accept {@link RenderSession.renderState}. Idempotent.
2627
+ */
2628
+ connect(): Promise<void>;
2629
+ /**
2630
+ * Render a canvas state for a placement. The server rasterizes it and fetches
2631
+ * the assets referenced inside — no pixels are uploaded. Results arrive via
2632
+ * {@link RenderSession.onMockups}. Safe to call repeatedly (e.g. on every
2633
+ * canvas edit); pass `throttleMs` to debounce during live dragging.
2634
+ */
2635
+ renderState(placement: string, state: RenderState, throttleMs?: number): Promise<void>;
2636
+ /** Update only the mockup ids to render (reuses the current state). */
2637
+ updateMockupIds(mockupIds: string[]): void;
2638
+ /** Current rendered results. */
2639
+ getMockups(): MockupResult[];
2640
+ /** Close the WebSocket and stop auto-renew. */
2641
+ close(): void;
2642
+ /** Escape hatch: the underlying low-level service. */
2643
+ get service(): RealtimeMockupService;
2644
+ private toConfig;
2645
+ }
2646
+
2484
2647
  interface ProductPlacement {
2485
2648
  label: string;
2486
2649
  x: number;
@@ -2535,4 +2698,4 @@ declare function getProduct(idOrSlug: string, config?: Partial<SdkConfig>): Prom
2535
2698
  */
2536
2699
  declare function createClient(config: SdkConfig): SnowconeClient;
2537
2700
 
2538
- export { AbstractTemplateRenderer, type AddToCartOptions, Animations, type ArtSelectorContext, type ArtSelectorDescriptor, type ArtSelectorOptions, type ArtworkData, type AspectRatio, Attributes, type BaseDescriptor, type BlendConfig, type BuildMockupUrlConfig, type CartDetail, type CatalogListResponse, type CatalogProduct$2 as CatalogProduct, ClassNames, type ColorDesignElement, ColorPickerUtils, Combination, CommonProps, ComponentContext, type ComponentDefinition, ComponentDescriptor, ComponentEventManager, ComponentFactory, ComponentLifecycle, ComponentLifecycleHooks, type ComponentMetadata, ComponentProps, ComponentRegistry, ComponentState, type ComponentTemplate, ComponentTemplates, type ContainerDescriptor, ContextBridge, type ContextComparator, type ContextConsumer, ContextInjector, type ContextProviderConfig, type ContextSubscriber, ContextSynchronizer, DEFAULT_ARTWORK_URL, DEFAULT_ASPECT_RATIO, DEFAULT_COLOR, DEFAULT_MOCKUP_BASE, DEFAULT_PLACEMENT_DIMENSIONS, type Descriptor, type Design, type DesignElement, type DesignGenerationContext, type Effects, Elements, type ErrorContext, type ErrorHandler, ErrorManager, type EventDefinition, EventDelegator, EventEmitter, EventHandler, type EventListener, type EventPayload, type Fill, Focus, FrameworkAdapter, FrameworkUtilities, type GetMockupUrlOptions, type ImageAlignment, type ImageDesignElement, type LifecycleHook, LifecycleManager, type LifecyclePhase, type LifecycleTransition, LitAdapter, type MaskOverride, type MockupGenerationOptions, type MockupService, type MockupServiceConfig, OptionAttribute, type OptionChoice, type OptionChoiceRenderData, type OptionRenderData, OptionSelection, type Placement, type PlacementDesign, type ProductArtAlignmentContext, type ProductArtAlignmentDescriptor, type ProductArtAlignmentOptions, type ProductContext, type ProductContextEvents, ProductContextManager, type ProductData, type ProductFetcher, type ProductImageDescriptor, type ProductImageOptions, ProductLoader, type ProductMockupData, type ProductOptionChoice, type ProductOptionData, type ProductOptionsDescriptor, type ProductOptionsOptions, type ProductPlacement, type ProductPriceDescriptor, type ProductPriceOptions, ProductProps, type ProductSpec, type ProductTitleDescriptor, type ProductTitleOptions, type ProductVariant, type PropDefinition, type PropSchema, type PropType, PropertyManager, type RateLimitState, type RegularArtwork, type SdkConfig, type SeamlessPattern, type SignedUrlResponse, type SnowconeClient, StandardComponents, StandardEvents, StateManager, type StateManagerOptions, type StateMiddleware, type StateSelector, type StateSubscriber, type StateUpdater, Styles, SvelteAdapter, SwatchUtils, type TagName, TemplateBuilder, type TemplateNode, type TemplateNodeType, type TemplateRenderer, type TextDescriptor, type TileCount, UniversalContextProvider, type UserSelection, type ValidationError, type ValidationResult, VueAdapter, autoRegister, buildMockupUrl, componentRegistry, createAddToCartEvent, createAddToCartHandler, createCartDetail, createClient, createContextProvider, createDesignForPlacements, createErrorHandler, createEventManager, createLifecycle, createLitComponent, createProductContext, createProductLoader, createPropertyManager, createStateHook, createStateStore, createSvelteComponent, createUniversalProvider, createVueComponent, describeArtSelector, describeProductArtAlignment, describeProductImage, describeProductOptions, describeProductPrice, describeProductTitle, extractProductId, filterImagePlacements, findClosestSnapPoint, findVariantForSelection, formatPrice, formatValidationErrors, getDefaultVariantId, getEffectiveAlignment, getIncompleteSelectionMessage, getMissingSelections, getMockupUrl, getOptionRenderType, getProduct, getSelectionDisplayText, getSnapPoints, getVariant, handleOptionChange, isSelectionComplete, isValidAlignment, isValidTileCount, listProducts, mockupUrl, normalizeChoice, prepareOptionRenderData, registerStandardComponents, resolveMockupId, resolveVariantId, retryOperation, simulateCartOperation, toCombinations, toOptionAttributes, useFrameworkAdapter as useVueAdapter, validateAlignment, validateDesignElement, validateEffects, validateImageUrl, validateMockupOptions, validateProductSelection, validateProductSpec, validateRequiredOptions, validateTileCount, withContext, withErrorHandling, withSyncErrorHandling };
2701
+ export { AbstractTemplateRenderer, type AddToCartOptions, Animations, type ArtSelectorContext, type ArtSelectorDescriptor, type ArtSelectorOptions, type ArtworkData, type AspectRatio, Attributes, type BaseDescriptor, type BlendConfig, type BuildMockupUrlConfig, type CartDetail, type CatalogListResponse, type CatalogProduct$2 as CatalogProduct, ClassNames, type ColorDesignElement, ColorPickerUtils, Combination, CommonProps, ComponentContext, type ComponentDefinition, ComponentDescriptor, ComponentEventManager, ComponentFactory, ComponentLifecycle, ComponentLifecycleHooks, type ComponentMetadata, ComponentProps, ComponentRegistry, ComponentState, type ComponentTemplate, ComponentTemplates, type ContainerDescriptor, ContextBridge, type ContextComparator, type ContextConsumer, ContextInjector, type ContextProviderConfig, type ContextSubscriber, ContextSynchronizer, DEFAULT_ARTWORK_URL, DEFAULT_ASPECT_RATIO, DEFAULT_COLOR, DEFAULT_GRANT_BASE, DEFAULT_MOCKUP_BASE, DEFAULT_PLACEMENT_DIMENSIONS, type Descriptor, type Design, type DesignElement, type DesignGenerationContext, type Effects, Elements, type ErrorContext, type ErrorHandler, ErrorManager, type EventDefinition, EventDelegator, EventEmitter, EventHandler, type EventListener, type EventPayload, type Fill, Focus, FrameworkAdapter, FrameworkUtilities, type GetMockupUrlOptions, type ImageAlignment, type ImageDesignElement, type LifecycleHook, LifecycleManager, type LifecyclePhase, type LifecycleTransition, LitAdapter, type MaskOverride, type MockupGenerationOptions, MockupResult, type MockupService, type MockupServiceConfig, OptionAttribute, type OptionChoice, type OptionChoiceRenderData, type OptionRenderData, OptionSelection, type Placement, type PlacementDesign, PlacementSettings, type ProductArtAlignmentContext, type ProductArtAlignmentDescriptor, type ProductArtAlignmentOptions, type ProductContext, type ProductContextEvents, ProductContextManager, type ProductData, type ProductFetcher, type ProductImageDescriptor, type ProductImageOptions, ProductLoader, type ProductMockupData, type ProductOptionChoice, type ProductOptionData, type ProductOptionsDescriptor, type ProductOptionsOptions, type ProductPlacement, type ProductPriceDescriptor, type ProductPriceOptions, ProductProps, type ProductSpec, type ProductTitleDescriptor, type ProductTitleOptions, type ProductVariant, type PropDefinition, type PropSchema, type PropType, PropertyManager, REALTIME_WS_URL, type RateLimitState, type RealtimeGrant, RealtimeMockupService, type RegularArtwork, type RenderProduct, RenderSession, type RenderSessionOptions, type RenderState, type SdkConfig, type SeamlessPattern, type SignedUrlResponse, type SnowconeClient, StandardComponents, StandardEvents, StateManager, type StateManagerOptions, type StateMiddleware, type StateSelector, type StateSubscriber, type StateUpdater, Styles, SvelteAdapter, SwatchUtils, type TagName, TemplateBuilder, type TemplateNode, type TemplateNodeType, type TemplateRenderer, type TextDescriptor, type TileCount, UniversalContextProvider, type UserSelection, type ValidationError, type ValidationResult, VueAdapter, autoRegister, buildMockupUrl, componentRegistry, createAddToCartEvent, createAddToCartHandler, createCartDetail, createClient, createContextProvider, createDesignForPlacements, createErrorHandler, createEventManager, createLifecycle, createLitComponent, createProductContext, createProductLoader, createPropertyManager, createStateHook, createStateStore, createSvelteComponent, createUniversalProvider, createVueComponent, describeArtSelector, describeProductArtAlignment, describeProductImage, describeProductOptions, describeProductPrice, describeProductTitle, extractProductId, fetchRealtimeGrant, filterImagePlacements, findClosestSnapPoint, findVariantForSelection, formatPrice, formatValidationErrors, getDefaultVariantId, getEffectiveAlignment, getIncompleteSelectionMessage, getMissingSelections, getMockupUrl, getOptionRenderType, getProduct, getSelectionDisplayText, getSnapPoints, getVariant, handleOptionChange, isSelectionComplete, isValidAlignment, isValidTileCount, listProducts, mintRealtimeGrant, mockupUrl, normalizeChoice, prepareOptionRenderData, registerStandardComponents, resolveMockupId, resolveVariantId, retryOperation, simulateCartOperation, toCombinations, toOptionAttributes, useFrameworkAdapter as useVueAdapter, validateAlignment, validateDesignElement, validateEffects, validateImageUrl, validateMockupOptions, validateProductSelection, validateProductSpec, validateRequiredOptions, validateTileCount, withContext, withErrorHandling, withSyncErrorHandling };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { createDevFetcher } from './dev-fetcher.js';
2
2
  import { PublicDesign, PublicFill, PublicOptions } from '@snowcone-app/mockup-url';
3
- import { O as OptionAttribute, a as OptionSelection, C as Combination, F as FrameworkAdapter, b as ComponentProps, c as ComponentDescriptor, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, g as FrameworkUtilities } from './websocket-Dum3OooZ.js';
4
- export { A as AdapterRegistry, M as MockupResult, P as ProductComponentContext, R as RealtimeMockupCallbacks, h as RealtimeMockupService, i as RealtimeMockupState, j as RenderResult, W as WebSocketConfig, k as WebSocketMessage, l as adapterRegistry, m as computeDisabledChoices, n as createComponent, o as defineComponent, p as deriveDefaultSelection, q as findBestCombination, r as getPricePreview, s as isOptionAvailable, t as resolveBestCombination } from './websocket-Dum3OooZ.js';
3
+ import { O as OptionAttribute, a as OptionSelection, C as Combination, F as FrameworkAdapter, b as ComponentProps, c as ComponentDescriptor, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, g as FrameworkUtilities, P as PlacementSettings, M as MockupResult, R as RealtimeMockupService } from './websocket-BQH1HYJp.js';
4
+ export { A as AdapterRegistry, h as ProductComponentContext, i as RealtimeMockupCallbacks, j as RealtimeMockupState, k as RenderResult, W as WebSocketConfig, l as WebSocketMessage, m as adapterRegistry, n as computeDisabledChoices, o as createComponent, p as defineComponent, q as deriveDefaultSelection, r as findBestCombination, s as getPricePreview, t as isOptionAvailable, u as resolveBestCombination } from './websocket-BQH1HYJp.js';
5
5
 
6
6
  interface CatalogProduct$2 {
7
7
  id: string;
@@ -2481,6 +2481,169 @@ declare class SvelteAdapter implements FrameworkAdapter<ComponentProps> {
2481
2481
  */
2482
2482
  declare function createSvelteComponent(descriptor: ComponentDescriptor, svelte: any): any;
2483
2483
 
2484
+ /**
2485
+ * Production realtime render WebSocket endpoint (the rendercenter edge).
2486
+ *
2487
+ * This is the value to connect to for server-side canvas rendering — open
2488
+ * `${REALTIME_WS_URL}?token=<grant>`. Replaces the old un-discoverable
2489
+ * `wss://WS_URL_NOT_CONFIGURED.invalid/realtime` placeholder so a 3rd party
2490
+ * can find the endpoint from the package alone (ADR-0079, Phase 2).
2491
+ */
2492
+ declare const REALTIME_WS_URL = "wss://cdn.snowcone.app/realtime";
2493
+
2494
+ /**
2495
+ * Realtime grant helpers (ADR-0079, Phase 2).
2496
+ *
2497
+ * A realtime render session is authorized by a short-lived (60s) grant token.
2498
+ * There are two ways to obtain one, mirroring Stripe's pk_/sk_ split:
2499
+ *
2500
+ * - {@link mintRealtimeGrant} — SERVER-SIDE, with a secret API key (sk_).
2501
+ * - {@link fetchRealtimeGrant} — BROWSER, from your own proxy endpoint.
2502
+ *
2503
+ * The browser then opens `${REALTIME_WS_URL}?token=<token>` (RenderSession does
2504
+ * this for you).
2505
+ */
2506
+ /** A short-lived realtime session grant. */
2507
+ interface RealtimeGrant {
2508
+ /** Opaque session token to put on the WS URL as `?token=`. */
2509
+ token: string;
2510
+ /** Expiry, epoch seconds. Renew before this (RenderSession auto-renews). */
2511
+ expiresAt: number;
2512
+ }
2513
+ /** Default backend base URL hosting `POST /realtime/grant`. */
2514
+ declare const DEFAULT_GRANT_BASE = "https://api.snowcone.app";
2515
+ /**
2516
+ * SERVER-SIDE: mint a realtime grant with a secret API key (sk_). Call this
2517
+ * from YOUR backend — never the browser; the API key must stay secret. The key
2518
+ * needs the `mockups:realtime` (or `mockups`) scope and its organization must
2519
+ * own the target `shop`. Returns a 60s grant your browser code opens the WS
2520
+ * with (hand it down via your own endpoint + {@link fetchRealtimeGrant}).
2521
+ *
2522
+ * @example
2523
+ * // your backend route: POST /api/realtime/grant
2524
+ * const grant = await mintRealtimeGrant({ apiKey: process.env.SNOWCONE_API_KEY!, shop });
2525
+ * return Response.json(grant);
2526
+ */
2527
+ declare function mintRealtimeGrant(opts: {
2528
+ /** Secret API key (sk_) with the `mockups:realtime` or `mockups` scope. */
2529
+ apiKey: string;
2530
+ /** Target shop id (= shop.id). Must belong to the key's organization. */
2531
+ shop: string;
2532
+ /** Backend base URL. Defaults to {@link DEFAULT_GRANT_BASE}. */
2533
+ base?: string;
2534
+ /** Override fetch (e.g. in tests / non-global-fetch runtimes). */
2535
+ fetch?: typeof fetch;
2536
+ }): Promise<RealtimeGrant>;
2537
+ /**
2538
+ * BROWSER: fetch a grant from your own proxy endpoint, which calls
2539
+ * {@link mintRealtimeGrant} server-side (so the secret key never reaches the
2540
+ * browser). The proxy receives `POST { shop }` and returns `{ token, expiresAt }`.
2541
+ * This is the default token provider {@link RenderSession} uses when given a
2542
+ * `grantUrl`.
2543
+ */
2544
+ declare function fetchRealtimeGrant(grantUrl: string, shop: string, fetchImpl?: typeof fetch): Promise<RealtimeGrant>;
2545
+
2546
+ /**
2547
+ * RenderSession — a high-level facade over {@link RealtimeMockupService} for the
2548
+ * server-side canvas render flow (ADR-0079, Phase 2).
2549
+ *
2550
+ * It hides the connect → grant → config → renew → canvas_state choreography so a
2551
+ * 3rd party can do what the www PDP does in a few calls, without holding the
2552
+ * artwork bytes or rendering each placement client-side:
2553
+ *
2554
+ * @example
2555
+ * const session = new RenderSession({
2556
+ * shop: 'YOUR_SHOP_ID',
2557
+ * grantUrl: '/api/realtime/grant', // your proxy → mintRealtimeGrant (server)
2558
+ * product: { productId: 'BEEB77', mockupIds: ['front'] },
2559
+ * });
2560
+ * session.onMockups((results) => { img.src = results[0].imageUrl; });
2561
+ * await session.connect();
2562
+ * session.renderState('Front', serializeStateForServer(canvasState));
2563
+ *
2564
+ * For the low-level escape hatch, use {@link RealtimeMockupService} directly.
2565
+ */
2566
+
2567
+ /**
2568
+ * The server-render canvas state — the JSON produced by `serializeStateForServer()`
2569
+ * in `@snowcone-app/canvas` (its `ServerRenderRequest`). Typed structurally here
2570
+ * so the SDK stays dependency-free; if you have `@snowcone-app/canvas`, its
2571
+ * `ServerRenderRequest` is assignable to this. `schemaVersion` is the wire
2572
+ * contract version (`CANVAS_STATE_SCHEMA_VERSION`); a missing value is treated
2573
+ * as `1` by the renderer.
2574
+ */
2575
+ interface RenderState {
2576
+ schemaVersion?: number;
2577
+ artboards?: Array<Record<string, unknown>>;
2578
+ elements?: Array<Record<string, unknown>>;
2579
+ [key: string]: unknown;
2580
+ }
2581
+ /** Product the session renders against (Snowcone catalog ids). */
2582
+ interface RenderProduct {
2583
+ productId: string;
2584
+ mockupIds: string[];
2585
+ /** Optional variant (gvid). Omit if the product has no variant axis. */
2586
+ variantId?: string;
2587
+ /** Render width in px (default 1000). */
2588
+ width?: number;
2589
+ /** Per-placement settings (tiling, scale mode). */
2590
+ placementSettings?: Record<string, PlacementSettings>;
2591
+ }
2592
+ interface RenderSessionOptions {
2593
+ /** Publishable shop id (= shop.id, like Stripe pk_). */
2594
+ shop: string;
2595
+ /** Product config. Can also be set later via {@link RenderSession.setProduct}. */
2596
+ product?: RenderProduct;
2597
+ /** Realtime WS endpoint. Defaults to {@link REALTIME_WS_URL}. */
2598
+ wsUrl?: string;
2599
+ /**
2600
+ * How to authorize the session. Provide exactly one:
2601
+ * - `grantUrl`: your endpoint that returns `{ token, expiresAt }` for
2602
+ * `POST { shop }` (recommended — a same-origin proxy to `mintRealtimeGrant`).
2603
+ * - `getToken`: full control over fetching the grant.
2604
+ */
2605
+ grantUrl?: string;
2606
+ getToken?: () => Promise<RealtimeGrant>;
2607
+ /** Override fetch (used with `grantUrl`). */
2608
+ fetch?: typeof fetch;
2609
+ }
2610
+ declare class RenderSession {
2611
+ private readonly svc;
2612
+ private readonly opts;
2613
+ private product;
2614
+ private mockupCb;
2615
+ private errorCb;
2616
+ private ready;
2617
+ constructor(opts: RenderSessionOptions);
2618
+ /** Register a callback fired whenever rendered mockup URLs update. */
2619
+ onMockups(cb: (results: MockupResult[]) => void): this;
2620
+ /** Register an error callback (server/transport errors). */
2621
+ onError(cb: (error: string) => void): this;
2622
+ /** Set or update the product. Sends config immediately if already connected. */
2623
+ setProduct(product: RenderProduct): void;
2624
+ /**
2625
+ * Connect, authorize, and configure. Resolves once the session is ready to
2626
+ * accept {@link RenderSession.renderState}. Idempotent.
2627
+ */
2628
+ connect(): Promise<void>;
2629
+ /**
2630
+ * Render a canvas state for a placement. The server rasterizes it and fetches
2631
+ * the assets referenced inside — no pixels are uploaded. Results arrive via
2632
+ * {@link RenderSession.onMockups}. Safe to call repeatedly (e.g. on every
2633
+ * canvas edit); pass `throttleMs` to debounce during live dragging.
2634
+ */
2635
+ renderState(placement: string, state: RenderState, throttleMs?: number): Promise<void>;
2636
+ /** Update only the mockup ids to render (reuses the current state). */
2637
+ updateMockupIds(mockupIds: string[]): void;
2638
+ /** Current rendered results. */
2639
+ getMockups(): MockupResult[];
2640
+ /** Close the WebSocket and stop auto-renew. */
2641
+ close(): void;
2642
+ /** Escape hatch: the underlying low-level service. */
2643
+ get service(): RealtimeMockupService;
2644
+ private toConfig;
2645
+ }
2646
+
2484
2647
  interface ProductPlacement {
2485
2648
  label: string;
2486
2649
  x: number;
@@ -2535,4 +2698,4 @@ declare function getProduct(idOrSlug: string, config?: Partial<SdkConfig>): Prom
2535
2698
  */
2536
2699
  declare function createClient(config: SdkConfig): SnowconeClient;
2537
2700
 
2538
- export { AbstractTemplateRenderer, type AddToCartOptions, Animations, type ArtSelectorContext, type ArtSelectorDescriptor, type ArtSelectorOptions, type ArtworkData, type AspectRatio, Attributes, type BaseDescriptor, type BlendConfig, type BuildMockupUrlConfig, type CartDetail, type CatalogListResponse, type CatalogProduct$2 as CatalogProduct, ClassNames, type ColorDesignElement, ColorPickerUtils, Combination, CommonProps, ComponentContext, type ComponentDefinition, ComponentDescriptor, ComponentEventManager, ComponentFactory, ComponentLifecycle, ComponentLifecycleHooks, type ComponentMetadata, ComponentProps, ComponentRegistry, ComponentState, type ComponentTemplate, ComponentTemplates, type ContainerDescriptor, ContextBridge, type ContextComparator, type ContextConsumer, ContextInjector, type ContextProviderConfig, type ContextSubscriber, ContextSynchronizer, DEFAULT_ARTWORK_URL, DEFAULT_ASPECT_RATIO, DEFAULT_COLOR, DEFAULT_MOCKUP_BASE, DEFAULT_PLACEMENT_DIMENSIONS, type Descriptor, type Design, type DesignElement, type DesignGenerationContext, type Effects, Elements, type ErrorContext, type ErrorHandler, ErrorManager, type EventDefinition, EventDelegator, EventEmitter, EventHandler, type EventListener, type EventPayload, type Fill, Focus, FrameworkAdapter, FrameworkUtilities, type GetMockupUrlOptions, type ImageAlignment, type ImageDesignElement, type LifecycleHook, LifecycleManager, type LifecyclePhase, type LifecycleTransition, LitAdapter, type MaskOverride, type MockupGenerationOptions, type MockupService, type MockupServiceConfig, OptionAttribute, type OptionChoice, type OptionChoiceRenderData, type OptionRenderData, OptionSelection, type Placement, type PlacementDesign, type ProductArtAlignmentContext, type ProductArtAlignmentDescriptor, type ProductArtAlignmentOptions, type ProductContext, type ProductContextEvents, ProductContextManager, type ProductData, type ProductFetcher, type ProductImageDescriptor, type ProductImageOptions, ProductLoader, type ProductMockupData, type ProductOptionChoice, type ProductOptionData, type ProductOptionsDescriptor, type ProductOptionsOptions, type ProductPlacement, type ProductPriceDescriptor, type ProductPriceOptions, ProductProps, type ProductSpec, type ProductTitleDescriptor, type ProductTitleOptions, type ProductVariant, type PropDefinition, type PropSchema, type PropType, PropertyManager, type RateLimitState, type RegularArtwork, type SdkConfig, type SeamlessPattern, type SignedUrlResponse, type SnowconeClient, StandardComponents, StandardEvents, StateManager, type StateManagerOptions, type StateMiddleware, type StateSelector, type StateSubscriber, type StateUpdater, Styles, SvelteAdapter, SwatchUtils, type TagName, TemplateBuilder, type TemplateNode, type TemplateNodeType, type TemplateRenderer, type TextDescriptor, type TileCount, UniversalContextProvider, type UserSelection, type ValidationError, type ValidationResult, VueAdapter, autoRegister, buildMockupUrl, componentRegistry, createAddToCartEvent, createAddToCartHandler, createCartDetail, createClient, createContextProvider, createDesignForPlacements, createErrorHandler, createEventManager, createLifecycle, createLitComponent, createProductContext, createProductLoader, createPropertyManager, createStateHook, createStateStore, createSvelteComponent, createUniversalProvider, createVueComponent, describeArtSelector, describeProductArtAlignment, describeProductImage, describeProductOptions, describeProductPrice, describeProductTitle, extractProductId, filterImagePlacements, findClosestSnapPoint, findVariantForSelection, formatPrice, formatValidationErrors, getDefaultVariantId, getEffectiveAlignment, getIncompleteSelectionMessage, getMissingSelections, getMockupUrl, getOptionRenderType, getProduct, getSelectionDisplayText, getSnapPoints, getVariant, handleOptionChange, isSelectionComplete, isValidAlignment, isValidTileCount, listProducts, mockupUrl, normalizeChoice, prepareOptionRenderData, registerStandardComponents, resolveMockupId, resolveVariantId, retryOperation, simulateCartOperation, toCombinations, toOptionAttributes, useFrameworkAdapter as useVueAdapter, validateAlignment, validateDesignElement, validateEffects, validateImageUrl, validateMockupOptions, validateProductSelection, validateProductSpec, validateRequiredOptions, validateTileCount, withContext, withErrorHandling, withSyncErrorHandling };
2701
+ export { AbstractTemplateRenderer, type AddToCartOptions, Animations, type ArtSelectorContext, type ArtSelectorDescriptor, type ArtSelectorOptions, type ArtworkData, type AspectRatio, Attributes, type BaseDescriptor, type BlendConfig, type BuildMockupUrlConfig, type CartDetail, type CatalogListResponse, type CatalogProduct$2 as CatalogProduct, ClassNames, type ColorDesignElement, ColorPickerUtils, Combination, CommonProps, ComponentContext, type ComponentDefinition, ComponentDescriptor, ComponentEventManager, ComponentFactory, ComponentLifecycle, ComponentLifecycleHooks, type ComponentMetadata, ComponentProps, ComponentRegistry, ComponentState, type ComponentTemplate, ComponentTemplates, type ContainerDescriptor, ContextBridge, type ContextComparator, type ContextConsumer, ContextInjector, type ContextProviderConfig, type ContextSubscriber, ContextSynchronizer, DEFAULT_ARTWORK_URL, DEFAULT_ASPECT_RATIO, DEFAULT_COLOR, DEFAULT_GRANT_BASE, DEFAULT_MOCKUP_BASE, DEFAULT_PLACEMENT_DIMENSIONS, type Descriptor, type Design, type DesignElement, type DesignGenerationContext, type Effects, Elements, type ErrorContext, type ErrorHandler, ErrorManager, type EventDefinition, EventDelegator, EventEmitter, EventHandler, type EventListener, type EventPayload, type Fill, Focus, FrameworkAdapter, FrameworkUtilities, type GetMockupUrlOptions, type ImageAlignment, type ImageDesignElement, type LifecycleHook, LifecycleManager, type LifecyclePhase, type LifecycleTransition, LitAdapter, type MaskOverride, type MockupGenerationOptions, MockupResult, type MockupService, type MockupServiceConfig, OptionAttribute, type OptionChoice, type OptionChoiceRenderData, type OptionRenderData, OptionSelection, type Placement, type PlacementDesign, PlacementSettings, type ProductArtAlignmentContext, type ProductArtAlignmentDescriptor, type ProductArtAlignmentOptions, type ProductContext, type ProductContextEvents, ProductContextManager, type ProductData, type ProductFetcher, type ProductImageDescriptor, type ProductImageOptions, ProductLoader, type ProductMockupData, type ProductOptionChoice, type ProductOptionData, type ProductOptionsDescriptor, type ProductOptionsOptions, type ProductPlacement, type ProductPriceDescriptor, type ProductPriceOptions, ProductProps, type ProductSpec, type ProductTitleDescriptor, type ProductTitleOptions, type ProductVariant, type PropDefinition, type PropSchema, type PropType, PropertyManager, REALTIME_WS_URL, type RateLimitState, type RealtimeGrant, RealtimeMockupService, type RegularArtwork, type RenderProduct, RenderSession, type RenderSessionOptions, type RenderState, type SdkConfig, type SeamlessPattern, type SignedUrlResponse, type SnowconeClient, StandardComponents, StandardEvents, StateManager, type StateManagerOptions, type StateMiddleware, type StateSelector, type StateSubscriber, type StateUpdater, Styles, SvelteAdapter, SwatchUtils, type TagName, TemplateBuilder, type TemplateNode, type TemplateNodeType, type TemplateRenderer, type TextDescriptor, type TileCount, UniversalContextProvider, type UserSelection, type ValidationError, type ValidationResult, VueAdapter, autoRegister, buildMockupUrl, componentRegistry, createAddToCartEvent, createAddToCartHandler, createCartDetail, createClient, createContextProvider, createDesignForPlacements, createErrorHandler, createEventManager, createLifecycle, createLitComponent, createProductContext, createProductLoader, createPropertyManager, createStateHook, createStateStore, createSvelteComponent, createUniversalProvider, createVueComponent, describeArtSelector, describeProductArtAlignment, describeProductImage, describeProductOptions, describeProductPrice, describeProductTitle, extractProductId, fetchRealtimeGrant, filterImagePlacements, findClosestSnapPoint, findVariantForSelection, formatPrice, formatValidationErrors, getDefaultVariantId, getEffectiveAlignment, getIncompleteSelectionMessage, getMissingSelections, getMockupUrl, getOptionRenderType, getProduct, getSelectionDisplayText, getSnapPoints, getVariant, handleOptionChange, isSelectionComplete, isValidAlignment, isValidTileCount, listProducts, mintRealtimeGrant, mockupUrl, normalizeChoice, prepareOptionRenderData, registerStandardComponents, resolveMockupId, resolveVariantId, retryOperation, simulateCartOperation, toCombinations, toOptionAttributes, useFrameworkAdapter as useVueAdapter, validateAlignment, validateDesignElement, validateEffects, validateImageUrl, validateMockupOptions, validateProductSelection, validateProductSpec, validateRequiredOptions, validateTileCount, withContext, withErrorHandling, withSyncErrorHandling };
package/dist/index.js CHANGED
@@ -2,8 +2,9 @@ import {
2
2
  createDevFetcher
3
3
  } from "./chunk-7VO4EL2V.js";
4
4
  import {
5
+ REALTIME_WS_URL,
5
6
  RealtimeMockupService
6
- } from "./chunk-6MV7TDTM.js";
7
+ } from "./chunk-RPA3B6I3.js";
7
8
 
8
9
  // src/validation.ts
9
10
  import { z } from "zod";
@@ -4648,6 +4649,154 @@ function createSvelteComponent(descriptor, svelte) {
4648
4649
  };
4649
4650
  }
4650
4651
 
4652
+ // src/realtime/grant.ts
4653
+ var DEFAULT_GRANT_BASE = "https://api.snowcone.app";
4654
+ async function mintRealtimeGrant(opts) {
4655
+ const f = opts.fetch ?? globalThis.fetch;
4656
+ const res = await f(`${opts.base ?? DEFAULT_GRANT_BASE}/realtime/grant`, {
4657
+ method: "POST",
4658
+ headers: {
4659
+ "Content-Type": "application/json",
4660
+ Authorization: `Bearer ${opts.apiKey}`
4661
+ },
4662
+ body: JSON.stringify({ shop: opts.shop })
4663
+ });
4664
+ if (!res.ok) {
4665
+ const detail = await res.text().catch(() => "");
4666
+ throw new Error(`realtime grant failed: ${res.status}${detail ? ` ${detail}` : ""}`);
4667
+ }
4668
+ return await res.json();
4669
+ }
4670
+ async function fetchRealtimeGrant(grantUrl, shop, fetchImpl) {
4671
+ const f = fetchImpl ?? globalThis.fetch;
4672
+ const res = await f(grantUrl, {
4673
+ method: "POST",
4674
+ headers: { "Content-Type": "application/json" },
4675
+ body: JSON.stringify({ shop })
4676
+ });
4677
+ if (!res.ok) throw new Error(`realtime grant failed: ${res.status}`);
4678
+ return await res.json();
4679
+ }
4680
+
4681
+ // src/realtime/session.ts
4682
+ var RenderSession = class {
4683
+ svc;
4684
+ opts;
4685
+ product;
4686
+ mockupCb = null;
4687
+ errorCb = null;
4688
+ ready = null;
4689
+ constructor(opts) {
4690
+ if (!opts.shop) throw new Error("RenderSession: `shop` is required");
4691
+ if (!opts.getToken && !opts.grantUrl) {
4692
+ throw new Error("RenderSession: provide `grantUrl` or `getToken` to authorize the session");
4693
+ }
4694
+ this.opts = opts;
4695
+ this.product = opts.product ?? null;
4696
+ this.svc = new RealtimeMockupService(opts.wsUrl ?? REALTIME_WS_URL);
4697
+ const getToken = opts.getToken ?? (() => fetchRealtimeGrant(opts.grantUrl, opts.shop, opts.fetch));
4698
+ this.svc.setTokenProvider(getToken);
4699
+ }
4700
+ /** Register a callback fired whenever rendered mockup URLs update. */
4701
+ onMockups(cb) {
4702
+ this.mockupCb = cb;
4703
+ return this;
4704
+ }
4705
+ /** Register an error callback (server/transport errors). */
4706
+ onError(cb) {
4707
+ this.errorCb = cb;
4708
+ return this;
4709
+ }
4710
+ /** Set or update the product. Sends config immediately if already connected. */
4711
+ setProduct(product) {
4712
+ this.product = product;
4713
+ this.svc.sendConfig(this.toConfig(product));
4714
+ }
4715
+ /**
4716
+ * Connect, authorize, and configure. Resolves once the session is ready to
4717
+ * accept {@link RenderSession.renderState}. Idempotent.
4718
+ */
4719
+ connect() {
4720
+ if (this.ready) return this.ready;
4721
+ if (!this.product) {
4722
+ return Promise.reject(
4723
+ new Error("RenderSession: set a product (via options.product or setProduct) before connect()")
4724
+ );
4725
+ }
4726
+ const product = this.product;
4727
+ this.ready = new Promise((resolve, reject) => {
4728
+ let settled = false;
4729
+ this.svc.setCallbacks({
4730
+ onConnected: () => {
4731
+ this.svc.sendConfig(this.toConfig(product));
4732
+ },
4733
+ onConfigReceived: () => {
4734
+ if (!settled) {
4735
+ settled = true;
4736
+ resolve();
4737
+ }
4738
+ },
4739
+ onMockupRendered: () => {
4740
+ this.mockupCb?.(this.svc.getState().mockupResults);
4741
+ },
4742
+ onAllMockupsRendered: (results) => {
4743
+ this.mockupCb?.(results);
4744
+ },
4745
+ onError: (error) => {
4746
+ this.errorCb?.(error);
4747
+ if (!settled) {
4748
+ settled = true;
4749
+ reject(new Error(error));
4750
+ }
4751
+ }
4752
+ });
4753
+ this.svc.sendConfig(this.toConfig(product));
4754
+ this.svc.connect();
4755
+ });
4756
+ return this.ready;
4757
+ }
4758
+ /**
4759
+ * Render a canvas state for a placement. The server rasterizes it and fetches
4760
+ * the assets referenced inside — no pixels are uploaded. Results arrive via
4761
+ * {@link RenderSession.onMockups}. Safe to call repeatedly (e.g. on every
4762
+ * canvas edit); pass `throttleMs` to debounce during live dragging.
4763
+ */
4764
+ async renderState(placement, state, throttleMs = 0) {
4765
+ await this.connect();
4766
+ this.svc.sendCanvasState(placement, state, this.product?.mockupIds.length ?? 1, throttleMs);
4767
+ }
4768
+ /** Update only the mockup ids to render (reuses the current state). */
4769
+ updateMockupIds(mockupIds) {
4770
+ if (this.product) this.product = { ...this.product, mockupIds };
4771
+ this.svc.updateMockupIds(mockupIds);
4772
+ }
4773
+ /** Current rendered results. */
4774
+ getMockups() {
4775
+ return this.svc.getState().mockupResults;
4776
+ }
4777
+ /** Close the WebSocket and stop auto-renew. */
4778
+ close() {
4779
+ this.svc.disconnect();
4780
+ this.ready = null;
4781
+ }
4782
+ /** Escape hatch: the underlying low-level service. */
4783
+ get service() {
4784
+ return this.svc;
4785
+ }
4786
+ toConfig(product) {
4787
+ return {
4788
+ productId: product.productId,
4789
+ mockupIds: product.mockupIds,
4790
+ // shop comes from the grant token server-side; sent for completeness.
4791
+ shop: this.opts.shop,
4792
+ // WebSocketConfig requires these; the server treats empty variant as "none".
4793
+ variantId: product.variantId ?? "",
4794
+ width: product.width ?? 1e3,
4795
+ ...product.placementSettings ? { placementSettings: product.placementSettings } : {}
4796
+ };
4797
+ }
4798
+ };
4799
+
4651
4800
  // src/index.ts
4652
4801
  function getFetcher(config) {
4653
4802
  return config?.fetcher || globalThis.fetch.bind(globalThis);
@@ -4734,6 +4883,7 @@ export {
4734
4883
  DEFAULT_ARTWORK_URL,
4735
4884
  DEFAULT_ASPECT_RATIO,
4736
4885
  DEFAULT_COLOR,
4886
+ DEFAULT_GRANT_BASE,
4737
4887
  DEFAULT_MOCKUP_BASE,
4738
4888
  DEFAULT_PLACEMENT_DIMENSIONS,
4739
4889
  Elements,
@@ -4747,7 +4897,9 @@ export {
4747
4897
  ProductLoader,
4748
4898
  ProductProps,
4749
4899
  PropertyManager,
4900
+ REALTIME_WS_URL,
4750
4901
  RealtimeMockupService,
4902
+ RenderSession,
4751
4903
  StandardComponents,
4752
4904
  StandardEvents,
4753
4905
  StateManager,
@@ -4791,6 +4943,7 @@ export {
4791
4943
  describeProductPrice,
4792
4944
  describeProductTitle,
4793
4945
  extractProductId,
4946
+ fetchRealtimeGrant,
4794
4947
  filterImagePlacements,
4795
4948
  findBestCombination,
4796
4949
  findClosestSnapPoint,
@@ -4814,6 +4967,7 @@ export {
4814
4967
  isValidAlignment,
4815
4968
  isValidTileCount,
4816
4969
  listProducts,
4970
+ mintRealtimeGrant,
4817
4971
  mockupUrl,
4818
4972
  normalizeChoice,
4819
4973
  prepareOptionRenderData,
package/dist/react.cjs CHANGED
@@ -30,9 +30,12 @@ module.exports = __toCommonJS(react_exports);
30
30
  // src/realtime/react.ts
31
31
  var import_react = require("react");
32
32
 
33
+ // src/realtime/constants.ts
34
+ var REALTIME_WS_URL = "wss://cdn.snowcone.app/realtime";
35
+
33
36
  // src/realtime/websocket.ts
34
37
  var RealtimeMockupService = class {
35
- constructor(wsUrl = "wss://WS_URL_NOT_CONFIGURED.invalid/realtime") {
38
+ constructor(wsUrl = REALTIME_WS_URL) {
36
39
  this.wsUrl = wsUrl;
37
40
  }
38
41
  ws = null;
package/dist/react.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { M as MockupResult, W as WebSocketConfig, u as PlacementSettings, F as FrameworkAdapter, b as ComponentProps, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, c as ComponentDescriptor, g as FrameworkUtilities } from './websocket-Dum3OooZ.cjs';
1
+ import { M as MockupResult, W as WebSocketConfig, P as PlacementSettings, F as FrameworkAdapter, b as ComponentProps, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, c as ComponentDescriptor, g as FrameworkUtilities } from './websocket-BQH1HYJp.cjs';
2
2
 
3
3
  interface UseRealtimeMockupOptions {
4
4
  wsUrl?: string;
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { M as MockupResult, W as WebSocketConfig, u as PlacementSettings, F as FrameworkAdapter, b as ComponentProps, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, c as ComponentDescriptor, g as FrameworkUtilities } from './websocket-Dum3OooZ.js';
1
+ import { M as MockupResult, W as WebSocketConfig, P as PlacementSettings, F as FrameworkAdapter, b as ComponentProps, d as ComponentState, e as ComponentContext, f as ComponentLifecycleHooks, E as EventHandler, c as ComponentDescriptor, g as FrameworkUtilities } from './websocket-BQH1HYJp.js';
2
2
 
3
3
  interface UseRealtimeMockupOptions {
4
4
  wsUrl?: string;
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RealtimeMockupService
3
- } from "./chunk-6MV7TDTM.js";
3
+ } from "./chunk-RPA3B6I3.js";
4
4
 
5
5
  // src/realtime/react.ts
6
6
  import { useCallback, useEffect, useRef, useState } from "react";
@@ -385,4 +385,4 @@ declare class RealtimeMockupService {
385
385
  clearMockups(): void;
386
386
  }
387
387
 
388
- export { AdapterRegistry as A, type Combination as C, type EventHandler as E, type FrameworkAdapter as F, type MockupResult as M, type OptionAttribute as O, type ProductComponentContext as P, type RealtimeMockupCallbacks as R, type WebSocketConfig as W, type OptionSelection as a, type ComponentProps as b, type ComponentDescriptor as c, type ComponentState as d, type ComponentContext as e, type ComponentLifecycleHooks as f, type FrameworkUtilities as g, RealtimeMockupService as h, type RealtimeMockupState as i, type RenderResult as j, type WebSocketMessage as k, adapterRegistry as l, computeDisabledChoices as m, createComponent as n, defineComponent as o, deriveDefaultSelection as p, findBestCombination as q, getPricePreview as r, isOptionAvailable as s, resolveBestCombination as t, type PlacementSettings as u };
388
+ export { AdapterRegistry as A, type Combination as C, type EventHandler as E, type FrameworkAdapter as F, type MockupResult as M, type OptionAttribute as O, type PlacementSettings as P, RealtimeMockupService as R, type WebSocketConfig as W, type OptionSelection as a, type ComponentProps as b, type ComponentDescriptor as c, type ComponentState as d, type ComponentContext as e, type ComponentLifecycleHooks as f, type FrameworkUtilities as g, type ProductComponentContext as h, type RealtimeMockupCallbacks as i, type RealtimeMockupState as j, type RenderResult as k, type WebSocketMessage as l, adapterRegistry as m, computeDisabledChoices as n, createComponent as o, defineComponent as p, deriveDefaultSelection as q, findBestCombination as r, getPricePreview as s, isOptionAvailable as t, resolveBestCombination as u };
@@ -385,4 +385,4 @@ declare class RealtimeMockupService {
385
385
  clearMockups(): void;
386
386
  }
387
387
 
388
- export { AdapterRegistry as A, type Combination as C, type EventHandler as E, type FrameworkAdapter as F, type MockupResult as M, type OptionAttribute as O, type ProductComponentContext as P, type RealtimeMockupCallbacks as R, type WebSocketConfig as W, type OptionSelection as a, type ComponentProps as b, type ComponentDescriptor as c, type ComponentState as d, type ComponentContext as e, type ComponentLifecycleHooks as f, type FrameworkUtilities as g, RealtimeMockupService as h, type RealtimeMockupState as i, type RenderResult as j, type WebSocketMessage as k, adapterRegistry as l, computeDisabledChoices as m, createComponent as n, defineComponent as o, deriveDefaultSelection as p, findBestCombination as q, getPricePreview as r, isOptionAvailable as s, resolveBestCombination as t, type PlacementSettings as u };
388
+ export { AdapterRegistry as A, type Combination as C, type EventHandler as E, type FrameworkAdapter as F, type MockupResult as M, type OptionAttribute as O, type PlacementSettings as P, RealtimeMockupService as R, type WebSocketConfig as W, type OptionSelection as a, type ComponentProps as b, type ComponentDescriptor as c, type ComponentState as d, type ComponentContext as e, type ComponentLifecycleHooks as f, type FrameworkUtilities as g, type ProductComponentContext as h, type RealtimeMockupCallbacks as i, type RealtimeMockupState as j, type RenderResult as k, type WebSocketMessage as l, adapterRegistry as m, computeDisabledChoices as n, createComponent as o, defineComponent as p, deriveDefaultSelection as q, findBestCombination as r, getPricePreview as s, isOptionAvailable as t, resolveBestCombination as u };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@snowcone-app/sdk",
3
- "version": "0.1.14",
4
- "description": "Merch Javascript SDK for product mockups and print-on-demand",
3
+ "version": "0.1.15",
4
+ "description": "Snowcone SDK for product mockups and print-on-demand",
5
5
  "keywords": [
6
6
  "merch",
7
7
  "mockup",
@@ -14,10 +14,13 @@
14
14
  "license": "MIT",
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/snowcone-app/ui-components.git",
17
+ "url": "https://github.com/snowcone-app/snowcone-monorepo.git",
18
18
  "directory": "packages/sdk"
19
19
  },
20
- "homepage": "https://snowcone.app",
20
+ "bugs": {
21
+ "url": "https://github.com/snowcone-app/snowcone-monorepo/issues"
22
+ },
23
+ "homepage": "https://developers.snowcone.app/sdk",
21
24
  "private": false,
22
25
  "type": "module",
23
26
  "main": "dist/index.cjs",