@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.
- package/ARCHITECTURE.md +59 -0
- package/README.md +131 -0
- package/dist/config/normalize.d.ts +6 -0
- package/dist/config/normalize.d.ts.map +1 -0
- package/dist/config/normalize.js +88 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/core/QAClient.d.ts +53 -0
- package/dist/core/QAClient.d.ts.map +1 -0
- package/dist/core/QAClient.js +318 -0
- package/dist/core/QAClient.js.map +1 -0
- package/dist/core/QAEventBus.d.ts +10 -0
- package/dist/core/QAEventBus.d.ts.map +1 -0
- package/dist/core/QAEventBus.js +27 -0
- package/dist/core/QAEventBus.js.map +1 -0
- package/dist/debug/Debugger.d.ts +4 -0
- package/dist/debug/Debugger.d.ts.map +1 -0
- package/dist/debug/Debugger.js +57 -0
- package/dist/debug/Debugger.js.map +1 -0
- package/dist/identity/AccessibilityResolver.d.ts +3 -0
- package/dist/identity/AccessibilityResolver.d.ts.map +1 -0
- package/dist/identity/AccessibilityResolver.js +76 -0
- package/dist/identity/AccessibilityResolver.js.map +1 -0
- package/dist/identity/DuplicateDetector.d.ts +9 -0
- package/dist/identity/DuplicateDetector.d.ts.map +1 -0
- package/dist/identity/DuplicateDetector.js +41 -0
- package/dist/identity/DuplicateDetector.js.map +1 -0
- package/dist/identity/ElementResolver.d.ts +5 -0
- package/dist/identity/ElementResolver.d.ts.map +1 -0
- package/dist/identity/ElementResolver.js +123 -0
- package/dist/identity/ElementResolver.js.map +1 -0
- package/dist/identity/FingerprintGenerator.d.ts +19 -0
- package/dist/identity/FingerprintGenerator.d.ts.map +1 -0
- package/dist/identity/FingerprintGenerator.js +49 -0
- package/dist/identity/FingerprintGenerator.js.map +1 -0
- package/dist/identity/IdentityValidator.d.ts +6 -0
- package/dist/identity/IdentityValidator.d.ts.map +1 -0
- package/dist/identity/IdentityValidator.js +28 -0
- package/dist/identity/IdentityValidator.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation/DOMObserver.d.ts +13 -0
- package/dist/instrumentation/DOMObserver.d.ts.map +1 -0
- package/dist/instrumentation/DOMObserver.js +45 -0
- package/dist/instrumentation/DOMObserver.js.map +1 -0
- package/dist/instrumentation/ElementRegistry.d.ts +15 -0
- package/dist/instrumentation/ElementRegistry.d.ts.map +1 -0
- package/dist/instrumentation/ElementRegistry.js +53 -0
- package/dist/instrumentation/ElementRegistry.js.map +1 -0
- package/dist/instrumentation/EventDelegator.d.ts +31 -0
- package/dist/instrumentation/EventDelegator.d.ts.map +1 -0
- package/dist/instrumentation/EventDelegator.js +238 -0
- package/dist/instrumentation/EventDelegator.js.map +1 -0
- package/dist/instrumentation/FormHarvest.d.ts +33 -0
- package/dist/instrumentation/FormHarvest.d.ts.map +1 -0
- package/dist/instrumentation/FormHarvest.js +179 -0
- package/dist/instrumentation/FormHarvest.js.map +1 -0
- package/dist/instrumentation/NavigationObserver.d.ts +11 -0
- package/dist/instrumentation/NavigationObserver.d.ts.map +1 -0
- package/dist/instrumentation/NavigationObserver.js +52 -0
- package/dist/instrumentation/NavigationObserver.js.map +1 -0
- package/dist/instrumentation/compiler-contract.d.ts +11 -0
- package/dist/instrumentation/compiler-contract.d.ts.map +1 -0
- package/dist/instrumentation/compiler-contract.js +11 -0
- package/dist/instrumentation/compiler-contract.js.map +1 -0
- package/dist/privacy/Redactor.d.ts +4 -0
- package/dist/privacy/Redactor.d.ts.map +1 -0
- package/dist/privacy/Redactor.js +50 -0
- package/dist/privacy/Redactor.js.map +1 -0
- package/dist/react/QAButton.d.ts +595 -0
- package/dist/react/QAButton.d.ts.map +1 -0
- package/dist/react/QAButton.js +22 -0
- package/dist/react/QAButton.js.map +1 -0
- package/dist/react/QAProvider.d.ts +23 -0
- package/dist/react/QAProvider.d.ts.map +1 -0
- package/dist/react/QAProvider.js +41 -0
- package/dist/react/QAProvider.js.map +1 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +5 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useQAElement.d.ts +3 -0
- package/dist/react/useQAElement.d.ts.map +1 -0
- package/dist/react/useQAElement.js +23 -0
- package/dist/react/useQAElement.js.map +1 -0
- package/dist/recorder/EventNormalizer.d.ts +32 -0
- package/dist/recorder/EventNormalizer.d.ts.map +1 -0
- package/dist/recorder/EventNormalizer.js +113 -0
- package/dist/recorder/EventNormalizer.js.map +1 -0
- package/dist/recorder.iife.js +14 -0
- package/dist/transport/BatchQueue.d.ts +26 -0
- package/dist/transport/BatchQueue.d.ts.map +1 -0
- package/dist/transport/BatchQueue.js +110 -0
- package/dist/transport/BatchQueue.js.map +1 -0
- package/dist/transport/HTTPTransport.d.ts +36 -0
- package/dist/transport/HTTPTransport.d.ts.map +1 -0
- package/dist/transport/HTTPTransport.js +121 -0
- package/dist/transport/HTTPTransport.js.map +1 -0
- package/dist/transport/RetryQueue.d.ts +10 -0
- package/dist/transport/RetryQueue.d.ts.map +1 -0
- package/dist/transport/RetryQueue.js +60 -0
- package/dist/transport/RetryQueue.js.map +1 -0
- package/dist/types/index.d.ts +147 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/dom.d.ts +24 -0
- package/dist/utils/dom.d.ts.map +1 -0
- package/dist/utils/dom.js +152 -0
- package/dist/utils/dom.js.map +1 -0
- package/dist/utils/env.d.ts +2 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +6 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/id.d.ts +13 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +74 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/safe.d.ts +5 -0
- package/dist/utils/safe.d.ts.map +1 -0
- package/dist/utils/safe.js +28 -0
- package/dist/utils/safe.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { QAClient, type QASnapshot } from '../core/QAClient';
|
|
3
|
+
import type { QAConfig, QARecording } from '../types';
|
|
4
|
+
export interface QAContextValue {
|
|
5
|
+
client: QAClient | null;
|
|
6
|
+
snapshot: QASnapshot;
|
|
7
|
+
}
|
|
8
|
+
declare const QAContext: import("react").Context<QAContextValue>;
|
|
9
|
+
export declare function QAProvider({ config, children, }: {
|
|
10
|
+
config: QAConfig;
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
}): import("react").FunctionComponentElement<import("react").ProviderProps<QAContextValue>>;
|
|
13
|
+
export declare function useQA(): {
|
|
14
|
+
client: QAClient | null;
|
|
15
|
+
startRecording: () => Promise<void>;
|
|
16
|
+
stopRecording: () => QARecording | null;
|
|
17
|
+
pauseRecording: () => void;
|
|
18
|
+
resumeRecording: () => void;
|
|
19
|
+
isRecording: boolean;
|
|
20
|
+
isPaused: boolean;
|
|
21
|
+
};
|
|
22
|
+
export { QAContext };
|
|
23
|
+
//# sourceMappingURL=QAProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QAProvider.d.ts","sourceRoot":"","sources":["../../src/react/QAProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED,QAAA,MAAM,SAAS,yCAGb,CAAC;AAEH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,2FA2BA;AAED,wBAAgB,KAAK,IAAI;IACvB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,aAAa,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACxC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAWA;AAMD,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { createContext, createElement, useContext, useEffect, useMemo, useRef, useSyncExternalStore, } from 'react';
|
|
3
|
+
import { QAClient } from '../core/QAClient';
|
|
4
|
+
const QAContext = createContext({
|
|
5
|
+
client: null,
|
|
6
|
+
snapshot: QAClient.getServerSnapshot(),
|
|
7
|
+
});
|
|
8
|
+
export function QAProvider({ config, children, }) {
|
|
9
|
+
const clientRef = useRef(null);
|
|
10
|
+
if (typeof window !== 'undefined' && !clientRef.current) {
|
|
11
|
+
clientRef.current = new QAClient(config);
|
|
12
|
+
}
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const client = clientRef.current;
|
|
15
|
+
client?.start();
|
|
16
|
+
client?.maybeArmFromQuery();
|
|
17
|
+
return () => {
|
|
18
|
+
void client?.shutdown();
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
const snapshot = useSyncExternalStore(clientRef.current?.subscribe ?? noopSubscribe, clientRef.current?.getSnapshot ?? QAClient.getServerSnapshot, QAClient.getServerSnapshot);
|
|
22
|
+
const value = useMemo(() => ({ client: clientRef.current, snapshot }), [snapshot]);
|
|
23
|
+
return createElement(QAContext.Provider, { value }, children);
|
|
24
|
+
}
|
|
25
|
+
export function useQA() {
|
|
26
|
+
const { client, snapshot } = useContext(QAContext);
|
|
27
|
+
return {
|
|
28
|
+
client,
|
|
29
|
+
startRecording: () => client?.startRecording() ?? Promise.resolve(),
|
|
30
|
+
stopRecording: () => client?.stopRecording() ?? null,
|
|
31
|
+
pauseRecording: () => client?.pauseRecording(),
|
|
32
|
+
resumeRecording: () => client?.resumeRecording(),
|
|
33
|
+
isRecording: snapshot.isRecording,
|
|
34
|
+
isPaused: snapshot.isPaused,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function noopSubscribe() {
|
|
38
|
+
return () => undefined;
|
|
39
|
+
}
|
|
40
|
+
export { QAContext };
|
|
41
|
+
//# sourceMappingURL=QAProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QAProvider.js","sourceRoot":"","sources":["../../src/react/QAProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EACL,aAAa,EACb,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,MAAM,EACN,oBAAoB,GAErB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAQ7D,MAAM,SAAS,GAAG,aAAa,CAAiB;IAC9C,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,EAAE;CACvC,CAAC,CAAC;AAEH,MAAM,UAAU,UAAU,CAAC,EACzB,MAAM,EACN,QAAQ,GAIT;IACC,MAAM,SAAS,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAC;IAChD,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACxD,SAAS,CAAC,OAAO,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC;QACjC,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,MAAM,EAAE,iBAAiB,EAAE,CAAC;QAC5B,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,EAAE,QAAQ,EAAE,CAAC;QAC1B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,QAAQ,GAAG,oBAAoB,CACnC,SAAS,CAAC,OAAO,EAAE,SAAS,IAAI,aAAa,EAC7C,SAAS,CAAC,OAAO,EAAE,WAAW,IAAI,QAAQ,CAAC,iBAAiB,EAC5D,QAAQ,CAAC,iBAAiB,CAC3B,CAAC;IAEF,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAC/C,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,OAAO,aAAa,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,KAAK;IASnB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACnD,OAAO;QACL,MAAM;QACN,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;QACnE,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,IAAI;QACpD,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE;QAC9C,eAAe,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE;QAChD,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC5B,CAAC;AACJ,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;AACzB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQAElement.d.ts","sourceRoot":"","sources":["../../src/react/useQAElement.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC;AAKtD,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,GACd,WAAW,CAAC,CAAC,CAAC,CAkBhB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { QA_ID_ATTRIBUTE, QA_SOURCE_ATTRIBUTE } from '../types';
|
|
4
|
+
import { validateQaId } from '../identity/IdentityValidator';
|
|
5
|
+
import { isNonProduction } from '../utils/env';
|
|
6
|
+
export function useQAElement(qaId, source) {
|
|
7
|
+
return useCallback((node) => {
|
|
8
|
+
if (!node) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const check = validateQaId(qaId);
|
|
12
|
+
if (check.ok) {
|
|
13
|
+
node.setAttribute(QA_ID_ATTRIBUTE, qaId);
|
|
14
|
+
}
|
|
15
|
+
else if (isNonProduction()) {
|
|
16
|
+
console.warn(`Invalid QA ID "${qaId}": ${check.reason}`);
|
|
17
|
+
}
|
|
18
|
+
if (source) {
|
|
19
|
+
node.setAttribute(QA_SOURCE_ATTRIBUTE, source);
|
|
20
|
+
}
|
|
21
|
+
}, [qaId, source]);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=useQAElement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQAElement.js","sourceRoot":"","sources":["../../src/react/useQAElement.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAoB,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,MAAe;IAEf,OAAO,WAAW,CAChB,CAAC,IAAI,EAAE,EAAE;QACP,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;YACb,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,eAAe,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,kBAAkB,IAAI,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,EACD,CAAC,IAAI,EAAE,MAAM,CAAC,CACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { QAEvent, QAEventType, QARecording } from '../types';
|
|
2
|
+
import type { QAElementIdentity } from '../types';
|
|
3
|
+
export declare class EventNormalizer {
|
|
4
|
+
private readonly emit;
|
|
5
|
+
private inputTimer;
|
|
6
|
+
private pendingInput;
|
|
7
|
+
constructor(emit: (event: Omit<QAEvent, 'id' | 'schemaVersion' | 'timestamp' | 'page'> & {
|
|
8
|
+
page?: QAEvent['page'];
|
|
9
|
+
}) => void);
|
|
10
|
+
click(target: QAElementIdentity, type?: 'click' | 'dblclick', extra?: Record<string, unknown>): void;
|
|
11
|
+
input(target: QAElementIdentity, value: string | undefined, extra?: Record<string, unknown>): void;
|
|
12
|
+
change(target: QAElementIdentity, value: string | undefined, type?: QAEventType, extra?: Record<string, unknown>): void;
|
|
13
|
+
simple(type: QAEventType, target?: QAElementIdentity, metadata?: Record<string, unknown>): void;
|
|
14
|
+
flushInput(): void;
|
|
15
|
+
dispose(): void;
|
|
16
|
+
}
|
|
17
|
+
export declare class RecordingSession {
|
|
18
|
+
private paused;
|
|
19
|
+
readonly recording: QARecording;
|
|
20
|
+
constructor(initialUrl: string);
|
|
21
|
+
get isPaused(): boolean;
|
|
22
|
+
pause(): void;
|
|
23
|
+
resume(): void;
|
|
24
|
+
push(event: QAEvent): void;
|
|
25
|
+
stop(): QARecording;
|
|
26
|
+
}
|
|
27
|
+
export declare function buildEvent(type: QAEventType, extras?: {
|
|
28
|
+
target?: QAElementIdentity;
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
30
|
+
page?: QAEvent['page'];
|
|
31
|
+
}): QAEvent;
|
|
32
|
+
//# sourceMappingURL=EventNormalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventNormalizer.d.ts","sourceRoot":"","sources":["../../src/recorder/EventNormalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAIlD,qBAAa,eAAe;IAMd,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,UAAU,CAA4C;IAC9D,OAAO,CAAC,YAAY,CAEN;gBAEe,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,eAAe,GAAG,WAAW,GAAG,MAAM,CAAC,GAAG;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,KAAK,IAAI;IAE7I,KAAK,CACH,MAAM,EAAE,iBAAiB,EACzB,IAAI,GAAE,OAAO,GAAG,UAAoB,EACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,IAAI;IASP,KAAK,CACH,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,IAAI;IAgBP,MAAM,CACJ,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,GAAE,WAAsB,EAC5B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,IAAI;IAaP,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAO/F,UAAU,IAAI,IAAI;IAiBlB,OAAO,IAAI,IAAI;CAGhB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;gBAEpB,UAAU,EAAE,MAAM;IAU9B,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,IAAI;IAId,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAO1B,IAAI,IAAI,WAAW;CAIpB;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EACjB,MAAM,GAAE;IACN,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CACnB,GACL,OAAO,CAUT"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createId, safeNow } from '../utils/id';
|
|
2
|
+
import { getPageContext } from '../utils/dom';
|
|
3
|
+
const INPUT_DEBOUNCE_MS = 400;
|
|
4
|
+
export class EventNormalizer {
|
|
5
|
+
emit;
|
|
6
|
+
inputTimer;
|
|
7
|
+
pendingInput;
|
|
8
|
+
constructor(emit) {
|
|
9
|
+
this.emit = emit;
|
|
10
|
+
}
|
|
11
|
+
click(target, type = 'click', extra) {
|
|
12
|
+
this.flushInput();
|
|
13
|
+
this.emit({
|
|
14
|
+
type,
|
|
15
|
+
target,
|
|
16
|
+
metadata: extra && Object.keys(extra).length > 0 ? extra : undefined,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
input(target, value, extra) {
|
|
20
|
+
if (this.pendingInput &&
|
|
21
|
+
this.pendingInput.target?.fingerprint !== target.fingerprint) {
|
|
22
|
+
this.flushInput();
|
|
23
|
+
}
|
|
24
|
+
this.pendingInput = { target, value, extra };
|
|
25
|
+
if (this.inputTimer) {
|
|
26
|
+
clearTimeout(this.inputTimer);
|
|
27
|
+
}
|
|
28
|
+
this.inputTimer = setTimeout(() => {
|
|
29
|
+
this.flushInput();
|
|
30
|
+
}, INPUT_DEBOUNCE_MS);
|
|
31
|
+
}
|
|
32
|
+
change(target, value, type = 'change', extra) {
|
|
33
|
+
this.flushInput();
|
|
34
|
+
const metadata = {
|
|
35
|
+
...(value === undefined ? {} : { value }),
|
|
36
|
+
...extra,
|
|
37
|
+
};
|
|
38
|
+
this.emit({
|
|
39
|
+
type,
|
|
40
|
+
target,
|
|
41
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
simple(type, target, metadata) {
|
|
45
|
+
if (type !== 'input') {
|
|
46
|
+
this.flushInput();
|
|
47
|
+
}
|
|
48
|
+
this.emit({ type, target, metadata });
|
|
49
|
+
}
|
|
50
|
+
flushInput() {
|
|
51
|
+
if (this.inputTimer) {
|
|
52
|
+
clearTimeout(this.inputTimer);
|
|
53
|
+
this.inputTimer = undefined;
|
|
54
|
+
}
|
|
55
|
+
if (!this.pendingInput) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const pending = this.pendingInput;
|
|
59
|
+
this.pendingInput = undefined;
|
|
60
|
+
this.emit({
|
|
61
|
+
type: 'input',
|
|
62
|
+
target: pending.target,
|
|
63
|
+
metadata: { value: pending.value, source: 'typed', ...pending.extra },
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
dispose() {
|
|
67
|
+
this.flushInput();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class RecordingSession {
|
|
71
|
+
paused = false;
|
|
72
|
+
recording;
|
|
73
|
+
constructor(initialUrl) {
|
|
74
|
+
this.recording = {
|
|
75
|
+
id: createId('rec'),
|
|
76
|
+
schemaVersion: '1',
|
|
77
|
+
startedAt: safeNow(),
|
|
78
|
+
initialUrl,
|
|
79
|
+
events: [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
get isPaused() {
|
|
83
|
+
return this.paused;
|
|
84
|
+
}
|
|
85
|
+
pause() {
|
|
86
|
+
this.paused = true;
|
|
87
|
+
}
|
|
88
|
+
resume() {
|
|
89
|
+
this.paused = false;
|
|
90
|
+
}
|
|
91
|
+
push(event) {
|
|
92
|
+
if (this.paused) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
this.recording.events.push(event);
|
|
96
|
+
}
|
|
97
|
+
stop() {
|
|
98
|
+
this.recording.endedAt = safeNow();
|
|
99
|
+
return this.recording;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function buildEvent(type, extras = {}) {
|
|
103
|
+
return {
|
|
104
|
+
id: createId('evt'),
|
|
105
|
+
schemaVersion: '1',
|
|
106
|
+
timestamp: safeNow(),
|
|
107
|
+
type,
|
|
108
|
+
target: extras.target,
|
|
109
|
+
page: extras.page ?? getPageContext(),
|
|
110
|
+
metadata: extras.metadata,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=EventNormalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventNormalizer.js","sourceRoot":"","sources":["../../src/recorder/EventNormalizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";(()=>{var Ne=Object.defineProperty;var He=(t,e,n)=>e in t?Ne(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var o=(t,e,n)=>He(t,typeof e!="symbol"?e+"":e,n);var p="data-qa-id",A="data-qa-source",le="data-qa-sensitive",I="data-testid",de="[REDACTED]",ce=["button","a","input","textarea","select","option","label",'[role="button"]','[role="link"]','[role="checkbox"]','[role="radio"]','[role="tab"]','[role="menuitem"]','[contenteditable="true"]','[contenteditable=""]'];var Be=new Set(["DATABASE_URL","SECRET_KEY","AUTH_SECRET","PRIVATE_API_KEY","GITHUB_APP_PRIVATE_KEY","ENCRYPTION_MASTER_KEY","SESSION_SECRET"]);function ue(t){return Object.keys(t).filter(e=>e==="publicClientToken"||e==="publishableKey"?!1:Be.has(e)||/secret|private.?key|password/i.test(e))}function pe(t){let e=t.enabled!==!1,n=t.environment??"development",i=t.publishableKey??void 0,r=t.publicClientToken??i,s=t.startOn??"manual",a=!!t.sessionId,u=!!r&&!a,c;u&&t.mode===void 0||n.toLowerCase()==="production"?c="disabled":c="observe";let b=e?t.mode??c:"disabled",E=(t.interactiveSelectors??[]).filter(h=>typeof h=="string"&&h.trim().length>0);return{projectId:t.projectId??"",sessionId:t.sessionId,environment:n,apiUrl:t.apiUrl??"",publishableKey:i,publicClientToken:r,enabled:e,mode:b,startOn:s,debug:!!t.debug,interactiveSelectors:Array.from(new Set([...ce,...E])),redactSelectors:(t.redactSelectors??[]).filter(Boolean),allowUnstableIds:!!t.allowUnstableIds,recordHover:!!t.recordHover,recordInputValues:!!t.recordInputValues,flushIntervalMs:k(t.flushIntervalMs,250,5e3,500),maxBatchSize:k(t.maxBatchSize,1,100,25),maxQueueSize:k(t.maxQueueSize,20,500,200),maxStorageBytes:k(t.maxStorageBytes,4096,64e3,32e3),transport:t.transport,onError:t.onError}}function k(t,e,n,i){return typeof t!="number"||Number.isNaN(t)?i:Math.min(n,Math.max(e,t))}function J(t){return t.enabled?t.mode:"disabled"}function fe(t){if(t!=="query"||typeof window>"u")return!1;try{return new URLSearchParams(window.location.search).get("lc_record")==="1"}catch{return!1}}var C=class{constructor(){o(this,"listeners",new Map)}on(e,n){let i=this.listeners.get(e)??new Set;return i.add(n),this.listeners.set(e,i),()=>this.off(e,n)}off(e,n){this.listeners.get(e)?.delete(n)}emit(e,n){let i=this.listeners.get(e);if(i)for(let r of i)try{r(n)}catch{}}};var _e=/^(?:react-aria|ember\d+|:r[\w-]+:)/i,Fe=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function T(t){return t?_e.test(t)||Fe.test(t):!0}function w(t){if(t)try{return t.startsWith("/")||t.startsWith("#")||t.startsWith("?")?t.split("?")[0]?.split("#")[0]:`${new URL(t,"https://loopcheck.invalid").pathname}`}catch{return}}function l(t,e){let n=t.getAttribute(e);return n&&n.trim()?n.trim():void 0}function G(t){return t?t instanceof Element?t:t instanceof Text?t.parentElement:null:null}function W(t){if(typeof t.composedPath=="function"){for(let e of t.composedPath())if(e instanceof Element)return e}return G(t.target)}function me(){if(typeof window>"u"||window===window.top)return null;try{let t=window.frameElement;if(!(t instanceof HTMLIFrameElement))return{inIframe:!0};if(t.name)return{inIframe:!0,frame:`iframe[name="${t.name}"]`};if(t.id&&!T(t.id))return{inIframe:!0,frame:`iframe#${typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(t.id):t.id.replace(/([^\w-])/g,"\\$1")}`};let e=t.getAttribute("title");return e?{inIframe:!0,frame:`iframe[title="${e.replace(/"/g,'\\"')}"]`}:{inIframe:!0,frame:"iframe"}}catch{return{inIframe:!0,crossOriginFrame:!0}}}function Z(t){if(!t||t.length>200||/javascript:|expression\(|@import/i.test(t))return!1;try{return document.createDocumentFragment().querySelector(t),!0}catch{return!1}}function Oe(t,e){for(let n of e)if(Z(n))try{if(t.matches(n))return!0}catch{}return!1}function P(t,e){let n=t;for(;n;){if(Oe(n,e))return n;n=n.parentElement}return null}function he(){return typeof window>"u"||typeof document>"u"?{url:"",pathname:"/"}:{url:window.location.href,pathname:window.location.pathname||"/",title:document.title||void 0}}function g(t){return!!t.closest("[data-loopcheck-ui],[data-loopcheck-recorder]")}function f(){return typeof window<"u"&&typeof document<"u"}function L(){return Date.now()}function X(t="qa"){let e=new Uint8Array(16),n=globalThis.crypto;if(n?.getRandomValues)n.getRandomValues(e);else for(let r=0;r<e.length;r+=1)e[r]=Math.floor(Math.random()*256);e[6]=(e[6]??0)&15|64,e[8]=(e[8]??0)&63|128;let i=Array.from(e,r=>r.toString(16).padStart(2,"0")).join("");return`${t}_${i.slice(0,8)}${i.slice(8,12)}${i.slice(12,16)}${i.slice(16,20)}${i.slice(20)}`}function ge(t){let e=t.filter(i=>!!(i&&i.length>0)).join("|"),n=2166136261;for(let i=0;i<e.length;i+=1)n^=e.charCodeAt(i),n=Math.imul(n,16777619);return`fp_${(n>>>0).toString(16).padStart(8,"0")}`}function m(t,e=80){if(!t)return;let n=t.replace(/\s+/g," ").trim();if(n)return n.length>e?`${n.slice(0,e)}\u2026`:n}function ve(t){if(!t)return;let e=t.trim();if(!e||e.length>400)return;let n=e.match(/^(.*?)(?::(\d+))?(?::(\d+))?(?:#(.+))?$/);if(!n)return{file:e};let i=n[2]?Number(n[2]):void 0,r=n[3]?Number(n[3]):void 0;return{file:n[1]||void 0,line:Number.isFinite(i)?i:void 0,column:Number.isFinite(r)?r:void 0,component:n[4]||void 0}}function ye(t){if(!t)return null;try{return JSON.parse(t)}catch{return null}}function je(t){let e=t.getAttribute("aria-labelledby");if(!e||typeof document>"u")return;let n=[];for(let i of e.split(/\s+/)){let s=document.getElementById(i)?.textContent;s&&n.push(s)}return m(n.join(" "))}function be(t){let e=t.getAttribute("aria-label");if(e?.trim())return m(e);let n=je(t);if(n)return n;if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){let i=t.getAttribute("placeholder");if(t.labels&&t.labels.length>0)return m(t.labels[0]?.textContent??void 0);if(i)return m(i)}return t instanceof HTMLElement&&t.title?m(t.title):m(t.textContent??void 0,60)}function Ee(t){let e=t.getAttribute("role")?.trim();if(e)return e;let n=t.tagName.toLowerCase();if(n==="button")return"button";if(n==="a")return"link";if(n==="input"){let i=(t.getAttribute("type")??"text").toLowerCase();return i==="checkbox"?"checkbox":i==="radio"?"radio":i==="submit"||i==="button"?"button":"textbox"}if(n==="textarea")return"textbox";if(n==="select")return"combobox";if(t.getAttribute("contenteditable")==="true")return"textbox"}function De(t){return ge([t.qaId,t.tagName,t.role,t.name,t.type,t.href,t.testId,t.id,t.parentFingerprint])}function qe(t,e=3){let n=[],i=t.parentElement,r=e;for(;i&&r>0;){let s=i.tagName.toLowerCase();if(s==="html"||s==="body")break;let a=l(i,p),u=l(i,"role"),c=l(i,"name");n.push([s,a,u,c].filter(Boolean).join(":")),i=i.parentElement,r-=1}return n.length>0?n.reverse().join(">"):void 0}function Ae(t,e={}){let n=e.id??(t.id||void 0);return De({qaId:e.qaId??l(t,p),tagName:e.tagName??t.tagName.toLowerCase(),role:e.role??l(t,"role"),name:e.name??l(t,"name"),type:e.type??l(t,"type"),href:e.href??w(l(t,"href")),testId:e.testId??l(t,I),id:n&&!T(n)?n:void 0,parentFingerprint:qe(t)})}var ze=/^(?=.{3,80}$)[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/,Ke=/^(?:button|element|el|node|item|id)-\d+$/i,$e=/[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;function U(t,e=!1){return e?t.trim().length>0&&t.length<=120:!ze.test(t)||$e.test(t)?!1:!t.split(".").some(n=>Ke.test(n))}var Ve=[p,A,I,"name","type","role","aria-label","title","placeholder","href","autocomplete"];function Ye(t){let e=Object.create(null);for(let n of Ve){let i=l(t,n);i&&(e[n]=n==="href"?w(i)??i:i)}return Object.keys(e).length>0?e:void 0}function Je(t){let e=t.parentElement;if(!(!e||e===document.body||e===document.documentElement))return{qaId:l(e,p),tagName:e.tagName.toLowerCase(),role:l(e,"role"),name:l(e,"name")??l(e,"aria-label")}}function M(t,e={}){let n=[],i=l(t,p),r=i&&U(i,e.allowUnstableIds)?i:void 0;i&&!r&&n.push("ignored unstable data-qa-id"),r&&n.push("explicit data-qa-id");let s=l(t,I);s&&n.push("data-testid");let a=Ee(t),u=be(t),c=ve(l(t,A)??null);c&&n.push("source metadata");let b=t.id||void 0,E=b&&!T(b)?b:void 0;E&&n.push("stable id"),a&&n.push("accessibility role"),u&&n.push("accessible name");let h=t.tagName.toLowerCase(),Y=l(t,"name"),se=l(t,"type"),ae=w(l(t,"href")),Ue=h==="input"||h==="textarea"?void 0:m(t.textContent??void 0,60),Me={qaId:r??(s&&U(s,e.allowUnstableIds)?s:void 0),tagName:h,role:a,accessibleName:u,text:Ue,name:Y,id:E,href:ae,type:se,source:c,parent:Je(t),attributes:Ye(t),fingerprint:Ae(t,{qaId:r??(s&&U(s,e.allowUnstableIds)?s:void 0),tagName:h,role:a,name:Y,type:se,href:ae,testId:s,id:E})},R="low";return r?R="exact":s||c?.file?(R="high",!n.includes("framework/source metadata")&&c?.file&&n.push("framework/source metadata")):a&&(u||Y)?(R="medium",n.push("semantic HTML")):n.push("deterministic DOM fingerprint"),{identity:Me,confidence:R,reasons:n}}var N=class{constructor(){o(this,"seen",new Map)}scan(e){this.seen.clear(),e.querySelectorAll(`[${p}]`).forEach(r=>{let s=l(r,p);if(!s)return;let a=l(r,A)??Ze(r),u=this.seen.get(s)??new Set;u.add(a),this.seen.set(s,u)});let i=[];for(let[r,s]of this.seen)(s.size>1||Ge(e,r)>1)&&i.push({qaId:r,sources:Array.from(s)});return i}};function Ge(t,e){return t.querySelectorAll(`[${p}="${We(e)}"]`).length}function We(t){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(t):t.replace(/["\\]/g,"\\$&")}function Ze(t){let e=t.tagName.toLowerCase(),n=t.getAttribute("aria-label")||t.getAttribute("name")||"";return n?`${e}[name=${n}]`:e}var H=class{constructor(e,n,i){this.config=e;this.onDuplicates=n;this.onResolved=i;o(this,"duplicates",new N);o(this,"lastScan",0);o(this,"scheduled",!1)}resolve(e){let n=P(e,this.config.interactiveSelectors)??e,i=M(n,{allowUnstableIds:this.config.allowUnstableIds});return this.onResolved?.(i),i}scheduleScan(e=document){if(this.scheduled)return;this.scheduled=!0;let n=()=>{this.scheduled=!1,this.scan(e)};typeof requestAnimationFrame=="function"?requestAnimationFrame(n):setTimeout(n,32)}scan(e=document){let n=Date.now();if(n-this.lastScan<80)return[];this.lastScan=n;let i=this.duplicates.scan(e);return i.length>0&&this.onDuplicates(i),i}};var B=class{constructor(e,n){this.config=e;this.registry=n;o(this,"observer");o(this,"timer")}start(e=document){typeof MutationObserver>"u"||(this.observer=new MutationObserver(()=>{this.schedule(e)}),e instanceof Node&&this.observer.observe(e,{subtree:!0,childList:!0,attributes:!0,attributeFilter:["data-qa-id","data-qa-source","role","name","type"]}),this.registry.scheduleScan(e))}stop(){this.observer?.disconnect(),this.observer=void 0,this.timer&&(clearTimeout(this.timer),this.timer=void 0)}schedule(e){this.timer||(this.timer=setTimeout(()=>{this.timer=void 0,this.registry.scheduleScan(e)},100))}};var Xe=new Set(["password","hidden"]),et=/^(cc-|card |current-password|new-password|one-time-code|tel|email)/i,tt=/password|passwd|secret|token|cvv|cvc|ssn|credit|card.?number|authorization|cookie|session/i;function nt(t,e){if(t.hasAttribute(le))return!0;if(t instanceof HTMLInputElement){if(Xe.has(t.type.toLowerCase()))return!0;let i=t.getAttribute("autocomplete")??"";if(i&&et.test(i))return!0}let n=t.getAttribute("name")??t.getAttribute("id")??"";if(n&&tt.test(n))return!0;for(let i of e.redactSelectors)if(Z(i))try{if(t.matches(i)||t.closest(i))return!0}catch{}return!1}function ee(t,e,n){return nt(t,n)||!n.recordInputValues?de:typeof e!="string"?e==null?void 0:String(e):e.length>200?`${e.slice(0,200)}\u2026`:e}var Ie=300,te="lc-on-autofill",ne="loopcheck-autofill-detect",it=new Set(["hidden","file","button","submit","reset","image"]);function Te(t){return t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement}function v(t){if(!(t instanceof HTMLInputElement))return!1;let e=t.type.toLowerCase();return e==="checkbox"||e==="radio"}function rt(t){if(t instanceof HTMLInputElement){let e=t.type.toLowerCase();return e==="submit"||e==="image"}return t instanceof HTMLButtonElement?t.type==="submit":!1}function we(t){return rt(t)?!0:t.closest("form")?t.matches('button, [role="button"], input[type="submit"], input[type="image"]'):!1}function S(t,e){if(t instanceof HTMLInputElement&&v(t))return{value:ee(t,t.value,e),checked:t.checked};let n=t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement||t instanceof HTMLSelectElement?t.value:void 0;return{value:ee(t,n,e)}}function ot(t,e,n,i){let r=[];if(typeof document>"u")return r;let s=t.querySelectorAll("input, textarea, select");for(let a of s){if(!Te(a)||g(a)||a instanceof HTMLInputElement&&it.has(a.type.toLowerCase())||"disabled"in a&&a.disabled)continue;if(v(a)){if(!(a instanceof HTMLInputElement)||!a.checked)continue}else if(!a.value.trim())continue;let u=e.resolve(a).identity;if(i.has(u.fingerprint))continue;let c=S(a,n);r.push({element:a,identity:u,value:c.value,checked:c.checked,eventType:a instanceof HTMLSelectElement?"select":v(a)?"change":"input"})}return r}function st(){if(typeof document>"u"||document.getElementById(ne))return;let t=document.createElement("style");t.id=ne,t.setAttribute("data-loopcheck-recorder","1"),t.textContent=`@keyframes ${te} {
|
|
2
|
+
from { opacity: 0.99; }
|
|
3
|
+
to { opacity: 1; }
|
|
4
|
+
}
|
|
5
|
+
input:-webkit-autofill,
|
|
6
|
+
textarea:-webkit-autofill,
|
|
7
|
+
select:-webkit-autofill {
|
|
8
|
+
animation-name: ${te};
|
|
9
|
+
}`,document.documentElement.appendChild(t)}function at(){typeof document>"u"||document.getElementById(ne)?.remove()}var _=class{constructor(e,n,i){this.config=e;this.registry=n;this.onField=i;o(this,"onAnimationStart",e=>{if(e.animationName!==te)return;let n=e.target;if(!(n instanceof Element)||!Te(n)||g(n)||v(n)||!n.value.trim())return;let i=this.registry.resolve(n).identity,r=S(n,this.config);this.onField({element:n,identity:i,value:r.value,checked:r.checked,eventType:n instanceof HTMLSelectElement?"select":"input"},"autofill")})}start(){typeof document>"u"||(st(),document.addEventListener("animationstart",this.onAnimationStart,!0))}stop(){typeof document>"u"||(document.removeEventListener("animationstart",this.onAnimationStart,!0),at())}collect(e,n,i){for(let r of ot(e,this.registry,this.config,n))this.onField(r,i)}};var Se=["click","dblclick","input","change","focus","blur","submit","keydown","dragstart","drop","mouseover"],lt=new Set(["Enter","Escape"]),F=class{constructor(e,n,i,r){this.config=e;this.registry=n;this.normalizer=i;this.shouldRecord=r;o(this,"attached",!1);o(this,"onEvent");o(this,"recordedFields",new Set);o(this,"lastClickedFingerprint");o(this,"harvest",null);o(this,"onScroll",e=>{if(!this.shouldRecord())return;let n=W(e);n&&g(n)||this.throttledScroll()});o(this,"scrollTimer");o(this,"throttledScroll",()=>{this.scrollTimer||(this.scrollTimer=setTimeout(()=>{this.scrollTimer=void 0,this.normalizer.simple("scroll",void 0,this.frameMeta())},400))});this.onEvent=s=>this.handle(s)}start(){if(!(this.attached||typeof document>"u")){this.harvest=new _(this.config,this.registry,(e,n)=>{this.emitHarvested(e,n)}),this.harvest.start();for(let e of Se)document.addEventListener(e,this.onEvent,!0);window.addEventListener("scroll",this.onScroll,!0),this.attached=!0}}stop(){if(!(!this.attached||typeof document>"u")){for(let e of Se)document.removeEventListener(e,this.onEvent,!0);window.removeEventListener("scroll",this.onScroll,!0),this.harvest?.stop(),this.harvest=null,this.attached=!1}}harvestPrefills(e="prefilled",n){!this.shouldRecord()||typeof document>"u"||this.harvest?.collect(n??document,this.recordedFields,e)}frameMeta(){let e=me();if(e)return{inIframe:!0,...e.frame?{frame:e.frame}:{},...e.crossOriginFrame?{crossOriginFrame:!0}:{}}}withFrame(e){let n=this.frameMeta();if(!(!n&&!e))return{...n,...e}}emitHarvested(e,n){this.shouldRecord()&&(this.recordedFields.has(e.identity.fingerprint)||(this.recordedFields.add(e.identity.fingerprint),this.normalizer.change(e.identity,e.value,e.eventType,this.withFrame({source:n,...e.checked!==void 0?{checked:e.checked}:{}}))))}handle(e){if(!this.shouldRecord())return;let n=W(e);if(!n||g(n))return;let i=P(n,this.config.interactiveSelectors);if(!i&&e.type!=="submit"&&e.type!=="keydown")return;let r=i??n,s=this.registry.resolve(r).identity;switch(e.type){case"click":we(r)&&this.harvestPrefills("prefilled",r.closest("form")??document),this.lastClickedFingerprint=s.fingerprint,this.normalizer.click(s,"click",this.frameMeta());break;case"dblclick":this.normalizer.click(s,"dblclick",this.frameMeta());break;case"input":if(v(r)||r instanceof HTMLInputElement&&r.type==="file")break;this.recordedFields.add(s.fingerprint),this.normalizer.input(s,S(r,this.config).value,this.withFrame({source:"typed"}));break;case"change":if(this.recordedFields.add(s.fingerprint),r instanceof HTMLInputElement&&r.type==="file"){this.emitFileChange(r,s);break}this.emitControlChange(r,s,"typed");break;case"focus":this.normalizer.simple("focus",s,this.frameMeta());break;case"blur":this.normalizer.flushInput(),this.normalizer.simple("blur",s,this.frameMeta());break;case"submit":this.handleSubmit(e,r,s);break;case"keydown":this.handleKey(e,s);break;case"dragstart":this.normalizer.simple("drag",s,this.frameMeta());break;case"drop":this.normalizer.simple("drop",s,this.frameMeta());break;case"mouseover":this.config.recordHover&&this.normalizer.simple("hover",s,this.frameMeta());break;default:break}}emitFileChange(e,n){let i=Array.from(e.files??[]).map(r=>r.name);this.normalizer.change(n,void 0,"change",this.withFrame({source:"typed",files:i.length>0?i:["upload.bin"],fileName:i[0]??"upload.bin"}))}handleSubmit(e,n,i){let r=n.closest("form")??n;this.harvestPrefills("prefilled",r);let s=dt(e,r);if(s){let a=this.registry.resolve(s).identity;a.fingerprint!==this.lastClickedFingerprint&&(this.lastClickedFingerprint=a.fingerprint,this.normalizer.click(a,"click",this.frameMeta()));return}this.normalizer.simple("submit",i,this.frameMeta())}emitControlChange(e,n,i){let r=S(e,this.config);this.normalizer.change(n,r.value,ct(e),this.withFrame({source:i,...r.checked!==void 0?{checked:r.checked}:{}}))}handleKey(e,n){lt.has(e.key)&&(this.normalizer.flushInput(),this.normalizer.simple("keydown",n,this.withFrame({key:e.key})))}};function dt(t,e){let n="submitter"in t?t.submitter:null;return n instanceof Element?n:e.querySelector('button[type="submit"], input[type="submit"], button:not([type]), input[type="image"]')}function ct(t){return t instanceof HTMLSelectElement?"select":"change"}var O=class{constructor(e){this.onNavigate=e;o(this,"originalPush");o(this,"originalReplace");o(this,"lastUrl","");o(this,"check",()=>{if(typeof window>"u")return;let e=window.location.href;e!==this.lastUrl&&(this.lastUrl=e,this.onNavigate(e,window.location.pathname||"/"))})}start(){typeof window>"u"||typeof history>"u"||(this.lastUrl=window.location.href,this.originalPush=history.pushState.bind(history),this.originalReplace=history.replaceState.bind(history),history.pushState=((e,n,i)=>{this.originalPush?.(e,n,i),this.check()}),history.replaceState=((e,n,i)=>{this.originalReplace?.(e,n,i),this.check()}),window.addEventListener("popstate",this.check),window.addEventListener("hashchange",this.check))}stop(){typeof window>"u"||typeof history>"u"||(this.originalPush&&(history.pushState=this.originalPush),this.originalReplace&&(history.replaceState=this.originalReplace),window.removeEventListener("popstate",this.check),window.removeEventListener("hashchange",this.check))}};var ut=400,j=class{constructor(e){this.emit=e;o(this,"inputTimer");o(this,"pendingInput")}click(e,n="click",i){this.flushInput(),this.emit({type:n,target:e,metadata:i&&Object.keys(i).length>0?i:void 0})}input(e,n,i){this.pendingInput&&this.pendingInput.target?.fingerprint!==e.fingerprint&&this.flushInput(),this.pendingInput={target:e,value:n,extra:i},this.inputTimer&&clearTimeout(this.inputTimer),this.inputTimer=setTimeout(()=>{this.flushInput()},ut)}change(e,n,i="change",r){this.flushInput();let s={...n===void 0?{}:{value:n},...r};this.emit({type:i,target:e,metadata:Object.keys(s).length>0?s:void 0})}simple(e,n,i){e!=="input"&&this.flushInput(),this.emit({type:e,target:n,metadata:i})}flushInput(){if(this.inputTimer&&(clearTimeout(this.inputTimer),this.inputTimer=void 0),!this.pendingInput)return;let e=this.pendingInput;this.pendingInput=void 0,this.emit({type:"input",target:e.target,metadata:{value:e.value,source:"typed",...e.extra}})}dispose(){this.flushInput()}},D=class{constructor(e){o(this,"paused",!1);o(this,"recording");this.recording={id:X("rec"),schemaVersion:"1",startedAt:L(),initialUrl:e,events:[]}}get isPaused(){return this.paused}pause(){this.paused=!0}resume(){this.paused=!1}push(e){this.paused||this.recording.events.push(e)}stop(){return this.recording.endedAt=L(),this.recording}};function q(t,e={}){return{id:X("evt"),schemaVersion:"1",timestamp:L(),type:t,target:e.target,page:e.page??he(),metadata:e.metadata}}function z(t,e="QAError"){if(t&&typeof t=="object"&&"message"in t){let n=t;return{name:typeof n.name=="string"?n.name:e,message:String(n.message),cause:t}}return{name:e,message:String(t),cause:t}}function y(t,e){try{t()}catch(n){e?.(z(n))}}async function ie(t,e){try{await t()}catch(n){e?.(z(n))}}var K=class{constructor(e){o(this,"pending",[]);o(this,"options");this.options={...e}}updateSession(e){this.options={...this.options,...e}}async send(e){await this.sendBatch([e])}async sendBatch(e){if(e.length===0)return;if(!this.options.apiUrl||!this.options.sessionId){this.pending.push(...e);return}let n=`${re(this.options.apiUrl)}/v1/sdk/events`,i=JSON.stringify({projectId:this.options.projectId,sessionId:this.options.sessionId,events:e}),r={"content-type":"application/json","x-loopcheck-project":this.options.projectId};this.options.publicClientToken&&(r["x-loopcheck-client-token"]=this.options.publicClientToken);let s=await fetch(n,{method:"POST",headers:r,body:i,credentials:"omit",keepalive:!0});if(!s.ok)throw new Error(`QA transport HTTP ${s.status}`)}async flush(){if(this.pending.length===0)return;let e=this.pending.splice(0,this.pending.length);await this.sendBatch(e)}};async function Qe(t){let e=`${re(t.apiUrl)}/v1/sdk/sessions`,n=await fetch(e,{method:"POST",headers:{"content-type":"application/json","x-loopcheck-client-token":t.publishableKey},body:JSON.stringify({initialUrl:t.initialUrl,projectId:t.projectId||void 0,environmentId:t.environmentId,publishableKey:t.publishableKey}),credentials:"omit"});if(!n.ok)throw new Error(`QA session create HTTP ${n.status}`);let i=await n.json();return{sessionId:i.sessionId,projectId:i.projectId,apiUrl:i.apiUrl??t.apiUrl}}function xe(t,e,n,i,r){if(typeof navigator>"u"||typeof navigator.sendBeacon!="function"||!t)return!1;try{let s=`${re(t)}/v1/sdk/events`,a=new Blob([JSON.stringify({projectId:e,sessionId:r,publicClientToken:i,events:n})],{type:"application/json"});return navigator.sendBeacon(s,a)}catch{return!1}}function re(t){return t.replace(/\/+$/,"")}var $=class{constructor(e,n){this.storageKey=e;this.maxBytes=n}load(){if(!f())return[];try{let e=window.localStorage.getItem(this.storageKey),n=ye(e);return Array.isArray(n?.events)?n.events.slice(0,200):[]}catch{return[]}}save(e){if(f())try{let n=e.slice(-200),i=JSON.stringify({events:n});for(;i.length>this.maxBytes&&n.length>0;)n=n.slice(Math.ceil(n.length/2)),i=JSON.stringify({events:n});if(i.length>this.maxBytes){window.localStorage.removeItem(this.storageKey);return}window.localStorage.setItem(this.storageKey,i)}catch{try{window.localStorage.removeItem(this.storageKey)}catch{}}}clear(){if(f())try{window.localStorage.removeItem(this.storageKey)}catch{}}};var V=class{constructor(e){o(this,"memory",[]);o(this,"timer");o(this,"retry");o(this,"transport");o(this,"httpTransport",null);o(this,"unloading",!1);o(this,"inflight",Promise.resolve());o(this,"config");o(this,"onPageHide",()=>{if(this.unloading=!0,this.memory.length===0)return;let e=this.memory.splice(0,this.memory.length);xe(this.config.apiUrl,this.config.projectId,e,this.config.publicClientToken,this.config.sessionId)||this.retry.save(e)});o(this,"onOnline",()=>{this.unloading||this.flush()});this.config=e,e.transport?this.transport=e.transport:(this.httpTransport=new K({apiUrl:e.apiUrl,projectId:e.projectId,sessionId:e.sessionId,publicClientToken:e.publicClientToken}),this.transport=this.httpTransport),this.retry=new $(`loopcheck.qa.queue.${e.projectId||"pending"}`,e.maxStorageBytes)}updateSession(e){e.projectId&&(this.config.projectId=e.projectId),e.sessionId&&(this.config.sessionId=e.sessionId),e.apiUrl&&(this.config.apiUrl=e.apiUrl),e.publicClientToken&&(this.config.publicClientToken=e.publicClientToken),this.httpTransport?.updateSession(e)}start(){this.memory.push(...this.retry.load()),this.retry.clear(),this.timer=setInterval(()=>{this.flush()},this.config.flushIntervalMs),typeof window<"u"&&(window.addEventListener("pagehide",this.onPageHide),window.addEventListener("online",this.onOnline))}enqueue(e){this.memory.length>=this.config.maxQueueSize&&this.memory.shift(),this.memory.push(e),this.memory.length>=this.config.maxBatchSize&&this.flush()}async flush(){this.inflight=this.inflight.then(()=>this.flushOnce()),await this.inflight}async flushOnce(){if(this.memory.length===0)return;let e=this.memory.splice(0,this.config.maxBatchSize);await ie(async()=>{await this.transport.sendBatch(e)},n=>{this.memory.unshift(...e),this.retry.save(this.memory),this.config.onError?.(n)})}async shutdown(){this.timer&&(clearInterval(this.timer),this.timer=void 0),typeof window<"u"&&(window.removeEventListener("pagehide",this.onPageHide),window.removeEventListener("online",this.onOnline)),await this.flush(),await ie(()=>this.transport.flush(),this.config.onError)}};var oe="loopcheck-qa-debug-panel",Q=null;function Re(t){if(typeof document>"u"||Q)return;let e=n=>{if(!n.altKey||!n.shiftKey){Ce();return}let i=G(n.target);if(!i)return;let r=t.resolveElement(i);pt(r)};document.addEventListener("mousemove",e,!0),Q={client:t,onMove:e}}function ke(){!Q||typeof document>"u"||(document.removeEventListener("mousemove",Q.onMove,!0),Ce(),Q=null)}function pt(t){let e=t.identity,n=document.getElementById(oe)??ft();n.textContent=["QA Element","\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",`ID: ${e.qaId??"(none)"}`,`Role: ${e.role??e.tagName}`,`Name: ${e.accessibleName??e.text??""}`,`Source: ${e.source?.file?`${e.source.file}${e.source.line?`:${e.source.line}`:""}`:"(none)"}`,`Fingerprint: ${e.fingerprint}`,`Confidence: ${t.confidence}`].join(`
|
|
10
|
+
`)}function ft(){let t=document.createElement("pre");return t.id=oe,t.setAttribute("data-qa-sensitive",""),t.style.cssText="position:fixed;z-index:2147483647;right:12px;bottom:12px;max-width:360px;margin:0;padding:12px;background:#111;color:#f5f5f5;font:12px/1.4 ui-monospace,monospace;border-radius:8px;pointer-events:none;white-space:pre-wrap;",document.body.appendChild(t),t}function Ce(){document.getElementById(oe)?.remove()}var Pe={isRecording:!1,isPaused:!1,mode:"disabled"},x=class{constructor(e){o(this,"config");o(this,"bus",new C);o(this,"subscribers",new Set);o(this,"session",null);o(this,"registry",null);o(this,"observer",null);o(this,"delegator",null);o(this,"navigation",null);o(this,"queue",null);o(this,"normalizer",null);o(this,"started",!1);o(this,"snapshot",Pe);o(this,"prefillTimer");o(this,"prefillRaf");o(this,"sessionBootstrap",null);o(this,"queryArmed",!1);o(this,"subscribe",e=>(this.subscribers.add(e),()=>{this.subscribers.delete(e)}));o(this,"getSnapshot",()=>this.snapshot);let n=ue(e);this.config=pe(e),n.length>0&&this.report({name:"QAConfigError",message:`Ignored privileged config keys: ${n.join(", ")}`}),this.snapshot={isRecording:!1,isPaused:!1,mode:J(this.config)}}start(){y(()=>{this.started||!f()||J(this.config)==="disabled"||(this.attachInstrumentation(),this.config.mode==="record"&&this.beginRecording())},e=>this.report(e))}maybeArmFromQuery(){this.queryArmed||!fe(this.config.startOn)||(this.queryArmed=!0,this.startRecording())}async shutdown(){this.clearPrefillHarvest(),this.normalizer?.dispose(),this.delegator?.stop(),this.observer?.stop(),this.navigation?.stop(),ke(),await this.queue?.shutdown(),this.started=!1,this.registry=null,this.observer=null,this.delegator=null,this.navigation=null,this.queue=null,this.normalizer=null}async startRecording(){try{if(!f()||this.config.enabled===!1)return;await this.ensureSession(),this.beginRecording()}catch(e){this.report(z(e))}}beginRecording(){y(()=>{if(!(!f()||this.config.enabled===!1)){if(this.config.mode="record",this.config.enabled=!0,this.started||this.attachInstrumentation(),this.session&&!this.session.recording.endedAt){this.session.resume(),this.setSnapshot({isRecording:!0,isPaused:!1,mode:"record"}),this.bus.emit("recording:resume",null);return}this.session=new D(window.location.href),this.setSnapshot({isRecording:!0,isPaused:!1,mode:"record"}),this.bus.emit("recording:start",this.session.recording),this.emitEvent(q("navigation",{page:{url:window.location.href,pathname:window.location.pathname||"/",title:document.title||void 0}})),this.schedulePrefillHarvest()}},e=>this.report(e))}stopRecording(){let e=null;return y(()=>{this.clearPrefillHarvest(),this.delegator?.harvestPrefills("prefilled"),this.normalizer?.flushInput(),this.session&&(e=this.session.stop(),this.session=null,this.setSnapshot({isRecording:!1,isPaused:!1,mode:this.config.mode==="record"?"observe":this.config.mode}),this.bus.emit("recording:stop",e))},n=>this.report(n)),e}pauseRecording(){y(()=>{this.session?.pause(),this.setSnapshot({isPaused:!0}),this.bus.emit("recording:pause",null)},e=>this.report(e))}resumeRecording(){y(()=>{this.session?.resume(),this.setSnapshot({isPaused:!1}),this.bus.emit("recording:resume",null)},e=>this.report(e))}get isRecording(){return this.snapshot.isRecording}get isPaused(){return this.snapshot.isPaused}resolveElement(e){return this.registry?this.registry.resolve(e):M(e,{allowUnstableIds:this.config.allowUnstableIds})}on(e,n){return this.bus.on(e,n)}attachInstrumentation(){this.started||!f()||(this.started=!0,this.registry=new H(this.config,e=>{for(let n of e)this.bus.emit("duplicate-id",n),(this.config.debug||this.config.environment!=="production")&&console.warn(`Duplicate QA ID detected:
|
|
11
|
+
${n.qaId}
|
|
12
|
+
Elements:
|
|
13
|
+
${n.sources.map((i,r)=>`${r+1}. ${i}`).join(`
|
|
14
|
+
`)}`)},e=>this.bus.emit("element:resolved",e)),this.observer=new B(this.config,this.registry),this.observer.start(document),this.navigation=new O((e,n)=>{this.normalizer?.flushInput(),this.emitEvent(q("navigation",{page:{url:e,pathname:n,title:document.title||void 0}})),this.queue?.flush()}),this.navigation.start(),this.normalizer=new j(e=>{this.emitEvent(q(e.type,{target:e.target,metadata:e.metadata,page:e.page}))}),this.delegator=new F(this.config,this.registry,this.normalizer,()=>this.isRecording&&!this.isPaused),this.delegator.start(),this.queue=new V(this.config),this.queue.start(),this.config.debug&&Re(this))}async ensureSession(){if(this.config.sessionId)return;let e=this.config.publishableKey??this.config.publicClientToken;if(e){if(!this.config.apiUrl)throw new Error("apiUrl is required to create a recording session");this.sessionBootstrap||(this.sessionBootstrap=(async()=>{let n=await Qe({apiUrl:this.config.apiUrl,publishableKey:e,initialUrl:window.location.href,projectId:this.config.projectId||void 0});this.config.sessionId=n.sessionId,this.config.projectId=n.projectId,n.apiUrl&&(this.config.apiUrl=n.apiUrl),this.queue?.updateSession({sessionId:n.sessionId,projectId:n.projectId,apiUrl:this.config.apiUrl,publicClientToken:e})})());try{await this.sessionBootstrap}catch(n){throw this.sessionBootstrap=null,n}}}schedulePrefillHarvest(){this.clearPrefillHarvest();let e=()=>{this.prefillTimer=setTimeout(()=>{this.prefillTimer=void 0,this.delegator?.harvestPrefills("prefilled")},Ie)};typeof requestAnimationFrame=="function"?this.prefillRaf=requestAnimationFrame(()=>{this.prefillRaf=void 0,e()}):e()}clearPrefillHarvest(){this.prefillRaf!==void 0&&typeof cancelAnimationFrame=="function"&&(cancelAnimationFrame(this.prefillRaf),this.prefillRaf=void 0),this.prefillTimer&&(clearTimeout(this.prefillTimer),this.prefillTimer=void 0)}emitEvent(e){!this.snapshot.isRecording||this.snapshot.isPaused||(this.session?.push(e),this.bus.emit("event",e),this.queue?.enqueue(e))}setSnapshot(e){this.snapshot={...this.snapshot,...e};for(let n of this.subscribers)n()}report(e){this.config.onError?.(e),this.bus.emit("error",e),this.config.debug&&console.warn("[loopcheck-qa]",e.message)}};o(x,"getServerSnapshot",()=>Pe);var d=null,Le=!0;function mt(t){if(d){if(!!t.sessionId&&d.config.sessionId===t.sessionId&&d.config.projectId===t.projectId)return t.mode==="record"&&!d.isRecording&&d.startRecording(),d;d.shutdown(),d=null}Le=t.ui!=="none";let e=t.publishableKey??t.publicClientToken,n={projectId:t.projectId,sessionId:t.sessionId,apiUrl:t.apiUrl,publishableKey:t.publishableKey,publicClientToken:e,mode:t.mode??(t.sessionId?"record":"disabled"),startOn:t.startOn??"manual",debug:!!t.debug,enabled:!0,recordInputValues:!0,flushIntervalMs:500};if(d=new x(n),d.start(),d.maybeArmFromQuery(),(t.mode==="record"||t.sessionId)&&d.startRecording(),Le&&typeof document<"u"){document.querySelector("[data-loopcheck-recorder]")?.remove();let i=document.createElement("div");i.setAttribute("data-loopcheck-recorder","1"),i.textContent="Loopcheck recording",i.style.cssText="position:fixed;z-index:2147483647;bottom:12px;right:12px;padding:6px 10px;border-radius:8px;background:#18181b;color:#fafafa;font:12px/1.4 system-ui,sans-serif;box-shadow:0 4px 16px rgba(0,0,0,.2)",document.documentElement.appendChild(i)}return d}async function ht(){d&&(d.stopRecording(),await d.shutdown(),d=null,document.querySelector("[data-loopcheck-recorder]")?.remove())}function gt(){d?.pauseRecording()}function vt(){d?.resumeRecording()}var yt={start:mt,stop:ht,pause:gt,resume:vt,getClient:()=>d};typeof window<"u"&&(window.LoopcheckQA=yt);})();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { QAEvent, ResolvedQAConfig } from '../types';
|
|
2
|
+
export declare class BatchQueue {
|
|
3
|
+
private readonly memory;
|
|
4
|
+
private timer;
|
|
5
|
+
private readonly retry;
|
|
6
|
+
private readonly transport;
|
|
7
|
+
private httpTransport;
|
|
8
|
+
private unloading;
|
|
9
|
+
private inflight;
|
|
10
|
+
private config;
|
|
11
|
+
constructor(config: ResolvedQAConfig);
|
|
12
|
+
updateSession(patch: {
|
|
13
|
+
projectId?: string;
|
|
14
|
+
sessionId?: string;
|
|
15
|
+
apiUrl?: string;
|
|
16
|
+
publicClientToken?: string;
|
|
17
|
+
}): void;
|
|
18
|
+
start(): void;
|
|
19
|
+
enqueue(event: QAEvent): void;
|
|
20
|
+
flush(): Promise<void>;
|
|
21
|
+
private flushOnce;
|
|
22
|
+
shutdown(): Promise<void>;
|
|
23
|
+
private readonly onPageHide;
|
|
24
|
+
private readonly onOnline;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=BatchQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchQueue.d.ts","sourceRoot":"","sources":["../../src/transport/BatchQueue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAe,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAKvE,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,MAAM,CAAmB;gBAErB,MAAM,EAAE,gBAAgB;IAmBpC,aAAa,CAAC,KAAK,EAAE;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,IAAI;IAgBR,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAUvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAKd,SAAS;IAcjB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAa/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAgBzB;IAEF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAIvB;CACH"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { swallowAsync } from '../utils/safe';
|
|
2
|
+
import { HTTPTransport, sendBeaconBatch } from './HTTPTransport';
|
|
3
|
+
import { RetryQueue } from './RetryQueue';
|
|
4
|
+
export class BatchQueue {
|
|
5
|
+
memory = [];
|
|
6
|
+
timer;
|
|
7
|
+
retry;
|
|
8
|
+
transport;
|
|
9
|
+
httpTransport = null;
|
|
10
|
+
unloading = false;
|
|
11
|
+
inflight = Promise.resolve();
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
if (config.transport) {
|
|
16
|
+
this.transport = config.transport;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
this.httpTransport = new HTTPTransport({
|
|
20
|
+
apiUrl: config.apiUrl,
|
|
21
|
+
projectId: config.projectId,
|
|
22
|
+
sessionId: config.sessionId,
|
|
23
|
+
publicClientToken: config.publicClientToken,
|
|
24
|
+
});
|
|
25
|
+
this.transport = this.httpTransport;
|
|
26
|
+
}
|
|
27
|
+
this.retry = new RetryQueue(`loopcheck.qa.queue.${config.projectId || 'pending'}`, config.maxStorageBytes);
|
|
28
|
+
}
|
|
29
|
+
updateSession(patch) {
|
|
30
|
+
if (patch.projectId) {
|
|
31
|
+
this.config.projectId = patch.projectId;
|
|
32
|
+
}
|
|
33
|
+
if (patch.sessionId) {
|
|
34
|
+
this.config.sessionId = patch.sessionId;
|
|
35
|
+
}
|
|
36
|
+
if (patch.apiUrl) {
|
|
37
|
+
this.config.apiUrl = patch.apiUrl;
|
|
38
|
+
}
|
|
39
|
+
if (patch.publicClientToken) {
|
|
40
|
+
this.config.publicClientToken = patch.publicClientToken;
|
|
41
|
+
}
|
|
42
|
+
this.httpTransport?.updateSession(patch);
|
|
43
|
+
}
|
|
44
|
+
start() {
|
|
45
|
+
this.memory.push(...this.retry.load());
|
|
46
|
+
this.retry.clear();
|
|
47
|
+
this.timer = setInterval(() => {
|
|
48
|
+
void this.flush();
|
|
49
|
+
}, this.config.flushIntervalMs);
|
|
50
|
+
if (typeof window !== 'undefined') {
|
|
51
|
+
window.addEventListener('pagehide', this.onPageHide);
|
|
52
|
+
window.addEventListener('online', this.onOnline);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
enqueue(event) {
|
|
56
|
+
if (this.memory.length >= this.config.maxQueueSize) {
|
|
57
|
+
this.memory.shift();
|
|
58
|
+
}
|
|
59
|
+
this.memory.push(event);
|
|
60
|
+
if (this.memory.length >= this.config.maxBatchSize) {
|
|
61
|
+
void this.flush();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async flush() {
|
|
65
|
+
this.inflight = this.inflight.then(() => this.flushOnce());
|
|
66
|
+
await this.inflight;
|
|
67
|
+
}
|
|
68
|
+
async flushOnce() {
|
|
69
|
+
if (this.memory.length === 0) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const batch = this.memory.splice(0, this.config.maxBatchSize);
|
|
73
|
+
await swallowAsync(async () => {
|
|
74
|
+
await this.transport.sendBatch(batch);
|
|
75
|
+
}, (error) => {
|
|
76
|
+
this.memory.unshift(...batch);
|
|
77
|
+
this.retry.save(this.memory);
|
|
78
|
+
this.config.onError?.(error);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async shutdown() {
|
|
82
|
+
if (this.timer) {
|
|
83
|
+
clearInterval(this.timer);
|
|
84
|
+
this.timer = undefined;
|
|
85
|
+
}
|
|
86
|
+
if (typeof window !== 'undefined') {
|
|
87
|
+
window.removeEventListener('pagehide', this.onPageHide);
|
|
88
|
+
window.removeEventListener('online', this.onOnline);
|
|
89
|
+
}
|
|
90
|
+
await this.flush();
|
|
91
|
+
await swallowAsync(() => this.transport.flush(), this.config.onError);
|
|
92
|
+
}
|
|
93
|
+
onPageHide = () => {
|
|
94
|
+
this.unloading = true;
|
|
95
|
+
if (this.memory.length === 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const batch = this.memory.splice(0, this.memory.length);
|
|
99
|
+
const sent = sendBeaconBatch(this.config.apiUrl, this.config.projectId, batch, this.config.publicClientToken, this.config.sessionId);
|
|
100
|
+
if (!sent) {
|
|
101
|
+
this.retry.save(batch);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
onOnline = () => {
|
|
105
|
+
if (!this.unloading) {
|
|
106
|
+
void this.flush();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=BatchQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchQueue.js","sourceRoot":"","sources":["../../src/transport/BatchQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { QAEvent, QATransport } from '../types';
|
|
2
|
+
export declare class MemoryTransport implements QATransport {
|
|
3
|
+
readonly events: QAEvent[];
|
|
4
|
+
failNext: boolean;
|
|
5
|
+
send(event: QAEvent): Promise<void>;
|
|
6
|
+
sendBatch(events: QAEvent[]): Promise<void>;
|
|
7
|
+
flush(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export type HTTPTransportOptions = {
|
|
10
|
+
apiUrl: string;
|
|
11
|
+
projectId: string;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
publicClientToken?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare class HTTPTransport implements QATransport {
|
|
16
|
+
private readonly pending;
|
|
17
|
+
private options;
|
|
18
|
+
constructor(options: HTTPTransportOptions);
|
|
19
|
+
updateSession(patch: Partial<HTTPTransportOptions>): void;
|
|
20
|
+
send(event: QAEvent): Promise<void>;
|
|
21
|
+
sendBatch(events: QAEvent[]): Promise<void>;
|
|
22
|
+
flush(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare function createSdkSession(input: {
|
|
25
|
+
apiUrl: string;
|
|
26
|
+
publishableKey: string;
|
|
27
|
+
initialUrl: string;
|
|
28
|
+
projectId?: string;
|
|
29
|
+
environmentId?: string;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
sessionId: string;
|
|
32
|
+
projectId: string;
|
|
33
|
+
apiUrl: string;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function sendBeaconBatch(apiUrl: string, projectId: string, events: QAEvent[], token?: string, sessionId?: string): boolean;
|
|
36
|
+
//# sourceMappingURL=HTTPTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HTTPTransport.d.ts","sourceRoot":"","sources":["../../src/transport/HTTPTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAErD,qBAAa,eAAgB,YAAW,WAAW;IACjD,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAM;IAChC,QAAQ,UAAS;IAEX,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,qBAAa,aAAc,YAAW,WAAW;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,OAAO,CAAuB;gBAE1B,OAAO,EAAE,oBAAoB;IAIzC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAInD,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BpE;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EAAE,EACjB,KAAK,CAAC,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAyBT"}
|