@snowcone-app/sdk 0.2.1 → 0.2.2
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 +18 -0
- package/dist/index.cjs +32 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +32 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#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`
|
|
8
|
+
|
|
9
|
+
A render that produces no mockup used to hang forever with no signal — the
|
|
10
|
+
classic trigger is a product with a color/variant axis where `variantId` is
|
|
11
|
+
omitted, so the server waits for a color blob that never arrives and never
|
|
12
|
+
errors. `RenderSession` now arms a per-render watchdog: if no mockup arrives in
|
|
13
|
+
time it reports an actionable timeout (with the `variantId` hint) through the
|
|
14
|
+
same `onError` channel as other errors, instead of silently hanging.
|
|
15
|
+
|
|
16
|
+
Configurable via the new `renderTimeoutMs` option (default `30000`; set to `0`
|
|
17
|
+
to disable). A successful mockup cancels the watchdog, each new render re-arms
|
|
18
|
+
it, and `close()` clears any pending timer. `renderState` still resolves on
|
|
19
|
+
send — the watchdog is a side-channel and throttle behavior is unchanged.
|
|
20
|
+
|
|
3
21
|
## 0.2.1
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -5511,6 +5511,7 @@ async function fetchRealtimeGrant(grantUrl, shop, fetchImpl) {
|
|
|
5511
5511
|
}
|
|
5512
5512
|
|
|
5513
5513
|
// src/realtime/session.ts
|
|
5514
|
+
var DEFAULT_RENDER_TIMEOUT_MS = 3e4;
|
|
5514
5515
|
var RenderSession = class {
|
|
5515
5516
|
svc;
|
|
5516
5517
|
opts;
|
|
@@ -5518,6 +5519,8 @@ var RenderSession = class {
|
|
|
5518
5519
|
mockupCb = null;
|
|
5519
5520
|
errorCb = null;
|
|
5520
5521
|
ready = null;
|
|
5522
|
+
renderTimeoutMs;
|
|
5523
|
+
watchdog = null;
|
|
5521
5524
|
constructor(opts) {
|
|
5522
5525
|
if (!opts.shop) throw new Error("RenderSession: `shop` is required");
|
|
5523
5526
|
if (!opts.getToken && !opts.grantUrl) {
|
|
@@ -5525,6 +5528,7 @@ var RenderSession = class {
|
|
|
5525
5528
|
}
|
|
5526
5529
|
this.opts = opts;
|
|
5527
5530
|
this.product = opts.product ?? null;
|
|
5531
|
+
this.renderTimeoutMs = opts.renderTimeoutMs ?? DEFAULT_RENDER_TIMEOUT_MS;
|
|
5528
5532
|
this.svc = new RealtimeMockupService(opts.wsUrl ?? REALTIME_WS_URL);
|
|
5529
5533
|
const getToken = opts.getToken ?? (() => fetchRealtimeGrant(opts.grantUrl, opts.shop, opts.fetch));
|
|
5530
5534
|
this.svc.setTokenProvider(getToken);
|
|
@@ -5569,9 +5573,11 @@ var RenderSession = class {
|
|
|
5569
5573
|
}
|
|
5570
5574
|
},
|
|
5571
5575
|
onMockupRendered: () => {
|
|
5576
|
+
this.clearWatchdog();
|
|
5572
5577
|
this.mockupCb?.(this.svc.getState().mockupResults);
|
|
5573
5578
|
},
|
|
5574
5579
|
onAllMockupsRendered: (results) => {
|
|
5580
|
+
this.clearWatchdog();
|
|
5575
5581
|
this.mockupCb?.(results);
|
|
5576
5582
|
},
|
|
5577
5583
|
onError: (error) => {
|
|
@@ -5606,6 +5612,7 @@ var RenderSession = class {
|
|
|
5606
5612
|
async renderState(placement, state, throttleMs = 0) {
|
|
5607
5613
|
await this.connect();
|
|
5608
5614
|
this.svc.sendCanvasState(placement, state, this.product?.mockupIds.length ?? 1, throttleMs);
|
|
5615
|
+
this.armWatchdog();
|
|
5609
5616
|
}
|
|
5610
5617
|
/**
|
|
5611
5618
|
* Render a SAVED canvas by reference (ADR-0079 Phase 4). The server resolves
|
|
@@ -5617,6 +5624,7 @@ var RenderSession = class {
|
|
|
5617
5624
|
async renderSavedState(placement, stateId) {
|
|
5618
5625
|
await this.connect();
|
|
5619
5626
|
this.svc.sendCanvasStateRef(placement, stateId);
|
|
5627
|
+
this.armWatchdog();
|
|
5620
5628
|
}
|
|
5621
5629
|
/** Update only the mockup ids to render (reuses the current state). */
|
|
5622
5630
|
updateMockupIds(mockupIds) {
|
|
@@ -5629,9 +5637,33 @@ var RenderSession = class {
|
|
|
5629
5637
|
}
|
|
5630
5638
|
/** Close the WebSocket and stop auto-renew. */
|
|
5631
5639
|
close() {
|
|
5640
|
+
this.clearWatchdog();
|
|
5632
5641
|
this.svc.disconnect();
|
|
5633
5642
|
this.ready = null;
|
|
5634
5643
|
}
|
|
5644
|
+
/**
|
|
5645
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
5646
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
5647
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
5648
|
+
* server/transport errors — with a hint at the most common cause.
|
|
5649
|
+
*/
|
|
5650
|
+
armWatchdog() {
|
|
5651
|
+
this.clearWatchdog();
|
|
5652
|
+
if (this.renderTimeoutMs <= 0) return;
|
|
5653
|
+
this.watchdog = setTimeout(() => {
|
|
5654
|
+
this.watchdog = null;
|
|
5655
|
+
this.errorCb?.(
|
|
5656
|
+
`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)`
|
|
5657
|
+
);
|
|
5658
|
+
}, this.renderTimeoutMs);
|
|
5659
|
+
}
|
|
5660
|
+
/** Cancel the pending render watchdog, if any. */
|
|
5661
|
+
clearWatchdog() {
|
|
5662
|
+
if (this.watchdog) {
|
|
5663
|
+
clearTimeout(this.watchdog);
|
|
5664
|
+
this.watchdog = null;
|
|
5665
|
+
}
|
|
5666
|
+
}
|
|
5635
5667
|
/** Escape hatch: the underlying low-level service. */
|
|
5636
5668
|
get service() {
|
|
5637
5669
|
return this.svc;
|
package/dist/index.d.cts
CHANGED
|
@@ -2627,6 +2627,23 @@ interface RenderSessionOptions {
|
|
|
2627
2627
|
getToken?: () => Promise<RealtimeGrant>;
|
|
2628
2628
|
/** Override fetch (used with `grantUrl`). */
|
|
2629
2629
|
fetch?: typeof fetch;
|
|
2630
|
+
/**
|
|
2631
|
+
* Watchdog for silent render hangs. After a render is dispatched (via
|
|
2632
|
+
* {@link RenderSession.renderState} or {@link RenderSession.renderSavedState}),
|
|
2633
|
+
* if NO mockup arrives within this many milliseconds the session surfaces a
|
|
2634
|
+
* timeout through {@link RenderSession.onError} — turning an otherwise-silent
|
|
2635
|
+
* infinite hang into an actionable error.
|
|
2636
|
+
*
|
|
2637
|
+
* The classic trigger is a product with a color/variant axis where
|
|
2638
|
+
* {@link RenderProduct.variantId} is omitted: the server waits for a color
|
|
2639
|
+
* blob that never arrives, so it neither renders nor errors. The watchdog
|
|
2640
|
+
* makes that visible.
|
|
2641
|
+
*
|
|
2642
|
+
* Defaults to `30000` (30s). A value of `0` (or negative) DISABLES the
|
|
2643
|
+
* watchdog entirely. A successful mockup always cancels the pending watchdog,
|
|
2644
|
+
* and each new render re-arms it.
|
|
2645
|
+
*/
|
|
2646
|
+
renderTimeoutMs?: number;
|
|
2630
2647
|
}
|
|
2631
2648
|
declare class RenderSession {
|
|
2632
2649
|
private readonly svc;
|
|
@@ -2635,6 +2652,8 @@ declare class RenderSession {
|
|
|
2635
2652
|
private mockupCb;
|
|
2636
2653
|
private errorCb;
|
|
2637
2654
|
private ready;
|
|
2655
|
+
private readonly renderTimeoutMs;
|
|
2656
|
+
private watchdog;
|
|
2638
2657
|
constructor(opts: RenderSessionOptions);
|
|
2639
2658
|
/** Register a callback fired whenever rendered mockup URLs update. */
|
|
2640
2659
|
onMockups(cb: (results: MockupResult[]) => void): this;
|
|
@@ -2678,6 +2697,15 @@ declare class RenderSession {
|
|
|
2678
2697
|
getMockups(): MockupResult[];
|
|
2679
2698
|
/** Close the WebSocket and stop auto-renew. */
|
|
2680
2699
|
close(): void;
|
|
2700
|
+
/**
|
|
2701
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
2702
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
2703
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
2704
|
+
* server/transport errors — with a hint at the most common cause.
|
|
2705
|
+
*/
|
|
2706
|
+
private armWatchdog;
|
|
2707
|
+
/** Cancel the pending render watchdog, if any. */
|
|
2708
|
+
private clearWatchdog;
|
|
2681
2709
|
/** Escape hatch: the underlying low-level service. */
|
|
2682
2710
|
get service(): RealtimeMockupService;
|
|
2683
2711
|
private toConfig;
|
package/dist/index.d.ts
CHANGED
|
@@ -2627,6 +2627,23 @@ interface RenderSessionOptions {
|
|
|
2627
2627
|
getToken?: () => Promise<RealtimeGrant>;
|
|
2628
2628
|
/** Override fetch (used with `grantUrl`). */
|
|
2629
2629
|
fetch?: typeof fetch;
|
|
2630
|
+
/**
|
|
2631
|
+
* Watchdog for silent render hangs. After a render is dispatched (via
|
|
2632
|
+
* {@link RenderSession.renderState} or {@link RenderSession.renderSavedState}),
|
|
2633
|
+
* if NO mockup arrives within this many milliseconds the session surfaces a
|
|
2634
|
+
* timeout through {@link RenderSession.onError} — turning an otherwise-silent
|
|
2635
|
+
* infinite hang into an actionable error.
|
|
2636
|
+
*
|
|
2637
|
+
* The classic trigger is a product with a color/variant axis where
|
|
2638
|
+
* {@link RenderProduct.variantId} is omitted: the server waits for a color
|
|
2639
|
+
* blob that never arrives, so it neither renders nor errors. The watchdog
|
|
2640
|
+
* makes that visible.
|
|
2641
|
+
*
|
|
2642
|
+
* Defaults to `30000` (30s). A value of `0` (or negative) DISABLES the
|
|
2643
|
+
* watchdog entirely. A successful mockup always cancels the pending watchdog,
|
|
2644
|
+
* and each new render re-arms it.
|
|
2645
|
+
*/
|
|
2646
|
+
renderTimeoutMs?: number;
|
|
2630
2647
|
}
|
|
2631
2648
|
declare class RenderSession {
|
|
2632
2649
|
private readonly svc;
|
|
@@ -2635,6 +2652,8 @@ declare class RenderSession {
|
|
|
2635
2652
|
private mockupCb;
|
|
2636
2653
|
private errorCb;
|
|
2637
2654
|
private ready;
|
|
2655
|
+
private readonly renderTimeoutMs;
|
|
2656
|
+
private watchdog;
|
|
2638
2657
|
constructor(opts: RenderSessionOptions);
|
|
2639
2658
|
/** Register a callback fired whenever rendered mockup URLs update. */
|
|
2640
2659
|
onMockups(cb: (results: MockupResult[]) => void): this;
|
|
@@ -2678,6 +2697,15 @@ declare class RenderSession {
|
|
|
2678
2697
|
getMockups(): MockupResult[];
|
|
2679
2698
|
/** Close the WebSocket and stop auto-renew. */
|
|
2680
2699
|
close(): void;
|
|
2700
|
+
/**
|
|
2701
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
2702
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
2703
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
2704
|
+
* server/transport errors — with a hint at the most common cause.
|
|
2705
|
+
*/
|
|
2706
|
+
private armWatchdog;
|
|
2707
|
+
/** Cancel the pending render watchdog, if any. */
|
|
2708
|
+
private clearWatchdog;
|
|
2681
2709
|
/** Escape hatch: the underlying low-level service. */
|
|
2682
2710
|
get service(): RealtimeMockupService;
|
|
2683
2711
|
private toConfig;
|
package/dist/index.js
CHANGED
|
@@ -4678,6 +4678,7 @@ async function fetchRealtimeGrant(grantUrl, shop, fetchImpl) {
|
|
|
4678
4678
|
}
|
|
4679
4679
|
|
|
4680
4680
|
// src/realtime/session.ts
|
|
4681
|
+
var DEFAULT_RENDER_TIMEOUT_MS = 3e4;
|
|
4681
4682
|
var RenderSession = class {
|
|
4682
4683
|
svc;
|
|
4683
4684
|
opts;
|
|
@@ -4685,6 +4686,8 @@ var RenderSession = class {
|
|
|
4685
4686
|
mockupCb = null;
|
|
4686
4687
|
errorCb = null;
|
|
4687
4688
|
ready = null;
|
|
4689
|
+
renderTimeoutMs;
|
|
4690
|
+
watchdog = null;
|
|
4688
4691
|
constructor(opts) {
|
|
4689
4692
|
if (!opts.shop) throw new Error("RenderSession: `shop` is required");
|
|
4690
4693
|
if (!opts.getToken && !opts.grantUrl) {
|
|
@@ -4692,6 +4695,7 @@ var RenderSession = class {
|
|
|
4692
4695
|
}
|
|
4693
4696
|
this.opts = opts;
|
|
4694
4697
|
this.product = opts.product ?? null;
|
|
4698
|
+
this.renderTimeoutMs = opts.renderTimeoutMs ?? DEFAULT_RENDER_TIMEOUT_MS;
|
|
4695
4699
|
this.svc = new RealtimeMockupService(opts.wsUrl ?? REALTIME_WS_URL);
|
|
4696
4700
|
const getToken = opts.getToken ?? (() => fetchRealtimeGrant(opts.grantUrl, opts.shop, opts.fetch));
|
|
4697
4701
|
this.svc.setTokenProvider(getToken);
|
|
@@ -4736,9 +4740,11 @@ var RenderSession = class {
|
|
|
4736
4740
|
}
|
|
4737
4741
|
},
|
|
4738
4742
|
onMockupRendered: () => {
|
|
4743
|
+
this.clearWatchdog();
|
|
4739
4744
|
this.mockupCb?.(this.svc.getState().mockupResults);
|
|
4740
4745
|
},
|
|
4741
4746
|
onAllMockupsRendered: (results) => {
|
|
4747
|
+
this.clearWatchdog();
|
|
4742
4748
|
this.mockupCb?.(results);
|
|
4743
4749
|
},
|
|
4744
4750
|
onError: (error) => {
|
|
@@ -4773,6 +4779,7 @@ var RenderSession = class {
|
|
|
4773
4779
|
async renderState(placement, state, throttleMs = 0) {
|
|
4774
4780
|
await this.connect();
|
|
4775
4781
|
this.svc.sendCanvasState(placement, state, this.product?.mockupIds.length ?? 1, throttleMs);
|
|
4782
|
+
this.armWatchdog();
|
|
4776
4783
|
}
|
|
4777
4784
|
/**
|
|
4778
4785
|
* Render a SAVED canvas by reference (ADR-0079 Phase 4). The server resolves
|
|
@@ -4784,6 +4791,7 @@ var RenderSession = class {
|
|
|
4784
4791
|
async renderSavedState(placement, stateId) {
|
|
4785
4792
|
await this.connect();
|
|
4786
4793
|
this.svc.sendCanvasStateRef(placement, stateId);
|
|
4794
|
+
this.armWatchdog();
|
|
4787
4795
|
}
|
|
4788
4796
|
/** Update only the mockup ids to render (reuses the current state). */
|
|
4789
4797
|
updateMockupIds(mockupIds) {
|
|
@@ -4796,9 +4804,33 @@ var RenderSession = class {
|
|
|
4796
4804
|
}
|
|
4797
4805
|
/** Close the WebSocket and stop auto-renew. */
|
|
4798
4806
|
close() {
|
|
4807
|
+
this.clearWatchdog();
|
|
4799
4808
|
this.svc.disconnect();
|
|
4800
4809
|
this.ready = null;
|
|
4801
4810
|
}
|
|
4811
|
+
/**
|
|
4812
|
+
* (Re)arm the render watchdog. Clears any prior timer and, unless disabled
|
|
4813
|
+
* (`renderTimeoutMs <= 0`), starts a fresh one. If it fires before a mockup
|
|
4814
|
+
* arrives, it surfaces a timeout via the error callback — the same channel as
|
|
4815
|
+
* server/transport errors — with a hint at the most common cause.
|
|
4816
|
+
*/
|
|
4817
|
+
armWatchdog() {
|
|
4818
|
+
this.clearWatchdog();
|
|
4819
|
+
if (this.renderTimeoutMs <= 0) return;
|
|
4820
|
+
this.watchdog = setTimeout(() => {
|
|
4821
|
+
this.watchdog = null;
|
|
4822
|
+
this.errorCb?.(
|
|
4823
|
+
`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)`
|
|
4824
|
+
);
|
|
4825
|
+
}, this.renderTimeoutMs);
|
|
4826
|
+
}
|
|
4827
|
+
/** Cancel the pending render watchdog, if any. */
|
|
4828
|
+
clearWatchdog() {
|
|
4829
|
+
if (this.watchdog) {
|
|
4830
|
+
clearTimeout(this.watchdog);
|
|
4831
|
+
this.watchdog = null;
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4802
4834
|
/** Escape hatch: the underlying low-level service. */
|
|
4803
4835
|
get service() {
|
|
4804
4836
|
return this.svc;
|