@sailfish-ai/recorder 1.12.4 → 1.12.6

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 (144) hide show
  1. package/README.md +8 -0
  2. package/dist/canvas/adapters.js +382 -0
  3. package/dist/canvas/adapters.js.br +0 -0
  4. package/dist/canvas/adapters.js.gz +0 -0
  5. package/dist/canvas/canvasManager.js +1949 -0
  6. package/dist/canvas/canvasManager.js.br +0 -0
  7. package/dist/canvas/canvasManager.js.gz +0 -0
  8. package/dist/canvas/canvasPrivacy.js +233 -0
  9. package/dist/canvas/canvasPrivacy.js.br +0 -0
  10. package/dist/canvas/canvasPrivacy.js.gz +0 -0
  11. package/dist/canvas/codec.js +314 -0
  12. package/dist/canvas/codec.js.br +0 -0
  13. package/dist/canvas/codec.js.gz +0 -0
  14. package/dist/canvas/deviceClass.js +67 -0
  15. package/dist/canvas/deviceClass.js.br +0 -0
  16. package/dist/canvas/deviceClass.js.gz +0 -0
  17. package/dist/canvas/encodeWorker.js +284 -0
  18. package/dist/canvas/encodeWorker.js.br +0 -0
  19. package/dist/canvas/encodeWorker.js.gz +0 -0
  20. package/dist/canvas/governor.js +79 -0
  21. package/dist/canvas/governor.js.br +0 -0
  22. package/dist/canvas/governor.js.gz +0 -0
  23. package/dist/canvas/keyframes.js +183 -0
  24. package/dist/canvas/keyframes.js.br +0 -0
  25. package/dist/canvas/keyframes.js.gz +0 -0
  26. package/dist/canvas/mediaRecorderCapture.js +257 -0
  27. package/dist/canvas/mediaRecorderCapture.js.br +0 -0
  28. package/dist/canvas/mediaRecorderCapture.js.gz +0 -0
  29. package/dist/canvas/objectLog.js +150 -0
  30. package/dist/canvas/objectLog.js.br +0 -0
  31. package/dist/canvas/objectLog.js.gz +0 -0
  32. package/dist/canvas/patch2d.js +1302 -0
  33. package/dist/canvas/patch2d.js.br +0 -0
  34. package/dist/canvas/patch2d.js.gz +0 -0
  35. package/dist/canvas/patchGL.js +371 -0
  36. package/dist/canvas/patchGL.js.br +0 -0
  37. package/dist/canvas/patchGL.js.gz +0 -0
  38. package/dist/canvas/patchWebGPU.js +361 -0
  39. package/dist/canvas/patchWebGPU.js.br +0 -0
  40. package/dist/canvas/patchWebGPU.js.gz +0 -0
  41. package/dist/canvas/piiDetect.js +155 -0
  42. package/dist/canvas/piiDetect.js.br +0 -0
  43. package/dist/canvas/piiDetect.js.gz +0 -0
  44. package/dist/canvas/protocol.js +122 -0
  45. package/dist/canvas/protocol.js.br +0 -0
  46. package/dist/canvas/protocol.js.gz +0 -0
  47. package/dist/canvas/videoCapture.js +252 -0
  48. package/dist/canvas/videoCapture.js.br +0 -0
  49. package/dist/canvas/videoCapture.js.gz +0 -0
  50. package/dist/canvas/workerRelay.js +99 -0
  51. package/dist/canvas/workerRelay.js.br +0 -0
  52. package/dist/canvas/workerRelay.js.gz +0 -0
  53. package/dist/canvas/workerShim.js +227 -0
  54. package/dist/canvas/workerShim.js.br +0 -0
  55. package/dist/canvas/workerShim.js.gz +0 -0
  56. package/dist/canvas-worker.cjs +74 -0
  57. package/dist/canvas-worker.cjs.br +0 -0
  58. package/dist/canvas-worker.cjs.gz +0 -0
  59. package/dist/canvas-worker.js +78 -0
  60. package/dist/canvas-worker.js.br +0 -0
  61. package/dist/canvas-worker.js.gz +0 -0
  62. package/dist/canvasFrameStore.js +198 -0
  63. package/dist/canvasFrameStore.js.br +0 -0
  64. package/dist/canvasFrameStore.js.gz +0 -0
  65. package/dist/chunks/canvasManager-BYn3_oyo.js +1440 -0
  66. package/dist/chunks/canvasManager-BYn3_oyo.js.br +0 -0
  67. package/dist/chunks/canvasManager-BYn3_oyo.js.gz +0 -0
  68. package/dist/chunks/canvasManager-CoX5072G.js +1456 -0
  69. package/dist/chunks/canvasManager-CoX5072G.js.br +0 -0
  70. package/dist/chunks/canvasManager-CoX5072G.js.gz +0 -0
  71. package/dist/chunks/{chunkSerializer-FQtY90Av.js → chunkSerializer-C_K0Wyk0.js} +1 -1
  72. package/dist/chunks/chunkSerializer-C_K0Wyk0.js.br +0 -0
  73. package/dist/chunks/chunkSerializer-C_K0Wyk0.js.gz +0 -0
  74. package/dist/chunks/{chunkSerializer-DDukZpgl.js → chunkSerializer-CghPitF4.js} +1 -1
  75. package/dist/chunks/chunkSerializer-CghPitF4.js.br +0 -0
  76. package/dist/chunks/chunkSerializer-CghPitF4.js.gz +0 -0
  77. package/dist/chunks/{index-C-qbsfKe.js → index-BIj4l3CV.js} +1028 -650
  78. package/dist/chunks/index-BIj4l3CV.js.br +0 -0
  79. package/dist/chunks/index-BIj4l3CV.js.gz +0 -0
  80. package/dist/chunks/{index-D6axlCRu.js → index-DIYomvdD.js} +1119 -720
  81. package/dist/chunks/index-DIYomvdD.js.br +0 -0
  82. package/dist/chunks/index-DIYomvdD.js.gz +0 -0
  83. package/dist/chunks/patch2d-9voowhJ_.js +816 -0
  84. package/dist/chunks/patch2d-9voowhJ_.js.br +0 -0
  85. package/dist/chunks/patch2d-9voowhJ_.js.gz +0 -0
  86. package/dist/chunks/patch2d-PQxcaE6r.js +886 -0
  87. package/dist/chunks/patch2d-PQxcaE6r.js.br +0 -0
  88. package/dist/chunks/patch2d-PQxcaE6r.js.gz +0 -0
  89. package/dist/graphql.js +12 -1
  90. package/dist/graphql.js.br +0 -0
  91. package/dist/graphql.js.gz +0 -0
  92. package/dist/inAppReportIssueModal/index.js +48 -0
  93. package/dist/inAppReportIssueModal/index.js.br +0 -0
  94. package/dist/inAppReportIssueModal/index.js.gz +0 -0
  95. package/dist/index.js +144 -2
  96. package/dist/index.js.br +0 -0
  97. package/dist/index.js.gz +0 -0
  98. package/dist/recorder.cjs +2 -2
  99. package/dist/recorder.cjs.br +0 -0
  100. package/dist/recorder.cjs.gz +0 -0
  101. package/dist/recorder.js +52 -41
  102. package/dist/recorder.js.br +0 -0
  103. package/dist/recorder.js.gz +0 -0
  104. package/dist/recorder.umd.cjs +4847 -2212
  105. package/dist/recorder.umd.cjs.br +0 -0
  106. package/dist/recorder.umd.cjs.gz +0 -0
  107. package/dist/recording.js +119 -10
  108. package/dist/recording.js.br +0 -0
  109. package/dist/recording.js.gz +0 -0
  110. package/dist/types/canvas/adapters.d.ts +71 -0
  111. package/dist/types/canvas/canvasManager.d.ts +273 -0
  112. package/dist/types/canvas/canvasPrivacy.d.ts +184 -0
  113. package/dist/types/canvas/codec.d.ts +27 -0
  114. package/dist/types/canvas/deviceClass.d.ts +40 -0
  115. package/dist/types/canvas/encodeWorker.d.ts +54 -0
  116. package/dist/types/canvas/governor.d.ts +44 -0
  117. package/dist/types/canvas/keyframes.d.ts +81 -0
  118. package/dist/types/canvas/mediaRecorderCapture.d.ts +91 -0
  119. package/dist/types/canvas/objectLog.d.ts +75 -0
  120. package/dist/types/canvas/patch2d.d.ts +339 -0
  121. package/dist/types/canvas/patchGL.d.ts +74 -0
  122. package/dist/types/canvas/patchWebGPU.d.ts +37 -0
  123. package/dist/types/canvas/piiDetect.d.ts +60 -0
  124. package/dist/types/canvas/protocol.d.ts +176 -0
  125. package/dist/types/canvas/videoCapture.d.ts +67 -0
  126. package/dist/types/canvas/workerRelay.d.ts +29 -0
  127. package/dist/types/canvas/workerShim.d.ts +10 -0
  128. package/dist/types/canvasFrameStore.d.ts +23 -0
  129. package/dist/types/graphql.d.ts +1 -1
  130. package/dist/types/index.d.ts +99 -1
  131. package/dist/types/types.d.ts +40 -0
  132. package/dist/types/websocket.d.ts +19 -0
  133. package/dist/websocket.js +210 -0
  134. package/dist/websocket.js.br +0 -0
  135. package/dist/websocket.js.gz +0 -0
  136. package/package.json +7 -1
  137. package/dist/chunks/chunkSerializer-DDukZpgl.js.br +0 -0
  138. package/dist/chunks/chunkSerializer-DDukZpgl.js.gz +0 -0
  139. package/dist/chunks/chunkSerializer-FQtY90Av.js.br +0 -0
  140. package/dist/chunks/chunkSerializer-FQtY90Av.js.gz +0 -0
  141. package/dist/chunks/index-C-qbsfKe.js.br +0 -0
  142. package/dist/chunks/index-C-qbsfKe.js.gz +0 -0
  143. package/dist/chunks/index-D6axlCRu.js.br +0 -0
  144. package/dist/chunks/index-D6axlCRu.js.gz +0 -0
@@ -0,0 +1,1456 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { i as e, u as t } from "./index-DIYomvdD.js";
5
+ import { k as n, R as r, B as o, o as s, d as a, D as i, q as c, s as d, T as l, i as u, t as f, u as h, v as p, w as m, x as v, y, C as g, z as w, A as k, E as b, F as C, G as x, H as S, I as R, J as L, K as M, L as I, M as T, a as E } from "./patch2d-PQxcaE6r.js";
6
+ function createBlobWorker(e2) {
7
+ const t2 = new Blob([e2], { type: "application/javascript" }), n2 = URL.createObjectURL(t2), r2 = new Worker(n2);
8
+ return URL.revokeObjectURL(n2), r2;
9
+ }
10
+ let P = null, D = 1;
11
+ const B = /* @__PURE__ */ new Map();
12
+ function encodeBitmap(e2, t2, n2 = false) {
13
+ const r2 = D++;
14
+ return new Promise((o2) => {
15
+ B.set(r2, o2), (function getImgWorker() {
16
+ return P || (P = createBlobWorker("\nself.onmessage = async (e) => {\n const { id, bitmap, quality, wantBytes } = e.data;\n try {\n const off = new OffscreenCanvas(bitmap.width, bitmap.height);\n const ctx = off.getContext('2d');\n ctx.drawImage(bitmap, 0, 0);\n bitmap.close();\n const blob = await off.convertToBlob({ type: 'image/webp', quality });\n if (wantBytes) {\n const buf = await blob.arrayBuffer();\n self.postMessage({ id, size: buf.byteLength, bytes: buf }, [buf]);\n } else {\n self.postMessage({ id, size: blob.size });\n }\n } catch (err) {\n self.postMessage({ id, size: 0, error: String(err) });\n }\n};\n"), P.onmessage = (e3) => {
17
+ const t3 = B.get(e3.data.id);
18
+ t3 && (B.delete(e3.data.id), t3({ size: e3.data.size, bytes: e3.data.bytes }));
19
+ }), P;
20
+ })().postMessage({ id: r2, bitmap: e2, quality: t2, wantBytes: n2 }, [e2]);
21
+ });
22
+ }
23
+ class VideoEncoderClient {
24
+ constructor(e2) {
25
+ __publicField(this, "worker");
26
+ __publicField(this, "configured", false);
27
+ __publicField(this, "doneResolve", null);
28
+ __publicField(this, "flushResolve", null);
29
+ __publicField(this, "configResolve", null);
30
+ this.events = e2, this.worker = createBlobWorker("\nlet encoder = null;\nlet decoderConfig = null;\nlet sentConfig = false;\n\nasync function pickCodec(codecs, width, height, bitrate) {\n for (const codec of codecs) {\n try {\n const support = await VideoEncoder.isConfigSupported({\n codec, width, height, bitrate, framerate: 30,\n ...(codec.startsWith('avc1') ? { avc: { format: 'avc' } } : {}),\n });\n if (support.supported) return codec;\n } catch (e) { /* try next */ }\n }\n return null;\n}\n\nself.onmessage = async (e) => {\n const msg = e.data;\n if (msg.type === 'config') {\n const codec = await pickCodec(msg.codecs, msg.width, msg.height, msg.bitrate);\n if (!codec) {\n self.postMessage({ type: 'config-failed' });\n return;\n }\n encoder = new VideoEncoder({\n output: (chunk, meta) => {\n if (meta && meta.decoderConfig && !decoderConfig) {\n const desc = meta.decoderConfig.description;\n decoderConfig = {\n codec: meta.decoderConfig.codec,\n description: desc\n ? (desc instanceof ArrayBuffer\n ? desc.slice(0)\n : desc.buffer.slice(desc.byteOffset, desc.byteOffset + desc.byteLength))\n : null,\n };\n }\n if (decoderConfig && !sentConfig) {\n sentConfig = true;\n self.postMessage({\n type: 'decoder-config',\n codec: decoderConfig.codec,\n description: decoderConfig.description,\n });\n }\n const data = new ArrayBuffer(chunk.byteLength);\n chunk.copyTo(data);\n self.postMessage({\n type: 'chunk',\n data,\n timestampUs: chunk.timestamp,\n key: chunk.type === 'key',\n }, [data]);\n },\n error: (err) => self.postMessage({ type: 'error', message: String(err) }),\n });\n encoder.configure({\n codec,\n width: msg.width,\n height: msg.height,\n bitrate: msg.bitrate,\n framerate: 30,\n latencyMode: 'realtime',\n ...(codec.startsWith('avc1') ? { avc: { format: 'avc' } } : {}),\n });\n self.postMessage({ type: 'configured', codec });\n return;\n }\n if (msg.type === 'frame') {\n try {\n if (encoder) encoder.encode(msg.frame, { keyFrame: msg.key });\n } catch (err) {\n self.postMessage({ type: 'error', message: String(err) });\n } finally {\n msg.frame.close();\n }\n return;\n }\n if (msg.type === 'flush') {\n // Non-terminal drain (visibilitychange:hidden): push queued frames out as\n // chunks WITHOUT closing the encoder, so capture can resume if the tab\n // returns. Chunks stream through the existing output handler above.\n try {\n if (encoder) await encoder.flush();\n } catch (e) { /* flush may fail when nothing was encoded */ }\n self.postMessage({ type: 'flushed' });\n return;\n }\n if (msg.type === 'stop') {\n try {\n if (encoder) await encoder.flush();\n } catch (e) { /* flush may fail when nothing was encoded */ }\n self.postMessage({ type: 'done' });\n if (encoder) encoder.close();\n encoder = null;\n }\n};\n"), this.worker.onmessage = (e3) => {
31
+ var _a, _b, _c, _d;
32
+ const t2 = e3.data;
33
+ switch (t2.type) {
34
+ case "configured":
35
+ this.configured = true, (_a = this.configResolve) == null ? void 0 : _a.call(this, true), this.configResolve = null;
36
+ break;
37
+ case "config-failed":
38
+ (_b = this.configResolve) == null ? void 0 : _b.call(this, false), this.configResolve = null;
39
+ break;
40
+ case "decoder-config":
41
+ this.events.onDecoderConfig(t2.codec, t2.description ?? null);
42
+ break;
43
+ case "chunk":
44
+ this.events.onChunk(t2.data, t2.timestampUs, t2.key);
45
+ break;
46
+ case "error":
47
+ this.events.onError(String(t2.message));
48
+ break;
49
+ case "done":
50
+ (_c = this.doneResolve) == null ? void 0 : _c.call(this), this.doneResolve = null;
51
+ break;
52
+ case "flushed":
53
+ (_d = this.flushResolve) == null ? void 0 : _d.call(this), this.flushResolve = null;
54
+ }
55
+ };
56
+ }
57
+ get isConfigured() {
58
+ return this.configured;
59
+ }
60
+ configure(e2) {
61
+ return new Promise((t2) => {
62
+ this.configResolve = t2, this.worker.postMessage({ type: "config", ...e2 });
63
+ });
64
+ }
65
+ encodeFrame(e2, t2) {
66
+ this.worker.postMessage({ type: "frame", frame: e2, key: t2 }, [e2]);
67
+ }
68
+ flush(e2 = 3e3) {
69
+ return new Promise((t2) => {
70
+ const n2 = setTimeout(() => {
71
+ this.flushResolve = null, t2();
72
+ }, e2);
73
+ this.flushResolve = () => {
74
+ clearTimeout(n2), t2();
75
+ };
76
+ try {
77
+ this.worker.postMessage({ type: "flush" });
78
+ } catch {
79
+ clearTimeout(n2), this.flushResolve = null, t2();
80
+ }
81
+ });
82
+ }
83
+ stop(e2 = 3e3) {
84
+ return new Promise((t2) => {
85
+ const n2 = setTimeout(() => {
86
+ this.doneResolve = null, t2();
87
+ }, e2);
88
+ this.doneResolve = () => {
89
+ clearTimeout(n2), t2();
90
+ };
91
+ try {
92
+ this.worker.postMessage({ type: "stop" });
93
+ } catch {
94
+ clearTimeout(n2), this.doneResolve = null, t2();
95
+ }
96
+ });
97
+ }
98
+ terminate() {
99
+ this.worker.terminate();
100
+ }
101
+ }
102
+ const G = { maxBytesPerSec: 524288, sustainMs: 3e3, maxVideoDrawsPerSec: 2, maxOpsPerFrame: 5e3 };
103
+ class CanvasGovernor {
104
+ constructor(e2, t2) {
105
+ __publicField(this, "thresholds");
106
+ __publicField(this, "byteSamples", []);
107
+ __publicField(this, "videoDraws", []);
108
+ __publicField(this, "frameT", NaN);
109
+ __publicField(this, "frameOps", 0);
110
+ __publicField(this, "opsExceeded", false);
111
+ this.now = e2, this.thresholds = { ...G, ...t2 };
112
+ }
113
+ addBytes(e2) {
114
+ const t2 = this.now();
115
+ this.byteSamples.push({ t: t2, n: e2 }), this.pruneBytes(t2);
116
+ }
117
+ addVideoDraw() {
118
+ const e2 = this.now();
119
+ this.videoDraws.push(e2), this.pruneVideo(e2);
120
+ }
121
+ addOp(e2) {
122
+ e2 !== this.frameT && (this.frameT = e2, this.frameOps = 0), ++this.frameOps > this.thresholds.maxOpsPerFrame && (this.opsExceeded = true);
123
+ }
124
+ shouldDemote() {
125
+ if (this.opsExceeded) return "ops";
126
+ const e2 = this.now();
127
+ if (this.pruneVideo(e2), this.videoDraws.length > this.thresholds.maxVideoDrawsPerSec) return "video-source";
128
+ this.pruneBytes(e2);
129
+ let t2 = 0;
130
+ for (const e3 of this.byteSamples) t2 += e3.n;
131
+ return t2 > this.thresholds.maxBytesPerSec * this.thresholds.sustainMs / 1e3 ? "bytes" : null;
132
+ }
133
+ pruneBytes(e2) {
134
+ const t2 = e2 - this.thresholds.sustainMs;
135
+ for (; this.byteSamples.length > 0 && this.byteSamples[0].t < t2; ) this.byteSamples.shift();
136
+ }
137
+ pruneVideo(e2) {
138
+ const t2 = e2 - 1e3;
139
+ for (; this.videoDraws.length > 0 && this.videoDraws[0] < t2; ) this.videoDraws.shift();
140
+ }
141
+ }
142
+ class KeyframeCapturer {
143
+ constructor(e2, t2, n2, r2, o2 = () => []) {
144
+ __publicField(this, "scratch", null);
145
+ __publicField(this, "scratchCtx", null);
146
+ __publicField(this, "lastKeyframe", -1 / 0);
147
+ __publicField(this, "dirtySinceKeyframe", false);
148
+ __publicField(this, "interactionRequested", false);
149
+ __publicField(this, "pending", []);
150
+ __publicField(this, "stopped", false);
151
+ this.canvas = e2, this.snapshotState = t2, this.emit = n2, this.note = r2, this.getMaskedRegions = o2;
152
+ }
153
+ onInteraction(e2) {
154
+ e2 - this.lastKeyframe >= 250 && (this.interactionRequested = true);
155
+ }
156
+ initialKeyframe(e2) {
157
+ if (this.stopped) return false;
158
+ if (!this.canvas.width || !this.canvas.height) return false;
159
+ const t2 = this.pending.length;
160
+ return this.takeKeyframe(e2), this.pending.length > t2;
161
+ }
162
+ afterRender(e2) {
163
+ this.dirtySinceKeyframe = true, (this.interactionRequested && (this.interactionRequested = false, e2 - this.lastKeyframe >= 250) || e2 - this.lastKeyframe >= 4e3) && this.takeKeyframe(e2);
164
+ }
165
+ takeKeyframe(e2) {
166
+ if (this.stopped) return;
167
+ this.lastKeyframe = e2, this.dirtySinceKeyframe = false;
168
+ const t2 = this.snapshotState();
169
+ this.scratch || (this.scratch = document.createElement("canvas"), this.scratchCtx = this.scratch.getContext("2d"), this.scratchCtx && n(this.scratchCtx));
170
+ const o2 = this.scratch, s2 = this.scratchCtx;
171
+ if (!s2) return;
172
+ o2.width !== this.canvas.width || o2.height !== this.canvas.height ? (o2.width = this.canvas.width, o2.height = this.canvas.height) : s2.clearRect(0, 0, o2.width, o2.height);
173
+ try {
174
+ s2.drawImage(this.canvas, 0, 0);
175
+ } catch {
176
+ return;
177
+ }
178
+ const a2 = this.getMaskedRegions();
179
+ if (a2.length > 0) {
180
+ s2.save(), s2.setTransform(1, 0, 0, 1, 0, 0), s2.fillStyle = r;
181
+ for (const e3 of a2) s2.fillRect(e3.x, e3.y, e3.w, e3.h);
182
+ s2.restore();
183
+ }
184
+ const i2 = o2.width, c2 = o2.height, d2 = createImageBitmap(o2).then(async (n2) => {
185
+ const r2 = await encodeBitmap(n2, 0.9, true);
186
+ r2.bytes && r2.bytes.byteLength > 0 && this.emit({ tMs: e2, w: i2, h: c2, state: t2, bytes: r2.bytes });
187
+ }).catch((e3) => this.note(`keyframe encode failed: ${e3.message}`));
188
+ this.pending.push(d2);
189
+ }
190
+ async stop(e2) {
191
+ this.dirtySinceKeyframe && this.takeKeyframe(e2), this.stopped = true, await Promise.all(this.pending);
192
+ }
193
+ dispose() {
194
+ if (this.stopped = true, this.scratch) try {
195
+ this.scratch.width = 0, this.scratch.height = 0;
196
+ } catch {
197
+ }
198
+ this.scratch = null, this.scratchCtx = null;
199
+ }
200
+ }
201
+ const A = /^create[A-Z]/, O = /* @__PURE__ */ new Set(["getUniformLocation", "getExtension"]), V = /^(get(?!Extension$|UniformLocation$)|is[A-Z]|check|read|finish$|flush$)/;
202
+ let W = false;
203
+ const U = /* @__PURE__ */ new WeakMap();
204
+ let F = null;
205
+ function texSourceToImageData(e2) {
206
+ if ("undefined" != typeof ImageData && e2 instanceof ImageData) return e2;
207
+ const t2 = e2, r2 = Number(t2.naturalWidth || t2.width) || 0, o2 = Number(t2.naturalHeight || t2.height) || 0;
208
+ if (!r2 || !o2) return null;
209
+ const s2 = (function texScratchCtx(e3, t3) {
210
+ if ("undefined" == typeof document) return null;
211
+ if (!F) {
212
+ F = document.createElement("canvas");
213
+ const e4 = F.getContext("2d");
214
+ e4 && n(e4);
215
+ }
216
+ F.width === e3 && F.height === t3 || (F.width = e3, F.height = t3);
217
+ const r3 = F.getContext("2d");
218
+ return r3 && n(r3), r3;
219
+ })(r2, o2);
220
+ return s2 ? (s2.clearRect(0, 0, r2, o2), s2.drawImage(e2, 0, 0), s2.getImageData(0, 0, r2, o2)) : null;
221
+ }
222
+ let K = null;
223
+ function setUntrackedGLContextNotifier(e2) {
224
+ K = e2;
225
+ }
226
+ let $ = null;
227
+ const H = /* @__PURE__ */ new Map();
228
+ function setGLAutoAttach(e2) {
229
+ $ = e2, e2 && H.clear();
230
+ }
231
+ class GLRecorder {
232
+ constructor(e2, t2) {
233
+ __publicField(this, "cpuMs", 0);
234
+ __publicField(this, "bound", false);
235
+ __publicField(this, "rawCtx", null);
236
+ __publicField(this, "refs", /* @__PURE__ */ new WeakMap());
237
+ __publicField(this, "nextId", 1e6);
238
+ __publicField(this, "sink");
239
+ __publicField(this, "pendingEncodes", /* @__PURE__ */ new Set());
240
+ __publicField(this, "assetBySource", /* @__PURE__ */ new WeakMap());
241
+ __publicField(this, "nextAssetId", 2e6);
242
+ __publicField(this, "assetCount", 0);
243
+ __publicField(this, "pendingSiteId");
244
+ this.now = t2, this.sink = e2;
245
+ }
246
+ async settle() {
247
+ for (; this.pendingEncodes.size; ) await Promise.all([...this.pendingEncodes]);
248
+ }
249
+ trackEncode(e2) {
250
+ this.pendingEncodes.add(e2), e2.then(() => {
251
+ }, () => {
252
+ }).finally(() => this.pendingEncodes.delete(e2));
253
+ }
254
+ captureTexSource(e2, t2) {
255
+ var _a, _b, _c;
256
+ const n2 = this.assetBySource.get(e2);
257
+ if (void 0 !== n2) return { $: "imagedata", id: n2 };
258
+ if (this.assetCount >= 64) return { $: "unsupported", kind: "texture-cap" };
259
+ if ((function texSourceRawBytes(e3) {
260
+ if ("undefined" != typeof ImageData && e3 instanceof ImageData) return e3.width * e3.height * 4;
261
+ const t3 = e3;
262
+ return (Number(t3.naturalWidth || t3.width) || 0) * (Number(t3.naturalHeight || t3.height) || 0) * 4;
263
+ })(e2) > 7340032) return { $: "unsupported", kind: "texture-too-large" };
264
+ let r2;
265
+ try {
266
+ r2 = texSourceToImageData(e2);
267
+ } catch (e3) {
268
+ return s(e3) ? ((_b = (_a = this.sink).onTaint) == null ? void 0 : _b.call(_a, t2), { $: "unsupported", kind: "texture-tainted" }) : { $: "unsupported", kind: "texture" };
269
+ }
270
+ if (!r2) return { $: "unsupported", kind: ((_c = e2.constructor) == null ? void 0 : _c.name) ?? "texture" };
271
+ const o2 = this.nextAssetId++;
272
+ this.assetCount++, this.assetBySource.set(e2, o2);
273
+ const i2 = r2.width, c2 = r2.height, d2 = new Uint8Array(r2.data.buffer.slice(r2.data.byteOffset, r2.data.byteOffset + r2.data.byteLength));
274
+ return this.trackEncode(a(d2).then((e3) => {
275
+ var _a2, _b2;
276
+ this.sink.onAssetBytes(o2, e3.length, t2), (_b2 = (_a2 = this.sink).onAssetData) == null ? void 0 : _b2.call(_a2, { id: o2, format: "imagedata", w: i2, h: c2, t: t2 }, e3);
277
+ }).catch((e3) => this.sink.note(`GL texture asset deflate failed: ${e3.message}`))), { $: "imagedata", id: o2 };
278
+ }
279
+ swapSink(e2) {
280
+ var _a;
281
+ const t2 = this.sink;
282
+ if (this.sink = e2, this.bound = true, t2 instanceof o) {
283
+ for (const n2 of t2.ops) e2.onOp(n2);
284
+ for (const n2 of t2.assetEvents) e2.onAssetBytes(n2.id, n2.bytes, n2.t);
285
+ for (const n2 of t2.assetData) (_a = e2.onAssetData) == null ? void 0 : _a.call(e2, n2.info, n2.payload);
286
+ for (const n2 of t2.notes) e2.note(n2);
287
+ }
288
+ }
289
+ recordCall(e2, t2, n2) {
290
+ if (this.sink instanceof i) return this.sink.onOp(c), void (this.pendingSiteId = void 0);
291
+ const r2 = performance.now(), o2 = this.now(), s2 = this.pendingSiteId;
292
+ if (this.pendingSiteId = void 0, (A.test(e2) || O.has(e2)) && n2 && "object" == typeof n2) {
293
+ const r3 = this.nextId++;
294
+ this.refs.set(n2, r3), this.sink.onOp({ t: o2, op: "__create", create: true, args: [e2, r3, ...t2.map((e3) => this.arg(e3, o2))] });
295
+ } else {
296
+ const n3 = { t: o2, op: e2, args: t2.map((e3) => this.arg(e3, o2)) };
297
+ s2 && (n3.sfId = s2), this.sink.onOp(n3);
298
+ }
299
+ this.cpuMs += performance.now() - r2;
300
+ }
301
+ arg(e2, t2) {
302
+ var _a;
303
+ if (null == e2) return null;
304
+ switch (typeof e2) {
305
+ case "number":
306
+ return Number.isFinite(e2) ? e2 : 0;
307
+ case "string":
308
+ case "boolean":
309
+ return e2;
310
+ case "object":
311
+ break;
312
+ default:
313
+ return { $: "unsupported", kind: typeof e2 };
314
+ }
315
+ const n2 = e2, r2 = this.refs.get(n2);
316
+ return void 0 !== r2 ? { $: "obj", id: r2 } : ArrayBuffer.isView(n2) || n2 instanceof ArrayBuffer ? d(n2) : Array.isArray(n2) ? { $: "arr", v: n2.map((e3) => Number(e3) || 0) } : (function isStaticTexSource(e3) {
317
+ return "undefined" != typeof ImageData && e3 instanceof ImageData || "undefined" != typeof HTMLImageElement && e3 instanceof HTMLImageElement || "undefined" != typeof ImageBitmap && e3 instanceof ImageBitmap;
318
+ })(n2) ? this.captureTexSource(n2, t2) : { $: "unsupported", kind: ((_a = n2.constructor) == null ? void 0 : _a.name) ?? "object" };
319
+ }
320
+ }
321
+ function attachGLRecorder(e2, t2, n2, r2) {
322
+ const o2 = H.get(e2);
323
+ if (o2) return o2.swapSink(n2), o2;
324
+ const s2 = e2.getContext(t2);
325
+ if (!s2) return null;
326
+ const a2 = new GLRecorder(n2, r2);
327
+ return a2.rawCtx = s2, a2.bound = true, U.set(s2, a2), a2;
328
+ }
329
+ function detachGLRecorderFromContext(e2) {
330
+ U.delete(e2);
331
+ }
332
+ const j = 7340032, q = "__gpu";
333
+ let N = false, z = null, _ = null, J = false, Z = false;
334
+ function setGPUDeviceLostNotifier(e2) {
335
+ _ = e2, J = false, Z = false;
336
+ }
337
+ let Q = null, nowFn = () => 0, X = 0, Y = 3e6, ee = false, te = null, ne = null;
338
+ const re = /* @__PURE__ */ new WeakMap(), oe = /* @__PURE__ */ new WeakMap(), se = /* @__PURE__ */ new WeakMap();
339
+ function emit(e2) {
340
+ Q == null ? void 0 : Q.onOp(e2);
341
+ }
342
+ function intern(e2) {
343
+ let t2 = re.get(e2);
344
+ return void 0 === t2 && (t2 = Y++, re.set(e2, t2)), t2;
345
+ }
346
+ function deproxy(e2) {
347
+ return e2 && "object" == typeof e2 && se.has(e2) ? se.get(e2) : e2;
348
+ }
349
+ function deepDeproxy(e2) {
350
+ if (!e2 || "object" != typeof e2) return e2;
351
+ if (se.has(e2)) return se.get(e2);
352
+ if (ArrayBuffer.isView(e2) || e2 instanceof ArrayBuffer) return e2;
353
+ if (Array.isArray(e2)) {
354
+ let t3 = false;
355
+ const n2 = e2.map((e3) => {
356
+ const n3 = deepDeproxy(e3);
357
+ return n3 !== e3 && (t3 = true), n3;
358
+ });
359
+ return t3 ? n2 : e2;
360
+ }
361
+ const t2 = Object.getPrototypeOf(e2);
362
+ if (t2 === Object.prototype || null === t2) {
363
+ let t3 = false;
364
+ const n2 = {};
365
+ for (const [r2, o2] of Object.entries(e2)) {
366
+ const e3 = deepDeproxy(o2);
367
+ e3 !== o2 && (t3 = true), n2[r2] = e3;
368
+ }
369
+ return t3 ? n2 : e2;
370
+ }
371
+ return e2;
372
+ }
373
+ const ae = function serializeGPUArg(e2) {
374
+ var _a;
375
+ if (null == e2) return null;
376
+ switch (typeof e2) {
377
+ case "number":
378
+ return Number.isFinite(e2) ? e2 : 0;
379
+ case "string":
380
+ case "boolean":
381
+ return e2;
382
+ case "object":
383
+ break;
384
+ default:
385
+ return { $: "unsupported", kind: typeof e2 };
386
+ }
387
+ const t2 = deproxy(e2);
388
+ if (ArrayBuffer.isView(t2) || t2 instanceof ArrayBuffer) return t2.byteLength > j ? { $: "unsupported", kind: "buffer-too-large" } : d(t2);
389
+ const n2 = re.get(t2);
390
+ if (void 0 !== n2) return { $: "obj", id: n2 };
391
+ try {
392
+ return "json:" + JSON.stringify(t2, (e3, t3) => {
393
+ if (t3 && "object" == typeof t3) {
394
+ const e4 = deproxy(t3), n3 = re.get(e4);
395
+ if (void 0 !== n3) return { __sfRef: n3 };
396
+ if (ArrayBuffer.isView(e4)) {
397
+ const t4 = e4;
398
+ if (t4.byteLength > j) return { __sfUnsupported: "buffer-too-large" };
399
+ const n4 = l.findIndex((e5) => t4 instanceof e5);
400
+ return n4 < 0 ? { __sfUnsupported: "typed-array-kind" } : { __sfTa: Array.from(t4), __sfK: n4 };
401
+ }
402
+ return e4 === t3 ? t3 : e4;
403
+ }
404
+ return t3;
405
+ });
406
+ } catch {
407
+ return { $: "unsupported", kind: ((_a = t2.constructor) == null ? void 0 : _a.name) ?? "object" };
408
+ }
409
+ };
410
+ function shouldProxyResult(e2) {
411
+ var _a;
412
+ if (!e2 || "object" != typeof e2) return false;
413
+ return (((_a = e2.constructor) == null ? void 0 : _a.name) ?? "").startsWith("GPU");
414
+ }
415
+ function wrap(e2) {
416
+ var _a;
417
+ const t2 = oe.get(e2);
418
+ if (t2) return t2;
419
+ "GPUDevice" === ((_a = e2.constructor) == null ? void 0 : _a.name) && (function watchDeviceLost(e3) {
420
+ const t3 = e3.lost;
421
+ if (t3 && "function" == typeof t3.then) {
422
+ if (Z && !J) {
423
+ J = true;
424
+ try {
425
+ _ == null ? void 0 : _(false);
426
+ } catch {
427
+ }
428
+ }
429
+ t3.then((e4) => {
430
+ if (!(e4 && "destroyed" === e4.reason || Z)) {
431
+ Z = true;
432
+ try {
433
+ _ == null ? void 0 : _(true);
434
+ } catch {
435
+ }
436
+ }
437
+ }).catch(() => {
438
+ });
439
+ }
440
+ })(e2);
441
+ const n2 = new Proxy(e2, { get(e3, t3, n3) {
442
+ const r2 = Reflect.get(e3, t3, e3);
443
+ if ("symbol" == typeof t3) return r2;
444
+ if ("function" == typeof r2) return (...n4) => {
445
+ const o2 = performance.now(), s2 = n4.map(deepDeproxy), a2 = r2.apply(e3, s2);
446
+ if (Q instanceof i) return Q.onOp(c), a2 && "object" == typeof a2 && "function" == typeof a2.then ? a2.then((e4) => e4 && "object" == typeof e4 && shouldProxyResult(e4) ? (intern(e4), wrap(e4)) : e4) : shouldProxyResult(a2) ? (intern(a2), wrap(a2)) : a2;
447
+ if (Q) {
448
+ const r3 = intern(e3);
449
+ if (a2 && "object" == typeof a2 && "function" == typeof a2.then) {
450
+ const e4 = Y++;
451
+ return emit({ t: nowFn(), op: q, objcall: true, args: [r3, String(t3), e4, ...n4.map(ae)] }), X += performance.now() - o2, a2.then((t4) => t4 && "object" == typeof t4 ? (re.set(t4, e4), wrap(t4)) : t4);
452
+ }
453
+ let s3 = 0;
454
+ return shouldProxyResult(a2) && (s3 = intern(a2)), emit({ t: nowFn(), op: q, objcall: true, args: [r3, String(t3), s3, ...n4.map(ae)] }), X += performance.now() - o2, shouldProxyResult(a2) ? wrap(a2) : a2;
455
+ }
456
+ return a2 && "object" == typeof a2 && "function" == typeof a2.then ? a2.then((e4) => e4 && "object" == typeof e4 && shouldProxyResult(e4) ? (intern(e4), wrap(e4)) : e4) : shouldProxyResult(a2) ? (intern(a2), wrap(a2)) : a2;
457
+ };
458
+ if (shouldProxyResult(r2)) {
459
+ const n4 = re.has(r2), o2 = intern(r2);
460
+ return n4 || !Q || Q instanceof i || emit({ t: nowFn(), op: "__gpuprop", objcall: true, args: [intern(e3), String(t3), o2] }), wrap(r2);
461
+ }
462
+ return r2;
463
+ } });
464
+ return oe.set(e2, n2), se.set(n2, e2), n2;
465
+ }
466
+ function setGPUAutoAttach(e2) {
467
+ z = e2, e2 && (nowFn = e2.now, Q || (Q = new o(), ee = false));
468
+ }
469
+ const ie = ["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm", "video/mp4"];
470
+ function pickMime() {
471
+ if ("undefined" == typeof MediaRecorder || "function" != typeof MediaRecorder.isTypeSupported) return null;
472
+ for (const e2 of ie) try {
473
+ if (MediaRecorder.isTypeSupported(e2)) return e2;
474
+ } catch {
475
+ }
476
+ return null;
477
+ }
478
+ class MediaRecorderCapture {
479
+ constructor(e2, t2) {
480
+ __publicField(this, "recorder", null);
481
+ __publicField(this, "stream", null);
482
+ __publicField(this, "stopped", false);
483
+ __publicField(this, "started", false);
484
+ __publicField(this, "seq", 0);
485
+ __publicField(this, "emitChain", Promise.resolve());
486
+ this.canvas = e2, this.out = t2;
487
+ }
488
+ static supported() {
489
+ return (function mediaRecorderSupported() {
490
+ return "undefined" != typeof MediaRecorder && "undefined" != typeof HTMLCanvasElement && "function" == typeof HTMLCanvasElement.prototype.captureStream && "function" == typeof MediaRecorder.isTypeSupported && null !== pickMime();
491
+ })();
492
+ }
493
+ async start() {
494
+ if (this.stopped) return false;
495
+ const e2 = this.canvas.width, t2 = this.canvas.height;
496
+ if (!e2 || !t2) return this.out.note("zero-size canvas — MediaRecorder capture unavailable"), false;
497
+ const n2 = pickMime();
498
+ if (!n2) return this.out.note("no MediaRecorder-supported mime — keyframes only"), false;
499
+ let r2, o2;
500
+ try {
501
+ r2 = this.canvas.captureStream(30);
502
+ } catch (e3) {
503
+ return this.out.note(`captureStream failed: ${e3.message}`), false;
504
+ }
505
+ try {
506
+ o2 = new MediaRecorder(r2, { mimeType: n2 });
507
+ } catch (e3) {
508
+ this.out.note(`MediaRecorder construct failed: ${e3.message}`);
509
+ try {
510
+ stopStream(r2);
511
+ } catch {
512
+ }
513
+ return false;
514
+ }
515
+ this.stream = r2, this.recorder = o2, o2.ondataavailable = (e3) => this.onData(e3.data), o2.onerror = (e3) => {
516
+ this.out.note(`MediaRecorder error: ${String(e3.error ?? e3)}`);
517
+ };
518
+ try {
519
+ o2.start(1e3);
520
+ } catch (e3) {
521
+ return this.out.note(`MediaRecorder start failed: ${e3.message}`), this.teardownStream(), false;
522
+ }
523
+ return this.started = true, this.out.onInit(o2.mimeType || n2, e2, t2), true;
524
+ }
525
+ onData(e2) {
526
+ if (!e2 || 0 === e2.size) return;
527
+ const t2 = this.seq++;
528
+ this.emitChain = this.emitChain.then(async () => {
529
+ try {
530
+ const n2 = await e2.arrayBuffer();
531
+ n2.byteLength > 0 && this.out.onChunk(t2, n2);
532
+ } catch (e3) {
533
+ this.out.note(`chunk read failed: ${e3.message}`);
534
+ }
535
+ });
536
+ }
537
+ afterRender(e2) {
538
+ }
539
+ onInteraction(e2) {
540
+ }
541
+ async flush() {
542
+ if (!this.stopped && this.recorder) {
543
+ try {
544
+ "recording" === this.recorder.state && this.recorder.requestData();
545
+ } catch {
546
+ }
547
+ await Promise.resolve(), await this.emitChain.catch(() => {
548
+ });
549
+ }
550
+ }
551
+ async stop() {
552
+ if (this.stopped) return;
553
+ this.stopped = true;
554
+ const e2 = this.recorder;
555
+ if (e2 && this.started) {
556
+ const t2 = new Promise((t3) => {
557
+ const done = () => t3();
558
+ e2.addEventListener("stop", done, { once: true }), setTimeout(done, 3e3);
559
+ });
560
+ try {
561
+ "inactive" !== e2.state && (e2.requestData(), e2.stop());
562
+ } catch {
563
+ }
564
+ await t2;
565
+ }
566
+ await this.emitChain.catch(() => {
567
+ }), this.teardownStream();
568
+ }
569
+ abort() {
570
+ if (!this.stopped) {
571
+ this.stopped = true;
572
+ try {
573
+ this.recorder && "inactive" !== this.recorder.state && this.recorder.stop();
574
+ } catch {
575
+ }
576
+ this.teardownStream();
577
+ }
578
+ }
579
+ teardownStream() {
580
+ this.recorder && (this.recorder.ondataavailable = null, this.recorder.onerror = null, this.recorder = null), this.stream && (stopStream(this.stream), this.stream = null);
581
+ }
582
+ }
583
+ function stopStream(e2) {
584
+ try {
585
+ for (const t2 of e2.getTracks()) try {
586
+ t2.stop();
587
+ } catch {
588
+ }
589
+ } catch {
590
+ }
591
+ }
592
+ const ce = 18e5;
593
+ class VideoCapture {
594
+ constructor(e2, t2, n2, r2) {
595
+ __publicField(this, "client", null);
596
+ __publicField(this, "configured", false);
597
+ __publicField(this, "failed", false);
598
+ __publicField(this, "stopped", false);
599
+ __publicField(this, "lastFrame", -1 / 0);
600
+ __publicField(this, "lastKey", -1 / 0);
601
+ __publicField(this, "boostUntil", -1 / 0);
602
+ __publicField(this, "configuredW", 0);
603
+ __publicField(this, "configuredH", 0);
604
+ __publicField(this, "intervalId", null);
605
+ __publicField(this, "throttledNoted", false);
606
+ __publicField(this, "restarting", false);
607
+ __publicField(this, "forceKeyNext", false);
608
+ this.canvas = e2, this.now = t2, this.out = n2, this.opts = r2;
609
+ }
610
+ static supported() {
611
+ return "function" == typeof VideoEncoder && "function" == typeof VideoFrame;
612
+ }
613
+ async start() {
614
+ var _a;
615
+ if (!VideoCapture.supported()) return this.failed = true, this.out.note("no WebCodecs — video capture unavailable"), false;
616
+ const e2 = this.canvas.width, t2 = this.canvas.height;
617
+ if (!e2 || !t2) return this.failed = true, this.out.note("zero-size canvas — video capture unavailable"), false;
618
+ this.client = new VideoEncoderClient({ onDecoderConfig: (e3, t3) => this.out.onInit(e3, t3), onChunk: (e3, t3, n2) => this.out.onChunk(n2, t3, e3), onError: (e3) => this.out.note(e3) });
619
+ return await this.client.configure({ width: e2, height: t2, bitrate: ce, codecs: ["avc1.42001f", "vp8", "vp09.00.10.08"] }) ? (this.configured = true, this.configuredW = e2, this.configuredH = t2, ((_a = this.opts) == null ? void 0 : _a.intervalPaced) && (this.intervalId = setInterval(() => this.afterRender(this.now()), 50)), true) : (this.failed = true, this.out.note("no supported video codec"), this.client.terminate(), this.client = null, false);
620
+ }
621
+ onInteraction(e2) {
622
+ this.boostUntil = e2 + 1500, this.lastKey = -1 / 0;
623
+ }
624
+ afterRender(e2) {
625
+ var _a, _b;
626
+ if (!this.configured || this.failed || this.stopped || !this.client) return;
627
+ if ((_b = (_a = this.out).isTransportSaturated) == null ? void 0 : _b.call(_a)) return void (this.throttledNoted || (this.throttledNoted = true, this.out.note("transport saturated — video frames throttled")));
628
+ if (this.throttledNoted = false, this.canvas.width !== this.configuredW || this.canvas.height !== this.configuredH) return void this.requestRestart();
629
+ const t2 = e2 < this.boostUntil ? 30 : 20;
630
+ if (e2 - this.lastFrame < 1e3 / t2) return;
631
+ this.lastFrame = e2;
632
+ const n2 = this.forceKeyNext;
633
+ this.forceKeyNext = false;
634
+ const r2 = n2 || e2 - this.lastKey >= 2e3;
635
+ r2 && (this.lastKey = e2);
636
+ try {
637
+ const t3 = new VideoFrame(this.canvas, { timestamp: Math.round(1e3 * e2) });
638
+ this.client.encodeFrame(t3, r2);
639
+ } catch (e3) {
640
+ this.out.note(String(e3));
641
+ }
642
+ }
643
+ requestRestart() {
644
+ if (this.restarting || this.stopped) return;
645
+ const e2 = this.canvas.width, t2 = this.canvas.height;
646
+ if (!e2 || !t2) return;
647
+ this.restarting = true;
648
+ const n2 = this.client;
649
+ this.client = null, this.configured = false, this.out.note(`canvas resized to ${e2}x${t2} during video capture — restarting encoder`), (async () => {
650
+ try {
651
+ if (n2) try {
652
+ n2.terminate();
653
+ } catch {
654
+ }
655
+ if (this.stopped) return;
656
+ const r2 = new VideoEncoderClient({ onDecoderConfig: (e3, t3) => this.out.onInit(e3, t3), onChunk: (e3, t3, n3) => this.out.onChunk(n3, t3, e3), onError: (e3) => this.out.note(e3) }), o2 = await r2.configure({ width: e2, height: t2, bitrate: ce, codecs: ["avc1.42001f", "vp8", "vp09.00.10.08"] });
657
+ if (this.stopped || !o2) return r2.terminate(), void (o2 || this.out.note("encoder restart failed after resize — frames dropped until next resize"));
658
+ this.client = r2, this.configuredW = e2, this.configuredH = t2, this.configured = true, this.forceKeyNext = true, this.lastFrame = -1 / 0, this.lastKey = -1 / 0;
659
+ } finally {
660
+ this.restarting = false;
661
+ }
662
+ })();
663
+ }
664
+ async flush() {
665
+ !this.stopped && this.client && await this.client.flush();
666
+ }
667
+ abort() {
668
+ this.stopped || (this.stopped = true, null != this.intervalId && (clearInterval(this.intervalId), this.intervalId = null), this.client && (this.client.terminate(), this.client = null));
669
+ }
670
+ async stop() {
671
+ this.stopped || (this.stopped = true, null != this.intervalId && (clearInterval(this.intervalId), this.intervalId = null), this.client && (await this.client.stop(), this.client.terminate(), this.client = null));
672
+ }
673
+ }
674
+ const de = /* @__PURE__ */ new WeakMap(), le = /* @__PURE__ */ new Map();
675
+ let ue = false, fe = null;
676
+ function setWorkerAssociationNotifier(e2) {
677
+ fe = e2;
678
+ }
679
+ const he = 1048576, pe = { deviceClass: "desktop", sessionByteBudget: 256 * he, maxConcurrentVideo: 4, governor: {}, preferMediaRecorder: false }, me = { deviceClass: "mobile", sessionByteBudget: 96 * he, maxConcurrentVideo: 2, governor: { maxBytesPerSec: 262144, maxOpsPerFrame: 3e3 }, preferMediaRecorder: false }, ve = { deviceClass: "mobile-lowend", sessionByteBudget: 48 * he, maxConcurrentVideo: 1, governor: { maxBytesPerSec: 131072, maxOpsPerFrame: 2e3, maxVideoDrawsPerSec: 1 }, preferMediaRecorder: false };
680
+ function resolveDeviceBudgets(e2) {
681
+ const t2 = "undefined" != typeof navigator ? navigator : void 0;
682
+ if (!t2) return pe;
683
+ const n2 = t2.deviceMemory, r2 = t2.hardwareConcurrency, o2 = "number" == typeof n2 && n2 <= 2, s2 = "number" == typeof r2 && r2 <= 4, a2 = (function isExplicitIOS(e3) {
684
+ return /iPhone|iPad|iPod/.test(e3.userAgent ?? "");
685
+ })(t2);
686
+ let i2;
687
+ return i2 = (function isMobileUA(e3) {
688
+ return /Mobi|Android|iPhone|iPad|iPod/.test(e3.userAgent ?? "") || (function isIPadDesktopUA(e4) {
689
+ return /Macintosh/.test(e4.userAgent ?? "") && (e4.maxTouchPoints ?? 0) > 1;
690
+ })(e3);
691
+ })(t2) ? o2 && s2 ? ve : me : o2 && s2 ? ve : pe, a2 ? { ...i2, preferMediaRecorder: true } : i2;
692
+ }
693
+ function decayBytes(e2, t2, n2, r2) {
694
+ return r2 <= 0 || t2 <= 0 || n2 <= 0 ? Math.max(0, e2) : Math.max(0, e2 - r2 * (t2 / n2));
695
+ }
696
+ const ye = 4;
697
+ class VideoSlotPool {
698
+ constructor(e2 = 4) {
699
+ __publicField(this, "used", 0);
700
+ this.max = e2;
701
+ }
702
+ acquire() {
703
+ return !(this.used >= this.max) && (this.used++, true);
704
+ }
705
+ release() {
706
+ this.used > 0 && this.used--;
707
+ }
708
+ get inUse() {
709
+ return this.used;
710
+ }
711
+ get available() {
712
+ return this.max - this.used;
713
+ }
714
+ }
715
+ let ge = null;
716
+ const now = () => Date.now(), encodeImage = (e2) => encodeBitmap(e2, 0.85, true);
717
+ function noteOnce(e2) {
718
+ var _a;
719
+ if (ge && !ge.notes.has(e2)) {
720
+ ge.notes.add(e2);
721
+ try {
722
+ (_a = console.debug) == null ? void 0 : _a.call(console, "[Sailfish][canvas]", e2);
723
+ } catch {
724
+ }
725
+ }
726
+ }
727
+ function emitEvent(e2) {
728
+ if (ge) try {
729
+ ge.deps.addSailfishEvent(e2);
730
+ } catch {
731
+ }
732
+ }
733
+ function sendFrame(e2, t2, n2, r2, o2 = Date.now()) {
734
+ const s2 = ge;
735
+ if (!s2) return;
736
+ const a2 = null == r2 ? 0 : r2.byteLength;
737
+ if (a2 > 8388608) return void noteOnce(`oversize ${t2} frame dropped (${a2}B > 8MiB)`);
738
+ const i2 = s2.budgets.sessionByteBudget;
739
+ if (s2.lastBudgetTickMs > 0 && (s2.totalBytes = decayBytes(s2.totalBytes, i2, 6e4, o2 - s2.lastBudgetTickMs)), s2.lastBudgetTickMs = Math.max(s2.lastBudgetTickMs, o2), s2.totalBytes > i2) return void (s2.budgetExceeded || (s2.budgetExceeded = true, noteOnce("per-session canvas byte budget exceeded — capture paused (auto-resumes as it drains)")));
740
+ s2.budgetExceeded && (s2.budgetExceeded = false);
741
+ const c2 = s2.deps.getContextIds(), d2 = M({ v: 1, kind: t2, sessionId: c2.session_id ?? "", pageVisitUuid: c2.page_visit_uuid ?? "", canvasId: e2.canvasId, seq: e2.seq++, tMs: o2, meta: n2 }, r2);
742
+ try {
743
+ s2.deps.sendBinary(d2);
744
+ } catch {
745
+ return;
746
+ }
747
+ s2.totalBytes += d2.byteLength;
748
+ }
749
+ function markDirty(e2) {
750
+ e2.dirty = true, e2.everDirty = true, e2.pumpScheduled || (e2.pumpScheduled = true, queueMicrotask(() => (function pumpCanvas(e3) {
751
+ var _a, _b, _c, _d, _e;
752
+ if (e3.pumpScheduled = false, !ge || e3.stopped || !e3.dirty) return;
753
+ if (e3.contextLost) return void (e3.dirty = false);
754
+ e3.dirty = false;
755
+ const t2 = now();
756
+ maybeEmitResize(e3, t2), ((_a = e3.recorder2d) == null ? void 0 : _a.keyframeUnsafe) && !e3.pixelSuppressed && suppressPixelCapture(e3);
757
+ ((_b = e3.recorder2d) == null ? void 0 : _b.hasMaskedDraws) && !e3.pixelSuppressed && "video" === e3.mode && suppressPixelCapture(e3);
758
+ "video" === e3.mode ? ((_c = e3.video) == null ? void 0 : _c.afterRender(t2), (_d = e3.mediaRecorder) == null ? void 0 : _d.afterRender(t2)) : (_e = e3.keyframes) == null ? void 0 : _e.afterRender(t2);
759
+ maybeDemote(e3);
760
+ })(e2)));
761
+ }
762
+ function suppressPixelCapture(e2) {
763
+ if (e2.pixelSuppressed = true, e2.keyframes = null, e2.video && (e2.video.stop(), e2.video = null, releaseVideoSlot(e2)), e2.mediaRecorder) {
764
+ try {
765
+ e2.mediaRecorder.stop();
766
+ } catch {
767
+ }
768
+ e2.mediaRecorder = null;
769
+ }
770
+ "video" === e2.mode && (e2.mode = "none", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: "maskCanvasDraws-pixel-suppressed" })), noteOnce("maskCanvasDraws used — pixel capture (keyframes/video) suppressed; sanitized command-only replay");
771
+ }
772
+ function flushBatch(e2, t2) {
773
+ if (!e2.encoder || 0 === e2.encoder.ops) return;
774
+ const n2 = e2.encoder.takeBatch(), r2 = a(n2);
775
+ e2.flushChain = e2.flushChain.then(async () => {
776
+ const t3 = await r2;
777
+ e2.governor.addBytes(t3.length), sendFrame(e2, "commands", { codec: "sfc-bin-1", compression: "deflate" }, t3), maybeDemote(e2);
778
+ }).catch(() => {
779
+ });
780
+ }
781
+ function makeCommandSink(e2) {
782
+ return { onOp(t2) {
783
+ e2.contextLost || (e2.encoder.encode(t2), e2.governor.addOp(t2.t), 0 === e2.batchStart && (e2.batchStart = t2.t), t2.t - e2.batchStart >= 1e3 ? (flushBatch(e2, t2.t), e2.batchStart = t2.t) : null === e2.flushTimer && (e2.flushTimer = setTimeout(() => {
784
+ e2.flushTimer = null, e2.stopped || (flushBatch(e2), e2.batchStart = 0);
785
+ }, 1100)), markDirty(e2));
786
+ }, onAssetBytes() {
787
+ }, onAssetData(t2, n2) {
788
+ sendFrame(e2, "asset", { assetId: t2.id, format: t2.format, w: t2.w, h: t2.h }, n2);
789
+ }, onVideoSource() {
790
+ e2.governor.addVideoDraw();
791
+ }, onTaint(t2) {
792
+ !(function emitTaint(e3, t3) {
793
+ if (e3.taintEmitted) return;
794
+ e3.taintEmitted = true, emitEvent({ op: "taint", canvasId: e3.canvasId, t: t3 });
795
+ })(e2, t2);
796
+ }, note(e3) {
797
+ noteOnce(e3);
798
+ } };
799
+ }
800
+ function maybeDemote(e2) {
801
+ var _a;
802
+ if ("commands" !== e2.mode || e2.demoted || e2.stopped || e2.worker) return;
803
+ if ("redact" === e2.privacyMode) return;
804
+ if ((_a = e2.recorder2d) == null ? void 0 : _a.hasMaskedDraws) return;
805
+ const t2 = e2.governor.shouldDemote();
806
+ t2 && demote(e2, t2);
807
+ }
808
+ function demote(e2, t2) {
809
+ var _a;
810
+ e2.demoted = true, flushBatch(e2), (_a = e2.keyframes) == null ? void 0 : _a.takeKeyframe(now());
811
+ const n2 = new i(() => markDirty(e2));
812
+ if (e2.recorder2d && e2.recorder2d.swapSink(n2), e2.recorderGL && e2.recorderGL.swapSink(n2), e2.recorderGPU && (function swapGPUSink(e3) {
813
+ Q && (Q = e3);
814
+ })(n2), !(ge == null ? void 0 : ge.budgets.preferMediaRecorder) || !tryStartMediaRecorder(e2, t2)) if (VideoCapture.supported()) {
815
+ if (!tryAcquireVideoSlot(e2)) return e2.mode = "none", noteOnce(`video-encoder cap (${(ge == null ? void 0 : ge.budgets.maxConcurrentVideo) ?? 4}) reached — canvas kept on keyframes`), void emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: `${t2} (video-encoder cap reached — keyframes only)` });
816
+ e2.mode = "video", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "video", reason: t2 });
817
+ const n3 = makeVideo(e2, false);
818
+ e2.video = n3, n3.start().then((t3) => {
819
+ t3 || e2.stopped || (e2.video = null, releaseVideoSlot(e2), e2.mode = "none", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: "video-start-failed" }));
820
+ });
821
+ } else tryStartMediaRecorder(e2, t2) || (e2.mode = "none", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: `${t2} (no WebCodecs — keyframes only)` }));
822
+ }
823
+ function makeKeyframes(e2) {
824
+ return new KeyframeCapturer(e2.canvas, () => e2.recorder2d && !e2.demoted ? e2.recorder2d.snapshotState() : null, (t2) => sendFrame(e2, "keyframe", { format: "webp", w: t2.w, h: t2.h, state: t2.state }, t2.bytes, t2.tMs), noteOnce, () => {
825
+ var _a;
826
+ return ((_a = e2.recorder2d) == null ? void 0 : _a.maskedRegions) ?? [];
827
+ });
828
+ }
829
+ function maybeInitialKeyframe(e2) {
830
+ const t2 = ge;
831
+ if (t2 && e2.keyframes && !R(e2.canvas) && t2.preExisting.has(e2.canvas)) {
832
+ t2.preExisting.delete(e2.canvas);
833
+ try {
834
+ e2.keyframes.initialKeyframe(now());
835
+ } catch {
836
+ }
837
+ }
838
+ }
839
+ function tryAcquireVideoSlot(e2) {
840
+ const t2 = ge;
841
+ return !!t2 && (!!e2.hasVideoSlot || !!t2.videoSlots.acquire() && (e2.hasVideoSlot = true, true));
842
+ }
843
+ function releaseVideoSlot(e2) {
844
+ e2.hasVideoSlot && (e2.hasVideoSlot = false, ge == null ? void 0 : ge.videoSlots.release());
845
+ }
846
+ function makeVideo(e2, t2) {
847
+ return new VideoCapture(e2.canvas, now, { onInit: (t3, n2) => sendFrame(e2, "video-init", { codec: t3, description: n2 ? S(n2) : null }, null), onChunk: (t3, n2, r2) => sendFrame(e2, "video-chunk", { key: t3, timestampUs: n2 }, r2), note: noteOnce, isTransportSaturated: (ge == null ? void 0 : ge.deps.isTransportSaturated) ? () => {
848
+ var _a, _b;
849
+ return !!((_b = ge == null ? void 0 : (_a = ge.deps).isTransportSaturated) == null ? void 0 : _b.call(_a));
850
+ } : void 0 }, { intervalPaced: t2 });
851
+ }
852
+ function tryStartMediaRecorder(e2, t2) {
853
+ if (!MediaRecorderCapture.supported()) return false;
854
+ if (!tryAcquireVideoSlot(e2)) return noteOnce(`video-encoder cap (${(ge == null ? void 0 : ge.budgets.maxConcurrentVideo) ?? 4}) reached — canvas kept on keyframes`), false;
855
+ const n2 = (function makeMediaRecorder(e3) {
856
+ return new MediaRecorderCapture(e3.canvas, { onInit: (t3, n3, r2) => sendFrame(e3, "video-init", { codec: "mediarecorder", mimeType: t3, w: n3, h: r2 }, null), onChunk: (t3, n3) => sendFrame(e3, "video-chunk", { codec: "mediarecorder", seq: t3 }, n3), note: noteOnce });
857
+ })(e2);
858
+ return e2.mediaRecorder = n2, e2.mode = "video", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "video", reason: `${t2} (MediaRecorder fallback)` }), n2.start().then((t3) => {
859
+ t3 || e2.stopped || (e2.mediaRecorder = null, releaseVideoSlot(e2), e2.mode = "none", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: "mediarecorder-start-failed" }));
860
+ }), true;
861
+ }
862
+ function baseController(e2, t2, n2, r2, o2 = "normal") {
863
+ var _a;
864
+ return { canvas: e2, canvasId: t2, contextType: n2, mode: r2, privacyMode: o2, seq: 0, dirty: false, everDirty: false, pumpScheduled: false, flushTimer: null, stopped: false, demoted: false, hasVideoSlot: false, contextLost: false, taintEmitted: false, lastW: e2.width, lastH: e2.height, removeContextLossListeners: null, governor: new CanvasGovernor(now, (_a = ge == null ? void 0 : ge.budgets) == null ? void 0 : _a.governor), encoder: null, batchStart: 0, flushChain: Promise.resolve(), keyframes: null, video: null, mediaRecorder: null, recorder2d: null, recorderGL: null, recorderGPU: null, worker: null, workerDone: null, removeWorkerListener: null, pixelSuppressed: false };
865
+ }
866
+ function dpr() {
867
+ return "undefined" != typeof window ? window.devicePixelRatio : 1;
868
+ }
869
+ function emitStart(e2) {
870
+ e2.lastW = e2.canvas.width, e2.lastH = e2.canvas.height, emitEvent({ op: "start", canvasId: e2.canvasId, contextType: e2.contextType, mode: e2.mode, w: e2.canvas.width, h: e2.canvas.height, dpr: dpr() });
871
+ }
872
+ function maybeEmitResize(e2, t2) {
873
+ var _a, _b, _c;
874
+ const n2 = e2.canvas.width, r2 = e2.canvas.height;
875
+ n2 === e2.lastW && r2 === e2.lastH || (e2.lastW = n2, e2.lastH = r2, "video" !== e2.mode && (emitEvent({ op: "resize", canvasId: e2.canvasId, w: n2, h: r2, dpr: dpr() }), ((_a = e2.recorder2d) == null ? void 0 : _a.keyframeUnsafe) && !e2.pixelSuppressed && suppressPixelCapture(e2), e2.pixelSuppressed || ((_b = e2.keyframes) == null ? void 0 : _b.takeKeyframe(t2)), (_c = e2.recorder2d) == null ? void 0 : _c.resetMaskedRegions()));
876
+ }
877
+ function collectMalformedSelectors(e2) {
878
+ if ("undefined" == typeof document) return [];
879
+ const t2 = [["maskTextSelector", e2.maskTextSelector], ["blockSelector", e2.blockSelector], ["unmaskSelector", e2.unmaskSelector]], n2 = [];
880
+ for (const [e3, r2] of t2) if (r2) try {
881
+ document.querySelector(r2);
882
+ } catch {
883
+ n2.push(e3);
884
+ }
885
+ return n2;
886
+ }
887
+ function derivePrivacySettings(e2) {
888
+ const nz = (e3) => e3 && e3.length > 0 ? e3 : void 0;
889
+ return { maskCanvasClass: e2.maskCanvasClass, maskTextClass: nz(e2.maskTextClass), maskTextSelector: nz(e2.maskTextSelector), blockSelector: nz(e2.blockSelector), unmaskSelector: nz(e2.unmaskSelector), maskCanvasText: e2.maskCanvasText, recordSsn: e2.recordSsn, recordCreditCardInfo: e2.recordCreditCardInfo, recordDob: e2.recordDob };
890
+ }
891
+ function deriveContentFlags(e2) {
892
+ return { recordSsn: e2.recordSsn, recordCreditCardInfo: e2.recordCreditCardInfo, recordDob: e2.recordDob };
893
+ }
894
+ function classify(e2) {
895
+ return ge ? k(e2, ge.privacySettings) : "normal";
896
+ }
897
+ function makeTextRedactor(e2) {
898
+ if ("redact" === e2) return (e3) => b(e3, "redact", {});
899
+ if ("normal" === e2 && (function contentDetectionActive() {
900
+ const e3 = ge == null ? void 0 : ge.contentFlags;
901
+ return !!e3 && (false === e3.recordCreditCardInfo || false === e3.recordSsn || false === e3.recordDob);
902
+ })()) {
903
+ const e3 = ge.contentFlags;
904
+ return (t2) => b(t2, "normal", e3);
905
+ }
906
+ }
907
+ function emitMasked(e2, t2) {
908
+ const n2 = ge ? L(e2, ge.privacySettings) : void 0, r2 = { op: "masked", canvasId: t2 };
909
+ n2 && (r2.reason = n2), emitEvent(r2), ge == null ? void 0 : ge.suppressed.add(e2);
910
+ }
911
+ function escalateRedactIfPixelText(e2, t2) {
912
+ return "redact" !== e2 ? e2 : "webgl" === t2 || "webgl2" === t2 || "experimental-webgl" === t2 || "webgpu" === t2 || "worker" === t2 ? (noteOnce(`redact canvas with pixel-only text (${t2}) — escalated to suppress`), "suppress") : e2;
913
+ }
914
+ function resolveCanvasId(e2) {
915
+ return new Promise((t2) => {
916
+ let n2 = 0;
917
+ const attempt = () => {
918
+ if (!ge || ge.stopped) return t2(null);
919
+ let r2 = -1;
920
+ try {
921
+ r2 = ge.deps.mirror.getId(e2);
922
+ } catch {
923
+ }
924
+ return "number" == typeof r2 && r2 >= 0 ? t2(String(r2)) : ++n2 > 30 ? (noteOnce("canvas never received an rrweb mirror id — not recorded"), t2(null)) : void setTimeout(attempt, 300);
925
+ };
926
+ attempt();
927
+ });
928
+ }
929
+ function rearmCanvas(e2) {
930
+ const t2 = ge;
931
+ t2 && !t2.stopped && (t2.handled.delete(e2), t2.suppressed.delete(e2), considerCanvas(e2));
932
+ }
933
+ function reevaluateAllMasking() {
934
+ const e2 = ge;
935
+ if (e2 && !e2.stopped) {
936
+ for (const t2 of [...e2.controllers.values()]) {
937
+ if (t2.stopped) continue;
938
+ const n2 = t2.canvas, r2 = k(n2, e2.privacySettings);
939
+ if ("suppress" === r2) {
940
+ const r3 = t2.canvasId;
941
+ teardownController(t2), e2.handled.add(n2), emitMasked(n2, r3);
942
+ continue;
943
+ }
944
+ r2 !== t2.privacyMode && (teardownController(t2), n2.isConnected && rearmCanvas(n2));
945
+ }
946
+ for (const t2 of [...e2.suppressed]) {
947
+ if (!t2.isConnected) {
948
+ e2.suppressed.delete(t2);
949
+ continue;
950
+ }
951
+ "suppress" !== k(t2, e2.privacySettings) && rearmCanvas(t2);
952
+ }
953
+ }
954
+ }
955
+ function onCanvasRemoved(e2) {
956
+ const t2 = ge;
957
+ if (!t2 || t2.stopped) return;
958
+ if (e2.isConnected) return;
959
+ const n2 = t2.controllers.get(e2);
960
+ if (n2) {
961
+ const e3 = n2.canvasId;
962
+ teardownController(n2), emitEvent({ op: "stop", canvasId: e3 });
963
+ }
964
+ t2.handled.delete(e2), t2.suppressed.delete(e2);
965
+ }
966
+ function considerCanvas(e2) {
967
+ const t2 = ge;
968
+ if (!t2 || t2.stopped || t2.handled.has(e2)) return;
969
+ if (!e2.isConnected) return C(e2), void noteOnce("disconnected canvas skipped — recorded only if attached to the document");
970
+ const n2 = classify(e2);
971
+ if ("suppress" === n2) return t2.handled.add(e2), void resolveCanvasId(e2).then((t3) => {
972
+ null != t3 && emitMasked(e2, t3);
973
+ });
974
+ const r2 = (function getWorkerForCanvas(e3) {
975
+ return le.get(e3);
976
+ })(e2), s2 = x(e2);
977
+ (r2 || s2) && (t2.handled.add(e2), resolveCanvasId(e2).then((t3) => {
978
+ if (null != t3 && ge && !ge.stopped) if (r2) {
979
+ if ("redact" === n2) return noteOnce("redact worker/offscreen canvas — escalated to suppress (no DOM to redact)"), void emitMasked(e2, t3);
980
+ !(async function buildWorkerController(e3, t4, n3) {
981
+ const r3 = await (function pingWorkerShim(e4, t5 = 500) {
982
+ return new Promise((n4) => {
983
+ let r4 = false;
984
+ const finish = (t6) => {
985
+ r4 || (r4 = true, clearTimeout(o3), e4.removeEventListener("message", onMsg), n4(t6));
986
+ }, onMsg = (e5) => {
987
+ var _a;
988
+ "sf-record-pong" === ((_a = e5.data) == null ? void 0 : _a.type) && finish(true);
989
+ }, o3 = setTimeout(() => finish(false), t5);
990
+ e4.addEventListener("message", onMsg);
991
+ try {
992
+ e4.postMessage({ type: "sf-record-ping" });
993
+ } catch {
994
+ finish(false);
995
+ }
996
+ });
997
+ })(n3), o2 = ge;
998
+ if (!o2 || o2.stopped) return;
999
+ if (r3) {
1000
+ const r4 = baseController(e3, t4, "worker", "commands");
1001
+ let s4;
1002
+ r4.worker = n3, r4.workerDone = new Promise((e4) => {
1003
+ s4 = e4;
1004
+ });
1005
+ const onMsg = (e4) => {
1006
+ const t5 = e4.data;
1007
+ if ("sf-record-done" === (t5 == null ? void 0 : t5.type)) s4(t5);
1008
+ else if ("sf-record-noctx" === (t5 == null ? void 0 : t5.type)) {
1009
+ if (!r4.stopped && "commands" === r4.mode && !r4.video && !r4.mediaRecorder) {
1010
+ const e5 = VideoCapture.supported() && tryAcquireVideoSlot(r4);
1011
+ if (VideoCapture.supported() && !e5 && noteOnce(`video-encoder cap (${(ge == null ? void 0 : ge.budgets.maxConcurrentVideo) ?? 4}) reached — worker canvas kept on keyframes`), e5) {
1012
+ r4.mode = "video", emitEvent({ op: "mode", canvasId: r4.canvasId, mode: "video", reason: "worker-no-2d-context" });
1013
+ const e6 = makeVideo(r4, true);
1014
+ r4.video = e6, e6.start().then((e7) => {
1015
+ e7 || r4.stopped || (r4.video = null, releaseVideoSlot(r4), r4.mode = "none", emitEvent({ op: "mode", canvasId: r4.canvasId, mode: "none", reason: "video-start-failed" }));
1016
+ });
1017
+ } else !VideoCapture.supported() && tryStartMediaRecorder(r4, "worker-no-2d-context") || (r4.mode = "none", emitEvent({ op: "mode", canvasId: r4.canvasId, mode: "none", reason: "worker-no-2d-context" }));
1018
+ }
1019
+ } else "sf-record-batch" === (t5 == null ? void 0 : t5.type) && (sendFrame(r4, "commands", { codec: "sfc-bin-1", compression: "deflate" }, new Uint8Array(t5.deflated), t5.tMs), r4.governor.addBytes(t5.deflated.byteLength));
1020
+ };
1021
+ n3.addEventListener("message", onMsg), r4.removeWorkerListener = () => n3.removeEventListener("message", onMsg);
1022
+ try {
1023
+ n3.postMessage({ type: "sf-record-start", contentFlags: o2.contentFlags });
1024
+ } catch {
1025
+ noteOnce("worker postMessage failed — worker canvas not recorded");
1026
+ }
1027
+ return o2.controllers.set(e3, r4), void emitStart(r4);
1028
+ }
1029
+ const s3 = baseController(e3, t4, "worker", "none");
1030
+ if (o2.controllers.set(e3, s3), VideoCapture.supported() && tryAcquireVideoSlot(s3)) {
1031
+ s3.mode = "video";
1032
+ const e4 = makeVideo(s3, true);
1033
+ s3.video = e4, e4.start().then((e5) => {
1034
+ e5 || s3.stopped || (s3.video = null, releaseVideoSlot(s3), s3.mode = "none", emitEvent({ op: "mode", canvasId: s3.canvasId, mode: "none", reason: "video-start-failed" }));
1035
+ });
1036
+ } else VideoCapture.supported() ? noteOnce(`video-encoder cap (${(ge == null ? void 0 : ge.budgets.maxConcurrentVideo) ?? 4}) reached — worker placeholder canvas not captured`) : tryStartMediaRecorder(s3, "worker-no-shim") || noteOnce("worker canvas without shim and no usable video backend — not captured");
1037
+ emitStart(s3);
1038
+ })(e2, t3, r2);
1039
+ } else if ("2d" === s2.type) build2DController(e2, t3, null, n2);
1040
+ else if ("webgl" === s2.type || "webgl2" === s2.type || "experimental-webgl" === s2.type) {
1041
+ const r3 = escalateRedactIfPixelText(n2, s2.type);
1042
+ if ("suppress" === r3) return void emitMasked(e2, t3);
1043
+ !(function buildGLController(e3, t4, n3, r4, o2 = "normal") {
1044
+ const s3 = ge;
1045
+ if (!s3 || s3.stopped) return;
1046
+ const a2 = "experimental-webgl" === n3 ? "webgl" : n3;
1047
+ if ("suppress" === escalateRedactIfPixelText(o2, a2)) return void emitMasked(e3, t4);
1048
+ const i2 = baseController(e3, t4, a2, "commands", o2);
1049
+ i2.encoder = new g();
1050
+ const c2 = makeCommandSink(i2);
1051
+ let d2;
1052
+ d2 = attachGLRecorder(e3, n3, c2, now), d2 || (i2.mode = "none", noteOnce("GL context not reachable — nothing recorded"));
1053
+ i2.recorderGL = d2, i2.keyframes = makeKeyframes(i2), installGLContextLossHandling(i2), s3.controllers.set(e3, i2), emitStart(i2), maybeInitialKeyframe(i2);
1054
+ })(e2, t3, s2.type, 0, r3);
1055
+ } else if ("webgpu" === s2.type) {
1056
+ const r3 = escalateRedactIfPixelText(n2, "webgpu");
1057
+ if ("suppress" === r3) return void emitMasked(e2, t3);
1058
+ !(function buildGPUController(e3, t4, n3 = "normal") {
1059
+ const r4 = ge;
1060
+ if (!r4 || r4.stopped) return;
1061
+ if ("suppress" === escalateRedactIfPixelText(n3, "webgpu")) return void emitMasked(e3, t4);
1062
+ const s3 = baseController(e3, t4, "webgpu", "commands", n3);
1063
+ s3.encoder = new g();
1064
+ const a2 = (function attachGPURecorder(e4, t5, n4) {
1065
+ if (te !== e4 || !Q) return null;
1066
+ ne = e4, nowFn = n4;
1067
+ const r5 = Q;
1068
+ if (Q = t5, r5 instanceof o) {
1069
+ for (const e5 of r5.ops) t5.onOp(e5);
1070
+ for (const e5 of r5.notes) t5.note(e5);
1071
+ }
1072
+ return { detach() {
1073
+ Q = null, ne = null, te = null;
1074
+ }, cpuMs: () => X };
1075
+ })(e3, makeCommandSink(s3), now);
1076
+ a2 || (s3.mode = "none", noteOnce("WebGPU recorder not armed for this canvas — nothing recorded"));
1077
+ s3.recorderGPU = a2, s3.keyframes = makeKeyframes(s3), (function installGPUContextLossHandling(e4) {
1078
+ setGPUDeviceLostNotifier((t5) => {
1079
+ var _a;
1080
+ if (!e4.stopped) if (t5) {
1081
+ if (e4.contextLost) return;
1082
+ e4.contextLost = true;
1083
+ try {
1084
+ flushBatch(e4, now());
1085
+ } catch {
1086
+ }
1087
+ emitEvent({ op: "context-lost", canvasId: e4.canvasId });
1088
+ } else {
1089
+ if (!e4.contextLost) return;
1090
+ e4.contextLost = false, emitEvent({ op: "context-restored", canvasId: e4.canvasId, w: e4.canvas.width, h: e4.canvas.height, dpr: dpr() }), e4.everDirty = true, markDirty(e4), (_a = e4.keyframes) == null ? void 0 : _a.onInteraction(now());
1091
+ }
1092
+ }), e4.removeContextLossListeners = () => setGPUDeviceLostNotifier(null);
1093
+ })(s3), r4.controllers.set(e3, s3), emitStart(s3), maybeInitialKeyframe(s3);
1094
+ })(e2, t3, r3);
1095
+ } else {
1096
+ const n3 = baseController(e2, t3, "unknown", "none");
1097
+ ge.controllers.set(e2, n3), emitStart(n3), noteOnce(`unsupported context type "${s2.type}" — not captured`);
1098
+ }
1099
+ }));
1100
+ }
1101
+ function build2DController(e2, t2, n2, r2 = "normal") {
1102
+ const o2 = ge;
1103
+ if (!o2 || o2.stopped) return;
1104
+ const s2 = baseController(e2, t2, "2d", "commands", r2);
1105
+ s2.encoder = new g();
1106
+ const a2 = makeCommandSink(s2);
1107
+ let i2 = n2;
1108
+ i2 ? i2.swapSink(a2) : i2 = w(e2, a2, now, "cas", encodeImage, { retainAssets: false }), i2 || (s2.mode = "none", noteOnce("canvas has no readable 2D context — nothing recorded")), i2 && (i2.textRedactor = makeTextRedactor(r2), i2.redactStyle = o2.redactStyle), s2.recorder2d = i2, s2.keyframes = makeKeyframes(s2), o2.controllers.set(e2, s2), emitStart(s2), maybeInitialKeyframe(s2);
1109
+ }
1110
+ function installGLContextLossHandling(e2) {
1111
+ const t2 = e2.canvas, onLost = (t3) => {
1112
+ try {
1113
+ t3.preventDefault();
1114
+ } catch {
1115
+ }
1116
+ if (!e2.stopped && !e2.contextLost) {
1117
+ e2.contextLost = true;
1118
+ try {
1119
+ flushBatch(e2, now());
1120
+ } catch {
1121
+ }
1122
+ emitEvent({ op: "context-lost", canvasId: e2.canvasId });
1123
+ }
1124
+ }, onRestored = () => {
1125
+ var _a, _b;
1126
+ if (e2.stopped || !e2.contextLost) return;
1127
+ try {
1128
+ ((_a = e2.recorderGL) == null ? void 0 : _a.rawCtx) && detachGLRecorderFromContext(e2.recorderGL.rawCtx);
1129
+ } catch {
1130
+ }
1131
+ const n2 = "webgl2" === e2.contextType ? "webgl2" : "webgl", r2 = attachGLRecorder(t2, n2, makeCommandSink(e2), now);
1132
+ e2.recorderGL = r2, e2.contextLost = false, emitEvent({ op: "context-restored", canvasId: e2.canvasId, w: t2.width, h: t2.height, dpr: dpr() }), e2.everDirty = true, markDirty(e2), (_b = e2.keyframes) == null ? void 0 : _b.onInteraction(now());
1133
+ };
1134
+ t2.addEventListener("webglcontextlost", onLost, false), t2.addEventListener("webglcontextrestored", onRestored, false), e2.removeContextLossListeners = () => {
1135
+ t2.removeEventListener("webglcontextlost", onLost, false), t2.removeEventListener("webglcontextrestored", onRestored, false);
1136
+ };
1137
+ }
1138
+ function onUntracked2D(e2) {
1139
+ const t2 = ge;
1140
+ if (!t2 || t2.stopped || t2.seenContexts.has(e2)) return;
1141
+ t2.seenContexts.add(e2);
1142
+ const n2 = e2.canvas;
1143
+ if (!(n2 instanceof HTMLCanvasElement)) return;
1144
+ if (!n2.isConnected) return;
1145
+ if (t2.handled.has(n2)) return;
1146
+ const r2 = classify(n2);
1147
+ if ("suppress" === r2) return t2.handled.add(n2), void resolveCanvasId(n2).then((e3) => {
1148
+ null != e3 && emitMasked(n2, e3);
1149
+ });
1150
+ t2.handled.add(n2);
1151
+ const s2 = E(e2, new o(), now, "cas", encodeImage, { retainAssets: false });
1152
+ resolveCanvasId(n2).then((t3) => {
1153
+ null != t3 && ge && !ge.stopped ? build2DController(n2, t3, s2, r2) : y(e2);
1154
+ });
1155
+ }
1156
+ function onUntrackedGL(e2) {
1157
+ const t2 = ge;
1158
+ if (!t2 || t2.stopped || t2.seenContexts.has(e2)) return;
1159
+ t2.seenContexts.add(e2);
1160
+ const n2 = e2.canvas;
1161
+ if (!(n2 instanceof HTMLCanvasElement)) return;
1162
+ if (!n2.isConnected) return;
1163
+ if (t2.handled.has(n2)) return;
1164
+ const r2 = classify(n2), s2 = "undefined" != typeof WebGL2RenderingContext && e2 instanceof WebGL2RenderingContext ? "webgl2" : "webgl";
1165
+ if ("suppress" === r2 || "suppress" === escalateRedactIfPixelText(r2, s2)) return t2.handled.add(n2), void resolveCanvasId(n2).then((e3) => {
1166
+ null != e3 && emitMasked(n2, e3);
1167
+ });
1168
+ t2.handled.add(n2);
1169
+ const a2 = s2, i2 = new o(), c2 = (function attachGLRecorderToContext(e3, t3, n3) {
1170
+ const r3 = new GLRecorder(t3, n3);
1171
+ return r3.rawCtx = e3, r3.bound = true, U.set(e3, r3), r3;
1172
+ })(e2, i2, now);
1173
+ resolveCanvasId(n2).then((t3) => {
1174
+ if (null == t3 || !ge || ge.stopped) return void detachGLRecorderFromContext(e2);
1175
+ const o2 = ge, s3 = baseController(n2, t3, a2, "commands", r2);
1176
+ s3.encoder = new g(), c2.swapSink(makeCommandSink(s3)), s3.recorderGL = c2, s3.keyframes = makeKeyframes(s3), installGLContextLossHandling(s3), o2.controllers.set(n2, s3), emitStart(s3), maybeInitialKeyframe(s3);
1177
+ });
1178
+ }
1179
+ function startCanvasRecording(t2) {
1180
+ if ("undefined" == typeof window || "undefined" == typeof document) return;
1181
+ if (ge) return;
1182
+ const n2 = t2.settings.maskCanvasClass || "sailfishSanitize", r2 = resolveDeviceBudgets();
1183
+ ge = { deps: t2, maskSelector: `.${n2}, [data-sf-mask]`, privacySettings: derivePrivacySettings(t2.settings), contentFlags: deriveContentFlags(t2.settings), redactStyle: u(f, t2.settings.canvasRedactStyle), budgets: r2, controllers: /* @__PURE__ */ new Map(), handled: /* @__PURE__ */ new WeakSet(), suppressed: /* @__PURE__ */ new Set(), preExisting: /* @__PURE__ */ new WeakSet(), seenContexts: /* @__PURE__ */ new WeakSet(), observer: null, removeListeners: [], totalBytes: 0, budgetExceeded: false, lastBudgetTickMs: 0, notes: /* @__PURE__ */ new Set(), stopped: false, videoSlots: new VideoSlotPool(r2.maxConcurrentVideo) };
1184
+ for (const e2 of collectMalformedSelectors(t2.settings)) noteOnce(`malformed canvas privacy selector "${e2}" is invalid and will not match — that privacy rule is disabled`);
1185
+ h(), (function installGLHooks() {
1186
+ if (W) return;
1187
+ W = true;
1188
+ const e2 = [];
1189
+ "undefined" != typeof WebGLRenderingContext && e2.push(WebGLRenderingContext.prototype), "undefined" != typeof WebGL2RenderingContext && e2.push(WebGL2RenderingContext.prototype);
1190
+ for (const t4 of e2) for (const e3 of Object.getOwnPropertyNames(t4)) {
1191
+ const n3 = Object.getOwnPropertyDescriptor(t4, e3);
1192
+ if (!n3 || "function" != typeof n3.value || "constructor" === e3) continue;
1193
+ if (V.test(e3) && !O.has(e3)) continue;
1194
+ const r3 = n3.value;
1195
+ t4[e3] = function(...t5) {
1196
+ const n4 = r3.apply(this, t5), o2 = U.get(this);
1197
+ return o2 ? o2.recordCall(e3, t5, n4) : K && K(this), n4;
1198
+ };
1199
+ }
1200
+ if ("undefined" == typeof HTMLCanvasElement) return;
1201
+ const t3 = HTMLCanvasElement.prototype.getContext;
1202
+ HTMLCanvasElement.prototype.getContext = function(e3, n3) {
1203
+ const r3 = t3.call(this, e3, n3);
1204
+ if (("webgl" === e3 || "webgl2" === e3 || "experimental-webgl" === e3) && r3 && $ && !U.has(r3)) {
1205
+ const e4 = new GLRecorder(new o(), $.now);
1206
+ e4.rawCtx = r3, U.set(r3, e4), H.set(this, e4);
1207
+ }
1208
+ return r3;
1209
+ };
1210
+ })(), (function installGPUHooks() {
1211
+ if (N) return;
1212
+ if (N = true, "undefined" == typeof navigator || !("gpu" in navigator)) return;
1213
+ const e2 = navigator.gpu;
1214
+ if (Object.defineProperty(navigator, "gpu", { configurable: true, get() {
1215
+ if (z || Q) {
1216
+ if (!ee) {
1217
+ ee = true;
1218
+ const t4 = intern(e2);
1219
+ emit({ t: nowFn(), op: "__gpuroot", args: [t4] });
1220
+ }
1221
+ return wrap(e2);
1222
+ }
1223
+ return e2;
1224
+ } }), "undefined" == typeof HTMLCanvasElement) return;
1225
+ const t3 = HTMLCanvasElement.prototype.getContext;
1226
+ HTMLCanvasElement.prototype.getContext = function(e3, n3) {
1227
+ const r3 = t3.call(this, e3, n3);
1228
+ if ("webgpu" === e3 && r3 && (z || Q)) {
1229
+ te = this;
1230
+ const e4 = re.has(r3), t4 = intern(r3);
1231
+ return e4 || emit({ t: nowFn(), op: "__gpuctx", args: [t4] }), wrap(r3);
1232
+ }
1233
+ return r3;
1234
+ };
1235
+ })(), (function installWorkerRelay() {
1236
+ if (!ue) {
1237
+ if (ue = true, "undefined" != typeof HTMLCanvasElement && "function" == typeof HTMLCanvasElement.prototype.transferControlToOffscreen) {
1238
+ const e2 = HTMLCanvasElement.prototype.transferControlToOffscreen;
1239
+ HTMLCanvasElement.prototype.transferControlToOffscreen = function() {
1240
+ const t3 = e2.call(this);
1241
+ return de.set(t3, this), t3;
1242
+ };
1243
+ }
1244
+ if ("undefined" != typeof Worker) {
1245
+ const e2 = Worker.prototype.postMessage;
1246
+ Worker.prototype.postMessage = function(t3, n3) {
1247
+ const r3 = Array.isArray(n3) ? n3 : n3 == null ? void 0 : n3.transfer;
1248
+ if (r3) for (const e3 of r3) {
1249
+ const t4 = e3 && "object" == typeof e3 ? de.get(e3) : void 0;
1250
+ t4 && !le.has(t4) && (le.set(t4, this), fe == null ? void 0 : fe(t4, this));
1251
+ }
1252
+ return e2.apply(this, [t3, n3]);
1253
+ };
1254
+ }
1255
+ }
1256
+ })(), p({ now, assetMode: "cas", encodeImage, retainAssets: false }), setGLAutoAttach({ now }), setGPUAutoAttach({ now }), I((e2) => {
1257
+ queueMicrotask(() => considerCanvas(e2));
1258
+ }), T(onUntracked2D), setUntrackedGLContextNotifier(onUntrackedGL), setWorkerAssociationNotifier((e2) => considerCanvas(e2));
1259
+ globalThis.__sfDrawSite = (e2, t3) => (e2 && "object" == typeof e2 && (m(e2, t3) || (function noteGLPendingSiteId(e3, t4) {
1260
+ const n3 = U.get(e3);
1261
+ return !!n3 && (n3.pendingSiteId = t4, true);
1262
+ })(e2, t3)), e2), e({ canvasIdFor: (e2) => {
1263
+ var _a;
1264
+ return ((_a = ge == null ? void 0 : ge.controllers.get(e2)) == null ? void 0 : _a.canvasId) ?? null;
1265
+ }, emitHit: (e2) => emitEvent(e2), now });
1266
+ const onInteraction = () => {
1267
+ var _a, _b, _c;
1268
+ const e2 = ge;
1269
+ if (!e2 || e2.stopped) return;
1270
+ const t3 = now();
1271
+ for (const n3 of e2.controllers.values()) n3.stopped || ("video" === n3.mode ? ((_a = n3.video) == null ? void 0 : _a.onInteraction(t3), (_b = n3.mediaRecorder) == null ? void 0 : _b.onInteraction(t3)) : (_c = n3.keyframes) == null ? void 0 : _c.onInteraction(t3));
1272
+ };
1273
+ window.addEventListener("pointerdown", onInteraction, { capture: true, passive: true }), window.addEventListener("keydown", onInteraction, { capture: true, passive: true }), ge.removeListeners.push(() => {
1274
+ window.removeEventListener("pointerdown", onInteraction, { capture: true }), window.removeEventListener("keydown", onInteraction, { capture: true });
1275
+ });
1276
+ const s2 = new MutationObserver((e2) => {
1277
+ let t3 = false;
1278
+ for (const n3 of e2) "attributes" !== n3.type ? (n3.addedNodes.forEach((e3) => {
1279
+ e3 instanceof Element && (e3 instanceof HTMLCanvasElement ? considerCanvas(e3) : e3.querySelectorAll("canvas").forEach((e4) => considerCanvas(e4)));
1280
+ }), n3.removedNodes.forEach((e3) => {
1281
+ e3 instanceof Element && (e3 instanceof HTMLCanvasElement ? onCanvasRemoved(e3) : e3.querySelectorAll("canvas").forEach((e4) => onCanvasRemoved(e4)));
1282
+ })) : t3 = true;
1283
+ t3 && reevaluateAllMasking();
1284
+ });
1285
+ s2.observe(document.documentElement, { childList: true, subtree: true, attributes: true }), ge.observer = s2, document.querySelectorAll("canvas").forEach((e2) => {
1286
+ ge.preExisting.add(e2), considerCanvas(e2);
1287
+ });
1288
+ }
1289
+ function teardownController(e2) {
1290
+ var _a, _b, _c, _d, _e, _f, _g;
1291
+ if (e2.stopped) ge == null ? void 0 : ge.controllers.delete(e2.canvas);
1292
+ else {
1293
+ e2.stopped = true;
1294
+ try {
1295
+ null !== e2.flushTimer && (clearTimeout(e2.flushTimer), e2.flushTimer = null);
1296
+ } catch {
1297
+ }
1298
+ try {
1299
+ (_a = e2.removeContextLossListeners) == null ? void 0 : _a.call(e2);
1300
+ } catch {
1301
+ }
1302
+ e2.removeContextLossListeners = null;
1303
+ try {
1304
+ (_b = e2.video) == null ? void 0 : _b.abort();
1305
+ } catch {
1306
+ }
1307
+ e2.video = null;
1308
+ try {
1309
+ (_c = e2.mediaRecorder) == null ? void 0 : _c.abort();
1310
+ } catch {
1311
+ }
1312
+ e2.mediaRecorder = null, releaseVideoSlot(e2);
1313
+ try {
1314
+ (_d = e2.keyframes) == null ? void 0 : _d.dispose();
1315
+ } catch {
1316
+ }
1317
+ if (e2.keyframes = null, e2.worker) try {
1318
+ e2.worker.postMessage({ type: "sf-record-stop" });
1319
+ } catch {
1320
+ }
1321
+ try {
1322
+ (_e = e2.removeWorkerListener) == null ? void 0 : _e.call(e2);
1323
+ } catch {
1324
+ }
1325
+ e2.removeWorkerListener = null;
1326
+ try {
1327
+ e2.recorder2d && y(e2.recorder2d.rawCtx);
1328
+ } catch {
1329
+ }
1330
+ try {
1331
+ ((_f = e2.recorderGL) == null ? void 0 : _f.rawCtx) && detachGLRecorderFromContext(e2.recorderGL.rawCtx);
1332
+ } catch {
1333
+ }
1334
+ try {
1335
+ (_g = e2.recorderGPU) == null ? void 0 : _g.detach();
1336
+ } catch {
1337
+ }
1338
+ ge == null ? void 0 : ge.controllers.delete(e2.canvas);
1339
+ }
1340
+ }
1341
+ function settleOrTimeout(e2, t2) {
1342
+ return Promise.race([e2.catch(() => {
1343
+ }), new Promise((e3) => setTimeout(e3, t2))]);
1344
+ }
1345
+ async function stopController(e2, t2) {
1346
+ var _a, _b, _c;
1347
+ if (!e2.stopped) {
1348
+ e2.stopped = true;
1349
+ try {
1350
+ (_a = e2.removeContextLossListeners) == null ? void 0 : _a.call(e2);
1351
+ } catch {
1352
+ }
1353
+ if (e2.removeContextLossListeners = null, null !== e2.flushTimer && (clearTimeout(e2.flushTimer), e2.flushTimer = null), e2.worker && e2.workerDone) {
1354
+ try {
1355
+ e2.worker.postMessage({ type: "sf-record-stop" });
1356
+ } catch {
1357
+ }
1358
+ const t3 = await Promise.race([e2.workerDone, new Promise((e3) => setTimeout(() => e3(null), 5e3))]);
1359
+ (_b = e2.removeWorkerListener) == null ? void 0 : _b.call(e2), t3 && await (async function convertWorkerResult(e3, t4) {
1360
+ for (const e4 of t4.notes ?? []) noteOnce(`worker: ${e4}`);
1361
+ for (const n2 of t4.batches ?? []) try {
1362
+ sendFrame(e3, "commands", { codec: "sfc-bin-1", compression: "deflate" }, await a(n2));
1363
+ } catch {
1364
+ }
1365
+ for (const n2 of t4.assets ?? []) try {
1366
+ if (n2.bitmap) {
1367
+ const t5 = n2.w ?? n2.bitmap.width, r2 = n2.h ?? n2.bitmap.height, o2 = await encodeBitmap(n2.bitmap, 0.85, true);
1368
+ o2.bytes && sendFrame(e3, "asset", { assetId: n2.id, format: "webp", w: t5, h: r2 }, o2.bytes);
1369
+ } else if (n2.imageData) {
1370
+ const t5 = n2.imageData, r2 = await a(new Uint8Array(t5.data.buffer, t5.data.byteOffset, t5.data.byteLength));
1371
+ sendFrame(e3, "asset", { assetId: n2.id, format: "imagedata", w: t5.width, h: t5.height }, r2);
1372
+ }
1373
+ } catch {
1374
+ }
1375
+ })(e2, t3), e2.video && await e2.video.stop(), e2.mediaRecorder && await e2.mediaRecorder.stop();
1376
+ } else flushBatch(e2), e2.video && await e2.video.stop(), e2.mediaRecorder && await e2.mediaRecorder.stop(), e2.keyframes && (e2.everDirty && e2.keyframes.takeKeyframe(t2), await e2.keyframes.stop(t2)), e2.recorder2d && (y(e2.recorder2d.rawCtx), flushBatch(e2), await settleOrTimeout(e2.recorder2d.settle(), 5e3)), e2.recorderGL && (e2.recorderGL.rawCtx && detachGLRecorderFromContext(e2.recorderGL.rawCtx), await settleOrTimeout(e2.recorderGL.settle(), 5e3)), (_c = e2.recorderGPU) == null ? void 0 : _c.detach(), await e2.flushChain;
1377
+ releaseVideoSlot(e2), emitEvent({ op: "stop", canvasId: e2.canvasId });
1378
+ }
1379
+ }
1380
+ async function stopCanvasRecording() {
1381
+ var _a;
1382
+ const e2 = ge;
1383
+ if (!e2 || e2.stopped) return;
1384
+ e2.stopped = true, p(null), setGLAutoAttach(null), setGPUAutoAttach(null), setGPUDeviceLostNotifier(null), I(null), T(null), setUntrackedGLContextNotifier(null), setWorkerAssociationNotifier(null), delete globalThis.__sfDrawSite, t(), (_a = e2.observer) == null ? void 0 : _a.disconnect();
1385
+ for (const t2 of e2.removeListeners) try {
1386
+ t2();
1387
+ } catch {
1388
+ }
1389
+ const n2 = now();
1390
+ await Promise.all([...e2.controllers.values()].map((e3) => stopController(e3, n2).catch(() => {
1391
+ }))), v(), (function pruneUnboundGLRecorders() {
1392
+ for (const [e3, t2] of H) t2.bound || (U.delete(t2.rawCtx), H.delete(e3));
1393
+ })(), (function pruneUnboundGPURecorders() {
1394
+ Q instanceof o && !ne && (te || (Q = null));
1395
+ })(), (function terminateImgEncoder() {
1396
+ P && (P.terminate(), P = null);
1397
+ for (const [e3, t2] of B) B.delete(e3), t2({ size: 0 });
1398
+ })(), ge = null;
1399
+ }
1400
+ async function flushAllCanvas() {
1401
+ const e2 = ge;
1402
+ if (!e2 || e2.stopped) return;
1403
+ now();
1404
+ const t2 = [];
1405
+ for (const n2 of e2.controllers.values()) if (!n2.stopped) {
1406
+ try {
1407
+ flushBatch(n2);
1408
+ } catch {
1409
+ }
1410
+ n2.video && t2.push(n2.video.flush().catch(() => {
1411
+ })), n2.mediaRecorder && t2.push(n2.mediaRecorder.flush().catch(() => {
1412
+ })), t2.push(n2.flushChain.catch(() => {
1413
+ }));
1414
+ }
1415
+ await Promise.all(t2).catch(() => {
1416
+ });
1417
+ }
1418
+ function isCanvasRecordingActive() {
1419
+ return null != ge && !ge.stopped;
1420
+ }
1421
+ const we = { initState(e2) {
1422
+ ge = { deps: e2, maskSelector: ".sailfishSanitize, [data-sf-mask]", privacySettings: derivePrivacySettings(e2.settings), contentFlags: deriveContentFlags(e2.settings), redactStyle: u(f, e2.settings.canvasRedactStyle), budgets: resolveDeviceBudgets(), controllers: /* @__PURE__ */ new Map(), handled: /* @__PURE__ */ new WeakSet(), suppressed: /* @__PURE__ */ new Set(), preExisting: /* @__PURE__ */ new WeakSet(), seenContexts: /* @__PURE__ */ new WeakSet(), observer: null, removeListeners: [], totalBytes: 0, budgetExceeded: false, lastBudgetTickMs: 0, notes: /* @__PURE__ */ new Set(), stopped: false, videoSlots: new VideoSlotPool(resolveDeviceBudgets().maxConcurrentVideo) };
1423
+ }, addController(e2, t2, n2 = "normal") {
1424
+ const r2 = baseController(e2, t2, "2d", "commands", n2);
1425
+ return ge.controllers.set(e2, r2), r2;
1426
+ }, classify: (e2) => classify(e2), makeTextRedactor: (e2) => makeTextRedactor(e2), reevaluate() {
1427
+ reevaluateAllMasking();
1428
+ }, escalate: (e2, t2) => escalateRedactIfPixelText(e2, t2), isTracked: (e2) => !!(ge == null ? void 0 : ge.controllers.get(e2)), isSuppressed: (e2) => !!(ge == null ? void 0 : ge.suppressed.has(e2)), markSuppressed(e2) {
1429
+ ge == null ? void 0 : ge.handled.add(e2), ge == null ? void 0 : ge.suppressed.add(e2);
1430
+ }, controllerPrivacy: (e2) => ({ mode: e2.privacyMode, hasKeyframes: null != e2.keyframes }), tryDemote(e2) {
1431
+ maybeDemote(e2);
1432
+ }, emitResize(e2) {
1433
+ maybeEmitResize(e2, now());
1434
+ }, build2DWithFakeRecorder(e2, t2, n2) {
1435
+ const r2 = { swapSink: () => {
1436
+ }, textRedactor: void 0, rawCtx: {} };
1437
+ return build2DController(e2, t2, r2, n2), { ctl: ge == null ? void 0 : ge.controllers.get(e2), redactor: r2.textRedactor };
1438
+ }, demote(e2, t2 = "bytes") {
1439
+ demote(e2, t2);
1440
+ }, teardown(e2) {
1441
+ teardownController(e2);
1442
+ }, slotsInUse: () => (ge == null ? void 0 : ge.videoSlots.inUse) ?? -1, controllerHasSlot: (e2) => e2.hasVideoSlot, reset() {
1443
+ ge = null;
1444
+ } };
1445
+ export {
1446
+ ye as MAX_CONCURRENT_VIDEO_CANVASES,
1447
+ VideoSlotPool,
1448
+ we as __canvasManagerTestHooks,
1449
+ collectMalformedSelectors,
1450
+ decayBytes,
1451
+ flushAllCanvas,
1452
+ isCanvasRecordingActive,
1453
+ settleOrTimeout,
1454
+ startCanvasRecording,
1455
+ stopCanvasRecording
1456
+ };