@checksum-ai/runtime 1.1.52 → 1.1.54-beta

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/checksumlib.js CHANGED
@@ -29412,14 +29412,74 @@
29412
29412
 
29413
29413
  // ../browser-lib/src/session-record-replay/session-replayer.ts
29414
29414
  var import_await_sleep3 = __toESM(require_await_sleep());
29415
+
29416
+ // ../browser-lib/src/session-record-replay/replayer-listeners-manager.ts
29417
+ var ReplayerListenersManager = class {
29418
+ constructor() {
29419
+ this._replayingState = "Paused" /* Paused */;
29420
+ // Internal state for isShowing
29421
+ this.listeners = [];
29422
+ }
29423
+ static {
29424
+ __name(this, "ReplayerListenersManager");
29425
+ }
29426
+ // Listeners array
29427
+ // Setter for isShowing with listener notification
29428
+ set replayingState(value) {
29429
+ this._replayingState = value;
29430
+ this.notifyListeners();
29431
+ }
29432
+ // Add a listener to observe changes to isShowing
29433
+ addListener(listener) {
29434
+ this.listeners.push(listener);
29435
+ }
29436
+ // Remove a listener
29437
+ removeListener(listener) {
29438
+ this.listeners = this.listeners.filter((l2) => l2 !== listener);
29439
+ }
29440
+ // Wrapper function to handle loading state
29441
+ async wrapWithLoadingState(fn, loadingCompletedState = "Paused" /* Paused */) {
29442
+ this.replayingState = "Processing" /* Processing */;
29443
+ return new Promise((resolve2, reject) => {
29444
+ requestAnimationFrame(() => {
29445
+ setTimeout(() => {
29446
+ fn().then((result2) => {
29447
+ resolve2(result2);
29448
+ }).catch((error) => {
29449
+ reject(error);
29450
+ }).finally(() => {
29451
+ this.replayingState = loadingCompletedState;
29452
+ });
29453
+ }, 0);
29454
+ });
29455
+ });
29456
+ }
29457
+ // Notify all listeners of the state change
29458
+ notifyListeners() {
29459
+ this.listeners.forEach((listener) => listener(this._replayingState));
29460
+ }
29461
+ };
29462
+
29463
+ // ../browser-lib/src/session-record-replay/session-replayer.ts
29415
29464
  var DEBUG_MODE = false;
29416
29465
  var SessionReplayer = class {
29417
29466
  constructor(config = {}) {
29418
- // array of events to init replayer
29419
- this.eventsBuffer = [];
29467
+ this.initialEventsBuffer = [];
29420
29468
  this.config = {
29421
29469
  enableInteract: false
29422
29470
  };
29471
+ this.overlayElement = null;
29472
+ this.timer = null;
29473
+ this.animationFrameStepHandler = {
29474
+ wait: /* @__PURE__ */ __name((callback) => requestAnimationFrame(callback), "wait"),
29475
+ cancel: /* @__PURE__ */ __name((id) => cancelAnimationFrame(id), "cancel")
29476
+ };
29477
+ this.timoutStepHandler = {
29478
+ wait: /* @__PURE__ */ __name((callback) => {
29479
+ return setTimeout(callback, 100);
29480
+ }, "wait"),
29481
+ cancel: /* @__PURE__ */ __name((id) => clearTimeout(id), "cancel")
29482
+ };
29423
29483
  this.stop = /* @__PURE__ */ __name(() => {
29424
29484
  try {
29425
29485
  if (this.replayer) {
@@ -29442,6 +29502,7 @@
29442
29502
  castedEvents: []
29443
29503
  };
29444
29504
  this.config = { ...this.config, ...config };
29505
+ this.replayerListenersManager = new ReplayerListenersManager();
29445
29506
  }
29446
29507
  static {
29447
29508
  __name(this, "SessionReplayer");
@@ -29487,18 +29548,53 @@
29487
29548
  }
29488
29549
  });
29489
29550
  }
29551
+ getCurrentTimestamp() {
29552
+ try {
29553
+ return this.replayer.getCurrentTime() + this.firstEvent.timestamp;
29554
+ } catch (e2) {
29555
+ return 0;
29556
+ }
29557
+ }
29558
+ monitorTime(targetTime, onTargetHook, stepHandler = this.animationFrameStepHandler) {
29559
+ const stopTimer = /* @__PURE__ */ __name(() => {
29560
+ if (this.timer) {
29561
+ stepHandler.cancel(this.timer);
29562
+ this.timer = null;
29563
+ }
29564
+ }, "stopTimer");
29565
+ stopTimer();
29566
+ const update = /* @__PURE__ */ __name(() => {
29567
+ const currentTime = this.replayer.getCurrentTime();
29568
+ if (targetTime && currentTime >= targetTime) {
29569
+ console.log(
29570
+ `[SessionReplayer] achieved target time: ${targetTime} with current time ${currentTime}`,
29571
+ Date.now()
29572
+ );
29573
+ onTargetHook();
29574
+ stopTimer();
29575
+ return;
29576
+ } else {
29577
+ console.log(
29578
+ `[SessionReplayer] monitoring time, current: ${currentTime}; target: ${targetTime}...`
29579
+ );
29580
+ }
29581
+ const meta = this.replayer.getMetaData();
29582
+ if (currentTime < meta.totalTime) {
29583
+ this.timer = stepHandler.wait(update);
29584
+ }
29585
+ }, "update");
29586
+ this.timer = stepHandler.wait(update);
29587
+ }
29490
29588
  seek(ts, pause = true) {
29491
29589
  return new Promise((resolve2) => {
29492
29590
  const delta = ts - this.firstEvent.timestamp;
29493
- this.replayer.play(delta);
29494
- if (pause) {
29495
- setTimeout(() => {
29496
- this.replayer?.pause();
29497
- resolve2();
29498
- }, 0);
29499
- } else {
29591
+ this.monitorTime(delta, () => {
29592
+ if (pause) {
29593
+ this.replayer.pause();
29594
+ }
29500
29595
  resolve2();
29501
- }
29596
+ });
29597
+ this.replayer.play(delta);
29502
29598
  });
29503
29599
  }
29504
29600
  start(options, castedEvents = []) {
@@ -29509,9 +29605,9 @@
29509
29605
  if (this.config.onlyLive) {
29510
29606
  this.makeReplayer([], { baselineTime: events[0].timestamp });
29511
29607
  } else {
29512
- this.eventsBuffer.push(...events);
29513
- if (this.eventsBuffer.length > 2) {
29514
- this.makeReplayer(this.eventsBuffer);
29608
+ this.initialEventsBuffer.push(...events);
29609
+ if (this.initialEventsBuffer.length >= 2) {
29610
+ this.makeReplayer(this.initialEventsBuffer);
29515
29611
  } else {
29516
29612
  return;
29517
29613
  }
@@ -29538,16 +29634,22 @@
29538
29634
  return promise;
29539
29635
  }
29540
29636
  async goLive() {
29541
- await this.seek(this.lastEvent.timestamp, false);
29542
- await (0, import_await_sleep3.default)(1e3);
29637
+ await this.replayerListenersManager.wrapWithLoadingState(async () => {
29638
+ await this.seek(this.lastEvent.timestamp, false);
29639
+ await (0, import_await_sleep3.default)(1e3);
29640
+ });
29543
29641
  }
29544
29642
  async goBack(timestamp, {
29545
29643
  sleepAfter = 1e3,
29546
29644
  beforeTimestamp = false,
29547
29645
  includeAllMatchingTimestamps = false
29548
29646
  } = {}) {
29549
- await this.seek(timestamp, true);
29550
- await (0, import_await_sleep3.default)(1e3);
29647
+ await this.replayerListenersManager.wrapWithLoadingState(async () => {
29648
+ await this.seek(timestamp, true);
29649
+ if (sleepAfter) {
29650
+ await (0, import_await_sleep3.default)(sleepAfter);
29651
+ }
29652
+ });
29551
29653
  }
29552
29654
  storeEvent(event) {
29553
29655
  if (!this.debugData.active) {
@@ -29565,7 +29667,7 @@
29565
29667
  this.debugData.active = true;
29566
29668
  window.__chkreplayer = {
29567
29669
  events: /* @__PURE__ */ __name(() => this.debugData.events, "events"),
29568
- back: /* @__PURE__ */ __name((ts) => this.goBack(ts, {}), "back"),
29670
+ back: /* @__PURE__ */ __name((ts) => this.goBack(ts), "back"),
29569
29671
  currentTime: /* @__PURE__ */ __name(() => this.replayer.getCurrentTime(), "currentTime"),
29570
29672
  castedEvents: /* @__PURE__ */ __name(() => this.debugData.castedEvents, "castedEvents")
29571
29673
  };
@@ -30691,12 +30793,6 @@
30691
30793
  this.observer = new MutationObserver((mutations) => {
30692
30794
  mutations.forEach((mutation) => {
30693
30795
  mutation.addedNodes.forEach((addedNode) => {
30694
- if (addedNode.querySelector) {
30695
- const ifr = addedNode.querySelector("iframe");
30696
- if (ifr) {
30697
- console.log("FFF", ifr);
30698
- }
30699
- }
30700
30796
  if (addedNode.nodeType !== Node.ELEMENT_NODE) {
30701
30797
  return;
30702
30798
  }
@@ -32409,7 +32505,7 @@
32409
32505
 
32410
32506
  // ../js-lib/src/helpers/helpers.ts
32411
32507
  var awaitSleep = /* @__PURE__ */ __name((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)), "awaitSleep");
32412
- var guardReturn = /* @__PURE__ */ __name(async (promise, timeout = 1e3, errMessage = "guardReturnTimedOut") => {
32508
+ var guardReturn = /* @__PURE__ */ __name(async (promise, timeout = 1e3, errMessage) => {
32413
32509
  if (timeout === null) {
32414
32510
  return promise;
32415
32511
  }
@@ -32420,7 +32516,10 @@
32420
32516
  }, "guard");
32421
32517
  const res = await Promise.race([promise, guard()]);
32422
32518
  if (typeof res === "string" && res === timeoutStringIdentifier) {
32423
- throw new Error(errMessage);
32519
+ if (typeof errMessage === "function") {
32520
+ throw new Error(errMessage());
32521
+ }
32522
+ throw new Error(errMessage ?? "guardReturnTimedOut");
32424
32523
  }
32425
32524
  return res;
32426
32525
  }, "guardReturn");
@@ -32516,6 +32615,7 @@
32516
32615
  this.expandCSSKeyFeatures(element, cssKeyElements);
32517
32616
  }
32518
32617
  while (element && element !== this.rootNode) {
32618
+ await awaitSleep(0);
32519
32619
  const elementCandidates = this.getAllLocators(
32520
32620
  element,
32521
32621
  cssKeyElements,
@@ -32525,11 +32625,12 @@
32525
32625
  }
32526
32626
  );
32527
32627
  const validLocators = [];
32528
- const testCandidate = /* @__PURE__ */ __name((chain) => {
32628
+ const testCandidate = /* @__PURE__ */ __name(async (chain) => {
32529
32629
  if (chain.hasDuplicateFilters()) {
32530
32630
  return;
32531
32631
  }
32532
32632
  try {
32633
+ await awaitSleep(0);
32533
32634
  const { elements } = this.getLocatorBase(element).locator(
32534
32635
  chain.getSelector()
32535
32636
  );
@@ -32543,15 +32644,15 @@
32543
32644
  }
32544
32645
  }, "testCandidate");
32545
32646
  if (!locatorsChains.length) {
32546
- elementCandidates.forEach(
32547
- (ec) => testCandidate(new LocatorChain([ec]))
32548
- );
32647
+ for (const ec of elementCandidates) {
32648
+ await testCandidate(new LocatorChain([ec]));
32649
+ }
32549
32650
  } else {
32550
- elementCandidates.forEach((ec) => {
32551
- locatorsChains.forEach(
32552
- (sc) => testCandidate(sc.cloneAndAddCandidate(ec))
32553
- );
32554
- });
32651
+ for (const ec of elementCandidates) {
32652
+ for (const sc of locatorsChains) {
32653
+ await testCandidate(sc.cloneAndAddCandidate(ec));
32654
+ }
32655
+ }
32555
32656
  }
32556
32657
  if (validLocators.length === 0 && locatorsChains.length === 0) {
32557
32658
  const selector = element.tagName.toLowerCase();
@@ -32944,7 +33045,7 @@
32944
33045
  * @returns array of new candidates that return only one element
32945
33046
  */
32946
33047
  async reduceMultiCandidates(candidate) {
32947
- await awaitSleep(100);
33048
+ await awaitSleep(0);
32948
33049
  const { elements } = candidate;
32949
33050
  const parts = candidate.getSelector().split(" >> ");
32950
33051
  const newCandidates = [];
@@ -34008,6 +34109,7 @@
34008
34109
  this.sessionMirror = sessionMirror;
34009
34110
  }
34010
34111
  // Get files for a specific input by rrwebId
34112
+ // !! used in msg broker
34011
34113
  async getFilesByRrwebId(rrwebId) {
34012
34114
  const files = this.filesMap[rrwebId] ?? [];
34013
34115
  try {
@@ -34074,7 +34176,10 @@
34074
34176
  onBodyReady();
34075
34177
  }
34076
34178
  });
34077
- bodyObserver.observe(document2.documentElement, { childList: true });
34179
+ bodyObserver.observe(document2.documentElement, {
34180
+ childList: true,
34181
+ subtree: true
34182
+ });
34078
34183
  }
34079
34184
  // Cleanup the observer and remove event listeners
34080
34185
  cleanup() {
@@ -34162,6 +34267,7 @@
34162
34267
  this.singleSelection = true;
34163
34268
  this.subDocumentInspector = null;
34164
34269
  this.listening = false;
34270
+ this.locatorCache = InspectedElementCache.getInstance();
34165
34271
  this.onMouseOut = /* @__PURE__ */ __name((event) => {
34166
34272
  elementHighlighter.clearHighlights();
34167
34273
  }, "onMouseOut");
@@ -34197,13 +34303,7 @@
34197
34303
  capture: true
34198
34304
  });
34199
34305
  }
34200
- const { locator, selector, parentFramesSelectors } = await this.playwrightElementSelectorGenerator.getSelectorAndLocator(targetElement).catch((error) => {
34201
- return {
34202
- locator: "",
34203
- selector: "",
34204
- parentFramesSelectors: []
34205
- };
34206
- });
34306
+ const { locator, selector, parentFramesSelectors, locatorRrwebId } = await this.getInspectedElementSelection(targetElement);
34207
34307
  elementHighlighter.highlightElement(targetElement, {
34208
34308
  text: locator.replace("frameLocator('iframe').", ""),
34209
34309
  textPosition: "below",
@@ -34212,15 +34312,17 @@
34212
34312
  classNames: ["element-inspector-ignore"],
34213
34313
  renderDocument: this.getRenderDocument(this.defaultView)
34214
34314
  });
34215
- const elementByLocator = await this.playwrightElementSelectorGenerator.selector(selector, parentFramesSelectors).catch(() => targetElement);
34216
- if (elementByLocator !== target) {
34217
- elementHighlighter.highlightElement(elementByLocator, {
34218
- // highlightStyle: { outlineColor: "blue" },
34219
- clear: false,
34220
- pointerEvents: "none",
34221
- classNames: ["element-inspector-ignore"],
34222
- renderDocument: this.getRenderDocument(this.defaultView)
34223
- });
34315
+ if (locatorRrwebId) {
34316
+ const element = window.checksum.timeMachine.sessionReplayer.getNodeById(locatorRrwebId);
34317
+ if (element) {
34318
+ elementHighlighter.highlightElement(element, {
34319
+ // highlightStyle: { outlineColor: "blue" },
34320
+ clear: false,
34321
+ pointerEvents: "none",
34322
+ classNames: ["element-inspector-ignore"],
34323
+ renderDocument: this.getRenderDocument(this.defaultView)
34324
+ });
34325
+ }
34224
34326
  }
34225
34327
  this.hoveredElement = targetElement;
34226
34328
  this.hoveredElementSelection = { locator, selector, parentFramesSelectors };
@@ -34261,7 +34363,10 @@
34261
34363
  topLevelInspector: this.topLevelInspector ?? this,
34262
34364
  getRenderDocument: this.getRenderDocument
34263
34365
  });
34264
- this.subDocumentInspector.start(this.singleSelection);
34366
+ this.subDocumentInspector.start({
34367
+ singleSelection: this.singleSelection,
34368
+ timestamp: this.currentTimestamp
34369
+ });
34265
34370
  return true;
34266
34371
  }, "handleSubDocument");
34267
34372
  this.stopSubDocumentInspector = /* @__PURE__ */ __name((clean) => {
@@ -34282,8 +34387,15 @@
34282
34387
  getDefaultView() {
34283
34388
  return this.rootDocument.nodeType === Node.DOCUMENT_NODE ? this.rootDocument.defaultView : window;
34284
34389
  }
34285
- start(singleSelection = true) {
34390
+ start({
34391
+ singleSelection,
34392
+ timestamp
34393
+ } = {
34394
+ singleSelection: true
34395
+ }) {
34286
34396
  this.singleSelection = singleSelection;
34397
+ this.locatorCache.setTimestamp(timestamp);
34398
+ this.currentTimestamp = timestamp;
34287
34399
  this.stop();
34288
34400
  this.cleanSelection();
34289
34401
  this.rootDocument.addEventListener("mouseover", this.onMouseOver);
@@ -34304,6 +34416,7 @@
34304
34416
  capture: true
34305
34417
  });
34306
34418
  }
34419
+ this.currentTimestamp = void 0;
34307
34420
  this.hoveredElement = null;
34308
34421
  this.wasHoveredElementSelected = false;
34309
34422
  this.rootDocument.removeEventListener("mouseover", this.onMouseOver);
@@ -34325,7 +34438,78 @@
34325
34438
  this.cleanSelection();
34326
34439
  return selected;
34327
34440
  }
34441
+ /**
34442
+ * Gets selection data for element.
34443
+ * Tried to fetch from cache first, if not found, generates new data, saves it to cache and returns it.
34444
+ */
34445
+ async getInspectedElementSelection(element) {
34446
+ let cache = this.locatorCache.getCachedLocatorForElement(element);
34447
+ if (!cache) {
34448
+ const { locator, selector, parentFramesSelectors } = await this.playwrightElementSelectorGenerator.getSelectorAndLocator(element).catch((error) => {
34449
+ return {
34450
+ locator: "",
34451
+ selector: "",
34452
+ parentFramesSelectors: []
34453
+ };
34454
+ });
34455
+ const locatorElement = await this.playwrightElementSelectorGenerator.selector(selector, parentFramesSelectors).catch(() => element);
34456
+ const locatorRrwebId = locatorElement !== element ? getNodeRrwebId(locatorElement) : void 0;
34457
+ cache = {
34458
+ locator,
34459
+ selector,
34460
+ parentFramesSelectors,
34461
+ locatorRrwebId
34462
+ };
34463
+ this.locatorCache.setCachedLocatorForElement(element, cache);
34464
+ }
34465
+ return cache;
34466
+ }
34328
34467
  };
34468
+ var InspectedElementCache = class _InspectedElementCache {
34469
+ constructor() {
34470
+ this.locatorCache = /* @__PURE__ */ new Map();
34471
+ }
34472
+ static {
34473
+ __name(this, "InspectedElementCache");
34474
+ }
34475
+ // key - rrwebid_timestamp
34476
+ static getInstance() {
34477
+ if (!_InspectedElementCache.instance) {
34478
+ _InspectedElementCache.instance = new _InspectedElementCache();
34479
+ }
34480
+ return _InspectedElementCache.instance;
34481
+ }
34482
+ setTimestamp(timestamp) {
34483
+ this.currentTimestamp = timestamp;
34484
+ }
34485
+ getCachedLocatorForElement(element) {
34486
+ try {
34487
+ if (!this.currentTimestamp) {
34488
+ return;
34489
+ }
34490
+ return this.locatorCache.get(this.getKeyForElement(element));
34491
+ } catch (e2) {
34492
+ return;
34493
+ }
34494
+ }
34495
+ setCachedLocatorForElement(element, cache) {
34496
+ if (!this.currentTimestamp) {
34497
+ return;
34498
+ }
34499
+ this.locatorCache.set(this.getKeyForElement(element), cache);
34500
+ }
34501
+ getKeyForElement(element) {
34502
+ const rrwebId = getNodeRrwebId(element);
34503
+ if (!rrwebId) {
34504
+ throw new Error("Can't find rrwebId for element");
34505
+ }
34506
+ return `${rrwebId}_${this.currentTimestamp}`;
34507
+ }
34508
+ };
34509
+ function getNodeRrwebId(node2) {
34510
+ return window.checksum.timeMachine.sessionReplayer.getMeta(node2)?.id;
34511
+ }
34512
+ __name(getNodeRrwebId, "getNodeRrwebId");
34329
34513
 
34330
34514
  // src/lib/test-generator/assertions-observer/keybindings-manager.ts
34331
34515
  var import_mousetrap = __toESM(require_mousetrap());
@@ -34598,7 +34782,6 @@ ${data.locator}`
34598
34782
  event.isCheckout = isCheckout;
34599
34783
  window.checksumSendBroadcastMessage?.("rrweb", [event]);
34600
34784
  this.lastRrwebEventTimestamp = event.timestamp;
34601
- console.log(event.timestamp);
34602
34785
  }, config.recordOptions);
34603
34786
  }
34604
34787
  if (initFilesObserver) {
@@ -35424,6 +35607,7 @@ ${data.locator}`
35424
35607
  constructor() {
35425
35608
  super({ enableInteract: true });
35426
35609
  this.shouldHandleEvents = true;
35610
+ this.name = "timeMachine";
35427
35611
  }
35428
35612
  static {
35429
35613
  __name(this, "TimeMachine");
@@ -35455,7 +35639,7 @@ ${data.locator}`
35455
35639
  if (!timestamp) {
35456
35640
  return this.goLive();
35457
35641
  }
35458
- return this.sessionReplayer.goBack(timestamp, options);
35642
+ return this.sessionReplayer.goBack(timestamp);
35459
35643
  }
35460
35644
  getElementByRRwebId(rrwebId) {
35461
35645
  return this.sessionReplayer.getNodeById(rrwebId);
@@ -35463,6 +35647,9 @@ ${data.locator}`
35463
35647
  goLive() {
35464
35648
  return this.sessionReplayer.goLive();
35465
35649
  }
35650
+ getCurrentTimestamp() {
35651
+ return this.sessionReplayer.getCurrentTimestamp();
35652
+ }
35466
35653
  };
35467
35654
 
35468
35655
  // ../browser-lib/src/visual-test-generator/time-machine-event-handlers.ts
@@ -36108,7 +36295,11 @@ ${data.locator}`
36108
36295
  setSendRecordedSteps(sendRecordedSteps) {
36109
36296
  this.sendRecordedSteps = sendRecordedSteps;
36110
36297
  }
36111
- startInspector(singleSelection = true, rootDocument) {
36298
+ startInspector({
36299
+ singleSelection = true,
36300
+ rootDocument,
36301
+ timestamp
36302
+ } = {}) {
36112
36303
  this.stopInspector();
36113
36304
  const getRenderDocument = /* @__PURE__ */ __name((defaultView) => {
36114
36305
  return defaultView.top.document.querySelector(
@@ -36119,7 +36310,7 @@ ${data.locator}`
36119
36310
  rootDocument: rootDocument ?? this.getRRwebReplayerDocument(),
36120
36311
  getRenderDocument
36121
36312
  });
36122
- this.elementInspector.start(singleSelection);
36313
+ this.elementInspector.start({ singleSelection, timestamp });
36123
36314
  }
36124
36315
  getRRwebReplayerDocument() {
36125
36316
  return document.querySelector(".replayer-wrapper > iframe").contentDocument;