@snowcone-app/sdk 0.2.1 → 0.3.1
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/CHANGELOG.md +35 -0
- package/dist/index.cjs +44 -0
- package/dist/index.d.cts +43 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +44 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#258](https://github.com/snowcone-app/snowcone-monorepo/pull/258) [`a6d53d8`](https://github.com/snowcone-app/snowcone-monorepo/commit/a6d53d82a18d6dbbb55be4525637cd8372aed760) Thanks [@kevinsproles](https://github.com/kevinsproles)! - Move `zod` from `peerDependencies` to `dependencies`. The SDK uses zod internally (to validate catalog responses) and never asks the consumer to supply a zod schema across the API boundary, so it should bring its own zod rather than demand one as a peer. This removes the unmet-peer warning consumers saw on npm (which is on zod 4 while the SDK targets zod 3).
|
|
8
|
+
|
|
9
|
+
## 0.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#256](https://github.com/snowcone-app/snowcone-monorepo/pull/256) [`49f18e2`](https://github.com/snowcone-app/snowcone-monorepo/commit/49f18e221b49422e88f6aa6a06a1de153f170ff3) Thanks [@kevinsproles](https://github.com/kevinsproles)! - Surface the renderer's required-placement contract on `getProduct()`. The catalog
|
|
14
|
+
product now carries a `requiredPlacements` array — `{ label, key?, type: "image" |
|
|
15
|
+
"color", autoFilledByVariant }` — so a developer can read exactly which placements
|
|
16
|
+
`renderState` will demand (and which are auto-filled from `variantId`) instead of
|
|
17
|
+
reverse-engineering it from a runtime timeout error. Image placements also no longer
|
|
18
|
+
report `type: null`; they default to `"image"`.
|
|
19
|
+
|
|
20
|
+
## 0.2.2
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- [#239](https://github.com/snowcone-app/snowcone-monorepo/pull/239) [`0556a8f`](https://github.com/snowcone-app/snowcone-monorepo/commit/0556a8f1fbef862dadc50463657fb716517b3264) Thanks [@kevinsproles](https://github.com/kevinsproles)! - fix(realtime): `RenderSession` now surfaces a render timeout via `onError`
|
|
25
|
+
|
|
26
|
+
A render that produces no mockup used to hang forever with no signal — the
|
|
27
|
+
classic trigger is a product with a color/variant axis where `variantId` is
|
|
28
|
+
omitted, so the server waits for a color blob that never arrives and never
|
|
29
|
+
errors. `RenderSession` now arms a per-render watchdog: if no mockup arrives in
|
|
30
|
+
time it reports an actionable timeout (with the `variantId` hint) through the
|
|
31
|
+
same `onError` channel as other errors, instead of silently hanging.
|
|
32
|
+
|
|
33
|
+
Configurable via the new `renderTimeoutMs` option (default `30000`; set to `0`
|
|
34
|
+
to disable). A successful mockup cancels the watchdog, each new render re-arms
|
|
35
|
+
it, and `close()` clears any pending timer. `renderState` still resolves on
|
|
36
|
+
send — the watchdog is a side-channel and throttle behavior is unchanged.
|
|
37
|
+
|
|
3
38
|
## 0.2.1
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -217,6 +217,18 @@ var CatalogProductSchema = import_zod.z.object({
|
|
|
217
217
|
offsetY: import_zod.z.number().optional()
|
|
218
218
|
})
|
|
219
219
|
).optional(),
|
|
220
|
+
// The renderer's required-placement contract, surfaced by the catalog so a
|
|
221
|
+
// dev reads exactly which placements renderState will demand. Image
|
|
222
|
+
// placements + variant-auto-filled color placements. Optional — older catalog
|
|
223
|
+
// docs predate it.
|
|
224
|
+
requiredPlacements: import_zod.z.array(
|
|
225
|
+
import_zod.z.object({
|
|
226
|
+
label: import_zod.z.string(),
|
|
227
|
+
key: import_zod.z.string().optional(),
|
|
228
|
+
type: import_zod.z.enum(["image", "color"]),
|
|
229
|
+
autoFilledByVariant: import_zod.z.boolean()
|
|
230
|
+
})
|
|
231
|
+
).optional(),
|
|
220
232
|
defaultGvid: import_zod.z.string().optional()
|
|
221
233
|
});
|
|
222
234
|
|
|
@@ -5511,6 +5523,7 @@ async function fetchRealtimeGrant(grantUrl, shop, fetchImpl) {
|
|
|
5511
5523
|
}
|
|
5512
5524
|
|
|
5513
5525
|
// src/realtime/session.ts
|
|
5526
|
+
var DEFAULT_RENDER_TIMEOUT_MS = 3e4;
|
|
5514
5527
|
var RenderSession = class {
|
|
5515
5528
|
svc;
|
|
5516
5529
|
opts;
|
|
@@ -5518,6 +5531,8 @@ var RenderSession = class {
|
|
|
5518
5531
|
mockupCb = null;
|
|
5519
5532
|
errorCb = null;
|
|
5520
5533
|
ready = null;
|
|
5534
|
+
renderTimeoutMs;
|
|
5535
|
+
watchdog = null;
|
|
5521
5536
|
constructor(opts) {
|
|
5522
5537
|
if (!opts.shop) throw new Error("RenderSession: `shop` is required");
|
|
5523
5538
|
if (!opts.getToken && !opts.grantUrl) {
|
|
@@ -5525,6 +5540,7 @@ var RenderSession = class {
|
|
|
5525
5540
|
}
|
|
5526
5541
|
this.opts = opts;
|
|
5527
5542
|
this.product = opts.product ?? null;
|
|
5543
|
+
this.renderTimeoutMs = opts.renderTimeoutMs ?? DEFAULT_RENDER_TIMEOUT_MS;
|
|
5528
5544
|
this.svc = new RealtimeMockupService(opts.wsUrl ?? REALTIME_WS_URL);
|
|
5529
5545
|
const getToken = opts.getToken ?? (() => fetchRealtimeGrant(opts.grantUrl, opts.shop, opts.fetch));
|
|
5530
5546
|
this.svc.setTokenProvider(getToken);
|
|
@@ -5569,9 +5585,11 @@ var RenderSession = class {
|
|
|
5569
5585
|
}
|
|
5570
5586
|
},
|
|
5571
5587
|
onMockupRendered: () => {
|
|
5588
|
+
this.clearWatchdog();
|
|
5572
5589
|
this.mockupCb?.(this.svc.getState().mockupResults);
|
|
5573
5590
|
},
|
|
5574
5591
|
onAllMockupsRendered: (results) => {
|
|
5592
|
+
this.clearWatchdog();
|
|
5575
5593
|
this.mockupCb?.(results);
|
|
5576
5594
|
},
|
|
5577
5595
|
onError: (error) => {
|
|
@@ -5606,6 +5624,7 @@ var RenderSession = class {
|
|
|
5606
5624
|
async renderState(placement, state, throttleMs = 0) {
|
|
5607
5625
|
await this.connect();
|
|
5608
5626
|
this.svc.sendCanvasState(placement, state, this.product?.mockupIds.length ?? 1, throttleMs);
|
|
5627
|
+
this.armWatchdog();
|
|
5609
5628
|
}
|
|
5610
5629
|
/**
|
|
5611
5630
|
* Render a SAVED canvas by reference (ADR-0079 Phase 4). The server resolves
|
|
@@ -5617,6 +5636,7 @@ var RenderSession = class {
|
|
|
5617
5636
|
async renderSavedState(placement, stateId) {
|
|
5618
5637
|
await this.connect();
|
|
5619
5638
|
this.svc.sendCanvasStateRef(placement, stateId);
|
|
5639
|
+
this.armWatchdog();
|
|
5620
5640
|
}
|
|
5621
5641
|
/** Update only the mockup ids to render (reuses the current state). */
|
|
5622
5642
|
updateMockupIds(mockupIds) {
|
|
@@ -5629,9 +5649,33 @@ var RenderSession = class {
|
|
|
5629
5649
|
}
|
|
5630
5650
|
/** Close the WebSocket and stop auto-renew. */
|
|
5631
5651
|
close() {
|
|
5652
|
+
this.clearWatchdog();
|
|
5632
5653
|
this.svc.disconnect();
|
|
5633
5654
|
this.ready = null;
|
|
5634
5655
|
}
|
|
5656
|
+
/**
|
|
5657
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
5658
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
5659
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
5660
|
+
* server/transport errors — with a hint at the most common cause.
|
|
5661
|
+
*/
|
|
5662
|
+
armWatchdog() {
|
|
5663
|
+
this.clearWatchdog();
|
|
5664
|
+
if (this.renderTimeoutMs <= 0) return;
|
|
5665
|
+
this.watchdog = setTimeout(() => {
|
|
5666
|
+
this.watchdog = null;
|
|
5667
|
+
this.errorCb?.(
|
|
5668
|
+
`realtime render timed out after ${this.renderTimeoutMs}ms with no mockup \u2014 a product with a color/variant axis needs \`variantId\` in the product config (see RenderProduct.variantId)`
|
|
5669
|
+
);
|
|
5670
|
+
}, this.renderTimeoutMs);
|
|
5671
|
+
}
|
|
5672
|
+
/** Cancel the pending render watchdog, if any. */
|
|
5673
|
+
clearWatchdog() {
|
|
5674
|
+
if (this.watchdog) {
|
|
5675
|
+
clearTimeout(this.watchdog);
|
|
5676
|
+
this.watchdog = null;
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5635
5679
|
/** Escape hatch: the underlying low-level service. */
|
|
5636
5680
|
get service() {
|
|
5637
5681
|
return this.svc;
|
package/dist/index.d.cts
CHANGED
|
@@ -80,6 +80,21 @@ interface CatalogProduct$2 {
|
|
|
80
80
|
offsetX?: number;
|
|
81
81
|
offsetY?: number;
|
|
82
82
|
}[];
|
|
83
|
+
/**
|
|
84
|
+
* The renderer's required-placement contract, surfaced so a developer reads exactly which placements `renderState` will demand. Image placements are always sent by the caller; color placements (autoFilledByVariant: true) are filled from `variantId` — omit them when you pass a variantId, send them otherwise.
|
|
85
|
+
*/
|
|
86
|
+
requiredPlacements?: {
|
|
87
|
+
label: string;
|
|
88
|
+
/**
|
|
89
|
+
* URL-safe slug derived from `label`. Present for image placements.
|
|
90
|
+
*/
|
|
91
|
+
key?: string;
|
|
92
|
+
type: 'image' | 'color';
|
|
93
|
+
/**
|
|
94
|
+
* When true, this (color) placement is auto-filled from the variant's option choice when a `variantId` is sent; otherwise the caller must send it explicitly.
|
|
95
|
+
*/
|
|
96
|
+
autoFilledByVariant: boolean;
|
|
97
|
+
}[];
|
|
83
98
|
defaultGvid?: string | null;
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -2627,6 +2642,23 @@ interface RenderSessionOptions {
|
|
|
2627
2642
|
getToken?: () => Promise<RealtimeGrant>;
|
|
2628
2643
|
/** Override fetch (used with `grantUrl`). */
|
|
2629
2644
|
fetch?: typeof fetch;
|
|
2645
|
+
/**
|
|
2646
|
+
* Watchdog for silent render hangs. After a render is dispatched (via
|
|
2647
|
+
* {@link RenderSession.renderState} or {@link RenderSession.renderSavedState}),
|
|
2648
|
+
* if NO mockup arrives within this many milliseconds the session surfaces a
|
|
2649
|
+
* timeout through {@link RenderSession.onError} — turning an otherwise-silent
|
|
2650
|
+
* infinite hang into an actionable error.
|
|
2651
|
+
*
|
|
2652
|
+
* The classic trigger is a product with a color/variant axis where
|
|
2653
|
+
* {@link RenderProduct.variantId} is omitted: the server waits for a color
|
|
2654
|
+
* blob that never arrives, so it neither renders nor errors. The watchdog
|
|
2655
|
+
* makes that visible.
|
|
2656
|
+
*
|
|
2657
|
+
* Defaults to `30000` (30s). A value of `0` (or negative) DISABLES the
|
|
2658
|
+
* watchdog entirely. A successful mockup always cancels the pending watchdog,
|
|
2659
|
+
* and each new render re-arms it.
|
|
2660
|
+
*/
|
|
2661
|
+
renderTimeoutMs?: number;
|
|
2630
2662
|
}
|
|
2631
2663
|
declare class RenderSession {
|
|
2632
2664
|
private readonly svc;
|
|
@@ -2635,6 +2667,8 @@ declare class RenderSession {
|
|
|
2635
2667
|
private mockupCb;
|
|
2636
2668
|
private errorCb;
|
|
2637
2669
|
private ready;
|
|
2670
|
+
private readonly renderTimeoutMs;
|
|
2671
|
+
private watchdog;
|
|
2638
2672
|
constructor(opts: RenderSessionOptions);
|
|
2639
2673
|
/** Register a callback fired whenever rendered mockup URLs update. */
|
|
2640
2674
|
onMockups(cb: (results: MockupResult[]) => void): this;
|
|
@@ -2678,6 +2712,15 @@ declare class RenderSession {
|
|
|
2678
2712
|
getMockups(): MockupResult[];
|
|
2679
2713
|
/** Close the WebSocket and stop auto-renew. */
|
|
2680
2714
|
close(): void;
|
|
2715
|
+
/**
|
|
2716
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
2717
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
2718
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
2719
|
+
* server/transport errors — with a hint at the most common cause.
|
|
2720
|
+
*/
|
|
2721
|
+
private armWatchdog;
|
|
2722
|
+
/** Cancel the pending render watchdog, if any. */
|
|
2723
|
+
private clearWatchdog;
|
|
2681
2724
|
/** Escape hatch: the underlying low-level service. */
|
|
2682
2725
|
get service(): RealtimeMockupService;
|
|
2683
2726
|
private toConfig;
|
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,21 @@ interface CatalogProduct$2 {
|
|
|
80
80
|
offsetX?: number;
|
|
81
81
|
offsetY?: number;
|
|
82
82
|
}[];
|
|
83
|
+
/**
|
|
84
|
+
* The renderer's required-placement contract, surfaced so a developer reads exactly which placements `renderState` will demand. Image placements are always sent by the caller; color placements (autoFilledByVariant: true) are filled from `variantId` — omit them when you pass a variantId, send them otherwise.
|
|
85
|
+
*/
|
|
86
|
+
requiredPlacements?: {
|
|
87
|
+
label: string;
|
|
88
|
+
/**
|
|
89
|
+
* URL-safe slug derived from `label`. Present for image placements.
|
|
90
|
+
*/
|
|
91
|
+
key?: string;
|
|
92
|
+
type: 'image' | 'color';
|
|
93
|
+
/**
|
|
94
|
+
* When true, this (color) placement is auto-filled from the variant's option choice when a `variantId` is sent; otherwise the caller must send it explicitly.
|
|
95
|
+
*/
|
|
96
|
+
autoFilledByVariant: boolean;
|
|
97
|
+
}[];
|
|
83
98
|
defaultGvid?: string | null;
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -2627,6 +2642,23 @@ interface RenderSessionOptions {
|
|
|
2627
2642
|
getToken?: () => Promise<RealtimeGrant>;
|
|
2628
2643
|
/** Override fetch (used with `grantUrl`). */
|
|
2629
2644
|
fetch?: typeof fetch;
|
|
2645
|
+
/**
|
|
2646
|
+
* Watchdog for silent render hangs. After a render is dispatched (via
|
|
2647
|
+
* {@link RenderSession.renderState} or {@link RenderSession.renderSavedState}),
|
|
2648
|
+
* if NO mockup arrives within this many milliseconds the session surfaces a
|
|
2649
|
+
* timeout through {@link RenderSession.onError} — turning an otherwise-silent
|
|
2650
|
+
* infinite hang into an actionable error.
|
|
2651
|
+
*
|
|
2652
|
+
* The classic trigger is a product with a color/variant axis where
|
|
2653
|
+
* {@link RenderProduct.variantId} is omitted: the server waits for a color
|
|
2654
|
+
* blob that never arrives, so it neither renders nor errors. The watchdog
|
|
2655
|
+
* makes that visible.
|
|
2656
|
+
*
|
|
2657
|
+
* Defaults to `30000` (30s). A value of `0` (or negative) DISABLES the
|
|
2658
|
+
* watchdog entirely. A successful mockup always cancels the pending watchdog,
|
|
2659
|
+
* and each new render re-arms it.
|
|
2660
|
+
*/
|
|
2661
|
+
renderTimeoutMs?: number;
|
|
2630
2662
|
}
|
|
2631
2663
|
declare class RenderSession {
|
|
2632
2664
|
private readonly svc;
|
|
@@ -2635,6 +2667,8 @@ declare class RenderSession {
|
|
|
2635
2667
|
private mockupCb;
|
|
2636
2668
|
private errorCb;
|
|
2637
2669
|
private ready;
|
|
2670
|
+
private readonly renderTimeoutMs;
|
|
2671
|
+
private watchdog;
|
|
2638
2672
|
constructor(opts: RenderSessionOptions);
|
|
2639
2673
|
/** Register a callback fired whenever rendered mockup URLs update. */
|
|
2640
2674
|
onMockups(cb: (results: MockupResult[]) => void): this;
|
|
@@ -2678,6 +2712,15 @@ declare class RenderSession {
|
|
|
2678
2712
|
getMockups(): MockupResult[];
|
|
2679
2713
|
/** Close the WebSocket and stop auto-renew. */
|
|
2680
2714
|
close(): void;
|
|
2715
|
+
/**
|
|
2716
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
2717
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
2718
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
2719
|
+
* server/transport errors — with a hint at the most common cause.
|
|
2720
|
+
*/
|
|
2721
|
+
private armWatchdog;
|
|
2722
|
+
/** Cancel the pending render watchdog, if any. */
|
|
2723
|
+
private clearWatchdog;
|
|
2681
2724
|
/** Escape hatch: the underlying low-level service. */
|
|
2682
2725
|
get service(): RealtimeMockupService;
|
|
2683
2726
|
private toConfig;
|
package/dist/index.js
CHANGED
|
@@ -72,6 +72,18 @@ var CatalogProductSchema = z.object({
|
|
|
72
72
|
offsetY: z.number().optional()
|
|
73
73
|
})
|
|
74
74
|
).optional(),
|
|
75
|
+
// The renderer's required-placement contract, surfaced by the catalog so a
|
|
76
|
+
// dev reads exactly which placements renderState will demand. Image
|
|
77
|
+
// placements + variant-auto-filled color placements. Optional — older catalog
|
|
78
|
+
// docs predate it.
|
|
79
|
+
requiredPlacements: z.array(
|
|
80
|
+
z.object({
|
|
81
|
+
label: z.string(),
|
|
82
|
+
key: z.string().optional(),
|
|
83
|
+
type: z.enum(["image", "color"]),
|
|
84
|
+
autoFilledByVariant: z.boolean()
|
|
85
|
+
})
|
|
86
|
+
).optional(),
|
|
75
87
|
defaultGvid: z.string().optional()
|
|
76
88
|
});
|
|
77
89
|
|
|
@@ -4678,6 +4690,7 @@ async function fetchRealtimeGrant(grantUrl, shop, fetchImpl) {
|
|
|
4678
4690
|
}
|
|
4679
4691
|
|
|
4680
4692
|
// src/realtime/session.ts
|
|
4693
|
+
var DEFAULT_RENDER_TIMEOUT_MS = 3e4;
|
|
4681
4694
|
var RenderSession = class {
|
|
4682
4695
|
svc;
|
|
4683
4696
|
opts;
|
|
@@ -4685,6 +4698,8 @@ var RenderSession = class {
|
|
|
4685
4698
|
mockupCb = null;
|
|
4686
4699
|
errorCb = null;
|
|
4687
4700
|
ready = null;
|
|
4701
|
+
renderTimeoutMs;
|
|
4702
|
+
watchdog = null;
|
|
4688
4703
|
constructor(opts) {
|
|
4689
4704
|
if (!opts.shop) throw new Error("RenderSession: `shop` is required");
|
|
4690
4705
|
if (!opts.getToken && !opts.grantUrl) {
|
|
@@ -4692,6 +4707,7 @@ var RenderSession = class {
|
|
|
4692
4707
|
}
|
|
4693
4708
|
this.opts = opts;
|
|
4694
4709
|
this.product = opts.product ?? null;
|
|
4710
|
+
this.renderTimeoutMs = opts.renderTimeoutMs ?? DEFAULT_RENDER_TIMEOUT_MS;
|
|
4695
4711
|
this.svc = new RealtimeMockupService(opts.wsUrl ?? REALTIME_WS_URL);
|
|
4696
4712
|
const getToken = opts.getToken ?? (() => fetchRealtimeGrant(opts.grantUrl, opts.shop, opts.fetch));
|
|
4697
4713
|
this.svc.setTokenProvider(getToken);
|
|
@@ -4736,9 +4752,11 @@ var RenderSession = class {
|
|
|
4736
4752
|
}
|
|
4737
4753
|
},
|
|
4738
4754
|
onMockupRendered: () => {
|
|
4755
|
+
this.clearWatchdog();
|
|
4739
4756
|
this.mockupCb?.(this.svc.getState().mockupResults);
|
|
4740
4757
|
},
|
|
4741
4758
|
onAllMockupsRendered: (results) => {
|
|
4759
|
+
this.clearWatchdog();
|
|
4742
4760
|
this.mockupCb?.(results);
|
|
4743
4761
|
},
|
|
4744
4762
|
onError: (error) => {
|
|
@@ -4773,6 +4791,7 @@ var RenderSession = class {
|
|
|
4773
4791
|
async renderState(placement, state, throttleMs = 0) {
|
|
4774
4792
|
await this.connect();
|
|
4775
4793
|
this.svc.sendCanvasState(placement, state, this.product?.mockupIds.length ?? 1, throttleMs);
|
|
4794
|
+
this.armWatchdog();
|
|
4776
4795
|
}
|
|
4777
4796
|
/**
|
|
4778
4797
|
* Render a SAVED canvas by reference (ADR-0079 Phase 4). The server resolves
|
|
@@ -4784,6 +4803,7 @@ var RenderSession = class {
|
|
|
4784
4803
|
async renderSavedState(placement, stateId) {
|
|
4785
4804
|
await this.connect();
|
|
4786
4805
|
this.svc.sendCanvasStateRef(placement, stateId);
|
|
4806
|
+
this.armWatchdog();
|
|
4787
4807
|
}
|
|
4788
4808
|
/** Update only the mockup ids to render (reuses the current state). */
|
|
4789
4809
|
updateMockupIds(mockupIds) {
|
|
@@ -4796,9 +4816,33 @@ var RenderSession = class {
|
|
|
4796
4816
|
}
|
|
4797
4817
|
/** Close the WebSocket and stop auto-renew. */
|
|
4798
4818
|
close() {
|
|
4819
|
+
this.clearWatchdog();
|
|
4799
4820
|
this.svc.disconnect();
|
|
4800
4821
|
this.ready = null;
|
|
4801
4822
|
}
|
|
4823
|
+
/**
|
|
4824
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
4825
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
4826
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
4827
|
+
* server/transport errors — with a hint at the most common cause.
|
|
4828
|
+
*/
|
|
4829
|
+
armWatchdog() {
|
|
4830
|
+
this.clearWatchdog();
|
|
4831
|
+
if (this.renderTimeoutMs <= 0) return;
|
|
4832
|
+
this.watchdog = setTimeout(() => {
|
|
4833
|
+
this.watchdog = null;
|
|
4834
|
+
this.errorCb?.(
|
|
4835
|
+
`realtime render timed out after ${this.renderTimeoutMs}ms with no mockup \u2014 a product with a color/variant axis needs \`variantId\` in the product config (see RenderProduct.variantId)`
|
|
4836
|
+
);
|
|
4837
|
+
}, this.renderTimeoutMs);
|
|
4838
|
+
}
|
|
4839
|
+
/** Cancel the pending render watchdog, if any. */
|
|
4840
|
+
clearWatchdog() {
|
|
4841
|
+
if (this.watchdog) {
|
|
4842
|
+
clearTimeout(this.watchdog);
|
|
4843
|
+
this.watchdog = null;
|
|
4844
|
+
}
|
|
4845
|
+
}
|
|
4802
4846
|
/** Escape hatch: the underlying low-level service. */
|
|
4803
4847
|
get service() {
|
|
4804
4848
|
return this.svc;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snowcone-app/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Snowcone SDK for product mockups and print-on-demand",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"merch",
|
|
@@ -56,7 +56,6 @@
|
|
|
56
56
|
},
|
|
57
57
|
"sideEffects": false,
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"zod": "^3.0.0",
|
|
60
59
|
"react": "^18 || ^19"
|
|
61
60
|
},
|
|
62
61
|
"peerDependenciesMeta": {
|
|
@@ -64,14 +63,15 @@
|
|
|
64
63
|
"optional": true
|
|
65
64
|
}
|
|
66
65
|
},
|
|
67
|
-
"dependencies": {
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"zod": "^3.23.8"
|
|
68
|
+
},
|
|
68
69
|
"devDependencies": {
|
|
69
70
|
"@types/node": "^20.11.0",
|
|
70
71
|
"@types/react": "^18.3.0",
|
|
71
72
|
"tsup": "^8.1.0",
|
|
72
73
|
"typescript": "^5.5.4",
|
|
73
74
|
"vitest": "^2.0.5",
|
|
74
|
-
"zod": "^3.23.8",
|
|
75
75
|
"@snowcone-app/mockup-url": "0.1.0"
|
|
76
76
|
},
|
|
77
77
|
"engines": {
|