@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,1440 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
6
+ const e = require("./index-BIj4l3CV.js"), t = require("./patch2d-9voowhJ_.js");
7
+ function createBlobWorker(e2) {
8
+ const t2 = new Blob([e2], { type: "application/javascript" }), n2 = URL.createObjectURL(t2), r2 = new Worker(n2);
9
+ return URL.revokeObjectURL(n2), r2;
10
+ }
11
+ let n = null, r = 1;
12
+ const o = /* @__PURE__ */ new Map();
13
+ function encodeBitmap(e2, t2, s2 = false) {
14
+ const a2 = r++;
15
+ return new Promise((r2) => {
16
+ o.set(a2, r2), (function getImgWorker() {
17
+ return n || (n = 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"), n.onmessage = (e3) => {
18
+ const t3 = o.get(e3.data.id);
19
+ t3 && (o.delete(e3.data.id), t3({ size: e3.data.size, bytes: e3.data.bytes }));
20
+ }), n;
21
+ })().postMessage({ id: a2, bitmap: e2, quality: t2, wantBytes: s2 }, [e2]);
22
+ });
23
+ }
24
+ class VideoEncoderClient {
25
+ constructor(e2) {
26
+ __publicField(this, "worker");
27
+ __publicField(this, "configured", false);
28
+ __publicField(this, "doneResolve", null);
29
+ __publicField(this, "flushResolve", null);
30
+ __publicField(this, "configResolve", null);
31
+ 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) => {
32
+ var _a, _b, _c, _d;
33
+ const t2 = e3.data;
34
+ switch (t2.type) {
35
+ case "configured":
36
+ this.configured = true, (_a = this.configResolve) == null ? void 0 : _a.call(this, true), this.configResolve = null;
37
+ break;
38
+ case "config-failed":
39
+ (_b = this.configResolve) == null ? void 0 : _b.call(this, false), this.configResolve = null;
40
+ break;
41
+ case "decoder-config":
42
+ this.events.onDecoderConfig(t2.codec, t2.description ?? null);
43
+ break;
44
+ case "chunk":
45
+ this.events.onChunk(t2.data, t2.timestampUs, t2.key);
46
+ break;
47
+ case "error":
48
+ this.events.onError(String(t2.message));
49
+ break;
50
+ case "done":
51
+ (_c = this.doneResolve) == null ? void 0 : _c.call(this), this.doneResolve = null;
52
+ break;
53
+ case "flushed":
54
+ (_d = this.flushResolve) == null ? void 0 : _d.call(this), this.flushResolve = null;
55
+ }
56
+ };
57
+ }
58
+ get isConfigured() {
59
+ return this.configured;
60
+ }
61
+ configure(e2) {
62
+ return new Promise((t2) => {
63
+ this.configResolve = t2, this.worker.postMessage({ type: "config", ...e2 });
64
+ });
65
+ }
66
+ encodeFrame(e2, t2) {
67
+ this.worker.postMessage({ type: "frame", frame: e2, key: t2 }, [e2]);
68
+ }
69
+ flush(e2 = 3e3) {
70
+ return new Promise((t2) => {
71
+ const n2 = setTimeout(() => {
72
+ this.flushResolve = null, t2();
73
+ }, e2);
74
+ this.flushResolve = () => {
75
+ clearTimeout(n2), t2();
76
+ };
77
+ try {
78
+ this.worker.postMessage({ type: "flush" });
79
+ } catch {
80
+ clearTimeout(n2), this.flushResolve = null, t2();
81
+ }
82
+ });
83
+ }
84
+ stop(e2 = 3e3) {
85
+ return new Promise((t2) => {
86
+ const n2 = setTimeout(() => {
87
+ this.doneResolve = null, t2();
88
+ }, e2);
89
+ this.doneResolve = () => {
90
+ clearTimeout(n2), t2();
91
+ };
92
+ try {
93
+ this.worker.postMessage({ type: "stop" });
94
+ } catch {
95
+ clearTimeout(n2), this.doneResolve = null, t2();
96
+ }
97
+ });
98
+ }
99
+ terminate() {
100
+ this.worker.terminate();
101
+ }
102
+ }
103
+ const s = { maxBytesPerSec: 524288, sustainMs: 3e3, maxVideoDrawsPerSec: 2, maxOpsPerFrame: 5e3 };
104
+ class CanvasGovernor {
105
+ constructor(e2, t2) {
106
+ __publicField(this, "thresholds");
107
+ __publicField(this, "byteSamples", []);
108
+ __publicField(this, "videoDraws", []);
109
+ __publicField(this, "frameT", NaN);
110
+ __publicField(this, "frameOps", 0);
111
+ __publicField(this, "opsExceeded", false);
112
+ this.now = e2, this.thresholds = { ...s, ...t2 };
113
+ }
114
+ addBytes(e2) {
115
+ const t2 = this.now();
116
+ this.byteSamples.push({ t: t2, n: e2 }), this.pruneBytes(t2);
117
+ }
118
+ addVideoDraw() {
119
+ const e2 = this.now();
120
+ this.videoDraws.push(e2), this.pruneVideo(e2);
121
+ }
122
+ addOp(e2) {
123
+ e2 !== this.frameT && (this.frameT = e2, this.frameOps = 0), ++this.frameOps > this.thresholds.maxOpsPerFrame && (this.opsExceeded = true);
124
+ }
125
+ shouldDemote() {
126
+ if (this.opsExceeded) return "ops";
127
+ const e2 = this.now();
128
+ if (this.pruneVideo(e2), this.videoDraws.length > this.thresholds.maxVideoDrawsPerSec) return "video-source";
129
+ this.pruneBytes(e2);
130
+ let t2 = 0;
131
+ for (const e3 of this.byteSamples) t2 += e3.n;
132
+ return t2 > this.thresholds.maxBytesPerSec * this.thresholds.sustainMs / 1e3 ? "bytes" : null;
133
+ }
134
+ pruneBytes(e2) {
135
+ const t2 = e2 - this.thresholds.sustainMs;
136
+ for (; this.byteSamples.length > 0 && this.byteSamples[0].t < t2; ) this.byteSamples.shift();
137
+ }
138
+ pruneVideo(e2) {
139
+ const t2 = e2 - 1e3;
140
+ for (; this.videoDraws.length > 0 && this.videoDraws[0] < t2; ) this.videoDraws.shift();
141
+ }
142
+ }
143
+ class KeyframeCapturer {
144
+ constructor(e2, t2, n2, r2, o2 = () => []) {
145
+ __publicField(this, "scratch", null);
146
+ __publicField(this, "scratchCtx", null);
147
+ __publicField(this, "lastKeyframe", -1 / 0);
148
+ __publicField(this, "dirtySinceKeyframe", false);
149
+ __publicField(this, "interactionRequested", false);
150
+ __publicField(this, "pending", []);
151
+ __publicField(this, "stopped", false);
152
+ this.canvas = e2, this.snapshotState = t2, this.emit = n2, this.note = r2, this.getMaskedRegions = o2;
153
+ }
154
+ onInteraction(e2) {
155
+ e2 - this.lastKeyframe >= 250 && (this.interactionRequested = true);
156
+ }
157
+ initialKeyframe(e2) {
158
+ if (this.stopped) return false;
159
+ if (!this.canvas.width || !this.canvas.height) return false;
160
+ const t2 = this.pending.length;
161
+ return this.takeKeyframe(e2), this.pending.length > t2;
162
+ }
163
+ afterRender(e2) {
164
+ this.dirtySinceKeyframe = true, (this.interactionRequested && (this.interactionRequested = false, e2 - this.lastKeyframe >= 250) || e2 - this.lastKeyframe >= 4e3) && this.takeKeyframe(e2);
165
+ }
166
+ takeKeyframe(e2) {
167
+ if (this.stopped) return;
168
+ this.lastKeyframe = e2, this.dirtySinceKeyframe = false;
169
+ const n2 = this.snapshotState();
170
+ this.scratch || (this.scratch = document.createElement("canvas"), this.scratchCtx = this.scratch.getContext("2d"), this.scratchCtx && t.ignore2DContext(this.scratchCtx));
171
+ const r2 = this.scratch, o2 = this.scratchCtx;
172
+ if (!o2) return;
173
+ r2.width !== this.canvas.width || r2.height !== this.canvas.height ? (r2.width = this.canvas.width, r2.height = this.canvas.height) : o2.clearRect(0, 0, r2.width, r2.height);
174
+ try {
175
+ o2.drawImage(this.canvas, 0, 0);
176
+ } catch {
177
+ return;
178
+ }
179
+ const s2 = this.getMaskedRegions();
180
+ if (s2.length > 0) {
181
+ o2.save(), o2.setTransform(1, 0, 0, 1, 0, 0), o2.fillStyle = t.REDACTION_COLOR;
182
+ for (const e3 of s2) o2.fillRect(e3.x, e3.y, e3.w, e3.h);
183
+ o2.restore();
184
+ }
185
+ const a2 = r2.width, i2 = r2.height, c2 = createImageBitmap(r2).then(async (t2) => {
186
+ const r3 = await encodeBitmap(t2, 0.9, true);
187
+ r3.bytes && r3.bytes.byteLength > 0 && this.emit({ tMs: e2, w: a2, h: i2, state: n2, bytes: r3.bytes });
188
+ }).catch((e3) => this.note(`keyframe encode failed: ${e3.message}`));
189
+ this.pending.push(c2);
190
+ }
191
+ async stop(e2) {
192
+ this.dirtySinceKeyframe && this.takeKeyframe(e2), this.stopped = true, await Promise.all(this.pending);
193
+ }
194
+ dispose() {
195
+ if (this.stopped = true, this.scratch) try {
196
+ this.scratch.width = 0, this.scratch.height = 0;
197
+ } catch {
198
+ }
199
+ this.scratch = null, this.scratchCtx = null;
200
+ }
201
+ }
202
+ const a = /^create[A-Z]/, i = /* @__PURE__ */ new Set(["getUniformLocation", "getExtension"]), c = /^(get(?!Extension$|UniformLocation$)|is[A-Z]|check|read|finish$|flush$)/;
203
+ let d = false;
204
+ const l = /* @__PURE__ */ new WeakMap();
205
+ let u = null;
206
+ function texSourceToImageData(e2) {
207
+ if ("undefined" != typeof ImageData && e2 instanceof ImageData) return e2;
208
+ const n2 = e2, r2 = Number(n2.naturalWidth || n2.width) || 0, o2 = Number(n2.naturalHeight || n2.height) || 0;
209
+ if (!r2 || !o2) return null;
210
+ const s2 = (function texScratchCtx(e3, n3) {
211
+ if ("undefined" == typeof document) return null;
212
+ if (!u) {
213
+ u = document.createElement("canvas");
214
+ const e4 = u.getContext("2d");
215
+ e4 && t.ignore2DContext(e4);
216
+ }
217
+ u.width === e3 && u.height === n3 || (u.width = e3, u.height = n3);
218
+ const r3 = u.getContext("2d");
219
+ return r3 && t.ignore2DContext(r3), r3;
220
+ })(r2, o2);
221
+ return s2 ? (s2.clearRect(0, 0, r2, o2), s2.drawImage(e2, 0, 0), s2.getImageData(0, 0, r2, o2)) : null;
222
+ }
223
+ let f = null;
224
+ function setUntrackedGLContextNotifier(e2) {
225
+ f = e2;
226
+ }
227
+ let p = null;
228
+ const h = /* @__PURE__ */ new Map();
229
+ function setGLAutoAttach(e2) {
230
+ p = e2, e2 && h.clear();
231
+ }
232
+ class GLRecorder {
233
+ constructor(e2, t2) {
234
+ __publicField(this, "cpuMs", 0);
235
+ __publicField(this, "bound", false);
236
+ __publicField(this, "rawCtx", null);
237
+ __publicField(this, "refs", /* @__PURE__ */ new WeakMap());
238
+ __publicField(this, "nextId", 1e6);
239
+ __publicField(this, "sink");
240
+ __publicField(this, "pendingEncodes", /* @__PURE__ */ new Set());
241
+ __publicField(this, "assetBySource", /* @__PURE__ */ new WeakMap());
242
+ __publicField(this, "nextAssetId", 2e6);
243
+ __publicField(this, "assetCount", 0);
244
+ __publicField(this, "pendingSiteId");
245
+ this.now = t2, this.sink = e2;
246
+ }
247
+ async settle() {
248
+ for (; this.pendingEncodes.size; ) await Promise.all([...this.pendingEncodes]);
249
+ }
250
+ trackEncode(e2) {
251
+ this.pendingEncodes.add(e2), e2.then(() => {
252
+ }, () => {
253
+ }).finally(() => this.pendingEncodes.delete(e2));
254
+ }
255
+ captureTexSource(e2, n2) {
256
+ var _a, _b, _c;
257
+ const r2 = this.assetBySource.get(e2);
258
+ if (void 0 !== r2) return { $: "imagedata", id: r2 };
259
+ if (this.assetCount >= 64) return { $: "unsupported", kind: "texture-cap" };
260
+ if ((function texSourceRawBytes(e3) {
261
+ if ("undefined" != typeof ImageData && e3 instanceof ImageData) return e3.width * e3.height * 4;
262
+ const t2 = e3;
263
+ return (Number(t2.naturalWidth || t2.width) || 0) * (Number(t2.naturalHeight || t2.height) || 0) * 4;
264
+ })(e2) > 7340032) return { $: "unsupported", kind: "texture-too-large" };
265
+ let o2;
266
+ try {
267
+ o2 = texSourceToImageData(e2);
268
+ } catch (e3) {
269
+ return t.isTaintError(e3) ? ((_b = (_a = this.sink).onTaint) == null ? void 0 : _b.call(_a, n2), { $: "unsupported", kind: "texture-tainted" }) : { $: "unsupported", kind: "texture" };
270
+ }
271
+ if (!o2) return { $: "unsupported", kind: ((_c = e2.constructor) == null ? void 0 : _c.name) ?? "texture" };
272
+ const s2 = this.nextAssetId++;
273
+ this.assetCount++, this.assetBySource.set(e2, s2);
274
+ const a2 = o2.width, i2 = o2.height, c2 = new Uint8Array(o2.data.buffer.slice(o2.data.byteOffset, o2.data.byteOffset + o2.data.byteLength));
275
+ return this.trackEncode(t.deflate(c2).then((e3) => {
276
+ var _a2, _b2;
277
+ this.sink.onAssetBytes(s2, e3.length, n2), (_b2 = (_a2 = this.sink).onAssetData) == null ? void 0 : _b2.call(_a2, { id: s2, format: "imagedata", w: a2, h: i2, t: n2 }, e3);
278
+ }).catch((e3) => this.sink.note(`GL texture asset deflate failed: ${e3.message}`))), { $: "imagedata", id: s2 };
279
+ }
280
+ swapSink(e2) {
281
+ var _a;
282
+ const n2 = this.sink;
283
+ if (this.sink = e2, this.bound = true, n2 instanceof t.BufferSink) {
284
+ for (const t2 of n2.ops) e2.onOp(t2);
285
+ for (const t2 of n2.assetEvents) e2.onAssetBytes(t2.id, t2.bytes, t2.t);
286
+ for (const t2 of n2.assetData) (_a = e2.onAssetData) == null ? void 0 : _a.call(e2, t2.info, t2.payload);
287
+ for (const t2 of n2.notes) e2.note(t2);
288
+ }
289
+ }
290
+ recordCall(e2, n2, r2) {
291
+ if (this.sink instanceof t.DiscardSink) return this.sink.onOp(t.DIRTY_OP), void (this.pendingSiteId = void 0);
292
+ const o2 = performance.now(), s2 = this.now(), c2 = this.pendingSiteId;
293
+ if (this.pendingSiteId = void 0, (a.test(e2) || i.has(e2)) && r2 && "object" == typeof r2) {
294
+ const t2 = this.nextId++;
295
+ this.refs.set(r2, t2), this.sink.onOp({ t: s2, op: "__create", create: true, args: [e2, t2, ...n2.map((e3) => this.arg(e3, s2))] });
296
+ } else {
297
+ const t2 = { t: s2, op: e2, args: n2.map((e3) => this.arg(e3, s2)) };
298
+ c2 && (t2.sfId = c2), this.sink.onOp(t2);
299
+ }
300
+ this.cpuMs += performance.now() - o2;
301
+ }
302
+ arg(e2, n2) {
303
+ var _a;
304
+ if (null == e2) return null;
305
+ switch (typeof e2) {
306
+ case "number":
307
+ return Number.isFinite(e2) ? e2 : 0;
308
+ case "string":
309
+ case "boolean":
310
+ return e2;
311
+ case "object":
312
+ break;
313
+ default:
314
+ return { $: "unsupported", kind: typeof e2 };
315
+ }
316
+ const r2 = e2, o2 = this.refs.get(r2);
317
+ return void 0 !== o2 ? { $: "obj", id: o2 } : ArrayBuffer.isView(r2) || r2 instanceof ArrayBuffer ? t.serializeTypedArray(r2) : Array.isArray(r2) ? { $: "arr", v: r2.map((e3) => Number(e3) || 0) } : (function isStaticTexSource(e3) {
318
+ return "undefined" != typeof ImageData && e3 instanceof ImageData || "undefined" != typeof HTMLImageElement && e3 instanceof HTMLImageElement || "undefined" != typeof ImageBitmap && e3 instanceof ImageBitmap;
319
+ })(r2) ? this.captureTexSource(r2, n2) : { $: "unsupported", kind: ((_a = r2.constructor) == null ? void 0 : _a.name) ?? "object" };
320
+ }
321
+ }
322
+ function attachGLRecorder(e2, t2, n2, r2) {
323
+ const o2 = h.get(e2);
324
+ if (o2) return o2.swapSink(n2), o2;
325
+ const s2 = e2.getContext(t2);
326
+ if (!s2) return null;
327
+ const a2 = new GLRecorder(n2, r2);
328
+ return a2.rawCtx = s2, a2.bound = true, l.set(s2, a2), a2;
329
+ }
330
+ function detachGLRecorderFromContext(e2) {
331
+ l.delete(e2);
332
+ }
333
+ const m = 7340032, v = "__gpu";
334
+ let y = false, g = null, w = null, k = false, C = false;
335
+ function setGPUDeviceLostNotifier(e2) {
336
+ w = e2, k = false, C = false;
337
+ }
338
+ let b = null, nowFn = () => 0, x = 0, S = 3e6, R = false, L = null, I = null;
339
+ const M = /* @__PURE__ */ new WeakMap(), T = /* @__PURE__ */ new WeakMap(), E = /* @__PURE__ */ new WeakMap();
340
+ function emit(e2) {
341
+ b == null ? void 0 : b.onOp(e2);
342
+ }
343
+ function intern(e2) {
344
+ let t2 = M.get(e2);
345
+ return void 0 === t2 && (t2 = S++, M.set(e2, t2)), t2;
346
+ }
347
+ function deproxy(e2) {
348
+ return e2 && "object" == typeof e2 && E.has(e2) ? E.get(e2) : e2;
349
+ }
350
+ function deepDeproxy(e2) {
351
+ if (!e2 || "object" != typeof e2) return e2;
352
+ if (E.has(e2)) return E.get(e2);
353
+ if (ArrayBuffer.isView(e2) || e2 instanceof ArrayBuffer) return e2;
354
+ if (Array.isArray(e2)) {
355
+ let t3 = false;
356
+ const n2 = e2.map((e3) => {
357
+ const n3 = deepDeproxy(e3);
358
+ return n3 !== e3 && (t3 = true), n3;
359
+ });
360
+ return t3 ? n2 : e2;
361
+ }
362
+ const t2 = Object.getPrototypeOf(e2);
363
+ if (t2 === Object.prototype || null === t2) {
364
+ let t3 = false;
365
+ const n2 = {};
366
+ for (const [r2, o2] of Object.entries(e2)) {
367
+ const e3 = deepDeproxy(o2);
368
+ e3 !== o2 && (t3 = true), n2[r2] = e3;
369
+ }
370
+ return t3 ? n2 : e2;
371
+ }
372
+ return e2;
373
+ }
374
+ const D = function serializeGPUArg(e2) {
375
+ var _a;
376
+ if (null == e2) return null;
377
+ switch (typeof e2) {
378
+ case "number":
379
+ return Number.isFinite(e2) ? e2 : 0;
380
+ case "string":
381
+ case "boolean":
382
+ return e2;
383
+ case "object":
384
+ break;
385
+ default:
386
+ return { $: "unsupported", kind: typeof e2 };
387
+ }
388
+ const n2 = deproxy(e2);
389
+ if (ArrayBuffer.isView(n2) || n2 instanceof ArrayBuffer) return n2.byteLength > m ? { $: "unsupported", kind: "buffer-too-large" } : t.serializeTypedArray(n2);
390
+ const r2 = M.get(n2);
391
+ if (void 0 !== r2) return { $: "obj", id: r2 };
392
+ try {
393
+ return "json:" + JSON.stringify(n2, (e3, n3) => {
394
+ if (n3 && "object" == typeof n3) {
395
+ const e4 = deproxy(n3), r3 = M.get(e4);
396
+ if (void 0 !== r3) return { __sfRef: r3 };
397
+ if (ArrayBuffer.isView(e4)) {
398
+ const n4 = e4;
399
+ if (n4.byteLength > m) return { __sfUnsupported: "buffer-too-large" };
400
+ const r4 = t.TYPED_ARRAY_KINDS.findIndex((e5) => n4 instanceof e5);
401
+ return r4 < 0 ? { __sfUnsupported: "typed-array-kind" } : { __sfTa: Array.from(n4), __sfK: r4 };
402
+ }
403
+ return e4 === n3 ? n3 : e4;
404
+ }
405
+ return n3;
406
+ });
407
+ } catch {
408
+ return { $: "unsupported", kind: ((_a = n2.constructor) == null ? void 0 : _a.name) ?? "object" };
409
+ }
410
+ };
411
+ function shouldProxyResult(e2) {
412
+ var _a;
413
+ if (!e2 || "object" != typeof e2) return false;
414
+ return (((_a = e2.constructor) == null ? void 0 : _a.name) ?? "").startsWith("GPU");
415
+ }
416
+ function wrap(e2) {
417
+ var _a;
418
+ const n2 = T.get(e2);
419
+ if (n2) return n2;
420
+ "GPUDevice" === ((_a = e2.constructor) == null ? void 0 : _a.name) && (function watchDeviceLost(e3) {
421
+ const t2 = e3.lost;
422
+ if (t2 && "function" == typeof t2.then) {
423
+ if (C && !k) {
424
+ k = true;
425
+ try {
426
+ w == null ? void 0 : w(false);
427
+ } catch {
428
+ }
429
+ }
430
+ t2.then((e4) => {
431
+ if (!(e4 && "destroyed" === e4.reason || C)) {
432
+ C = true;
433
+ try {
434
+ w == null ? void 0 : w(true);
435
+ } catch {
436
+ }
437
+ }
438
+ }).catch(() => {
439
+ });
440
+ }
441
+ })(e2);
442
+ const r2 = new Proxy(e2, { get(e3, n3, r3) {
443
+ const o2 = Reflect.get(e3, n3, e3);
444
+ if ("symbol" == typeof n3) return o2;
445
+ if ("function" == typeof o2) return (...r4) => {
446
+ const s2 = performance.now(), a2 = r4.map(deepDeproxy), i2 = o2.apply(e3, a2);
447
+ if (b instanceof t.DiscardSink) return b.onOp(t.DIRTY_OP), i2 && "object" == typeof i2 && "function" == typeof i2.then ? i2.then((e4) => e4 && "object" == typeof e4 && shouldProxyResult(e4) ? (intern(e4), wrap(e4)) : e4) : shouldProxyResult(i2) ? (intern(i2), wrap(i2)) : i2;
448
+ if (b) {
449
+ const t2 = intern(e3);
450
+ if (i2 && "object" == typeof i2 && "function" == typeof i2.then) {
451
+ const e4 = S++;
452
+ return emit({ t: nowFn(), op: v, objcall: true, args: [t2, String(n3), e4, ...r4.map(D)] }), x += performance.now() - s2, i2.then((t3) => t3 && "object" == typeof t3 ? (M.set(t3, e4), wrap(t3)) : t3);
453
+ }
454
+ let o3 = 0;
455
+ return shouldProxyResult(i2) && (o3 = intern(i2)), emit({ t: nowFn(), op: v, objcall: true, args: [t2, String(n3), o3, ...r4.map(D)] }), x += performance.now() - s2, shouldProxyResult(i2) ? wrap(i2) : i2;
456
+ }
457
+ return i2 && "object" == typeof i2 && "function" == typeof i2.then ? i2.then((e4) => e4 && "object" == typeof e4 && shouldProxyResult(e4) ? (intern(e4), wrap(e4)) : e4) : shouldProxyResult(i2) ? (intern(i2), wrap(i2)) : i2;
458
+ };
459
+ if (shouldProxyResult(o2)) {
460
+ const r4 = M.has(o2), s2 = intern(o2);
461
+ return r4 || !b || b instanceof t.DiscardSink || emit({ t: nowFn(), op: "__gpuprop", objcall: true, args: [intern(e3), String(n3), s2] }), wrap(o2);
462
+ }
463
+ return o2;
464
+ } });
465
+ return T.set(e2, r2), E.set(r2, e2), r2;
466
+ }
467
+ function setGPUAutoAttach(e2) {
468
+ g = e2, e2 && (nowFn = e2.now, b || (b = new t.BufferSink(), R = false));
469
+ }
470
+ const P = ["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm", "video/mp4"];
471
+ function pickMime() {
472
+ if ("undefined" == typeof MediaRecorder || "function" != typeof MediaRecorder.isTypeSupported) return null;
473
+ for (const e2 of P) try {
474
+ if (MediaRecorder.isTypeSupported(e2)) return e2;
475
+ } catch {
476
+ }
477
+ return null;
478
+ }
479
+ class MediaRecorderCapture {
480
+ constructor(e2, t2) {
481
+ __publicField(this, "recorder", null);
482
+ __publicField(this, "stream", null);
483
+ __publicField(this, "stopped", false);
484
+ __publicField(this, "started", false);
485
+ __publicField(this, "seq", 0);
486
+ __publicField(this, "emitChain", Promise.resolve());
487
+ this.canvas = e2, this.out = t2;
488
+ }
489
+ static supported() {
490
+ return (function mediaRecorderSupported() {
491
+ return "undefined" != typeof MediaRecorder && "undefined" != typeof HTMLCanvasElement && "function" == typeof HTMLCanvasElement.prototype.captureStream && "function" == typeof MediaRecorder.isTypeSupported && null !== pickMime();
492
+ })();
493
+ }
494
+ async start() {
495
+ if (this.stopped) return false;
496
+ const e2 = this.canvas.width, t2 = this.canvas.height;
497
+ if (!e2 || !t2) return this.out.note("zero-size canvas — MediaRecorder capture unavailable"), false;
498
+ const n2 = pickMime();
499
+ if (!n2) return this.out.note("no MediaRecorder-supported mime — keyframes only"), false;
500
+ let r2, o2;
501
+ try {
502
+ r2 = this.canvas.captureStream(30);
503
+ } catch (e3) {
504
+ return this.out.note(`captureStream failed: ${e3.message}`), false;
505
+ }
506
+ try {
507
+ o2 = new MediaRecorder(r2, { mimeType: n2 });
508
+ } catch (e3) {
509
+ this.out.note(`MediaRecorder construct failed: ${e3.message}`);
510
+ try {
511
+ stopStream(r2);
512
+ } catch {
513
+ }
514
+ return false;
515
+ }
516
+ this.stream = r2, this.recorder = o2, o2.ondataavailable = (e3) => this.onData(e3.data), o2.onerror = (e3) => {
517
+ this.out.note(`MediaRecorder error: ${String(e3.error ?? e3)}`);
518
+ };
519
+ try {
520
+ o2.start(1e3);
521
+ } catch (e3) {
522
+ return this.out.note(`MediaRecorder start failed: ${e3.message}`), this.teardownStream(), false;
523
+ }
524
+ return this.started = true, this.out.onInit(o2.mimeType || n2, e2, t2), true;
525
+ }
526
+ onData(e2) {
527
+ if (!e2 || 0 === e2.size) return;
528
+ const t2 = this.seq++;
529
+ this.emitChain = this.emitChain.then(async () => {
530
+ try {
531
+ const n2 = await e2.arrayBuffer();
532
+ n2.byteLength > 0 && this.out.onChunk(t2, n2);
533
+ } catch (e3) {
534
+ this.out.note(`chunk read failed: ${e3.message}`);
535
+ }
536
+ });
537
+ }
538
+ afterRender(e2) {
539
+ }
540
+ onInteraction(e2) {
541
+ }
542
+ async flush() {
543
+ if (!this.stopped && this.recorder) {
544
+ try {
545
+ "recording" === this.recorder.state && this.recorder.requestData();
546
+ } catch {
547
+ }
548
+ await Promise.resolve(), await this.emitChain.catch(() => {
549
+ });
550
+ }
551
+ }
552
+ async stop() {
553
+ if (this.stopped) return;
554
+ this.stopped = true;
555
+ const e2 = this.recorder;
556
+ if (e2 && this.started) {
557
+ const t2 = new Promise((t3) => {
558
+ const done = () => t3();
559
+ e2.addEventListener("stop", done, { once: true }), setTimeout(done, 3e3);
560
+ });
561
+ try {
562
+ "inactive" !== e2.state && (e2.requestData(), e2.stop());
563
+ } catch {
564
+ }
565
+ await t2;
566
+ }
567
+ await this.emitChain.catch(() => {
568
+ }), this.teardownStream();
569
+ }
570
+ abort() {
571
+ if (!this.stopped) {
572
+ this.stopped = true;
573
+ try {
574
+ this.recorder && "inactive" !== this.recorder.state && this.recorder.stop();
575
+ } catch {
576
+ }
577
+ this.teardownStream();
578
+ }
579
+ }
580
+ teardownStream() {
581
+ this.recorder && (this.recorder.ondataavailable = null, this.recorder.onerror = null, this.recorder = null), this.stream && (stopStream(this.stream), this.stream = null);
582
+ }
583
+ }
584
+ function stopStream(e2) {
585
+ try {
586
+ for (const t2 of e2.getTracks()) try {
587
+ t2.stop();
588
+ } catch {
589
+ }
590
+ } catch {
591
+ }
592
+ }
593
+ const B = 18e5;
594
+ class VideoCapture {
595
+ constructor(e2, t2, n2, r2) {
596
+ __publicField(this, "client", null);
597
+ __publicField(this, "configured", false);
598
+ __publicField(this, "failed", false);
599
+ __publicField(this, "stopped", false);
600
+ __publicField(this, "lastFrame", -1 / 0);
601
+ __publicField(this, "lastKey", -1 / 0);
602
+ __publicField(this, "boostUntil", -1 / 0);
603
+ __publicField(this, "configuredW", 0);
604
+ __publicField(this, "configuredH", 0);
605
+ __publicField(this, "intervalId", null);
606
+ __publicField(this, "throttledNoted", false);
607
+ __publicField(this, "restarting", false);
608
+ __publicField(this, "forceKeyNext", false);
609
+ this.canvas = e2, this.now = t2, this.out = n2, this.opts = r2;
610
+ }
611
+ static supported() {
612
+ return "function" == typeof VideoEncoder && "function" == typeof VideoFrame;
613
+ }
614
+ async start() {
615
+ var _a;
616
+ if (!VideoCapture.supported()) return this.failed = true, this.out.note("no WebCodecs — video capture unavailable"), false;
617
+ const e2 = this.canvas.width, t2 = this.canvas.height;
618
+ if (!e2 || !t2) return this.failed = true, this.out.note("zero-size canvas — video capture unavailable"), false;
619
+ 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) });
620
+ return await this.client.configure({ width: e2, height: t2, bitrate: B, 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);
621
+ }
622
+ onInteraction(e2) {
623
+ this.boostUntil = e2 + 1500, this.lastKey = -1 / 0;
624
+ }
625
+ afterRender(e2) {
626
+ var _a, _b;
627
+ if (!this.configured || this.failed || this.stopped || !this.client) return;
628
+ 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")));
629
+ if (this.throttledNoted = false, this.canvas.width !== this.configuredW || this.canvas.height !== this.configuredH) return void this.requestRestart();
630
+ const t2 = e2 < this.boostUntil ? 30 : 20;
631
+ if (e2 - this.lastFrame < 1e3 / t2) return;
632
+ this.lastFrame = e2;
633
+ const n2 = this.forceKeyNext;
634
+ this.forceKeyNext = false;
635
+ const r2 = n2 || e2 - this.lastKey >= 2e3;
636
+ r2 && (this.lastKey = e2);
637
+ try {
638
+ const t3 = new VideoFrame(this.canvas, { timestamp: Math.round(1e3 * e2) });
639
+ this.client.encodeFrame(t3, r2);
640
+ } catch (e3) {
641
+ this.out.note(String(e3));
642
+ }
643
+ }
644
+ requestRestart() {
645
+ if (this.restarting || this.stopped) return;
646
+ const e2 = this.canvas.width, t2 = this.canvas.height;
647
+ if (!e2 || !t2) return;
648
+ this.restarting = true;
649
+ const n2 = this.client;
650
+ this.client = null, this.configured = false, this.out.note(`canvas resized to ${e2}x${t2} during video capture — restarting encoder`), (async () => {
651
+ try {
652
+ if (n2) try {
653
+ n2.terminate();
654
+ } catch {
655
+ }
656
+ if (this.stopped) return;
657
+ 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: B, codecs: ["avc1.42001f", "vp8", "vp09.00.10.08"] });
658
+ if (this.stopped || !o2) return r2.terminate(), void (o2 || this.out.note("encoder restart failed after resize — frames dropped until next resize"));
659
+ this.client = r2, this.configuredW = e2, this.configuredH = t2, this.configured = true, this.forceKeyNext = true, this.lastFrame = -1 / 0, this.lastKey = -1 / 0;
660
+ } finally {
661
+ this.restarting = false;
662
+ }
663
+ })();
664
+ }
665
+ async flush() {
666
+ !this.stopped && this.client && await this.client.flush();
667
+ }
668
+ abort() {
669
+ this.stopped || (this.stopped = true, null != this.intervalId && (clearInterval(this.intervalId), this.intervalId = null), this.client && (this.client.terminate(), this.client = null));
670
+ }
671
+ async stop() {
672
+ 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));
673
+ }
674
+ }
675
+ const A = /* @__PURE__ */ new WeakMap(), O = /* @__PURE__ */ new Map();
676
+ let G = false, V = null;
677
+ function setWorkerAssociationNotifier(e2) {
678
+ V = e2;
679
+ }
680
+ const U = 1048576, W = { deviceClass: "desktop", sessionByteBudget: 256 * U, maxConcurrentVideo: 4, governor: {}, preferMediaRecorder: false }, F = { deviceClass: "mobile", sessionByteBudget: 96 * U, maxConcurrentVideo: 2, governor: { maxBytesPerSec: 262144, maxOpsPerFrame: 3e3 }, preferMediaRecorder: false }, K = { deviceClass: "mobile-lowend", sessionByteBudget: 48 * U, maxConcurrentVideo: 1, governor: { maxBytesPerSec: 131072, maxOpsPerFrame: 2e3, maxVideoDrawsPerSec: 1 }, preferMediaRecorder: false };
681
+ function resolveDeviceBudgets(e2) {
682
+ const t2 = "undefined" != typeof navigator ? navigator : void 0;
683
+ if (!t2) return W;
684
+ const n2 = t2.deviceMemory, r2 = t2.hardwareConcurrency, o2 = "number" == typeof n2 && n2 <= 2, s2 = "number" == typeof r2 && r2 <= 4, a2 = (function isExplicitIOS(e3) {
685
+ return /iPhone|iPad|iPod/.test(e3.userAgent ?? "");
686
+ })(t2);
687
+ let i2;
688
+ return i2 = (function isMobileUA(e3) {
689
+ return /Mobi|Android|iPhone|iPad|iPod/.test(e3.userAgent ?? "") || (function isIPadDesktopUA(e4) {
690
+ return /Macintosh/.test(e4.userAgent ?? "") && (e4.maxTouchPoints ?? 0) > 1;
691
+ })(e3);
692
+ })(t2) ? o2 && s2 ? K : F : o2 && s2 ? K : W, a2 ? { ...i2, preferMediaRecorder: true } : i2;
693
+ }
694
+ function decayBytes(e2, t2, n2, r2) {
695
+ return r2 <= 0 || t2 <= 0 || n2 <= 0 ? Math.max(0, e2) : Math.max(0, e2 - r2 * (t2 / n2));
696
+ }
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 $ = null;
716
+ const now = () => Date.now(), encodeImage = (e2) => encodeBitmap(e2, 0.85, true);
717
+ function noteOnce(e2) {
718
+ var _a;
719
+ if ($ && !$.notes.has(e2)) {
720
+ $.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 ($) try {
729
+ $.deps.addSailfishEvent(e2);
730
+ } catch {
731
+ }
732
+ }
733
+ function sendFrame(e2, n2, r2, o2, s2 = Date.now()) {
734
+ const a2 = $;
735
+ if (!a2) return;
736
+ const i2 = null == o2 ? 0 : o2.byteLength;
737
+ if (i2 > 8388608) return void noteOnce(`oversize ${n2} frame dropped (${i2}B > 8MiB)`);
738
+ const c2 = a2.budgets.sessionByteBudget;
739
+ if (a2.lastBudgetTickMs > 0 && (a2.totalBytes = decayBytes(a2.totalBytes, c2, 6e4, s2 - a2.lastBudgetTickMs)), a2.lastBudgetTickMs = Math.max(a2.lastBudgetTickMs, s2), a2.totalBytes > c2) return void (a2.budgetExceeded || (a2.budgetExceeded = true, noteOnce("per-session canvas byte budget exceeded — capture paused (auto-resumes as it drains)")));
740
+ a2.budgetExceeded && (a2.budgetExceeded = false);
741
+ const d2 = a2.deps.getContextIds(), l2 = t.buildFrame({ v: 1, kind: n2, sessionId: d2.session_id ?? "", pageVisitUuid: d2.page_visit_uuid ?? "", canvasId: e2.canvasId, seq: e2.seq++, tMs: s2, meta: r2 }, o2);
742
+ try {
743
+ a2.deps.sendBinary(l2);
744
+ } catch {
745
+ return;
746
+ }
747
+ a2.totalBytes += l2.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, !$ || 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, n2) {
773
+ if (!e2.encoder || 0 === e2.encoder.ops) return;
774
+ const r2 = e2.encoder.takeBatch(), o2 = t.deflate(r2);
775
+ e2.flushChain = e2.flushChain.then(async () => {
776
+ const t2 = await o2;
777
+ e2.governor.addBytes(t2.length), sendFrame(e2, "commands", { codec: "sfc-bin-1", compression: "deflate" }, t2), 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, n2) {
809
+ var _a;
810
+ e2.demoted = true, flushBatch(e2), (_a = e2.keyframes) == null ? void 0 : _a.takeKeyframe(now());
811
+ const r2 = new t.DiscardSink(() => markDirty(e2));
812
+ if (e2.recorder2d && e2.recorder2d.swapSink(r2), e2.recorderGL && e2.recorderGL.swapSink(r2), e2.recorderGPU && (function swapGPUSink(e3) {
813
+ b && (b = e3);
814
+ })(r2), !($ == null ? void 0 : $.budgets.preferMediaRecorder) || !tryStartMediaRecorder(e2, n2)) if (VideoCapture.supported()) {
815
+ if (!tryAcquireVideoSlot(e2)) return e2.mode = "none", noteOnce(`video-encoder cap (${($ == null ? void 0 : $.budgets.maxConcurrentVideo) ?? 4}) reached — canvas kept on keyframes`), void emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: `${n2} (video-encoder cap reached — keyframes only)` });
816
+ e2.mode = "video", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "video", reason: n2 });
817
+ const t2 = makeVideo(e2, false);
818
+ e2.video = t2, t2.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, n2) || (e2.mode = "none", emitEvent({ op: "mode", canvasId: e2.canvasId, mode: "none", reason: `${n2} (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 n2 = $;
831
+ if (n2 && e2.keyframes && !t.wasPreAttachMaskUsed(e2.canvas) && n2.preExisting.has(e2.canvas)) {
832
+ n2.preExisting.delete(e2.canvas);
833
+ try {
834
+ e2.keyframes.initialKeyframe(now());
835
+ } catch {
836
+ }
837
+ }
838
+ }
839
+ function tryAcquireVideoSlot(e2) {
840
+ const t2 = $;
841
+ return !!t2 && (!!e2.hasVideoSlot || !!t2.videoSlots.acquire() && (e2.hasVideoSlot = true, true));
842
+ }
843
+ function releaseVideoSlot(e2) {
844
+ e2.hasVideoSlot && (e2.hasVideoSlot = false, $ == null ? void 0 : $.videoSlots.release());
845
+ }
846
+ function makeVideo(e2, n2) {
847
+ return new VideoCapture(e2.canvas, now, { onInit: (n3, r2) => sendFrame(e2, "video-init", { codec: n3, description: r2 ? t.bytesToBase64(r2) : null }, null), onChunk: (t2, n3, r2) => sendFrame(e2, "video-chunk", { key: t2, timestampUs: n3 }, r2), note: noteOnce, isTransportSaturated: ($ == null ? void 0 : $.deps.isTransportSaturated) ? () => {
848
+ var _a, _b;
849
+ return !!((_b = $ == null ? void 0 : (_a = $.deps).isTransportSaturated) == null ? void 0 : _b.call(_a));
850
+ } : void 0 }, { intervalPaced: n2 });
851
+ }
852
+ function tryStartMediaRecorder(e2, t2) {
853
+ if (!MediaRecorderCapture.supported()) return false;
854
+ if (!tryAcquireVideoSlot(e2)) return noteOnce(`video-encoder cap (${($ == null ? void 0 : $.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 = $ == null ? void 0 : $.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 $ ? t.classifyCanvasPrivacy(e2, $.privacySettings) : "normal";
896
+ }
897
+ function makeTextRedactor(e2) {
898
+ if ("redact" === e2) return (e3) => t.redactCanvasText(e3, "redact", {});
899
+ if ("normal" === e2 && (function contentDetectionActive() {
900
+ const e3 = $ == null ? void 0 : $.contentFlags;
901
+ return !!e3 && (false === e3.recordCreditCardInfo || false === e3.recordSsn || false === e3.recordDob);
902
+ })()) {
903
+ const e3 = $.contentFlags;
904
+ return (n2) => t.redactCanvasText(n2, "normal", e3);
905
+ }
906
+ }
907
+ function emitMasked(e2, n2) {
908
+ const r2 = $ ? t.suppressReason(e2, $.privacySettings) : void 0, o2 = { op: "masked", canvasId: n2 };
909
+ r2 && (o2.reason = r2), emitEvent(o2), $ == null ? void 0 : $.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 (!$ || $.stopped) return t2(null);
919
+ let r2 = -1;
920
+ try {
921
+ r2 = $.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 = $;
931
+ t2 && !t2.stopped && (t2.handled.delete(e2), t2.suppressed.delete(e2), considerCanvas(e2));
932
+ }
933
+ function reevaluateAllMasking() {
934
+ const e2 = $;
935
+ if (e2 && !e2.stopped) {
936
+ for (const n2 of [...e2.controllers.values()]) {
937
+ if (n2.stopped) continue;
938
+ const r2 = n2.canvas, o2 = t.classifyCanvasPrivacy(r2, e2.privacySettings);
939
+ if ("suppress" === o2) {
940
+ const t2 = n2.canvasId;
941
+ teardownController(n2), e2.handled.add(r2), emitMasked(r2, t2);
942
+ continue;
943
+ }
944
+ o2 !== n2.privacyMode && (teardownController(n2), r2.isConnected && rearmCanvas(r2));
945
+ }
946
+ for (const n2 of [...e2.suppressed]) {
947
+ if (!n2.isConnected) {
948
+ e2.suppressed.delete(n2);
949
+ continue;
950
+ }
951
+ "suppress" !== t.classifyCanvasPrivacy(n2, e2.privacySettings) && rearmCanvas(n2);
952
+ }
953
+ }
954
+ }
955
+ function onCanvasRemoved(e2) {
956
+ const t2 = $;
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 n2 = $;
968
+ if (!n2 || n2.stopped || n2.handled.has(e2)) return;
969
+ if (!e2.isConnected) return t.releaseAutoRecorder(e2), void noteOnce("disconnected canvas skipped — recorded only if attached to the document");
970
+ const r2 = classify(e2);
971
+ if ("suppress" === r2) return n2.handled.add(e2), void resolveCanvasId(e2).then((t2) => {
972
+ null != t2 && emitMasked(e2, t2);
973
+ });
974
+ const o2 = (function getWorkerForCanvas(e3) {
975
+ return O.get(e3);
976
+ })(e2), s2 = t.getContextInfo(e2);
977
+ (o2 || s2) && (n2.handled.add(e2), resolveCanvasId(e2).then((n3) => {
978
+ if (null != n3 && $ && !$.stopped) if (o2) {
979
+ if ("redact" === r2) return noteOnce("redact worker/offscreen canvas — escalated to suppress (no DOM to redact)"), void emitMasked(e2, n3);
980
+ !(async function buildWorkerController(e3, t2, n4) {
981
+ const r3 = await (function pingWorkerShim(e4, t3 = 500) {
982
+ return new Promise((n5) => {
983
+ let r4 = false;
984
+ const finish = (t4) => {
985
+ r4 || (r4 = true, clearTimeout(o4), e4.removeEventListener("message", onMsg), n5(t4));
986
+ }, onMsg = (e5) => {
987
+ var _a;
988
+ "sf-record-pong" === ((_a = e5.data) == null ? void 0 : _a.type) && finish(true);
989
+ }, o4 = setTimeout(() => finish(false), t3);
990
+ e4.addEventListener("message", onMsg);
991
+ try {
992
+ e4.postMessage({ type: "sf-record-ping" });
993
+ } catch {
994
+ finish(false);
995
+ }
996
+ });
997
+ })(n4), o3 = $;
998
+ if (!o3 || o3.stopped) return;
999
+ if (r3) {
1000
+ const r4 = baseController(e3, t2, "worker", "commands");
1001
+ let s4;
1002
+ r4.worker = n4, r4.workerDone = new Promise((e4) => {
1003
+ s4 = e4;
1004
+ });
1005
+ const onMsg = (e4) => {
1006
+ const t3 = e4.data;
1007
+ if ("sf-record-done" === (t3 == null ? void 0 : t3.type)) s4(t3);
1008
+ else if ("sf-record-noctx" === (t3 == null ? void 0 : t3.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 (${($ == null ? void 0 : $.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" === (t3 == null ? void 0 : t3.type) && (sendFrame(r4, "commands", { codec: "sfc-bin-1", compression: "deflate" }, new Uint8Array(t3.deflated), t3.tMs), r4.governor.addBytes(t3.deflated.byteLength));
1020
+ };
1021
+ n4.addEventListener("message", onMsg), r4.removeWorkerListener = () => n4.removeEventListener("message", onMsg);
1022
+ try {
1023
+ n4.postMessage({ type: "sf-record-start", contentFlags: o3.contentFlags });
1024
+ } catch {
1025
+ noteOnce("worker postMessage failed — worker canvas not recorded");
1026
+ }
1027
+ return o3.controllers.set(e3, r4), void emitStart(r4);
1028
+ }
1029
+ const s3 = baseController(e3, t2, "worker", "none");
1030
+ if (o3.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 (${($ == null ? void 0 : $.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, n3, o2);
1039
+ } else if ("2d" === s2.type) build2DController(e2, n3, null, r2);
1040
+ else if ("webgl" === s2.type || "webgl2" === s2.type || "experimental-webgl" === s2.type) {
1041
+ const o3 = escalateRedactIfPixelText(r2, s2.type);
1042
+ if ("suppress" === o3) return void emitMasked(e2, n3);
1043
+ !(function buildGLController(e3, n4, r3, o4, s3 = "normal") {
1044
+ const a2 = $;
1045
+ if (!a2 || a2.stopped) return;
1046
+ const i2 = "experimental-webgl" === r3 ? "webgl" : r3;
1047
+ if ("suppress" === escalateRedactIfPixelText(s3, i2)) return void emitMasked(e3, n4);
1048
+ const c2 = baseController(e3, n4, i2, "commands", s3);
1049
+ c2.encoder = new t.CommandEncoder();
1050
+ const d2 = makeCommandSink(c2);
1051
+ let l2;
1052
+ l2 = attachGLRecorder(e3, r3, d2, now), l2 || (c2.mode = "none", noteOnce("GL context not reachable — nothing recorded"));
1053
+ c2.recorderGL = l2, c2.keyframes = makeKeyframes(c2), installGLContextLossHandling(c2), a2.controllers.set(e3, c2), emitStart(c2), maybeInitialKeyframe(c2);
1054
+ })(e2, n3, s2.type, 0, o3);
1055
+ } else if ("webgpu" === s2.type) {
1056
+ const o3 = escalateRedactIfPixelText(r2, "webgpu");
1057
+ if ("suppress" === o3) return void emitMasked(e2, n3);
1058
+ !(function buildGPUController(e3, n4, r3 = "normal") {
1059
+ const o4 = $;
1060
+ if (!o4 || o4.stopped) return;
1061
+ if ("suppress" === escalateRedactIfPixelText(r3, "webgpu")) return void emitMasked(e3, n4);
1062
+ const s3 = baseController(e3, n4, "webgpu", "commands", r3);
1063
+ s3.encoder = new t.CommandEncoder();
1064
+ const a2 = (function attachGPURecorder(e4, n5, r4) {
1065
+ if (L !== e4 || !b) return null;
1066
+ I = e4, nowFn = r4;
1067
+ const o5 = b;
1068
+ if (b = n5, o5 instanceof t.BufferSink) {
1069
+ for (const e5 of o5.ops) n5.onOp(e5);
1070
+ for (const e5 of o5.notes) n5.note(e5);
1071
+ }
1072
+ return { detach() {
1073
+ b = null, I = null, L = 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((t2) => {
1079
+ var _a;
1080
+ if (!e4.stopped) if (t2) {
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), o4.controllers.set(e3, s3), emitStart(s3), maybeInitialKeyframe(s3);
1094
+ })(e2, n3, o3);
1095
+ } else {
1096
+ const t2 = baseController(e2, n3, "unknown", "none");
1097
+ $.controllers.set(e2, t2), emitStart(t2), noteOnce(`unsupported context type "${s2.type}" — not captured`);
1098
+ }
1099
+ }));
1100
+ }
1101
+ function build2DController(e2, n2, r2, o2 = "normal") {
1102
+ const s2 = $;
1103
+ if (!s2 || s2.stopped) return;
1104
+ const a2 = baseController(e2, n2, "2d", "commands", o2);
1105
+ a2.encoder = new t.CommandEncoder();
1106
+ const i2 = makeCommandSink(a2);
1107
+ let c2 = r2;
1108
+ c2 ? c2.swapSink(i2) : c2 = t.attachRecorder(e2, i2, now, "cas", encodeImage, { retainAssets: false }), c2 || (a2.mode = "none", noteOnce("canvas has no readable 2D context — nothing recorded")), c2 && (c2.textRedactor = makeTextRedactor(o2), c2.redactStyle = s2.redactStyle), a2.recorder2d = c2, a2.keyframes = makeKeyframes(a2), s2.controllers.set(e2, a2), emitStart(a2), maybeInitialKeyframe(a2);
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 n2 = $;
1140
+ if (!n2 || n2.stopped || n2.seenContexts.has(e2)) return;
1141
+ n2.seenContexts.add(e2);
1142
+ const r2 = e2.canvas;
1143
+ if (!(r2 instanceof HTMLCanvasElement)) return;
1144
+ if (!r2.isConnected) return;
1145
+ if (n2.handled.has(r2)) return;
1146
+ const o2 = classify(r2);
1147
+ if ("suppress" === o2) return n2.handled.add(r2), void resolveCanvasId(r2).then((e3) => {
1148
+ null != e3 && emitMasked(r2, e3);
1149
+ });
1150
+ n2.handled.add(r2);
1151
+ const s2 = t.attachRecorderToContext(e2, new t.BufferSink(), now, "cas", encodeImage, { retainAssets: false });
1152
+ resolveCanvasId(r2).then((n3) => {
1153
+ null != n3 && $ && !$.stopped ? build2DController(r2, n3, s2, o2) : t.detachRecorderFromContext(e2);
1154
+ });
1155
+ }
1156
+ function onUntrackedGL(e2) {
1157
+ const n2 = $;
1158
+ if (!n2 || n2.stopped || n2.seenContexts.has(e2)) return;
1159
+ n2.seenContexts.add(e2);
1160
+ const r2 = e2.canvas;
1161
+ if (!(r2 instanceof HTMLCanvasElement)) return;
1162
+ if (!r2.isConnected) return;
1163
+ if (n2.handled.has(r2)) return;
1164
+ const o2 = classify(r2), s2 = "undefined" != typeof WebGL2RenderingContext && e2 instanceof WebGL2RenderingContext ? "webgl2" : "webgl";
1165
+ if ("suppress" === o2 || "suppress" === escalateRedactIfPixelText(o2, s2)) return n2.handled.add(r2), void resolveCanvasId(r2).then((e3) => {
1166
+ null != e3 && emitMasked(r2, e3);
1167
+ });
1168
+ n2.handled.add(r2);
1169
+ const a2 = s2, i2 = new t.BufferSink(), c2 = (function attachGLRecorderToContext(e3, t2, n3) {
1170
+ const r3 = new GLRecorder(t2, n3);
1171
+ return r3.rawCtx = e3, r3.bound = true, l.set(e3, r3), r3;
1172
+ })(e2, i2, now);
1173
+ resolveCanvasId(r2).then((n3) => {
1174
+ if (null == n3 || !$ || $.stopped) return void detachGLRecorderFromContext(e2);
1175
+ const s3 = $, i3 = baseController(r2, n3, a2, "commands", o2);
1176
+ i3.encoder = new t.CommandEncoder(), c2.swapSink(makeCommandSink(i3)), i3.recorderGL = c2, i3.keyframes = makeKeyframes(i3), installGLContextLossHandling(i3), s3.controllers.set(r2, i3), emitStart(i3), maybeInitialKeyframe(i3);
1177
+ });
1178
+ }
1179
+ function teardownController(e2) {
1180
+ var _a, _b, _c, _d, _e, _f, _g;
1181
+ if (e2.stopped) $ == null ? void 0 : $.controllers.delete(e2.canvas);
1182
+ else {
1183
+ e2.stopped = true;
1184
+ try {
1185
+ null !== e2.flushTimer && (clearTimeout(e2.flushTimer), e2.flushTimer = null);
1186
+ } catch {
1187
+ }
1188
+ try {
1189
+ (_a = e2.removeContextLossListeners) == null ? void 0 : _a.call(e2);
1190
+ } catch {
1191
+ }
1192
+ e2.removeContextLossListeners = null;
1193
+ try {
1194
+ (_b = e2.video) == null ? void 0 : _b.abort();
1195
+ } catch {
1196
+ }
1197
+ e2.video = null;
1198
+ try {
1199
+ (_c = e2.mediaRecorder) == null ? void 0 : _c.abort();
1200
+ } catch {
1201
+ }
1202
+ e2.mediaRecorder = null, releaseVideoSlot(e2);
1203
+ try {
1204
+ (_d = e2.keyframes) == null ? void 0 : _d.dispose();
1205
+ } catch {
1206
+ }
1207
+ if (e2.keyframes = null, e2.worker) try {
1208
+ e2.worker.postMessage({ type: "sf-record-stop" });
1209
+ } catch {
1210
+ }
1211
+ try {
1212
+ (_e = e2.removeWorkerListener) == null ? void 0 : _e.call(e2);
1213
+ } catch {
1214
+ }
1215
+ e2.removeWorkerListener = null;
1216
+ try {
1217
+ e2.recorder2d && t.detachRecorderFromContext(e2.recorder2d.rawCtx);
1218
+ } catch {
1219
+ }
1220
+ try {
1221
+ ((_f = e2.recorderGL) == null ? void 0 : _f.rawCtx) && detachGLRecorderFromContext(e2.recorderGL.rawCtx);
1222
+ } catch {
1223
+ }
1224
+ try {
1225
+ (_g = e2.recorderGPU) == null ? void 0 : _g.detach();
1226
+ } catch {
1227
+ }
1228
+ $ == null ? void 0 : $.controllers.delete(e2.canvas);
1229
+ }
1230
+ }
1231
+ function settleOrTimeout(e2, t2) {
1232
+ return Promise.race([e2.catch(() => {
1233
+ }), new Promise((e3) => setTimeout(e3, t2))]);
1234
+ }
1235
+ async function stopController(e2, n2) {
1236
+ var _a, _b, _c;
1237
+ if (!e2.stopped) {
1238
+ e2.stopped = true;
1239
+ try {
1240
+ (_a = e2.removeContextLossListeners) == null ? void 0 : _a.call(e2);
1241
+ } catch {
1242
+ }
1243
+ if (e2.removeContextLossListeners = null, null !== e2.flushTimer && (clearTimeout(e2.flushTimer), e2.flushTimer = null), e2.worker && e2.workerDone) {
1244
+ try {
1245
+ e2.worker.postMessage({ type: "sf-record-stop" });
1246
+ } catch {
1247
+ }
1248
+ const n3 = await Promise.race([e2.workerDone, new Promise((e3) => setTimeout(() => e3(null), 5e3))]);
1249
+ (_b = e2.removeWorkerListener) == null ? void 0 : _b.call(e2), n3 && await (async function convertWorkerResult(e3, n4) {
1250
+ for (const e4 of n4.notes ?? []) noteOnce(`worker: ${e4}`);
1251
+ for (const r2 of n4.batches ?? []) try {
1252
+ sendFrame(e3, "commands", { codec: "sfc-bin-1", compression: "deflate" }, await t.deflate(r2));
1253
+ } catch {
1254
+ }
1255
+ for (const r2 of n4.assets ?? []) try {
1256
+ if (r2.bitmap) {
1257
+ const t2 = r2.w ?? r2.bitmap.width, n5 = r2.h ?? r2.bitmap.height, o2 = await encodeBitmap(r2.bitmap, 0.85, true);
1258
+ o2.bytes && sendFrame(e3, "asset", { assetId: r2.id, format: "webp", w: t2, h: n5 }, o2.bytes);
1259
+ } else if (r2.imageData) {
1260
+ const n5 = r2.imageData, o2 = await t.deflate(new Uint8Array(n5.data.buffer, n5.data.byteOffset, n5.data.byteLength));
1261
+ sendFrame(e3, "asset", { assetId: r2.id, format: "imagedata", w: n5.width, h: n5.height }, o2);
1262
+ }
1263
+ } catch {
1264
+ }
1265
+ })(e2, n3), e2.video && await e2.video.stop(), e2.mediaRecorder && await e2.mediaRecorder.stop();
1266
+ } else flushBatch(e2), e2.video && await e2.video.stop(), e2.mediaRecorder && await e2.mediaRecorder.stop(), e2.keyframes && (e2.everDirty && e2.keyframes.takeKeyframe(n2), await e2.keyframes.stop(n2)), e2.recorder2d && (t.detachRecorderFromContext(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;
1267
+ releaseVideoSlot(e2), emitEvent({ op: "stop", canvasId: e2.canvasId });
1268
+ }
1269
+ }
1270
+ const N = { initState(e2) {
1271
+ $ = { deps: e2, maskSelector: ".sailfishSanitize, [data-sf-mask]", privacySettings: derivePrivacySettings(e2.settings), contentFlags: deriveContentFlags(e2.settings), redactStyle: t.resolveRedactStyle(t.DEFAULT_REDACT_STYLE, 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) };
1272
+ }, addController(e2, t2, n2 = "normal") {
1273
+ const r2 = baseController(e2, t2, "2d", "commands", n2);
1274
+ return $.controllers.set(e2, r2), r2;
1275
+ }, classify: (e2) => classify(e2), makeTextRedactor: (e2) => makeTextRedactor(e2), reevaluate() {
1276
+ reevaluateAllMasking();
1277
+ }, escalate: (e2, t2) => escalateRedactIfPixelText(e2, t2), isTracked: (e2) => !!($ == null ? void 0 : $.controllers.get(e2)), isSuppressed: (e2) => !!($ == null ? void 0 : $.suppressed.has(e2)), markSuppressed(e2) {
1278
+ $ == null ? void 0 : $.handled.add(e2), $ == null ? void 0 : $.suppressed.add(e2);
1279
+ }, controllerPrivacy: (e2) => ({ mode: e2.privacyMode, hasKeyframes: null != e2.keyframes }), tryDemote(e2) {
1280
+ maybeDemote(e2);
1281
+ }, emitResize(e2) {
1282
+ maybeEmitResize(e2, now());
1283
+ }, build2DWithFakeRecorder(e2, t2, n2) {
1284
+ const r2 = { swapSink: () => {
1285
+ }, textRedactor: void 0, rawCtx: {} };
1286
+ return build2DController(e2, t2, r2, n2), { ctl: $ == null ? void 0 : $.controllers.get(e2), redactor: r2.textRedactor };
1287
+ }, demote(e2, t2 = "bytes") {
1288
+ demote(e2, t2);
1289
+ }, teardown(e2) {
1290
+ teardownController(e2);
1291
+ }, slotsInUse: () => ($ == null ? void 0 : $.videoSlots.inUse) ?? -1, controllerHasSlot: (e2) => e2.hasVideoSlot, reset() {
1292
+ $ = null;
1293
+ } };
1294
+ exports.MAX_CONCURRENT_VIDEO_CANVASES = 4, exports.VideoSlotPool = VideoSlotPool, exports.__canvasManagerTestHooks = N, exports.collectMalformedSelectors = collectMalformedSelectors, exports.decayBytes = decayBytes, exports.flushAllCanvas = async function flushAllCanvas() {
1295
+ const e2 = $;
1296
+ if (!e2 || e2.stopped) return;
1297
+ now();
1298
+ const t2 = [];
1299
+ for (const n2 of e2.controllers.values()) if (!n2.stopped) {
1300
+ try {
1301
+ flushBatch(n2);
1302
+ } catch {
1303
+ }
1304
+ n2.video && t2.push(n2.video.flush().catch(() => {
1305
+ })), n2.mediaRecorder && t2.push(n2.mediaRecorder.flush().catch(() => {
1306
+ })), t2.push(n2.flushChain.catch(() => {
1307
+ }));
1308
+ }
1309
+ await Promise.all(t2).catch(() => {
1310
+ });
1311
+ }, exports.isCanvasRecordingActive = function isCanvasRecordingActive() {
1312
+ return null != $ && !$.stopped;
1313
+ }, exports.settleOrTimeout = settleOrTimeout, exports.startCanvasRecording = function startCanvasRecording(n2) {
1314
+ if ("undefined" == typeof window || "undefined" == typeof document) return;
1315
+ if ($) return;
1316
+ const r2 = n2.settings.maskCanvasClass || "sailfishSanitize", o2 = resolveDeviceBudgets();
1317
+ $ = { deps: n2, maskSelector: `.${r2}, [data-sf-mask]`, privacySettings: derivePrivacySettings(n2.settings), contentFlags: deriveContentFlags(n2.settings), redactStyle: t.resolveRedactStyle(t.DEFAULT_REDACT_STYLE, n2.settings.canvasRedactStyle), budgets: o2, 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(o2.maxConcurrentVideo) };
1318
+ for (const e2 of collectMalformedSelectors(n2.settings)) noteOnce(`malformed canvas privacy selector "${e2}" is invalid and will not match — that privacy rule is disabled`);
1319
+ t.installCommandHooks(), (function installGLHooks() {
1320
+ if (d) return;
1321
+ d = true;
1322
+ const e2 = [];
1323
+ "undefined" != typeof WebGLRenderingContext && e2.push(WebGLRenderingContext.prototype), "undefined" != typeof WebGL2RenderingContext && e2.push(WebGL2RenderingContext.prototype);
1324
+ for (const t2 of e2) for (const e3 of Object.getOwnPropertyNames(t2)) {
1325
+ const n4 = Object.getOwnPropertyDescriptor(t2, e3);
1326
+ if (!n4 || "function" != typeof n4.value || "constructor" === e3) continue;
1327
+ if (c.test(e3) && !i.has(e3)) continue;
1328
+ const r3 = n4.value;
1329
+ t2[e3] = function(...t3) {
1330
+ const n5 = r3.apply(this, t3), o3 = l.get(this);
1331
+ return o3 ? o3.recordCall(e3, t3, n5) : f && f(this), n5;
1332
+ };
1333
+ }
1334
+ if ("undefined" == typeof HTMLCanvasElement) return;
1335
+ const n3 = HTMLCanvasElement.prototype.getContext;
1336
+ HTMLCanvasElement.prototype.getContext = function(e3, r3) {
1337
+ const o3 = n3.call(this, e3, r3);
1338
+ if (("webgl" === e3 || "webgl2" === e3 || "experimental-webgl" === e3) && o3 && p && !l.has(o3)) {
1339
+ const e4 = new GLRecorder(new t.BufferSink(), p.now);
1340
+ e4.rawCtx = o3, l.set(o3, e4), h.set(this, e4);
1341
+ }
1342
+ return o3;
1343
+ };
1344
+ })(), (function installGPUHooks() {
1345
+ if (y) return;
1346
+ if (y = true, "undefined" == typeof navigator || !("gpu" in navigator)) return;
1347
+ const e2 = navigator.gpu;
1348
+ if (Object.defineProperty(navigator, "gpu", { configurable: true, get() {
1349
+ if (g || b) {
1350
+ if (!R) {
1351
+ R = true;
1352
+ const t3 = intern(e2);
1353
+ emit({ t: nowFn(), op: "__gpuroot", args: [t3] });
1354
+ }
1355
+ return wrap(e2);
1356
+ }
1357
+ return e2;
1358
+ } }), "undefined" == typeof HTMLCanvasElement) return;
1359
+ const t2 = HTMLCanvasElement.prototype.getContext;
1360
+ HTMLCanvasElement.prototype.getContext = function(e3, n3) {
1361
+ const r3 = t2.call(this, e3, n3);
1362
+ if ("webgpu" === e3 && r3 && (g || b)) {
1363
+ L = this;
1364
+ const e4 = M.has(r3), t3 = intern(r3);
1365
+ return e4 || emit({ t: nowFn(), op: "__gpuctx", args: [t3] }), wrap(r3);
1366
+ }
1367
+ return r3;
1368
+ };
1369
+ })(), (function installWorkerRelay() {
1370
+ if (!G) {
1371
+ if (G = true, "undefined" != typeof HTMLCanvasElement && "function" == typeof HTMLCanvasElement.prototype.transferControlToOffscreen) {
1372
+ const e2 = HTMLCanvasElement.prototype.transferControlToOffscreen;
1373
+ HTMLCanvasElement.prototype.transferControlToOffscreen = function() {
1374
+ const t2 = e2.call(this);
1375
+ return A.set(t2, this), t2;
1376
+ };
1377
+ }
1378
+ if ("undefined" != typeof Worker) {
1379
+ const e2 = Worker.prototype.postMessage;
1380
+ Worker.prototype.postMessage = function(t2, n3) {
1381
+ const r3 = Array.isArray(n3) ? n3 : n3 == null ? void 0 : n3.transfer;
1382
+ if (r3) for (const e3 of r3) {
1383
+ const t3 = e3 && "object" == typeof e3 ? A.get(e3) : void 0;
1384
+ t3 && !O.has(t3) && (O.set(t3, this), V == null ? void 0 : V(t3, this));
1385
+ }
1386
+ return e2.apply(this, [t2, n3]);
1387
+ };
1388
+ }
1389
+ }
1390
+ })(), t.setAutoAttach({ now, assetMode: "cas", encodeImage, retainAssets: false }), setGLAutoAttach({ now }), setGPUAutoAttach({ now }), t.setContextCreatedNotifier((e2) => {
1391
+ queueMicrotask(() => considerCanvas(e2));
1392
+ }), t.setUntracked2DContextNotifier(onUntracked2D), setUntrackedGLContextNotifier(onUntrackedGL), setWorkerAssociationNotifier((e2) => considerCanvas(e2)), globalThis.__sfDrawSite = (e2, n3) => (e2 && "object" == typeof e2 && (t.noteCtxPendingSiteId(e2, n3) || (function noteGLPendingSiteId(e3, t2) {
1393
+ const n4 = l.get(e3);
1394
+ return !!n4 && (n4.pendingSiteId = t2, true);
1395
+ })(e2, n3)), e2), e.installAdapters({ canvasIdFor: (e2) => {
1396
+ var _a;
1397
+ return ((_a = $ == null ? void 0 : $.controllers.get(e2)) == null ? void 0 : _a.canvasId) ?? null;
1398
+ }, emitHit: (e2) => emitEvent(e2), now });
1399
+ const onInteraction = () => {
1400
+ var _a, _b, _c;
1401
+ const e2 = $;
1402
+ if (!e2 || e2.stopped) return;
1403
+ const t2 = now();
1404
+ for (const n3 of e2.controllers.values()) n3.stopped || ("video" === n3.mode ? ((_a = n3.video) == null ? void 0 : _a.onInteraction(t2), (_b = n3.mediaRecorder) == null ? void 0 : _b.onInteraction(t2)) : (_c = n3.keyframes) == null ? void 0 : _c.onInteraction(t2));
1405
+ };
1406
+ window.addEventListener("pointerdown", onInteraction, { capture: true, passive: true }), window.addEventListener("keydown", onInteraction, { capture: true, passive: true }), $.removeListeners.push(() => {
1407
+ window.removeEventListener("pointerdown", onInteraction, { capture: true }), window.removeEventListener("keydown", onInteraction, { capture: true });
1408
+ });
1409
+ const s2 = new MutationObserver((e2) => {
1410
+ let t2 = false;
1411
+ for (const n3 of e2) "attributes" !== n3.type ? (n3.addedNodes.forEach((e3) => {
1412
+ e3 instanceof Element && (e3 instanceof HTMLCanvasElement ? considerCanvas(e3) : e3.querySelectorAll("canvas").forEach((e4) => considerCanvas(e4)));
1413
+ }), n3.removedNodes.forEach((e3) => {
1414
+ e3 instanceof Element && (e3 instanceof HTMLCanvasElement ? onCanvasRemoved(e3) : e3.querySelectorAll("canvas").forEach((e4) => onCanvasRemoved(e4)));
1415
+ })) : t2 = true;
1416
+ t2 && reevaluateAllMasking();
1417
+ });
1418
+ s2.observe(document.documentElement, { childList: true, subtree: true, attributes: true }), $.observer = s2, document.querySelectorAll("canvas").forEach((e2) => {
1419
+ $.preExisting.add(e2), considerCanvas(e2);
1420
+ });
1421
+ }, exports.stopCanvasRecording = async function stopCanvasRecording() {
1422
+ var _a;
1423
+ const r2 = $;
1424
+ if (!r2 || r2.stopped) return;
1425
+ r2.stopped = true, t.setAutoAttach(null), setGLAutoAttach(null), setGPUAutoAttach(null), setGPUDeviceLostNotifier(null), t.setContextCreatedNotifier(null), t.setUntracked2DContextNotifier(null), setUntrackedGLContextNotifier(null), setWorkerAssociationNotifier(null), delete globalThis.__sfDrawSite, e.uninstallAdapters(), (_a = r2.observer) == null ? void 0 : _a.disconnect();
1426
+ for (const e2 of r2.removeListeners) try {
1427
+ e2();
1428
+ } catch {
1429
+ }
1430
+ const s2 = now();
1431
+ await Promise.all([...r2.controllers.values()].map((e2) => stopController(e2, s2).catch(() => {
1432
+ }))), t.pruneUnboundRecorders(), (function pruneUnboundGLRecorders() {
1433
+ for (const [e2, t2] of h) t2.bound || (l.delete(t2.rawCtx), h.delete(e2));
1434
+ })(), (function pruneUnboundGPURecorders() {
1435
+ b instanceof t.BufferSink && !I && (L || (b = null));
1436
+ })(), (function terminateImgEncoder() {
1437
+ n && (n.terminate(), n = null);
1438
+ for (const [e2, t2] of o) o.delete(e2), t2({ size: 0 });
1439
+ })(), $ = null;
1440
+ };