@loopcheck/qa-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/ARCHITECTURE.md +59 -0
  2. package/README.md +131 -0
  3. package/dist/config/normalize.d.ts +6 -0
  4. package/dist/config/normalize.d.ts.map +1 -0
  5. package/dist/config/normalize.js +88 -0
  6. package/dist/config/normalize.js.map +1 -0
  7. package/dist/core/QAClient.d.ts +53 -0
  8. package/dist/core/QAClient.d.ts.map +1 -0
  9. package/dist/core/QAClient.js +318 -0
  10. package/dist/core/QAClient.js.map +1 -0
  11. package/dist/core/QAEventBus.d.ts +10 -0
  12. package/dist/core/QAEventBus.d.ts.map +1 -0
  13. package/dist/core/QAEventBus.js +27 -0
  14. package/dist/core/QAEventBus.js.map +1 -0
  15. package/dist/debug/Debugger.d.ts +4 -0
  16. package/dist/debug/Debugger.d.ts.map +1 -0
  17. package/dist/debug/Debugger.js +57 -0
  18. package/dist/debug/Debugger.js.map +1 -0
  19. package/dist/identity/AccessibilityResolver.d.ts +3 -0
  20. package/dist/identity/AccessibilityResolver.d.ts.map +1 -0
  21. package/dist/identity/AccessibilityResolver.js +76 -0
  22. package/dist/identity/AccessibilityResolver.js.map +1 -0
  23. package/dist/identity/DuplicateDetector.d.ts +9 -0
  24. package/dist/identity/DuplicateDetector.d.ts.map +1 -0
  25. package/dist/identity/DuplicateDetector.js +41 -0
  26. package/dist/identity/DuplicateDetector.js.map +1 -0
  27. package/dist/identity/ElementResolver.d.ts +5 -0
  28. package/dist/identity/ElementResolver.d.ts.map +1 -0
  29. package/dist/identity/ElementResolver.js +123 -0
  30. package/dist/identity/ElementResolver.js.map +1 -0
  31. package/dist/identity/FingerprintGenerator.d.ts +19 -0
  32. package/dist/identity/FingerprintGenerator.d.ts.map +1 -0
  33. package/dist/identity/FingerprintGenerator.js +49 -0
  34. package/dist/identity/FingerprintGenerator.js.map +1 -0
  35. package/dist/identity/IdentityValidator.d.ts +6 -0
  36. package/dist/identity/IdentityValidator.d.ts.map +1 -0
  37. package/dist/identity/IdentityValidator.js +28 -0
  38. package/dist/identity/IdentityValidator.js.map +1 -0
  39. package/dist/index.d.ts +10 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +9 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/instrumentation/DOMObserver.d.ts +13 -0
  44. package/dist/instrumentation/DOMObserver.d.ts.map +1 -0
  45. package/dist/instrumentation/DOMObserver.js +45 -0
  46. package/dist/instrumentation/DOMObserver.js.map +1 -0
  47. package/dist/instrumentation/ElementRegistry.d.ts +15 -0
  48. package/dist/instrumentation/ElementRegistry.d.ts.map +1 -0
  49. package/dist/instrumentation/ElementRegistry.js +53 -0
  50. package/dist/instrumentation/ElementRegistry.js.map +1 -0
  51. package/dist/instrumentation/EventDelegator.d.ts +31 -0
  52. package/dist/instrumentation/EventDelegator.d.ts.map +1 -0
  53. package/dist/instrumentation/EventDelegator.js +238 -0
  54. package/dist/instrumentation/EventDelegator.js.map +1 -0
  55. package/dist/instrumentation/FormHarvest.d.ts +33 -0
  56. package/dist/instrumentation/FormHarvest.d.ts.map +1 -0
  57. package/dist/instrumentation/FormHarvest.js +179 -0
  58. package/dist/instrumentation/FormHarvest.js.map +1 -0
  59. package/dist/instrumentation/NavigationObserver.d.ts +11 -0
  60. package/dist/instrumentation/NavigationObserver.d.ts.map +1 -0
  61. package/dist/instrumentation/NavigationObserver.js +52 -0
  62. package/dist/instrumentation/NavigationObserver.js.map +1 -0
  63. package/dist/instrumentation/compiler-contract.d.ts +11 -0
  64. package/dist/instrumentation/compiler-contract.d.ts.map +1 -0
  65. package/dist/instrumentation/compiler-contract.js +11 -0
  66. package/dist/instrumentation/compiler-contract.js.map +1 -0
  67. package/dist/privacy/Redactor.d.ts +4 -0
  68. package/dist/privacy/Redactor.d.ts.map +1 -0
  69. package/dist/privacy/Redactor.js +50 -0
  70. package/dist/privacy/Redactor.js.map +1 -0
  71. package/dist/react/QAButton.d.ts +595 -0
  72. package/dist/react/QAButton.d.ts.map +1 -0
  73. package/dist/react/QAButton.js +22 -0
  74. package/dist/react/QAButton.js.map +1 -0
  75. package/dist/react/QAProvider.d.ts +23 -0
  76. package/dist/react/QAProvider.d.ts.map +1 -0
  77. package/dist/react/QAProvider.js +41 -0
  78. package/dist/react/QAProvider.js.map +1 -0
  79. package/dist/react/index.d.ts +4 -0
  80. package/dist/react/index.d.ts.map +1 -0
  81. package/dist/react/index.js +5 -0
  82. package/dist/react/index.js.map +1 -0
  83. package/dist/react/useQAElement.d.ts +3 -0
  84. package/dist/react/useQAElement.d.ts.map +1 -0
  85. package/dist/react/useQAElement.js +23 -0
  86. package/dist/react/useQAElement.js.map +1 -0
  87. package/dist/recorder/EventNormalizer.d.ts +32 -0
  88. package/dist/recorder/EventNormalizer.d.ts.map +1 -0
  89. package/dist/recorder/EventNormalizer.js +113 -0
  90. package/dist/recorder/EventNormalizer.js.map +1 -0
  91. package/dist/recorder.iife.js +14 -0
  92. package/dist/transport/BatchQueue.d.ts +26 -0
  93. package/dist/transport/BatchQueue.d.ts.map +1 -0
  94. package/dist/transport/BatchQueue.js +110 -0
  95. package/dist/transport/BatchQueue.js.map +1 -0
  96. package/dist/transport/HTTPTransport.d.ts +36 -0
  97. package/dist/transport/HTTPTransport.d.ts.map +1 -0
  98. package/dist/transport/HTTPTransport.js +121 -0
  99. package/dist/transport/HTTPTransport.js.map +1 -0
  100. package/dist/transport/RetryQueue.d.ts +10 -0
  101. package/dist/transport/RetryQueue.d.ts.map +1 -0
  102. package/dist/transport/RetryQueue.js +60 -0
  103. package/dist/transport/RetryQueue.js.map +1 -0
  104. package/dist/types/index.d.ts +147 -0
  105. package/dist/types/index.d.ts.map +1 -0
  106. package/dist/types/index.js +24 -0
  107. package/dist/types/index.js.map +1 -0
  108. package/dist/utils/dom.d.ts +24 -0
  109. package/dist/utils/dom.d.ts.map +1 -0
  110. package/dist/utils/dom.js +152 -0
  111. package/dist/utils/dom.js.map +1 -0
  112. package/dist/utils/env.d.ts +2 -0
  113. package/dist/utils/env.d.ts.map +1 -0
  114. package/dist/utils/env.js +6 -0
  115. package/dist/utils/env.js.map +1 -0
  116. package/dist/utils/id.d.ts +13 -0
  117. package/dist/utils/id.d.ts.map +1 -0
  118. package/dist/utils/id.js +74 -0
  119. package/dist/utils/id.js.map +1 -0
  120. package/dist/utils/safe.d.ts +5 -0
  121. package/dist/utils/safe.d.ts.map +1 -0
  122. package/dist/utils/safe.js +28 -0
  123. package/dist/utils/safe.js.map +1 -0
  124. package/package.json +79 -0
@@ -0,0 +1,45 @@
1
+ export class DOMObserver {
2
+ config;
3
+ registry;
4
+ observer;
5
+ timer;
6
+ constructor(config, registry) {
7
+ this.config = config;
8
+ this.registry = registry;
9
+ }
10
+ start(root = document) {
11
+ if (typeof MutationObserver === 'undefined') {
12
+ return;
13
+ }
14
+ this.observer = new MutationObserver(() => {
15
+ this.schedule(root);
16
+ });
17
+ if (root instanceof Node) {
18
+ this.observer.observe(root, {
19
+ subtree: true,
20
+ childList: true,
21
+ attributes: true,
22
+ attributeFilter: ['data-qa-id', 'data-qa-source', 'role', 'name', 'type'],
23
+ });
24
+ }
25
+ this.registry.scheduleScan(root);
26
+ }
27
+ stop() {
28
+ this.observer?.disconnect();
29
+ this.observer = undefined;
30
+ if (this.timer) {
31
+ clearTimeout(this.timer);
32
+ this.timer = undefined;
33
+ }
34
+ }
35
+ schedule(root) {
36
+ if (this.timer) {
37
+ return;
38
+ }
39
+ this.timer = setTimeout(() => {
40
+ this.timer = undefined;
41
+ this.registry.scheduleScan(root);
42
+ }, 100);
43
+ }
44
+ }
45
+ //# sourceMappingURL=DOMObserver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DOMObserver.js","sourceRoot":"","sources":["../../src/instrumentation/DOMObserver.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,WAAW;IAKH;IACA;IALX,QAAQ,CAA+B;IACvC,KAAK,CAA4C;IAEzD,YACmB,MAAwB,EACxB,QAAyB;QADzB,WAAM,GAAN,MAAM,CAAkB;QACxB,aAAQ,GAAR,QAAQ,CAAiB;IACzC,CAAC;IAEJ,KAAK,CAAC,OAAmB,QAAQ;QAC/B,IAAI,OAAO,gBAAgB,KAAK,WAAW,EAAE,CAAC;YAC5C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE;YACxC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE;gBAC1B,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,IAAI;gBACf,UAAU,EAAE,IAAI;gBAChB,eAAe,EAAE,CAAC,YAAY,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAC1E,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,IAAI;QACF,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAEO,QAAQ,CAAC,IAAgB;QAC/B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ import type { QAElementResolution, ResolvedQAConfig } from '../types';
2
+ import { type DuplicateHit } from '../identity/DuplicateDetector';
3
+ export declare class ElementRegistry {
4
+ private readonly config;
5
+ private readonly onDuplicates;
6
+ private readonly onResolved?;
7
+ private readonly duplicates;
8
+ private lastScan;
9
+ private scheduled;
10
+ constructor(config: ResolvedQAConfig, onDuplicates: (hits: DuplicateHit[]) => void, onResolved?: ((resolution: QAElementResolution) => void) | undefined);
11
+ resolve(element: Element): QAElementResolution;
12
+ scheduleScan(root?: ParentNode): void;
13
+ scan(root?: ParentNode): DuplicateHit[];
14
+ }
15
+ //# sourceMappingURL=ElementRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElementRegistry.d.ts","sourceRoot":"","sources":["../../src/instrumentation/ElementRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGtE,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAErF,qBAAa,eAAe;IAMxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAP9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IACtD,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAS;gBAGP,MAAM,EAAE,gBAAgB,EACxB,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,IAAI,EAC5C,UAAU,CAAC,GAAE,CAAC,UAAU,EAAE,mBAAmB,KAAK,IAAI,aAAA;IAGzE,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB;IAU9C,YAAY,CAAC,IAAI,GAAE,UAAqB,GAAG,IAAI;IAgB/C,IAAI,CAAC,IAAI,GAAE,UAAqB,GAAG,YAAY,EAAE;CAYlD"}
@@ -0,0 +1,53 @@
1
+ import { closestInteractive } from '../utils/dom';
2
+ import { resolveElement } from '../identity/ElementResolver';
3
+ import { DuplicateDetector } from '../identity/DuplicateDetector';
4
+ export class ElementRegistry {
5
+ config;
6
+ onDuplicates;
7
+ onResolved;
8
+ duplicates = new DuplicateDetector();
9
+ lastScan = 0;
10
+ scheduled = false;
11
+ constructor(config, onDuplicates, onResolved) {
12
+ this.config = config;
13
+ this.onDuplicates = onDuplicates;
14
+ this.onResolved = onResolved;
15
+ }
16
+ resolve(element) {
17
+ const target = closestInteractive(element, this.config.interactiveSelectors) ?? element;
18
+ const resolution = resolveElement(target, {
19
+ allowUnstableIds: this.config.allowUnstableIds,
20
+ });
21
+ this.onResolved?.(resolution);
22
+ return resolution;
23
+ }
24
+ scheduleScan(root = document) {
25
+ if (this.scheduled) {
26
+ return;
27
+ }
28
+ this.scheduled = true;
29
+ const run = () => {
30
+ this.scheduled = false;
31
+ this.scan(root);
32
+ };
33
+ if (typeof requestAnimationFrame === 'function') {
34
+ requestAnimationFrame(run);
35
+ }
36
+ else {
37
+ setTimeout(run, 32);
38
+ }
39
+ }
40
+ scan(root = document) {
41
+ const now = Date.now();
42
+ if (now - this.lastScan < 80) {
43
+ return [];
44
+ }
45
+ this.lastScan = now;
46
+ const hits = this.duplicates.scan(root);
47
+ if (hits.length > 0) {
48
+ this.onDuplicates(hits);
49
+ }
50
+ return hits;
51
+ }
52
+ }
53
+ //# sourceMappingURL=ElementRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElementRegistry.js","sourceRoot":"","sources":["../../src/instrumentation/ElementRegistry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAqB,MAAM,+BAA+B,CAAC;AAErF,MAAM,OAAO,eAAe;IAMP;IACA;IACA;IAPF,UAAU,GAAG,IAAI,iBAAiB,EAAE,CAAC;IAC9C,QAAQ,GAAG,CAAC,CAAC;IACb,SAAS,GAAG,KAAK,CAAC;IAE1B,YACmB,MAAwB,EACxB,YAA4C,EAC5C,UAAsD;QAFtD,WAAM,GAAN,MAAM,CAAkB;QACxB,iBAAY,GAAZ,YAAY,CAAgC;QAC5C,eAAU,GAAV,UAAU,CAA4C;IACtE,CAAC;IAEJ,OAAO,CAAC,OAAgB;QACtB,MAAM,MAAM,GACV,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,OAAO,CAAC;QAC3E,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,EAAE;YACxC,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB;SAC/C,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC;QAC9B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,YAAY,CAAC,OAAmB,QAAQ;QACtC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,MAAM,GAAG,GAAG,GAAS,EAAE;YACrB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC,CAAC;QACF,IAAI,OAAO,qBAAqB,KAAK,UAAU,EAAE,CAAC;YAChD,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAmB,QAAQ;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,EAAE,EAAE,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ import type { ResolvedQAConfig } from '../types';
2
+ import { ElementRegistry } from './ElementRegistry';
3
+ import { EventNormalizer } from '../recorder/EventNormalizer';
4
+ import { type FillSource } from './FormHarvest';
5
+ export declare class EventDelegator {
6
+ private readonly config;
7
+ private readonly registry;
8
+ private readonly normalizer;
9
+ private readonly shouldRecord;
10
+ private attached;
11
+ private readonly onEvent;
12
+ private readonly recordedFields;
13
+ private lastClickedFingerprint;
14
+ private harvest;
15
+ constructor(config: ResolvedQAConfig, registry: ElementRegistry, normalizer: EventNormalizer, shouldRecord: () => boolean);
16
+ start(): void;
17
+ stop(): void;
18
+ harvestPrefills(source?: FillSource, root?: ParentNode): void;
19
+ private frameMeta;
20
+ private withFrame;
21
+ private emitHarvested;
22
+ private handle;
23
+ private emitFileChange;
24
+ private handleSubmit;
25
+ private emitControlChange;
26
+ private handleKey;
27
+ private readonly onScroll;
28
+ private scrollTimer;
29
+ private throttledScroll;
30
+ }
31
+ //# sourceMappingURL=EventDelegator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventDelegator.d.ts","sourceRoot":"","sources":["../../src/instrumentation/EventDelegator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkC,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAOjF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,eAAe,CAAC;AAkBvB,qBAAa,cAAc;IAQvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAV/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,OAAO,CAA4B;gBAGxB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,eAAe,EAC3B,YAAY,EAAE,MAAM,OAAO;IAK9C,KAAK,IAAI,IAAI;IAeb,IAAI,IAAI,IAAI;IAaZ,eAAe,CAAC,MAAM,GAAE,UAAwB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI;IAO1E,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,MAAM;IA6Ed,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CASvB;IAEF,OAAO,CAAC,WAAW,CAA4C;IAC/D,OAAO,CAAC,eAAe,CAQrB;CACH"}
@@ -0,0 +1,238 @@
1
+ import { closestInteractive, eventTargetElement, frameContext, isRecorderUi, } from '../utils/dom';
2
+ import { FormHarvest, controlState, isCheckableControl, shouldHarvestBeforeClick, } from './FormHarvest';
3
+ const DELEGATED_EVENTS = [
4
+ 'click',
5
+ 'dblclick',
6
+ 'input',
7
+ 'change',
8
+ 'focus',
9
+ 'blur',
10
+ 'submit',
11
+ 'keydown',
12
+ 'dragstart',
13
+ 'drop',
14
+ 'mouseover',
15
+ ];
16
+ const RECORDED_KEYS = new Set(['Enter', 'Escape']);
17
+ export class EventDelegator {
18
+ config;
19
+ registry;
20
+ normalizer;
21
+ shouldRecord;
22
+ attached = false;
23
+ onEvent;
24
+ recordedFields = new Set();
25
+ lastClickedFingerprint;
26
+ harvest = null;
27
+ constructor(config, registry, normalizer, shouldRecord) {
28
+ this.config = config;
29
+ this.registry = registry;
30
+ this.normalizer = normalizer;
31
+ this.shouldRecord = shouldRecord;
32
+ this.onEvent = (event) => this.handle(event);
33
+ }
34
+ start() {
35
+ if (this.attached || typeof document === 'undefined') {
36
+ return;
37
+ }
38
+ this.harvest = new FormHarvest(this.config, this.registry, (field, source) => {
39
+ this.emitHarvested(field, source);
40
+ });
41
+ this.harvest.start();
42
+ for (const type of DELEGATED_EVENTS) {
43
+ document.addEventListener(type, this.onEvent, true);
44
+ }
45
+ window.addEventListener('scroll', this.onScroll, true);
46
+ this.attached = true;
47
+ }
48
+ stop() {
49
+ if (!this.attached || typeof document === 'undefined') {
50
+ return;
51
+ }
52
+ for (const type of DELEGATED_EVENTS) {
53
+ document.removeEventListener(type, this.onEvent, true);
54
+ }
55
+ window.removeEventListener('scroll', this.onScroll, true);
56
+ this.harvest?.stop();
57
+ this.harvest = null;
58
+ this.attached = false;
59
+ }
60
+ harvestPrefills(source = 'prefilled', root) {
61
+ if (!this.shouldRecord() || typeof document === 'undefined') {
62
+ return;
63
+ }
64
+ this.harvest?.collect(root ?? document, this.recordedFields, source);
65
+ }
66
+ frameMeta() {
67
+ const ctx = frameContext();
68
+ if (!ctx) {
69
+ return undefined;
70
+ }
71
+ return {
72
+ inIframe: true,
73
+ ...(ctx.frame ? { frame: ctx.frame } : {}),
74
+ ...(ctx.crossOriginFrame ? { crossOriginFrame: true } : {}),
75
+ };
76
+ }
77
+ withFrame(extra) {
78
+ const frame = this.frameMeta();
79
+ if (!frame && !extra) {
80
+ return undefined;
81
+ }
82
+ return { ...frame, ...extra };
83
+ }
84
+ emitHarvested(field, source) {
85
+ if (!this.shouldRecord()) {
86
+ return;
87
+ }
88
+ if (this.recordedFields.has(field.identity.fingerprint)) {
89
+ return;
90
+ }
91
+ this.recordedFields.add(field.identity.fingerprint);
92
+ this.normalizer.change(field.identity, field.value, field.eventType, this.withFrame({
93
+ source,
94
+ ...(field.checked !== undefined ? { checked: field.checked } : {}),
95
+ }));
96
+ }
97
+ handle(event) {
98
+ if (!this.shouldRecord()) {
99
+ return;
100
+ }
101
+ const element = eventTargetElement(event);
102
+ if (!element || isRecorderUi(element)) {
103
+ return;
104
+ }
105
+ const interactive = closestInteractive(element, this.config.interactiveSelectors);
106
+ if (!interactive && event.type !== 'submit' && event.type !== 'keydown') {
107
+ return;
108
+ }
109
+ const targetEl = interactive ?? element;
110
+ const identity = this.registry.resolve(targetEl).identity;
111
+ switch (event.type) {
112
+ case 'click':
113
+ if (shouldHarvestBeforeClick(targetEl)) {
114
+ this.harvestPrefills('prefilled', targetEl.closest('form') ?? document);
115
+ }
116
+ this.lastClickedFingerprint = identity.fingerprint;
117
+ this.normalizer.click(identity, 'click', this.frameMeta());
118
+ break;
119
+ case 'dblclick':
120
+ this.normalizer.click(identity, 'dblclick', this.frameMeta());
121
+ break;
122
+ case 'input':
123
+ if (isCheckableControl(targetEl)) {
124
+ break;
125
+ }
126
+ if (targetEl instanceof HTMLInputElement && targetEl.type === 'file') {
127
+ break;
128
+ }
129
+ this.recordedFields.add(identity.fingerprint);
130
+ this.normalizer.input(identity, controlState(targetEl, this.config).value, this.withFrame({ source: 'typed' }));
131
+ break;
132
+ case 'change':
133
+ this.recordedFields.add(identity.fingerprint);
134
+ if (targetEl instanceof HTMLInputElement && targetEl.type === 'file') {
135
+ this.emitFileChange(targetEl, identity);
136
+ break;
137
+ }
138
+ this.emitControlChange(targetEl, identity, 'typed');
139
+ break;
140
+ case 'focus':
141
+ this.normalizer.simple('focus', identity, this.frameMeta());
142
+ break;
143
+ case 'blur':
144
+ this.normalizer.flushInput();
145
+ this.normalizer.simple('blur', identity, this.frameMeta());
146
+ break;
147
+ case 'submit':
148
+ this.handleSubmit(event, targetEl, identity);
149
+ break;
150
+ case 'keydown':
151
+ this.handleKey(event, identity);
152
+ break;
153
+ case 'dragstart':
154
+ this.normalizer.simple('drag', identity, this.frameMeta());
155
+ break;
156
+ case 'drop':
157
+ this.normalizer.simple('drop', identity, this.frameMeta());
158
+ break;
159
+ case 'mouseover':
160
+ if (this.config.recordHover) {
161
+ this.normalizer.simple('hover', identity, this.frameMeta());
162
+ }
163
+ break;
164
+ default:
165
+ break;
166
+ }
167
+ }
168
+ emitFileChange(element, identity) {
169
+ const files = Array.from(element.files ?? []).map((file) => file.name);
170
+ this.normalizer.change(identity, undefined, 'change', this.withFrame({
171
+ source: 'typed',
172
+ files: files.length > 0 ? files : ['upload.bin'],
173
+ fileName: files[0] ?? 'upload.bin',
174
+ }));
175
+ }
176
+ handleSubmit(event, targetEl, identity) {
177
+ const form = targetEl.closest('form') ?? targetEl;
178
+ this.harvestPrefills('prefilled', form);
179
+ const submitter = submitterOf(event, form);
180
+ if (submitter) {
181
+ const submitterIdentity = this.registry.resolve(submitter).identity;
182
+ if (submitterIdentity.fingerprint !== this.lastClickedFingerprint) {
183
+ this.lastClickedFingerprint = submitterIdentity.fingerprint;
184
+ this.normalizer.click(submitterIdentity, 'click', this.frameMeta());
185
+ }
186
+ return;
187
+ }
188
+ this.normalizer.simple('submit', identity, this.frameMeta());
189
+ }
190
+ emitControlChange(element, identity, source) {
191
+ const state = controlState(element, this.config);
192
+ this.normalizer.change(identity, state.value, changeType(element), this.withFrame({
193
+ source,
194
+ ...(state.checked !== undefined ? { checked: state.checked } : {}),
195
+ }));
196
+ }
197
+ handleKey(event, identity) {
198
+ if (!RECORDED_KEYS.has(event.key)) {
199
+ return;
200
+ }
201
+ this.normalizer.flushInput();
202
+ this.normalizer.simple('keydown', identity, this.withFrame({ key: event.key }));
203
+ }
204
+ onScroll = (event) => {
205
+ if (!this.shouldRecord()) {
206
+ return;
207
+ }
208
+ const element = eventTargetElement(event);
209
+ if (element && isRecorderUi(element)) {
210
+ return;
211
+ }
212
+ this.throttledScroll();
213
+ };
214
+ scrollTimer;
215
+ throttledScroll = () => {
216
+ if (this.scrollTimer) {
217
+ return;
218
+ }
219
+ this.scrollTimer = setTimeout(() => {
220
+ this.scrollTimer = undefined;
221
+ this.normalizer.simple('scroll', undefined, this.frameMeta());
222
+ }, 400);
223
+ };
224
+ }
225
+ function submitterOf(event, form) {
226
+ const submitter = 'submitter' in event ? event.submitter : null;
227
+ if (submitter instanceof Element) {
228
+ return submitter;
229
+ }
230
+ return form.querySelector('button[type="submit"], input[type="submit"], button:not([type]), input[type="image"]');
231
+ }
232
+ function changeType(element) {
233
+ if (element instanceof HTMLSelectElement) {
234
+ return 'select';
235
+ }
236
+ return 'change';
237
+ }
238
+ //# sourceMappingURL=EventDelegator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventDelegator.js","sourceRoot":"","sources":["../../src/instrumentation/EventDelegator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { QAElementIdentity, QAEventType, ResolvedQAConfig } from '../types';
2
+ import { ElementRegistry } from './ElementRegistry';
3
+ export type FillSource = 'typed' | 'autofill' | 'prefilled';
4
+ export declare const PREFILL_HARVEST_MS = 300;
5
+ export declare const AUTOFILL_ANIMATION = "lc-on-autofill";
6
+ export declare const AUTOFILL_STYLE_ID = "loopcheck-autofill-detect";
7
+ export type HarvestedField = {
8
+ element: Element;
9
+ identity: QAElementIdentity;
10
+ value: string | undefined;
11
+ checked?: boolean;
12
+ eventType: QAEventType;
13
+ };
14
+ export declare function isFormControl(element: Element): element is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
15
+ export declare function isCheckableControl(element: Element): boolean;
16
+ export declare function isSubmitControl(element: Element): boolean;
17
+ export declare function shouldHarvestBeforeClick(element: Element): boolean;
18
+ export declare function controlState(element: Element, config: ResolvedQAConfig): {
19
+ value: string | undefined;
20
+ checked?: boolean;
21
+ };
22
+ export declare function collectFilledFields(root: ParentNode, registry: ElementRegistry, config: ResolvedQAConfig, skip: Set<string>): HarvestedField[];
23
+ export declare class FormHarvest {
24
+ private readonly config;
25
+ private readonly registry;
26
+ private readonly onField;
27
+ constructor(config: ResolvedQAConfig, registry: ElementRegistry, onField: (field: HarvestedField, source: FillSource) => void);
28
+ start(): void;
29
+ stop(): void;
30
+ collect(root: ParentNode, skip: Set<string>, source: FillSource): void;
31
+ private readonly onAnimationStart;
32
+ }
33
+ //# sourceMappingURL=FormHarvest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormHarvest.d.ts","sourceRoot":"","sources":["../../src/instrumentation/FormHarvest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAE5D,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,iBAAiB,8BAA8B,CAAC;AAW7D,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,GACf,OAAO,IAAI,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAMvE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAM5D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CASzD;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAQlE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,gBAAgB,GACvB;IAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAclD;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAChB,cAAc,EAAE,CA0ClB;AA4BD,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFP,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI;IAG/E,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;IAQZ,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAMtE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CA0B/B;CACH"}
@@ -0,0 +1,179 @@
1
+ import { redactValue } from '../privacy/Redactor';
2
+ import { isRecorderUi } from '../utils/dom';
3
+ export const PREFILL_HARVEST_MS = 300;
4
+ export const AUTOFILL_ANIMATION = 'lc-on-autofill';
5
+ export const AUTOFILL_STYLE_ID = 'loopcheck-autofill-detect';
6
+ const SKIP_INPUT_TYPES = new Set([
7
+ 'hidden',
8
+ 'file',
9
+ 'button',
10
+ 'submit',
11
+ 'reset',
12
+ 'image',
13
+ ]);
14
+ export function isFormControl(element) {
15
+ return (element instanceof HTMLInputElement ||
16
+ element instanceof HTMLTextAreaElement ||
17
+ element instanceof HTMLSelectElement);
18
+ }
19
+ export function isCheckableControl(element) {
20
+ if (!(element instanceof HTMLInputElement)) {
21
+ return false;
22
+ }
23
+ const type = element.type.toLowerCase();
24
+ return type === 'checkbox' || type === 'radio';
25
+ }
26
+ export function isSubmitControl(element) {
27
+ if (element instanceof HTMLInputElement) {
28
+ const type = element.type.toLowerCase();
29
+ return type === 'submit' || type === 'image';
30
+ }
31
+ if (element instanceof HTMLButtonElement) {
32
+ return element.type === 'submit';
33
+ }
34
+ return false;
35
+ }
36
+ export function shouldHarvestBeforeClick(element) {
37
+ if (isSubmitControl(element)) {
38
+ return true;
39
+ }
40
+ if (!element.closest('form')) {
41
+ return false;
42
+ }
43
+ return element.matches('button, [role="button"], input[type="submit"], input[type="image"]');
44
+ }
45
+ export function controlState(element, config) {
46
+ if (element instanceof HTMLInputElement && isCheckableControl(element)) {
47
+ return {
48
+ value: redactValue(element, element.value, config),
49
+ checked: element.checked,
50
+ };
51
+ }
52
+ const raw = element instanceof HTMLInputElement ||
53
+ element instanceof HTMLTextAreaElement ||
54
+ element instanceof HTMLSelectElement
55
+ ? element.value
56
+ : undefined;
57
+ return { value: redactValue(element, raw, config) };
58
+ }
59
+ export function collectFilledFields(root, registry, config, skip) {
60
+ const out = [];
61
+ if (typeof document === 'undefined') {
62
+ return out;
63
+ }
64
+ const nodes = root.querySelectorAll('input, textarea, select');
65
+ for (const node of nodes) {
66
+ if (!isFormControl(node) || isRecorderUi(node)) {
67
+ continue;
68
+ }
69
+ if (node instanceof HTMLInputElement && SKIP_INPUT_TYPES.has(node.type.toLowerCase())) {
70
+ continue;
71
+ }
72
+ if ('disabled' in node && node.disabled) {
73
+ continue;
74
+ }
75
+ if (isCheckableControl(node)) {
76
+ if (!(node instanceof HTMLInputElement) || !node.checked) {
77
+ continue;
78
+ }
79
+ }
80
+ else if (!node.value.trim()) {
81
+ continue;
82
+ }
83
+ const identity = registry.resolve(node).identity;
84
+ if (skip.has(identity.fingerprint)) {
85
+ continue;
86
+ }
87
+ const state = controlState(node, config);
88
+ out.push({
89
+ element: node,
90
+ identity,
91
+ value: state.value,
92
+ checked: state.checked,
93
+ eventType: node instanceof HTMLSelectElement
94
+ ? 'select'
95
+ : isCheckableControl(node)
96
+ ? 'change'
97
+ : 'input',
98
+ });
99
+ }
100
+ return out;
101
+ }
102
+ function injectAutofillStyle() {
103
+ if (typeof document === 'undefined' || document.getElementById(AUTOFILL_STYLE_ID)) {
104
+ return;
105
+ }
106
+ const style = document.createElement('style');
107
+ style.id = AUTOFILL_STYLE_ID;
108
+ style.setAttribute('data-loopcheck-recorder', '1');
109
+ style.textContent = `@keyframes ${AUTOFILL_ANIMATION} {
110
+ from { opacity: 0.99; }
111
+ to { opacity: 1; }
112
+ }
113
+ input:-webkit-autofill,
114
+ textarea:-webkit-autofill,
115
+ select:-webkit-autofill {
116
+ animation-name: ${AUTOFILL_ANIMATION};
117
+ }`;
118
+ document.documentElement.appendChild(style);
119
+ }
120
+ function removeAutofillStyle() {
121
+ if (typeof document === 'undefined') {
122
+ return;
123
+ }
124
+ document.getElementById(AUTOFILL_STYLE_ID)?.remove();
125
+ }
126
+ export class FormHarvest {
127
+ config;
128
+ registry;
129
+ onField;
130
+ constructor(config, registry, onField) {
131
+ this.config = config;
132
+ this.registry = registry;
133
+ this.onField = onField;
134
+ }
135
+ start() {
136
+ if (typeof document === 'undefined') {
137
+ return;
138
+ }
139
+ injectAutofillStyle();
140
+ document.addEventListener('animationstart', this.onAnimationStart, true);
141
+ }
142
+ stop() {
143
+ if (typeof document === 'undefined') {
144
+ return;
145
+ }
146
+ document.removeEventListener('animationstart', this.onAnimationStart, true);
147
+ removeAutofillStyle();
148
+ }
149
+ collect(root, skip, source) {
150
+ for (const field of collectFilledFields(root, this.registry, this.config, skip)) {
151
+ this.onField(field, source);
152
+ }
153
+ }
154
+ onAnimationStart = (event) => {
155
+ if (event.animationName !== AUTOFILL_ANIMATION) {
156
+ return;
157
+ }
158
+ const element = event.target;
159
+ if (!(element instanceof Element) || !isFormControl(element) || isRecorderUi(element)) {
160
+ return;
161
+ }
162
+ if (isCheckableControl(element)) {
163
+ return;
164
+ }
165
+ if (!element.value.trim()) {
166
+ return;
167
+ }
168
+ const identity = this.registry.resolve(element).identity;
169
+ const state = controlState(element, this.config);
170
+ this.onField({
171
+ element,
172
+ identity,
173
+ value: state.value,
174
+ checked: state.checked,
175
+ eventType: element instanceof HTMLSelectElement ? 'select' : 'input',
176
+ }, 'autofill');
177
+ };
178
+ }
179
+ //# sourceMappingURL=FormHarvest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormHarvest.js","sourceRoot":"","sources":["../../src/instrumentation/FormHarvest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare class NavigationObserver {
2
+ private readonly onNavigate;
3
+ private originalPush?;
4
+ private originalReplace?;
5
+ private lastUrl;
6
+ constructor(onNavigate: (url: string, pathname: string) => void);
7
+ start(): void;
8
+ stop(): void;
9
+ private readonly check;
10
+ }
11
+ //# sourceMappingURL=NavigationObserver.d.ts.map