cursedbelt 5.102.0 → 5.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/react/engagement/index.d.ts +1 -0
  2. package/dist/react/engagement/index.d.ts.map +1 -1
  3. package/dist/react/engagement/index.js +3 -1
  4. package/dist/react/engagement/index.js.map +1 -1
  5. package/dist/react/engagement/playbackBeacon.d.ts +3 -0
  6. package/dist/react/engagement/playbackBeacon.d.ts.map +1 -0
  7. package/dist/react/engagement/playbackBeacon.js +27 -0
  8. package/dist/react/engagement/playbackBeacon.js.map +1 -0
  9. package/dist/react/media/MediaLightbox.js +1 -1
  10. package/dist/react/media/MediaLightbox.js.map +1 -1
  11. package/dist/react/media/VideoPlayer.d.ts +3 -1
  12. package/dist/react/media/VideoPlayer.d.ts.map +1 -1
  13. package/dist/react/media/VideoPlayer.js +62 -14
  14. package/dist/react/media/VideoPlayer.js.map +1 -1
  15. package/dist/react/media/VideoSlideContent.d.ts +12 -7
  16. package/dist/react/media/VideoSlideContent.d.ts.map +1 -1
  17. package/dist/react/media/VideoSlideContent.js +19 -9
  18. package/dist/react/media/VideoSlideContent.js.map +1 -1
  19. package/dist/react/media/mediaPhoto.d.ts +3 -0
  20. package/dist/react/media/mediaPhoto.d.ts.map +1 -1
  21. package/dist/react/media/mediaPhoto.js.map +1 -1
  22. package/dist/react/media/playbackWatch.d.ts +83 -0
  23. package/dist/react/media/playbackWatch.d.ts.map +1 -0
  24. package/dist/react/media/playbackWatch.js +167 -0
  25. package/dist/react/media/playbackWatch.js.map +1 -0
  26. package/dist/react/media/playerSource.d.ts +24 -0
  27. package/dist/react/media/playerSource.d.ts.map +1 -0
  28. package/dist/react/media/playerSource.js +22 -0
  29. package/dist/react/media/playerSource.js.map +1 -0
  30. package/dist/react/media/sourceFault.d.ts +5 -59
  31. package/dist/react/media/sourceFault.d.ts.map +1 -1
  32. package/dist/react/media/sourceFault.js +69 -2
  33. package/dist/react/media/sourceFault.js.map +1 -1
  34. package/dist/react/media/usePlaybackWatch.d.ts +14 -0
  35. package/dist/react/media/usePlaybackWatch.d.ts.map +1 -0
  36. package/dist/react/media/usePlaybackWatch.js +32 -0
  37. package/dist/react/media/usePlaybackWatch.js.map +1 -0
  38. package/dist/react/media-gallery/MediaGallery.d.ts.map +1 -1
  39. package/dist/react/media-gallery/MediaGallery.js +21 -5
  40. package/dist/react/media-gallery/MediaGallery.js.map +1 -1
  41. package/package.json +2 -2
  42. package/src/react/engagement/index.ts +3 -1
  43. package/src/react/engagement/playbackBeacon.ts +27 -0
  44. package/src/react/media/MediaLightbox.tsx +2 -2
  45. package/src/react/media/VideoPlayer.spec.tsx +24 -0
  46. package/src/react/media/VideoPlayer.tsx +72 -12
  47. package/src/react/media/VideoSlideContent.spec.tsx +28 -0
  48. package/src/react/media/VideoSlideContent.tsx +49 -32
  49. package/src/react/media/mediaPhoto.ts +3 -0
  50. package/src/react/media/playbackWatch.spec.ts +196 -0
  51. package/src/react/media/playbackWatch.ts +218 -0
  52. package/src/react/media/playerSource.ts +30 -0
  53. package/src/react/media/sourceFault.spec.tsx +12 -0
  54. package/src/react/media/sourceFault.tsx +25 -1
  55. package/src/react/media/usePlaybackWatch.tsx +34 -0
  56. package/src/react/media-gallery/MediaGallery.tsx +32 -13
@@ -0,0 +1,167 @@
1
+ /**
2
+ * How long a video took to start, and what went wrong if it did not — measured in the browser,
3
+ * because nothing else can see it.
4
+ *
5
+ * The owner, 2026-10-30: *"since a bug can make it load forever it has to proactively send metrics
6
+ * when the delay is taking longer than expected for a video."* A report sent when loading FINISHES
7
+ * can never describe the worst case, so the clock is the point: from the moment a video is asked
8
+ * for, {@link SLOW_CHECKPOINTS_MS} report it as still `waiting`, however the wait ends. Closing the
9
+ * page or the player mid-wait reports `abandoned` — a person giving up on a spinner, which is the
10
+ * signature of the bug nobody tells you about.
11
+ *
12
+ * One open is one {@link PlaybackReport#id}, so a sink can keep one row per open and let each report
13
+ * replace the last. A fast load costs exactly one report.
14
+ *
15
+ * Nothing runs until an app installs a reporter ({@link setPlaybackReporter}). The seam is the
16
+ * player itself, so every surface and every app gets it from one line at boot rather than a prop
17
+ * threaded through each gallery. Failure is silence, as in `engagement/beaconClient.ts`.
18
+ *
19
+ * Pure of the DOM on purpose: the clock and the timers are injected, so a spec can state a stuck
20
+ * load and read the reports without waiting for one.
21
+ */
22
+ /**
23
+ * When a wait stops being normal. The first is what "longer than expected" means: a warm start
24
+ * takes well under a second and a cold ladder segment about two (`cwip/edge-warm`'s measurements).
25
+ * The list ends so that a tab left on a spinner overnight does not report all night.
26
+ */
27
+ export const SLOW_CHECKPOINTS_MS = [5_000, 15_000, 30_000, 60_000, 120_000, 300_000, 600_000];
28
+ /** A stall this long is reported as it happens rather than when the player closes. */
29
+ export const SLOW_STALL_MS = 5_000;
30
+ /** Stepping past a video in under this is not a person giving up on it. */
31
+ const MIN_ABANDONED_MS = 1_500;
32
+ let reporter = null;
33
+ /** Install the sink — once, at boot. Null removes it. */
34
+ export function setPlaybackReporter(next) {
35
+ reporter = next;
36
+ }
37
+ export function createPlaybackWatch(input, deps = {}) {
38
+ const now = deps.now ?? (() => Date.now());
39
+ const setTimer = deps.setTimer ?? ((run, ms) => setTimeout(run, ms));
40
+ const clearTimer = deps.clearTimer ?? ((timer) => clearTimeout(timer));
41
+ const isHidden = deps.isHidden ?? (() => typeof document !== 'undefined' && document.visibilityState === 'hidden');
42
+ const id = deps.newId?.() ?? crypto.randomUUID();
43
+ let state = 'waiting';
44
+ let source = 'none';
45
+ let startedAt = null;
46
+ let readyMs;
47
+ let stalls = 0;
48
+ let stallMs = 0;
49
+ let stallBegan = null;
50
+ let error;
51
+ let hidden = false;
52
+ let timer = null;
53
+ let over = false;
54
+ const clear = () => {
55
+ if (timer !== null)
56
+ clearTimer(timer);
57
+ timer = null;
58
+ };
59
+ const send = (leaving = false) => {
60
+ if (startedAt === null)
61
+ return;
62
+ const at = now();
63
+ const report = {
64
+ id,
65
+ itemId: input.itemId,
66
+ surface: input.surface,
67
+ source,
68
+ state,
69
+ waitedMs: readyMs ?? at - startedAt,
70
+ ...(readyMs !== undefined ? { readyMs } : {}),
71
+ stalls,
72
+ stallMs: stallMs + (stallBegan === null ? 0 : at - stallBegan),
73
+ ...(error ? { error } : {}),
74
+ hidden: hidden || isHidden(),
75
+ };
76
+ try {
77
+ reporter?.(report, leaving);
78
+ }
79
+ catch {
80
+ // Telemetry never becomes the viewer's problem.
81
+ }
82
+ };
83
+ const nextCheckpoint = (index) => {
84
+ const at = SLOW_CHECKPOINTS_MS[index];
85
+ if (at === undefined || startedAt === null)
86
+ return;
87
+ timer = setTimer(() => {
88
+ timer = null;
89
+ if (state !== 'waiting')
90
+ return;
91
+ hidden ||= isHidden();
92
+ send();
93
+ nextCheckpoint(index + 1);
94
+ }, Math.max(0, at - (now() - startedAt)));
95
+ };
96
+ return {
97
+ itemId: input.itemId,
98
+ start() {
99
+ if (startedAt !== null || over || !reporter)
100
+ return;
101
+ startedAt = now();
102
+ nextCheckpoint(0);
103
+ },
104
+ source(next) {
105
+ source = next;
106
+ },
107
+ ready() {
108
+ if (over || startedAt === null || readyMs !== undefined)
109
+ return;
110
+ clear();
111
+ readyMs = now() - startedAt;
112
+ state = 'ready';
113
+ send();
114
+ },
115
+ stalled() {
116
+ if (over || readyMs === undefined || stallBegan !== null)
117
+ return;
118
+ stallBegan = now();
119
+ stalls += 1;
120
+ timer = setTimer(() => {
121
+ timer = null;
122
+ state = 'stalled';
123
+ send();
124
+ }, SLOW_STALL_MS);
125
+ },
126
+ resumed() {
127
+ if (stallBegan === null)
128
+ return;
129
+ stallMs += now() - stallBegan;
130
+ stallBegan = null;
131
+ clear();
132
+ state = 'ready';
133
+ },
134
+ note(next) {
135
+ error = next;
136
+ },
137
+ failed(next) {
138
+ if (over || state === 'failed')
139
+ return;
140
+ clear();
141
+ error = next;
142
+ state = 'failed';
143
+ send();
144
+ },
145
+ cancel() {
146
+ over = true;
147
+ clear();
148
+ },
149
+ close() {
150
+ if (over)
151
+ return;
152
+ over = true;
153
+ clear();
154
+ if (startedAt === null)
155
+ return;
156
+ if (state === 'waiting') {
157
+ if (now() - startedAt < MIN_ABANDONED_MS)
158
+ return;
159
+ state = 'abandoned';
160
+ send(true);
161
+ }
162
+ else if (state !== 'failed' && stalls > 0)
163
+ send(true);
164
+ },
165
+ };
166
+ }
167
+ //# sourceMappingURL=playbackWatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playbackWatch.js","sourceRoot":"","sources":["../../../src/react/media/playbackWatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { PlayerVideo } from './VideoPlayer.js';
2
+ /**
3
+ * What the element is handed, given what the sources have answered.
4
+ *
5
+ * 🔴 "The copy that always exists" stopped being true when a film's progressive copies began to be
6
+ * released against its ladder (collections, forge task 3228). With no `streamUrl`, handing over
7
+ * from the ladder is handing over to NOTHING: no source, no element, no event, a spinner for ever
8
+ * (forge task 4062). So `progressive` is absent for a ladder alone, and its failure is the fault.
9
+ *
10
+ * 🔴 The type is STATED, never left for Vidstack to work out. A URL with no extension is read as
11
+ * unknown, and Vidstack then asks it with a HEAD and trusts the Content-Type. A service worker that
12
+ * decrypts media answers only GETs, so that HEAD reached the store and came back
13
+ * `application/x-collections-cipher`, which no loader plays: `error` code 4 on a perfectly playable
14
+ * video (forge task 4062). The element sniffs the real container from the bytes either way.
15
+ */
16
+ export declare function playerSource(video: Pick<PlayerVideo, 'hlsUrl' | 'streamUrl'>, ladderAnswered: boolean): {
17
+ src?: {
18
+ src: string;
19
+ type: 'application/x-mpegurl' | 'video/mp4';
20
+ };
21
+ onLadder: boolean;
22
+ progressive?: string;
23
+ };
24
+ //# sourceMappingURL=playerSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playerSource.d.ts","sourceRoot":"","sources":["../../../src/react/media/playerSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,WAAW,CAAC,EAChD,cAAc,EAAE,OAAO,GACtB;IACD,GAAG,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,uBAAuB,GAAG,WAAW,CAAA;KAAE,CAAC;IACnE,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAMA"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * What the element is handed, given what the sources have answered.
3
+ *
4
+ * 🔴 "The copy that always exists" stopped being true when a film's progressive copies began to be
5
+ * released against its ladder (collections, forge task 3228). With no `streamUrl`, handing over
6
+ * from the ladder is handing over to NOTHING: no source, no element, no event, a spinner for ever
7
+ * (forge task 4062). So `progressive` is absent for a ladder alone, and its failure is the fault.
8
+ *
9
+ * 🔴 The type is STATED, never left for Vidstack to work out. A URL with no extension is read as
10
+ * unknown, and Vidstack then asks it with a HEAD and trusts the Content-Type. A service worker that
11
+ * decrypts media answers only GETs, so that HEAD reached the store and came back
12
+ * `application/x-collections-cipher`, which no loader plays: `error` code 4 on a perfectly playable
13
+ * video (forge task 4062). The element sniffs the real container from the bytes either way.
14
+ */
15
+ export function playerSource(video, ladderAnswered) {
16
+ const progressive = video.streamUrl || undefined;
17
+ const fallback = progressive ? { progressive } : {};
18
+ if (video.hlsUrl && !ladderAnswered)
19
+ return { src: { src: video.hlsUrl, type: 'application/x-mpegurl' }, onLadder: true, ...fallback };
20
+ return { ...(progressive ? { src: { src: progressive, type: 'video/mp4' } } : {}), onLadder: false, ...fallback };
21
+ }
22
+ //# sourceMappingURL=playerSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playerSource.js","sourceRoot":"","sources":["../../../src/react/media/playerSource.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAgD,EAChD,cAAuB;IAMvB,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,IAAI,SAAS,CAAC;IACjD,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,cAAc;QACjC,OAAO,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,CAAC;IACpG,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;AACpH,CAAC"}
@@ -1,61 +1,3 @@
1
- /**
2
- * What a media URL ANSWERED, when what it answered was not the bytes.
3
- *
4
- * ── 🔴 The report this exists for ───────────────────────────────────────────────────────
5
- * Owner, 2026-09-17: *"make a 404 stop the media player spinner so I don't think it's going
6
- * to eventually load."* One item in his catalog has no ladder, so the very first request a
7
- * player makes is answered honestly and immediately:
8
- *
9
- * GET …/u_fd668e6a….hls/master.m3u8 → 404 {"error":"not_found"} in 0.2 s
10
- *
11
- * and the spinner then ran until he gave up. **A 404 is a COMPLETE ANSWER** — there is
12
- * nothing still in flight, nothing to wait for, and no amount of waiting changes it — and it
13
- * was the one status every surface here treated as "still loading".
14
- *
15
- * ── 🔴 The distinction this module is entirely about ────────────────────────────────────
16
- * A hang and an answer must not look the same to somebody watching a spinner:
17
- *
18
- * | what happened | is it an answer? | what the viewer should see |
19
- * |---|---|---|
20
- * | slow segment, tunnel blinked, origin waking | no — still in flight | keep spinning |
21
- * | `404` / `410` | yes, and it is final | the reason, now |
22
- * | `401` / `403` | yes, and it is RECOVERABLE | re-ask the app, then the reason |
23
- * | any other `4xx`/`5xx` | yes, and we cannot name it | the reason, now |
24
- *
25
- * `403` is split out because it is the one that comes back on its own: every signed URL in
26
- * this fleet carries `exp = iat + 2 × window`, so a page left open across a window boundary
27
- * meets a stale token legitimately and the fix is to ASK THE APP AGAIN, not to tell the
28
- * viewer his film is gone. Collapsing it into "gone" would put a false and permanent-sounding
29
- * sentence on screen for the one fault that clears itself.
30
- *
31
- * ── 🔴 Why a probe, and why only on the failure path ────────────────────────────────────
32
- * `hls.js` hands us the status directly (`ErrorData.response.code`), so the ladder and its
33
- * rungs cost nothing. An `<img>` and a `<video>` do NOT: both fire a bare `error` event that
34
- * carries no status at all, so "the file is gone" and "the token went stale" and "the codec
35
- * is unplayable" arrive as the same undifferentiated failure. {@link probeSourceFault} is the
36
- * one way to tell them apart, and it runs ONLY after the element has already given up — so a
37
- * gallery that is working costs exactly nothing, and a one-byte `Range` request is the whole
38
- * price of a sentence that is true.
39
- *
40
- * (`bytes=0-0` is a CORS-safelisted range, so the probe is a simple request and never costs a
41
- * preflight; the 404 in the report above answers `access-control-allow-origin: *`, which is
42
- * what makes the status readable cross-origin at all. When it is not readable the fetch
43
- * throws, and that is `unknown` — honest, still not a spinner.)
44
- *
45
- * ── 🔴 Why one module holds the reading, the wording AND the overlay ────────────────────
46
- * Three surfaces have to agree about the same fault — the gallery's picture stage, its native
47
- * video stage and the shared player — and the thing they must agree on is not the mechanism,
48
- * it is the SENTENCE. Split across three files this becomes three wordings, and the owner
49
- * meets whichever one his file happens to be behind.
50
- *
51
- * It is deliberately NOT a published subpath and nothing here is re-exported from
52
- * `react/media/index.ts`. `publicSurface.baseline` charges for a permanent promise, and none
53
- * of this is one: the wording is copy, the overlay is chrome, and a consumer that wanted to
54
- * draw its own would be re-implementing the corner rather than importing it. (Same call the
55
- * badge stack in `VideoPlayer.tsx` made — see that baseline entry's "what did NOT go on the
56
- * surface".) A `.tsx` holding a component beside its helpers is `galleryItemMedia.tsx`'s
57
- * shape, for the same reason.
58
- */
59
1
  /** Which of the three answers came back. `expired` is the only one worth re-asking. */
60
2
  export type SourceFaultKind =
61
3
  /** The source said there is nothing here — `404`/`410`. Final. */
@@ -123,6 +65,8 @@ export declare function sourceFaultMessage(fault: SourceFault, subject: string):
123
65
  * every file that reads one of its payloads.
124
66
  */
125
67
  export declare function hlsErrorIsAnswer(detail: unknown): boolean;
68
+ /** A fatal hls.js error as one short word for telemetry, or null for one it recovers from. */
69
+ export declare function hlsErrorName(detail: unknown): string | null;
126
70
  /**
127
71
  * What a video surface says once every source has ANSWERED.
128
72
  *
@@ -139,8 +83,10 @@ export declare function hlsErrorIsAnswer(detail: unknown): boolean;
139
83
  * later. The gallery's stages do the opposite and REPLACE their element — there the `<video>`
140
84
  * is the spinner, so nothing short of removing it would do.
141
85
  */
142
- export declare function SourceFaultOverlay({ fault, name, ...rest }: {
86
+ export declare function SourceFaultOverlay({ fault, name, onRetry, ...rest }: {
143
87
  fault: SourceFault;
144
88
  name: string;
89
+ /** A fresh attempt without reloading the page. Most failures here are a moment, not a verdict. */
90
+ onRetry?: () => void;
145
91
  }): import("react").JSX.Element;
146
92
  //# sourceMappingURL=sourceFault.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sourceFault.d.ts","sourceRoot":"","sources":["../../../src/react/media/sourceFault.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,uFAAuF;AACvF,MAAM,MAAM,eAAe;AACzB,kEAAkE;AAChE,MAAM;AACR,6EAA6E;GAC3E,SAAS;AACX,qFAAqF;GACnF,SAAS,CAAC;AAEd,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKxE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAqBpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAS9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAKzD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,+BA6BhG"}
1
+ {"version":3,"file":"sourceFault.d.ts","sourceRoot":"","sources":["../../../src/react/media/sourceFault.tsx"],"names":[],"mappings":"AA4DA,uFAAuF;AACvF,MAAM,MAAM,eAAe;AACzB,kEAAkE;AAChE,MAAM;AACR,6EAA6E;GAC3E,SAAS;AACX,qFAAqF;GACnF,SAAS,CAAC;AAEd,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKxE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAqBpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAS9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAKzD;AAED,8FAA8F;AAC9F,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAK3D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,OAAO,EACP,GAAG,IAAI,EACR,EAAE;IACD,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,+BAkCA"}
@@ -1,4 +1,63 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * What a media URL ANSWERED, when what it answered was not the bytes.
4
+ *
5
+ * ── 🔴 The report this exists for ───────────────────────────────────────────────────────
6
+ * Owner, 2026-09-17: *"make a 404 stop the media player spinner so I don't think it's going
7
+ * to eventually load."* One item in his catalog has no ladder, so the very first request a
8
+ * player makes is answered honestly and immediately:
9
+ *
10
+ * GET …/u_fd668e6a….hls/master.m3u8 → 404 {"error":"not_found"} in 0.2 s
11
+ *
12
+ * and the spinner then ran until he gave up. **A 404 is a COMPLETE ANSWER** — there is
13
+ * nothing still in flight, nothing to wait for, and no amount of waiting changes it — and it
14
+ * was the one status every surface here treated as "still loading".
15
+ *
16
+ * ── 🔴 The distinction this module is entirely about ────────────────────────────────────
17
+ * A hang and an answer must not look the same to somebody watching a spinner:
18
+ *
19
+ * | what happened | is it an answer? | what the viewer should see |
20
+ * |---|---|---|
21
+ * | slow segment, tunnel blinked, origin waking | no — still in flight | keep spinning |
22
+ * | `404` / `410` | yes, and it is final | the reason, now |
23
+ * | `401` / `403` | yes, and it is RECOVERABLE | re-ask the app, then the reason |
24
+ * | any other `4xx`/`5xx` | yes, and we cannot name it | the reason, now |
25
+ *
26
+ * `403` is split out because it is the one that comes back on its own: every signed URL in
27
+ * this fleet carries `exp = iat + 2 × window`, so a page left open across a window boundary
28
+ * meets a stale token legitimately and the fix is to ASK THE APP AGAIN, not to tell the
29
+ * viewer his film is gone. Collapsing it into "gone" would put a false and permanent-sounding
30
+ * sentence on screen for the one fault that clears itself.
31
+ *
32
+ * ── 🔴 Why a probe, and why only on the failure path ────────────────────────────────────
33
+ * `hls.js` hands us the status directly (`ErrorData.response.code`), so the ladder and its
34
+ * rungs cost nothing. An `<img>` and a `<video>` do NOT: both fire a bare `error` event that
35
+ * carries no status at all, so "the file is gone" and "the token went stale" and "the codec
36
+ * is unplayable" arrive as the same undifferentiated failure. {@link probeSourceFault} is the
37
+ * one way to tell them apart, and it runs ONLY after the element has already given up — so a
38
+ * gallery that is working costs exactly nothing, and a one-byte `Range` request is the whole
39
+ * price of a sentence that is true.
40
+ *
41
+ * (`bytes=0-0` is a CORS-safelisted range, so the probe is a simple request and never costs a
42
+ * preflight; the 404 in the report above answers `access-control-allow-origin: *`, which is
43
+ * what makes the status readable cross-origin at all. When it is not readable the fetch
44
+ * throws, and that is `unknown` — honest, still not a spinner.)
45
+ *
46
+ * ── 🔴 Why one module holds the reading, the wording AND the overlay ────────────────────
47
+ * Three surfaces have to agree about the same fault — the gallery's picture stage, its native
48
+ * video stage and the shared player — and the thing they must agree on is not the mechanism,
49
+ * it is the SENTENCE. Split across three files this becomes three wordings, and the owner
50
+ * meets whichever one his file happens to be behind.
51
+ *
52
+ * It is deliberately NOT a published subpath and nothing here is re-exported from
53
+ * `react/media/index.ts`. `publicSurface.baseline` charges for a permanent promise, and none
54
+ * of this is one: the wording is copy, the overlay is chrome, and a consumer that wanted to
55
+ * draw its own would be re-implementing the corner rather than importing it. (Same call the
56
+ * badge stack in `VideoPlayer.tsx` made — see that baseline entry's "what did NOT go on the
57
+ * surface".) A `.tsx` holding a component beside its helpers is `galleryItemMedia.tsx`'s
58
+ * shape, for the same reason.
59
+ */
60
+ import { Button } from '../components/Button.js';
2
61
  /**
3
62
  * Classify one HTTP status. `null` for anything below 400 — a source that answered `200` and
4
63
  * still would not play is not a fault of the URL, and saying otherwise would blame the store
@@ -101,6 +160,14 @@ export function hlsErrorIsAnswer(detail) {
101
160
  return false;
102
161
  return sourceFaultFromStatus(code) !== null;
103
162
  }
163
+ /** A fatal hls.js error as one short word for telemetry, or null for one it recovers from. */
164
+ export function hlsErrorName(detail) {
165
+ const data = detail;
166
+ if (!data?.fatal)
167
+ return null;
168
+ const code = data.response?.code;
169
+ return `hls:${data.details ?? 'unknown'}${typeof code === 'number' ? `:${code}` : ''}`;
170
+ }
104
171
  /**
105
172
  * What a video surface says once every source has ANSWERED.
106
173
  *
@@ -117,7 +184,7 @@ export function hlsErrorIsAnswer(detail) {
117
184
  * later. The gallery's stages do the opposite and REPLACE their element — there the `<video>`
118
185
  * is the spinner, so nothing short of removing it would do.
119
186
  */
120
- export function SourceFaultOverlay({ fault, name, ...rest }) {
187
+ export function SourceFaultOverlay({ fault, name, onRetry, ...rest }) {
121
188
  return (_jsxs("div", { ...rest, role: 'status', style: {
122
189
  position: 'absolute',
123
190
  inset: 0,
@@ -134,6 +201,6 @@ export function SourceFaultOverlay({ fault, name, ...rest }) {
134
201
  background: 'rgba(0, 0, 0, 0.82)',
135
202
  // guardrails-ignore no-hardcoded-colors: see comment above.
136
203
  color: 'rgba(255, 255, 255, 0.92)',
137
- }, children: [_jsx("span", { style: { fontSize: 13, fontWeight: 600 }, children: name }), _jsx("span", { style: { fontSize: 13, lineHeight: 1.5, maxWidth: '42ch' }, children: sourceFaultMessage(fault, 'This video') })] }));
204
+ }, children: [_jsx("span", { style: { fontSize: 13, fontWeight: 600 }, children: name }), _jsx("span", { style: { fontSize: 13, lineHeight: 1.5, maxWidth: '42ch' }, children: sourceFaultMessage(fault, 'This video') }), onRetry ? (_jsx(Button, { onClick: onRetry, size: 'sm', tooltip: 'Ask for this video again', tooltipMobile: 'off', variant: 'secondary', children: "Try again" })) : null] }));
138
205
  }
139
206
  //# sourceMappingURL=sourceFault.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sourceFault.js","sourceRoot":"","sources":["../../../src/react/media/sourceFault.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sourceFault.js","sourceRoot":"","sources":["../../../src/react/media/sourceFault.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAiBjD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACtE,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACzE,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;AAClC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAuB;IAC5D,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC;IACnC,IAAI,CAAC,GAAG,IAAI,OAAO,SAAS,KAAK,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACxE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YAC/B,MAAM,EAAE,KAAK;YACb,sFAAsF;YACtF,oCAAoC;YACpC,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;YAC/B,KAAK,EAAE,UAAU;SAClB,CAAC,CAAC;QACH,0FAA0F;QAC1F,uFAAuF;QACvF,0FAA0F;QAC1F,0EAA0E;QAC1E,OAAO,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,qFAAqF;QACrF,gEAAgE;QAChE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkB,EAAE,OAAe;IACpE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO,GAAG,OAAO,mCAAmC,MAAM,8BAA8B,CAAC;IAC3F,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,GAAG,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;IAC/E,CAAC;IACD,OAAO,GAAG,OAAO,uBAAuB,MAAM,8BAA8B,CAAC;AAC/E,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,MAAM,IAAI,GAAG,MAA8E,CAAC;IAC5F,MAAM,IAAI,GAAG,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC;IAClC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3D,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;AAC9C,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,YAAY,CAAC,MAAe;IAC1C,MAAM,IAAI,GAAG,MAAgG,CAAC;IAC9G,IAAI,CAAC,IAAI,EAAE,KAAK;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;IACjC,OAAO,OAAO,IAAI,CAAC,OAAO,IAAI,SAAS,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACzF,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,OAAO,EACP,GAAG,IAAI,EAMR;IACC,OAAO,CACL,kBACM,IAAI,EACR,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,GAAG,EAAE,CAAC;YACN,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,QAAQ;YACnB,uFAAuF;YACvF,qEAAqE;YACrE,4DAA4D;YAC5D,UAAU,EAAE,qBAAqB;YACjC,4DAA4D;YAC5D,KAAK,EAAE,2BAA2B;SACnC,aAED,eAAM,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,YAAG,IAAI,GAAQ,EAC7D,eAAM,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YAC7D,kBAAkB,CAAC,KAAK,EAAE,YAAY,CAAC,GACnC,EACN,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,MAAM,IAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,0BAA0B,EAAC,aAAa,EAAC,KAAK,EAAC,OAAO,EAAC,WAAW,0BAErG,CACV,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type RefObject } from 'react';
2
+ import { type PlaybackWatch } from './playbackWatch.js';
3
+ /**
4
+ * The watch a surface opened before its player existed, so the clock covers the wait for a URL too:
5
+ * a hung `resolveMedia` is a spinner with no player under it. A `VideoPlayer` with none opens its own.
6
+ */
7
+ export declare const PlaybackWatchContext: import("react").Context<RefObject<PlaybackWatch | null> | null>;
8
+ /**
9
+ * One watch per open of one video. Made during render, because a child's effects run before its
10
+ * parent's and a player mounting with a cached URL names its source first; only the timers wait
11
+ * for the effect. Pass a null `itemId` for anything that is not a video.
12
+ */
13
+ export declare function usePlaybackWatch(itemId: string | null, surface: string): RefObject<PlaybackWatch | null>;
14
+ //# sourceMappingURL=usePlaybackWatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePlaybackWatch.d.ts","sourceRoot":"","sources":["../../../src/react/media/usePlaybackWatch.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAiC,MAAM,OAAO,CAAC;AACrF,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,oBAAoB,iEAA8D,CAAC;AAEhG;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,aAAa,GAAG,IAAI,CAAC,CAmBxG"}
@@ -0,0 +1,32 @@
1
+ import { createContext, useContext, useEffect, useRef } from 'react';
2
+ import { createPlaybackWatch } from './playbackWatch.js';
3
+ /**
4
+ * The watch a surface opened before its player existed, so the clock covers the wait for a URL too:
5
+ * a hung `resolveMedia` is a spinner with no player under it. A `VideoPlayer` with none opens its own.
6
+ */
7
+ export const PlaybackWatchContext = createContext(null);
8
+ /**
9
+ * One watch per open of one video. Made during render, because a child's effects run before its
10
+ * parent's and a player mounting with a cached URL names its source first; only the timers wait
11
+ * for the effect. Pass a null `itemId` for anything that is not a video.
12
+ */
13
+ export function usePlaybackWatch(itemId, surface) {
14
+ const inherited = useContext(PlaybackWatchContext);
15
+ const own = useRef(null);
16
+ if (!inherited && own.current?.itemId !== (itemId ?? undefined))
17
+ own.current = itemId ? createPlaybackWatch({ itemId, surface }) : null;
18
+ useEffect(() => {
19
+ if (inherited || !itemId)
20
+ return;
21
+ const watch = own.current;
22
+ watch?.start();
23
+ const leaving = () => watch?.close();
24
+ addEventListener('pagehide', leaving);
25
+ return () => {
26
+ removeEventListener('pagehide', leaving);
27
+ watch?.close();
28
+ };
29
+ }, [inherited, itemId]);
30
+ return inherited ?? own;
31
+ }
32
+ //# sourceMappingURL=usePlaybackWatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePlaybackWatch.js","sourceRoot":"","sources":["../../../src/react/media/usePlaybackWatch.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAsB,MAAM,oBAAoB,CAAC;AAE7E;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAAyC,IAAI,CAAC,CAAC;AAEhG;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB,EAAE,OAAe;IACrE,MAAM,SAAS,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,MAAM,CAAuB,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;QAC7D,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEzE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,IAAI,CAAC,MAAM;YAAE,OAAO;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC;QAC1B,KAAK,EAAE,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,GAAS,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;QAC3C,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACtC,OAAO,GAAG,EAAE;YACV,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACzC,KAAK,EAAE,KAAK,EAAE,CAAC;QACjB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAExB,OAAO,SAAS,IAAI,GAAG,CAAC;AAC1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MediaGallery.d.ts","sourceRoot":"","sources":["../../../src/react/media-gallery/MediaGallery.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaGallery.d.ts","sourceRoot":"","sources":["../../../src/react/media-gallery/MediaGallery.tsx"],"names":[],"mappings":"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"}
@@ -43,6 +43,7 @@ import { DenseGalleryDetail, DenseGalleryShell } from '../media/DenseGalleryShel
43
43
  import { CBGD_BARE_TILE_HEIGHT } from '../media/VirtualMediaGrid.js';
44
44
  import { useGalleryReturn } from './galleryReturn.js';
45
45
  import { useHlsSource } from '../media/hlsSource.js';
46
+ import { PlaybackWatchContext, usePlaybackWatch } from '../media/usePlaybackWatch.js';
46
47
  import { VideoQualitySelect } from '../media/VideoQualitySelect.js';
47
48
  import { ImageOriginalToggle } from '../media/ImageOriginalToggle.js';
48
49
  import { useImageOriginal } from '../media/useImageOriginal.js';
@@ -740,6 +741,21 @@ function ImageSurface({ item, url, originalUrl, reAsk, }) {
740
741
  function GalleryStage({ item, mediaCache, bytesCache, loadBytes, nativeVideoStage, repeat, onEnded, onStep, canStep, fullscreenOnDoubleClick, fillWindow, onFillWindowChange, }) {
741
742
  const category = galleryItemCategory(item);
742
743
  const { media, resolving, refresh } = useItemMedia(item, mediaCache);
744
+ /*
745
+ * 🔴 The clock starts HERE, at the stage, and not at the player: a hung `resolveMedia` is a
746
+ * spinner with no player under it, and the player's own clock would never have started. See
747
+ * `media/playbackWatch.ts`. A video still converting is a wait the app already explains.
748
+ */
749
+ const watch = usePlaybackWatch(category === 'video' ? item.id : null, 'stage');
750
+ const noSource = !(media.streamUrl || media.url || media.hlsUrl);
751
+ const stillConverting = noSource && Boolean(media.pending);
752
+ const unavailable = noSource && !media.pending && !resolving;
753
+ useEffect(() => {
754
+ if (stillConverting)
755
+ watch.current?.cancel();
756
+ else if (unavailable)
757
+ watch.current?.failed('unavailable');
758
+ }, [watch, stillConverting, unavailable]);
743
759
  if (category === 'video') {
744
760
  const src = media.streamUrl ?? media.url ?? '';
745
761
  /*
@@ -777,11 +793,11 @@ function GalleryStage({ item, mediaCache, bytesCache, loadBytes, nativeVideoStag
777
793
  if (nativeVideoStage) {
778
794
  return frame(_jsx(NativeVideoSurface, { item: item, media: media, streamUrl: src, repeat: repeat, reAsk: refresh, ...(onEnded ? { onEnded } : {}) }, media.hlsUrl ?? src));
779
795
  }
780
- return frame(_jsx(React.Suspense, { fallback: _jsx(StageLoading, { label: 'Loading player\u2026' }), children: _jsx(LazyVideoPlayer, { video: stagePlayableVideo(item, media, src), autoPlay: true,
781
- // 🔴 The STAGE's own volume memory, not the shared primitive's default key — see
782
- // `playbackPreferences.ts`. It is what makes the level he set on this clip apply to
783
- // the next one, and it is per session, so a refresh is silent again.
784
- volumeKey: STAGE_VOLUME_KEY, loop: repeat, ...(repeat ? {} : { onEnded }), ...(onStep ? { onStep, canStep: canStep !== false } : {}), ...(fullscreenOnDoubleClick === false ? { fullscreenOnDoubleClick: false } : {}), ...(onFillWindowChange ? { fillWindow: fillWindow === true, onFillWindowChange } : {}) }) }));
796
+ return frame(_jsx(React.Suspense, { fallback: _jsx(StageLoading, { label: 'Loading player\u2026' }), children: _jsx(PlaybackWatchContext.Provider, { value: watch, children: _jsx(LazyVideoPlayer, { video: stagePlayableVideo(item, media, src), autoPlay: true,
797
+ // 🔴 The STAGE's own volume memory, not the shared primitive's default key — see
798
+ // `playbackPreferences.ts`. It is what makes the level he set on this clip apply to
799
+ // the next one, and it is per session, so a refresh is silent again.
800
+ volumeKey: STAGE_VOLUME_KEY, loop: repeat, ...(repeat ? {} : { onEnded }), ...(onStep ? { onStep, canStep: canStep !== false } : {}), ...(fullscreenOnDoubleClick === false ? { fullscreenOnDoubleClick: false } : {}), ...(onFillWindowChange ? { fillWindow: fillWindow === true, onFillWindowChange } : {}) }, item.id) }) }));
785
801
  }
786
802
  if (category === 'image') {
787
803
  if (!media.url)