@highlight-run/rrweb 2.0.0-lambda.7 → 2.0.0-lambda.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/rrweb.js CHANGED
@@ -1873,6 +1873,7 @@ function requireStringifier$1() {
1873
1873
  hasRequiredStringifier$1 = 1;
1874
1874
  const STYLE_TAG = /(<)(\/?style\b)/gi;
1875
1875
  const COMMENT_OPEN = /(<)(!--)/g;
1876
+ const AT_NAME_END = /[\t\n\f\r "#'()/;[\\\]{}]/;
1876
1877
  function escapeHTMLInCSS(str) {
1877
1878
  if (typeof str !== "string") return str;
1878
1879
  if (!str.includes("<")) return str;
@@ -1898,12 +1899,13 @@ function requireStringifier$1() {
1898
1899
  function atruleStart(str, node2) {
1899
1900
  let name = "@" + node2.name;
1900
1901
  let params = node2.params ? str.rawValue(node2, "params") : "";
1901
- if (typeof node2.raws.afterName !== "undefined") {
1902
- name += node2.raws.afterName;
1903
- } else if (params) {
1904
- name += " ";
1902
+ let afterName = node2.raws.afterName;
1903
+ if (typeof afterName === "undefined") {
1904
+ afterName = params ? " " : "";
1905
+ } else if (afterName === "" && params && !AT_NAME_END.test(params[0])) {
1906
+ afterName = " ";
1905
1907
  }
1906
- return name + params;
1908
+ return name + afterName + params;
1907
1909
  }
1908
1910
  function pushBody(str, stack, node2) {
1909
1911
  let nodes = node2.nodes;
@@ -1915,10 +1917,15 @@ function requireStringifier$1() {
1915
1917
  let semicolon = str.raw(node2, "semicolon");
1916
1918
  let isDocument = node2.type === "document";
1917
1919
  for (let i2 = nodes.length - 1; i2 >= 0; i2--) {
1920
+ let child = nodes[i2];
1921
+ let childSemicolon = last !== i2 || semicolon;
1922
+ if (!childSemicolon && i2 < nodes.length - 1 && (child.type === "atrule" && !child.nodes || child.type === "decl" && child.prop.startsWith("--"))) {
1923
+ childSemicolon = true;
1924
+ }
1918
1925
  stack.push({
1919
1926
  document: isDocument,
1920
- node: nodes[i2],
1921
- semicolon: last !== i2 || semicolon
1927
+ node: child,
1928
+ semicolon: childSemicolon
1922
1929
  });
1923
1930
  }
1924
1931
  }
@@ -2209,6 +2216,9 @@ function requireStringifier$1() {
2209
2216
  return value;
2210
2217
  }
2211
2218
  root(node2) {
2219
+ if (node2.source && node2.source.input.hasBOM) {
2220
+ this.builder("\uFEFF", node2, "start");
2221
+ }
2212
2222
  this.body(node2);
2213
2223
  if (node2.raws.after) {
2214
2224
  let after = node2.raws.after;
@@ -3281,15 +3291,12 @@ function requirePreviousMap$1() {
3281
3291
  }
3282
3292
  loadFile(path, cssFile, trusted) {
3283
3293
  if (!trusted && !this.unsafeMap) {
3284
- if (!/\.map$/i.test(path)) {
3294
+ if (!/\.map$/i.test(path)) return void 0;
3295
+ if (!cssFile) return void 0;
3296
+ let rel = relative(dirname(cssFile), path);
3297
+ if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute(rel)) {
3285
3298
  return void 0;
3286
3299
  }
3287
- if (cssFile) {
3288
- let relativePath = relative(dirname(cssFile), path);
3289
- if (relativePath === ".." || relativePath.startsWith(".." + sep) || isAbsolute(relativePath)) {
3290
- return void 0;
3291
- }
3292
- }
3293
3300
  }
3294
3301
  this.root = dirname(path);
3295
3302
  if (existsSync(path)) {
@@ -3661,6 +3668,7 @@ function requireList$1() {
3661
3668
  return list.split(string, spaces);
3662
3669
  },
3663
3670
  split(string, separators, last) {
3671
+ if (!string) return [];
3664
3672
  let array = [];
3665
3673
  let current = "";
3666
3674
  let split = false;
@@ -4947,11 +4955,16 @@ var hasRequiredWarning$1;
4947
4955
  function requireWarning$1() {
4948
4956
  if (hasRequiredWarning$1) return warning$1;
4949
4957
  hasRequiredWarning$1 = 1;
4958
+ let Container = requireContainer$1();
4959
+ let { my } = requireSymbols$1();
4950
4960
  class Warning {
4951
4961
  constructor(text, opts = {}) {
4952
4962
  this.type = "warning";
4953
4963
  this.text = text;
4954
4964
  if (opts.node && opts.node.source) {
4965
+ if (!opts.node[my]) {
4966
+ Container.rebuild(opts.node);
4967
+ }
4955
4968
  let range = opts.node.rangeBy(opts);
4956
4969
  this.line = range.start.line;
4957
4970
  this.column = range.start.column;
@@ -5461,14 +5474,19 @@ function requireLazyResult$1() {
5461
5474
  }
5462
5475
  if (visit2.iterator !== 0) {
5463
5476
  let iterator = visit2.iterator;
5477
+ if (visit2.descending) {
5478
+ visit2.descending = false;
5479
+ node2.indexes[iterator] += 1;
5480
+ }
5464
5481
  let child;
5465
5482
  while (child = node2.nodes[node2.indexes[iterator]]) {
5466
- node2.indexes[iterator] += 1;
5467
5483
  if (!child[isClean]) {
5468
5484
  child[isClean] = true;
5485
+ visit2.descending = true;
5469
5486
  stack.push(toStack(child));
5470
5487
  return;
5471
5488
  }
5489
+ node2.indexes[iterator] += 1;
5472
5490
  }
5473
5491
  visit2.iterator = 0;
5474
5492
  delete node2.indexes[iterator];
@@ -5498,12 +5516,16 @@ function requireLazyResult$1() {
5498
5516
  let visitNode = visit2.node;
5499
5517
  if (visit2.iterator !== 0) {
5500
5518
  let iterator = visit2.iterator;
5519
+ if (visit2.descending) {
5520
+ visit2.descending = false;
5521
+ visitNode.indexes[iterator] += 1;
5522
+ }
5501
5523
  let child;
5502
5524
  let descended = false;
5503
5525
  while (child = visitNode.nodes[visitNode.indexes[iterator]]) {
5504
- visitNode.indexes[iterator] += 1;
5505
5526
  if (!child[isClean]) {
5506
5527
  child[isClean] = true;
5528
+ visit2.descending = true;
5507
5529
  stack.push({
5508
5530
  eventIndex: 0,
5509
5531
  events: getEvents(child),
@@ -5513,6 +5535,7 @@ function requireLazyResult$1() {
5513
5535
  descended = true;
5514
5536
  break;
5515
5537
  }
5538
+ visitNode.indexes[iterator] += 1;
5516
5539
  }
5517
5540
  if (descended) continue;
5518
5541
  visit2.iterator = 0;
@@ -5675,7 +5698,7 @@ function requireProcessor$1() {
5675
5698
  let Root = requireRoot$1();
5676
5699
  class Processor {
5677
5700
  constructor(plugins = []) {
5678
- this.version = "8.5.19";
5701
+ this.version = "8.5.25";
5679
5702
  this.plugins = this.normalize(plugins);
5680
5703
  }
5681
5704
  normalize(plugins) {
@@ -6542,6 +6565,7 @@ function requireStringifier() {
6542
6565
  hasRequiredStringifier = 1;
6543
6566
  const STYLE_TAG = /(<)(\/?style\b)/gi;
6544
6567
  const COMMENT_OPEN = /(<)(!--)/g;
6568
+ const AT_NAME_END = /[\t\n\f\r "#'()/;[\\\]{}]/;
6545
6569
  function escapeHTMLInCSS(str) {
6546
6570
  if (typeof str !== "string") return str;
6547
6571
  if (!str.includes("<")) return str;
@@ -6567,12 +6591,13 @@ function requireStringifier() {
6567
6591
  function atruleStart(str, node2) {
6568
6592
  let name = "@" + node2.name;
6569
6593
  let params = node2.params ? str.rawValue(node2, "params") : "";
6570
- if (typeof node2.raws.afterName !== "undefined") {
6571
- name += node2.raws.afterName;
6572
- } else if (params) {
6573
- name += " ";
6594
+ let afterName = node2.raws.afterName;
6595
+ if (typeof afterName === "undefined") {
6596
+ afterName = params ? " " : "";
6597
+ } else if (afterName === "" && params && !AT_NAME_END.test(params[0])) {
6598
+ afterName = " ";
6574
6599
  }
6575
- return name + params;
6600
+ return name + afterName + params;
6576
6601
  }
6577
6602
  function pushBody(str, stack, node2) {
6578
6603
  let nodes = node2.nodes;
@@ -6584,10 +6609,15 @@ function requireStringifier() {
6584
6609
  let semicolon = str.raw(node2, "semicolon");
6585
6610
  let isDocument = node2.type === "document";
6586
6611
  for (let i2 = nodes.length - 1; i2 >= 0; i2--) {
6612
+ let child = nodes[i2];
6613
+ let childSemicolon = last !== i2 || semicolon;
6614
+ if (!childSemicolon && i2 < nodes.length - 1 && (child.type === "atrule" && !child.nodes || child.type === "decl" && child.prop.startsWith("--"))) {
6615
+ childSemicolon = true;
6616
+ }
6587
6617
  stack.push({
6588
6618
  document: isDocument,
6589
- node: nodes[i2],
6590
- semicolon: last !== i2 || semicolon
6619
+ node: child,
6620
+ semicolon: childSemicolon
6591
6621
  });
6592
6622
  }
6593
6623
  }
@@ -6878,6 +6908,9 @@ function requireStringifier() {
6878
6908
  return value;
6879
6909
  }
6880
6910
  root(node2) {
6911
+ if (node2.source && node2.source.input.hasBOM) {
6912
+ this.builder("\uFEFF", node2, "start");
6913
+ }
6881
6914
  this.body(node2);
6882
6915
  if (node2.raws.after) {
6883
6916
  let after = node2.raws.after;
@@ -7950,15 +7983,12 @@ function requirePreviousMap() {
7950
7983
  }
7951
7984
  loadFile(path, cssFile, trusted) {
7952
7985
  if (!trusted && !this.unsafeMap) {
7953
- if (!/\.map$/i.test(path)) {
7986
+ if (!/\.map$/i.test(path)) return void 0;
7987
+ if (!cssFile) return void 0;
7988
+ let rel = relative(dirname(cssFile), path);
7989
+ if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute(rel)) {
7954
7990
  return void 0;
7955
7991
  }
7956
- if (cssFile) {
7957
- let relativePath = relative(dirname(cssFile), path);
7958
- if (relativePath === ".." || relativePath.startsWith(".." + sep) || isAbsolute(relativePath)) {
7959
- return void 0;
7960
- }
7961
- }
7962
7992
  }
7963
7993
  this.root = dirname(path);
7964
7994
  if (existsSync(path)) {
@@ -8330,6 +8360,7 @@ function requireList() {
8330
8360
  return list.split(string, spaces);
8331
8361
  },
8332
8362
  split(string, separators, last) {
8363
+ if (!string) return [];
8333
8364
  let array = [];
8334
8365
  let current = "";
8335
8366
  let split = false;
@@ -9616,11 +9647,16 @@ var hasRequiredWarning;
9616
9647
  function requireWarning() {
9617
9648
  if (hasRequiredWarning) return warning;
9618
9649
  hasRequiredWarning = 1;
9650
+ let Container = requireContainer();
9651
+ let { my } = requireSymbols();
9619
9652
  class Warning {
9620
9653
  constructor(text, opts = {}) {
9621
9654
  this.type = "warning";
9622
9655
  this.text = text;
9623
9656
  if (opts.node && opts.node.source) {
9657
+ if (!opts.node[my]) {
9658
+ Container.rebuild(opts.node);
9659
+ }
9624
9660
  let range = opts.node.rangeBy(opts);
9625
9661
  this.line = range.start.line;
9626
9662
  this.column = range.start.column;
@@ -10130,14 +10166,19 @@ function requireLazyResult() {
10130
10166
  }
10131
10167
  if (visit2.iterator !== 0) {
10132
10168
  let iterator = visit2.iterator;
10169
+ if (visit2.descending) {
10170
+ visit2.descending = false;
10171
+ node2.indexes[iterator] += 1;
10172
+ }
10133
10173
  let child;
10134
10174
  while (child = node2.nodes[node2.indexes[iterator]]) {
10135
- node2.indexes[iterator] += 1;
10136
10175
  if (!child[isClean]) {
10137
10176
  child[isClean] = true;
10177
+ visit2.descending = true;
10138
10178
  stack.push(toStack(child));
10139
10179
  return;
10140
10180
  }
10181
+ node2.indexes[iterator] += 1;
10141
10182
  }
10142
10183
  visit2.iterator = 0;
10143
10184
  delete node2.indexes[iterator];
@@ -10167,12 +10208,16 @@ function requireLazyResult() {
10167
10208
  let visitNode = visit2.node;
10168
10209
  if (visit2.iterator !== 0) {
10169
10210
  let iterator = visit2.iterator;
10211
+ if (visit2.descending) {
10212
+ visit2.descending = false;
10213
+ visitNode.indexes[iterator] += 1;
10214
+ }
10170
10215
  let child;
10171
10216
  let descended = false;
10172
10217
  while (child = visitNode.nodes[visitNode.indexes[iterator]]) {
10173
- visitNode.indexes[iterator] += 1;
10174
10218
  if (!child[isClean]) {
10175
10219
  child[isClean] = true;
10220
+ visit2.descending = true;
10176
10221
  stack.push({
10177
10222
  eventIndex: 0,
10178
10223
  events: getEvents(child),
@@ -10182,6 +10227,7 @@ function requireLazyResult() {
10182
10227
  descended = true;
10183
10228
  break;
10184
10229
  }
10230
+ visitNode.indexes[iterator] += 1;
10185
10231
  }
10186
10232
  if (descended) continue;
10187
10233
  visit2.iterator = 0;
@@ -10344,7 +10390,7 @@ function requireProcessor() {
10344
10390
  let Root = requireRoot();
10345
10391
  class Processor {
10346
10392
  constructor(plugins = []) {
10347
- this.version = "8.5.19";
10393
+ this.version = "8.5.25";
10348
10394
  this.plugins = this.normalize(plugins);
10349
10395
  }
10350
10396
  normalize(plugins) {
@@ -19147,20 +19193,530 @@ class Replayer {
19147
19193
  this.config.logger.log(REPLAY_CONSOLE_PREFIX, ...args);
19148
19194
  }
19149
19195
  }
19196
+ const RRWEB_EMBEDDED_CHANNEL = "rrweb-embedded";
19197
+ const RRWEB_EMBEDDED_PROTOCOL_VERSION = 1;
19198
+ const SERIALIZABLE_CONFIG_KEYS = [
19199
+ "speed",
19200
+ "maxSpeed",
19201
+ "loadTimeout",
19202
+ "skipInactive",
19203
+ "inactivePeriodThreshold",
19204
+ "showWarning",
19205
+ "showDebug",
19206
+ "blockClass",
19207
+ "liveMode",
19208
+ "insertStyleRules",
19209
+ "triggerFocus",
19210
+ "UNSAFE_replayCanvas",
19211
+ "cspContent",
19212
+ "pauseAnimation",
19213
+ "mouseTail",
19214
+ "useVirtualDom",
19215
+ "inactiveThreshold",
19216
+ "inactiveSkipTime"
19217
+ ];
19218
+ function pickSerializableConfig(config) {
19219
+ const out = {};
19220
+ if (config && typeof config === "object") {
19221
+ for (const key of SERIALIZABLE_CONFIG_KEYS) {
19222
+ const value = config[key];
19223
+ if (value !== void 0 && typeof value !== "function") {
19224
+ out[key] = value;
19225
+ }
19226
+ }
19227
+ }
19228
+ return out;
19229
+ }
19230
+ function wrap(message) {
19231
+ return {
19232
+ channel: RRWEB_EMBEDDED_CHANNEL,
19233
+ version: RRWEB_EMBEDDED_PROTOCOL_VERSION,
19234
+ message
19235
+ };
19236
+ }
19237
+ function isEnvelope(data) {
19238
+ if (!data || typeof data !== "object") return false;
19239
+ const e2 = data;
19240
+ return e2.channel === RRWEB_EMBEDDED_CHANNEL && e2.version === RRWEB_EMBEDDED_PROTOCOL_VERSION && !!e2.message && typeof e2.message === "object" && typeof e2.message.type === "string";
19241
+ }
19242
+ const PAYLOAD_EVENTS = /* @__PURE__ */ new Set([
19243
+ ReplayerEvents.Resize,
19244
+ ReplayerEvents.EventCast,
19245
+ ReplayerEvents.CustomEvent
19246
+ ]);
19247
+ class EmbeddedReplayerHost {
19248
+ constructor(options = {}) {
19249
+ __publicField(this, "root");
19250
+ __publicField(this, "parentWindow");
19251
+ __publicField(this, "timeUpdateIntervalMs");
19252
+ __publicField(this, "expectedParentOrigin");
19253
+ __publicField(this, "replayer", null);
19254
+ __publicField(this, "playing", false);
19255
+ __publicField(this, "timer", null);
19256
+ __publicField(this, "started", false);
19257
+ /**
19258
+ * Last layout the parent asked for. Retained because each `Replayer` builds
19259
+ * its own wrapper element, so a re-init would otherwise drop the scaling and
19260
+ * render the replay at 1:1 in the corner.
19261
+ */
19262
+ __publicField(this, "layout", null);
19263
+ __publicField(this, "onMessage", (event) => {
19264
+ if (event.source !== this.parentWindow) return;
19265
+ if (this.expectedParentOrigin === null) return;
19266
+ if (event.origin !== this.expectedParentOrigin) return;
19267
+ if (!isEnvelope(event.data)) return;
19268
+ try {
19269
+ this.handle(event.data.message);
19270
+ } catch (err) {
19271
+ this.post({
19272
+ type: "error",
19273
+ message: err instanceof Error ? err.message : String(err)
19274
+ });
19275
+ }
19276
+ });
19277
+ this.root = options.root ?? document.body;
19278
+ this.parentWindow = options.parentWindow ?? window.parent;
19279
+ this.timeUpdateIntervalMs = options.timeUpdateIntervalMs ?? 50;
19280
+ this.expectedParentOrigin = options.expectedParentOrigin ?? new URLSearchParams(location.search).get("parentOrigin") ?? null;
19281
+ }
19282
+ /** Install the message listener and announce readiness to the parent. */
19283
+ start() {
19284
+ if (this.started) return;
19285
+ this.started = true;
19286
+ if (this.expectedParentOrigin === null) {
19287
+ console.warn(
19288
+ "[rrweb-embedded] no parentOrigin configured; all incoming messages will be ignored"
19289
+ );
19290
+ }
19291
+ window.addEventListener("message", this.onMessage);
19292
+ this.post({ type: "ready" });
19293
+ }
19294
+ /** Tear everything down (also invoked on a `destroy` command). */
19295
+ stop() {
19296
+ var _a2;
19297
+ window.removeEventListener("message", this.onMessage);
19298
+ this.setPlaying(false);
19299
+ (_a2 = this.replayer) == null ? void 0 : _a2.destroy();
19300
+ this.replayer = null;
19301
+ this.started = false;
19302
+ }
19303
+ handle(command) {
19304
+ var _a2, _b, _c, _d, _e, _f, _g;
19305
+ switch (command.type) {
19306
+ case "ping":
19307
+ this.post({ type: "ready" });
19308
+ return;
19309
+ case "init":
19310
+ this.init(command.events, command.config, command.autoplay);
19311
+ return;
19312
+ case "play":
19313
+ (_a2 = this.replayer) == null ? void 0 : _a2.play(command.timeOffset ?? 0);
19314
+ this.setPlaying(true);
19315
+ return;
19316
+ case "pause":
19317
+ (_b = this.replayer) == null ? void 0 : _b.pause(command.timeOffset);
19318
+ this.setPlaying(false);
19319
+ this.postTime();
19320
+ return;
19321
+ case "resume":
19322
+ (_c = this.replayer) == null ? void 0 : _c.resume(command.timeOffset ?? 0);
19323
+ this.setPlaying(true);
19324
+ return;
19325
+ case "setLayout":
19326
+ this.layout = {
19327
+ scale: command.scale,
19328
+ anchor: command.anchor ?? "center"
19329
+ };
19330
+ this.applyLayout();
19331
+ this.postDimensions();
19332
+ return;
19333
+ case "setConfig":
19334
+ (_d = this.replayer) == null ? void 0 : _d.setConfig(pickSerializableConfig(command.config));
19335
+ return;
19336
+ case "replaceEvents":
19337
+ if (this.replayer) {
19338
+ this.replayer.replaceEvents(command.events);
19339
+ this.postInitialized();
19340
+ }
19341
+ return;
19342
+ case "addEvent":
19343
+ (_e = this.replayer) == null ? void 0 : _e.addEvent(command.event);
19344
+ return;
19345
+ case "enableInteract":
19346
+ (_f = this.replayer) == null ? void 0 : _f.enableInteract();
19347
+ return;
19348
+ case "disableInteract":
19349
+ (_g = this.replayer) == null ? void 0 : _g.disableInteract();
19350
+ return;
19351
+ case "destroy":
19352
+ this.stop();
19353
+ return;
19354
+ }
19355
+ }
19356
+ init(events, config, autoplay) {
19357
+ if (this.replayer) {
19358
+ this.setPlaying(false);
19359
+ this.replayer.destroy();
19360
+ }
19361
+ const replayerConfig = {
19362
+ ...pickSerializableConfig(config),
19363
+ root: this.root
19364
+ };
19365
+ this.replayer = new Replayer(events, replayerConfig);
19366
+ this.wireEvents(this.replayer);
19367
+ this.applyLayout();
19368
+ this.postInitialized();
19369
+ this.postDimensions();
19370
+ if (autoplay) {
19371
+ this.replayer.play(0);
19372
+ this.setPlaying(true);
19373
+ }
19374
+ }
19375
+ /**
19376
+ * Translate the parent's layout intent into styles on the replay wrapper.
19377
+ *
19378
+ * Mirrors what an embedder would otherwise apply from its own stylesheet:
19379
+ * `transform-origin: top left` with `left: 50%` to center horizontally, and
19380
+ * either `top: 50%` + a -50% Y translate to center vertically, or `top: 0`
19381
+ * with no Y translate to anchor at the top edge.
19382
+ */
19383
+ applyLayout() {
19384
+ var _a2;
19385
+ const wrapper = (_a2 = this.replayer) == null ? void 0 : _a2.wrapper;
19386
+ if (!wrapper || !this.layout) return;
19387
+ const { scale, anchor } = this.layout;
19388
+ const top = anchor === "top";
19389
+ wrapper.style.position = "absolute";
19390
+ wrapper.style.transformOrigin = "top left";
19391
+ wrapper.style.left = "50%";
19392
+ wrapper.style.top = top ? "0" : "50%";
19393
+ wrapper.style.transform = top ? `scale(${scale}) translate(-50%, 0)` : `scale(${scale}) translate(-50%, -50%)`;
19394
+ }
19395
+ /** Report the wrapper's rendered geometry; the parent cannot measure it. */
19396
+ postDimensions() {
19397
+ var _a2;
19398
+ const wrapper = (_a2 = this.replayer) == null ? void 0 : _a2.wrapper;
19399
+ if (!wrapper) return;
19400
+ const rect = wrapper.getBoundingClientRect();
19401
+ this.post({
19402
+ type: "dimensions",
19403
+ width: rect.width,
19404
+ height: rect.height,
19405
+ top: rect.top,
19406
+ left: rect.left
19407
+ });
19408
+ }
19409
+ /** Push the stable getters (metadata, activity intervals) to the parent. */
19410
+ postInitialized() {
19411
+ if (!this.replayer) return;
19412
+ this.post({
19413
+ type: "initialized",
19414
+ metadata: this.replayer.getMetaData(),
19415
+ activityIntervals: this.replayer.getActivityIntervals()
19416
+ });
19417
+ }
19418
+ wireEvents(replayer) {
19419
+ for (const name of Object.values(ReplayerEvents)) {
19420
+ replayer.on(name, (payload) => {
19421
+ if (name === ReplayerEvents.Finish) {
19422
+ this.setPlaying(false);
19423
+ this.postTime();
19424
+ }
19425
+ if (name === ReplayerEvents.Resize) {
19426
+ this.postDimensions();
19427
+ }
19428
+ this.post(
19429
+ PAYLOAD_EVENTS.has(name) && payload !== void 0 ? { type: "replayer-event", event: name, payload } : { type: "replayer-event", event: name }
19430
+ );
19431
+ });
19432
+ }
19433
+ }
19434
+ /* --- current-time telemetry ------------------------------------------- */
19435
+ setPlaying(playing) {
19436
+ if (this.playing === playing) return;
19437
+ this.playing = playing;
19438
+ if (playing) this.startTimePump();
19439
+ else this.stopTimePump();
19440
+ }
19441
+ startTimePump() {
19442
+ if (this.timer !== null) return;
19443
+ this.timer = setInterval(() => this.postTime(), this.timeUpdateIntervalMs);
19444
+ }
19445
+ /**
19446
+ * Push the current playback position across the bridge.
19447
+ *
19448
+ * The parent cannot read the position synchronously — it lives in this realm
19449
+ * behind an origin boundary — so the client's `getCurrentTime()` is only ever
19450
+ * as fresh as the last push. While playing, the pump keeps it current. When
19451
+ * playback stops the pump stops too, so the last pumped value would be up to
19452
+ * one interval stale; callers that seek from it (`play(getCurrentTime())` to
19453
+ * resume) would drift backwards. Pausing and finishing therefore push one
19454
+ * final, settled value.
19455
+ */
19456
+ postTime() {
19457
+ if (!this.replayer) return;
19458
+ this.post({ type: "time", currentTime: this.replayer.getCurrentTime() });
19459
+ }
19460
+ stopTimePump() {
19461
+ if (this.timer !== null) {
19462
+ clearInterval(this.timer);
19463
+ this.timer = null;
19464
+ }
19465
+ }
19466
+ post(message) {
19467
+ this.parentWindow.postMessage(
19468
+ wrap(message),
19469
+ this.expectedParentOrigin ?? "*"
19470
+ );
19471
+ }
19472
+ }
19473
+ function startEmbeddedReplayerHost(options) {
19474
+ const host2 = new EmbeddedReplayerHost(options);
19475
+ host2.start();
19476
+ return host2;
19477
+ }
19478
+ class EmbeddedReplayerClient {
19479
+ constructor(iframe, options = {}) {
19480
+ __publicField(this, "iframe");
19481
+ __publicField(this, "hostOrigin");
19482
+ __publicField(this, "listeners", /* @__PURE__ */ new Map());
19483
+ __publicField(this, "metadata", null);
19484
+ __publicField(this, "activityIntervals", []);
19485
+ __publicField(this, "dimensions", null);
19486
+ __publicField(this, "lastCurrentTime", 0);
19487
+ __publicField(this, "ready", false);
19488
+ __publicField(this, "readyResolvers", []);
19489
+ __publicField(this, "disposed", false);
19490
+ /**
19491
+ * Commands issued before the host handshakes. A command posted while the
19492
+ * iframe is still on its initial `about:blank` (which carries the PARENT's
19493
+ * origin) is rejected by the browser as an origin mismatch and lost — the
19494
+ * viewer calls `setLayout` on mount, well before the host boots. Buffer until
19495
+ * `ready`, then flush; by then the frame is on the host origin.
19496
+ */
19497
+ __publicField(this, "pending", []);
19498
+ __publicField(this, "onMessage", (event) => {
19499
+ if (event.source !== this.iframe.contentWindow) return;
19500
+ if (!isEnvelope(event.data)) return;
19501
+ this.handle(event.data.message);
19502
+ });
19503
+ this.iframe = iframe;
19504
+ this.hostOrigin = options.hostOrigin ?? "*";
19505
+ window.addEventListener("message", this.onMessage);
19506
+ this.probe();
19507
+ }
19508
+ /** Resolves once the host iframe has loaded and announced readiness. */
19509
+ whenReady() {
19510
+ if (this.ready) return Promise.resolve();
19511
+ return new Promise((resolve) => this.readyResolvers.push(resolve));
19512
+ }
19513
+ /* --- commands --------------------------------------------------------- */
19514
+ init(events, config, autoplay = false) {
19515
+ this.send({ type: "init", events, config, autoplay });
19516
+ }
19517
+ play(timeOffset) {
19518
+ this.send({ type: "play", timeOffset });
19519
+ }
19520
+ pause(timeOffset) {
19521
+ this.send({ type: "pause", timeOffset });
19522
+ }
19523
+ resume(timeOffset) {
19524
+ this.send({ type: "resume", timeOffset });
19525
+ }
19526
+ setConfig(config) {
19527
+ this.send({ type: "setConfig", config });
19528
+ }
19529
+ /**
19530
+ * Scale and position the replay. Compute `scale` from your own container size
19531
+ * and the recorded viewport, as you would when driving a local `Replayer`;
19532
+ * the host applies it, since the wrapper element is not reachable from here.
19533
+ * The layout is retained across re-inits.
19534
+ */
19535
+ setLayout(scale, anchor) {
19536
+ this.send({ type: "setLayout", scale, anchor });
19537
+ }
19538
+ replaceEvents(events) {
19539
+ this.send({ type: "replaceEvents", events });
19540
+ }
19541
+ addEvent(event) {
19542
+ this.send({ type: "addEvent", event });
19543
+ }
19544
+ enableInteract() {
19545
+ this.send({ type: "enableInteract" });
19546
+ }
19547
+ disableInteract() {
19548
+ this.send({ type: "disableInteract" });
19549
+ }
19550
+ /** Tear down: destroys the host replayer and detaches the listener. */
19551
+ destroy() {
19552
+ if (this.disposed) return;
19553
+ this.disposed = true;
19554
+ try {
19555
+ this.send({ type: "destroy" });
19556
+ } finally {
19557
+ window.removeEventListener("message", this.onMessage);
19558
+ this.listeners.clear();
19559
+ }
19560
+ }
19561
+ /* --- event surface ---------------------------------------------------- */
19562
+ on(event, listener) {
19563
+ let set = this.listeners.get(event);
19564
+ if (!set) {
19565
+ set = /* @__PURE__ */ new Set();
19566
+ this.listeners.set(event, set);
19567
+ }
19568
+ set.add(listener);
19569
+ }
19570
+ off(event, listener) {
19571
+ var _a2;
19572
+ (_a2 = this.listeners.get(event)) == null ? void 0 : _a2.delete(listener);
19573
+ }
19574
+ /* --- getters ---------------------------------------------------------- */
19575
+ // Cached getters mirroring the local Replayer's synchronous ones. Metadata
19576
+ // and activity intervals arrive on `initialized` (re-sent on replaceEvents);
19577
+ // current time is streamed by the host while playing.
19578
+ /** Last-known current time (pushed by the host while playing). */
19579
+ getCurrentTime() {
19580
+ return this.lastCurrentTime;
19581
+ }
19582
+ getMetaData() {
19583
+ return this.metadata;
19584
+ }
19585
+ getActivityIntervals() {
19586
+ return this.activityIntervals;
19587
+ }
19588
+ /**
19589
+ * Rendered geometry of the replay, in the host document's coordinate space —
19590
+ * the cross-origin stand-in for `replayer.wrapper.getBoundingClientRect()`.
19591
+ * Null until the host has reported it (listen for `'dimensions'`).
19592
+ */
19593
+ getDimensions() {
19594
+ return this.dimensions;
19595
+ }
19596
+ /* --- internals -------------------------------------------------------- */
19597
+ send(command) {
19598
+ if (!this.ready) {
19599
+ this.pending.push(command);
19600
+ return;
19601
+ }
19602
+ this.postToHost(command);
19603
+ }
19604
+ postToHost(command) {
19605
+ const target = this.iframe.contentWindow;
19606
+ if (!target) return;
19607
+ target.postMessage(wrap(command), this.hostOrigin);
19608
+ }
19609
+ flushPending() {
19610
+ const queued = this.pending;
19611
+ this.pending = [];
19612
+ queued.forEach((command) => this.postToHost(command));
19613
+ }
19614
+ /** Data-free handshake probe; see the note in the constructor. */
19615
+ probe() {
19616
+ var _a2;
19617
+ (_a2 = this.iframe.contentWindow) == null ? void 0 : _a2.postMessage(wrap({ type: "ping" }), "*");
19618
+ }
19619
+ handle(message) {
19620
+ switch (message.type) {
19621
+ case "ready":
19622
+ this.ready = true;
19623
+ this.flushPending();
19624
+ this.readyResolvers.forEach((r2) => r2());
19625
+ this.readyResolvers = [];
19626
+ return;
19627
+ case "initialized":
19628
+ this.metadata = message.metadata;
19629
+ this.activityIntervals = message.activityIntervals;
19630
+ this.emit("initialized", message.metadata);
19631
+ return;
19632
+ case "replayer-event":
19633
+ this.emit(message.event, message.payload);
19634
+ return;
19635
+ case "time":
19636
+ this.lastCurrentTime = message.currentTime;
19637
+ this.emit("time", message.currentTime);
19638
+ return;
19639
+ case "dimensions":
19640
+ this.dimensions = {
19641
+ width: message.width,
19642
+ height: message.height,
19643
+ top: message.top,
19644
+ left: message.left
19645
+ };
19646
+ this.emit("dimensions", this.dimensions);
19647
+ return;
19648
+ case "error":
19649
+ this.emit("error", message.message);
19650
+ return;
19651
+ }
19652
+ }
19653
+ emit(event, payload) {
19654
+ var _a2;
19655
+ (_a2 = this.listeners.get(event)) == null ? void 0 : _a2.forEach((listener) => listener(payload));
19656
+ }
19657
+ }
19658
+ function originOf(url) {
19659
+ try {
19660
+ return new URL(url).origin;
19661
+ } catch {
19662
+ return "'self'";
19663
+ }
19664
+ }
19665
+ function buildHostDocument(options) {
19666
+ const scriptOrigin = originOf(options.scriptUrl);
19667
+ const styleSources = [
19668
+ "'unsafe-inline'",
19669
+ scriptOrigin,
19670
+ ...options.extraStyleSources ?? []
19671
+ ].join(" ");
19672
+ const csp = [
19673
+ `default-src 'none'`,
19674
+ `script-src ${scriptOrigin}`,
19675
+ `style-src ${styleSources}`,
19676
+ `img-src * data: blob:`,
19677
+ `font-src * data:`,
19678
+ `media-src * data: blob:`,
19679
+ `frame-src *`,
19680
+ `connect-src 'none'`,
19681
+ `worker-src 'none'`
19682
+ ].join("; ");
19683
+ const styleTag = options.styleUrl ? `<link rel="stylesheet" href="${escapeAttr(options.styleUrl)}">` : "";
19684
+ return `<!DOCTYPE html>
19685
+ <html>
19686
+ <head>
19687
+ <meta charset="utf-8">
19688
+ <meta http-equiv="Content-Security-Policy" content="${escapeAttr(csp)}">
19689
+ <style>html,body{margin:0;padding:0;height:100%;overflow:hidden;background:transparent}</style>
19690
+ ${styleTag}
19691
+ <script type="module" src="${escapeAttr(options.scriptUrl)}"><\/script>
19692
+ </head>
19693
+ <body></body>
19694
+ </html>`;
19695
+ }
19696
+ function escapeAttr(value) {
19697
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19698
+ }
19150
19699
  const { addCustomEvent } = record;
19151
19700
  const { freezePage } = record;
19152
19701
  const { takeFullSnapshot } = record;
19153
19702
  export {
19703
+ EmbeddedReplayerClient,
19704
+ EmbeddedReplayerHost,
19154
19705
  EventType,
19155
19706
  IncrementalSource,
19156
19707
  MouseInteractions,
19708
+ RRWEB_EMBEDDED_CHANNEL,
19709
+ RRWEB_EMBEDDED_PROTOCOL_VERSION,
19157
19710
  Replayer,
19158
19711
  ReplayerEvents,
19159
19712
  addCustomEvent,
19713
+ buildHostDocument,
19160
19714
  canvasMutation,
19161
19715
  freezePage,
19162
19716
  _mirror as mirror,
19717
+ pickSerializableConfig,
19163
19718
  record,
19719
+ startEmbeddedReplayerHost,
19164
19720
  takeFullSnapshot,
19165
19721
  utils
19166
19722
  };