@purespectrum1/purescore-client 0.7.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 (136) hide show
  1. package/README.md +55 -0
  2. package/lib/application/auto-init.d.ts +44 -0
  3. package/lib/application/auto-init.js +245 -0
  4. package/lib/application/device-identifier.d.ts +116 -0
  5. package/lib/application/device-identifier.js +169 -0
  6. package/lib/domain/models/crosscutting/device-intelligence.d.ts +11 -0
  7. package/lib/domain/models/crosscutting/device-intelligence.js +18 -0
  8. package/lib/domain/models/crosscutting/index.d.ts +1 -0
  9. package/lib/domain/models/crosscutting/index.js +17 -0
  10. package/lib/domain/protocols/cache/get-storage.d.ts +8 -0
  11. package/lib/domain/protocols/cache/get-storage.js +2 -0
  12. package/lib/domain/protocols/cache/index.d.ts +3 -0
  13. package/lib/domain/protocols/cache/index.js +19 -0
  14. package/lib/domain/protocols/cache/remove-storage.d.ts +6 -0
  15. package/lib/domain/protocols/cache/remove-storage.js +2 -0
  16. package/lib/domain/protocols/cache/set-storage.d.ts +7 -0
  17. package/lib/domain/protocols/cache/set-storage.js +2 -0
  18. package/lib/domain/protocols/http/http-client.d.ts +23 -0
  19. package/lib/domain/protocols/http/http-client.js +13 -0
  20. package/lib/domain/protocols/services/behavioural-biometrics/cursor-behavior.d.ts +63 -0
  21. package/lib/domain/protocols/services/behavioural-biometrics/cursor-behavior.js +2 -0
  22. package/lib/domain/protocols/services/behavioural-biometrics/index.d.ts +3 -0
  23. package/lib/domain/protocols/services/behavioural-biometrics/index.js +19 -0
  24. package/lib/domain/protocols/services/behavioural-biometrics/keystorke-metrics.d.ts +35 -0
  25. package/lib/domain/protocols/services/behavioural-biometrics/keystorke-metrics.js +2 -0
  26. package/lib/domain/protocols/services/behavioural-biometrics/touch-behavior.d.ts +88 -0
  27. package/lib/domain/protocols/services/behavioural-biometrics/touch-behavior.js +2 -0
  28. package/lib/domain/protocols/services/device-fingerprint/display.d.ts +22 -0
  29. package/lib/domain/protocols/services/device-fingerprint/display.js +2 -0
  30. package/lib/domain/protocols/services/device-fingerprint/index.d.ts +3 -0
  31. package/lib/domain/protocols/services/device-fingerprint/index.js +19 -0
  32. package/lib/domain/protocols/services/device-fingerprint/navigator.d.ts +63 -0
  33. package/lib/domain/protocols/services/device-fingerprint/navigator.js +2 -0
  34. package/lib/domain/protocols/services/device-fingerprint/utils.d.ts +40 -0
  35. package/lib/domain/protocols/services/device-fingerprint/utils.js +2 -0
  36. package/lib/domain/protocols/services/device-identifier.d.ts +96 -0
  37. package/lib/domain/protocols/services/device-identifier.js +2 -0
  38. package/lib/domain/protocols/services/device-intelligence.d.ts +5 -0
  39. package/lib/domain/protocols/services/device-intelligence.js +2 -0
  40. package/lib/domain/protocols/services/listeners.d.ts +9 -0
  41. package/lib/domain/protocols/services/listeners.js +2 -0
  42. package/lib/domain/protocols/services/single-script-injection/auto-init.d.ts +120 -0
  43. package/lib/domain/protocols/services/single-script-injection/auto-init.js +2 -0
  44. package/lib/domain/protocols/services/single-script-injection/index.d.ts +1 -0
  45. package/lib/domain/protocols/services/single-script-injection/index.js +17 -0
  46. package/lib/domain/services/behavioural-biometrics/collector.d.ts +94 -0
  47. package/lib/domain/services/behavioural-biometrics/collector.js +229 -0
  48. package/lib/domain/services/behavioural-biometrics/cursor-behavior.d.ts +87 -0
  49. package/lib/domain/services/behavioural-biometrics/cursor-behavior.js +369 -0
  50. package/lib/domain/services/behavioural-biometrics/index.d.ts +4 -0
  51. package/lib/domain/services/behavioural-biometrics/index.js +20 -0
  52. package/lib/domain/services/behavioural-biometrics/keystroke-metrics.d.ts +60 -0
  53. package/lib/domain/services/behavioural-biometrics/keystroke-metrics.js +213 -0
  54. package/lib/domain/services/behavioural-biometrics/touch-behavior.d.ts +125 -0
  55. package/lib/domain/services/behavioural-biometrics/touch-behavior.js +413 -0
  56. package/lib/domain/services/device-fingerprint/audio.d.ts +14 -0
  57. package/lib/domain/services/device-fingerprint/audio.js +109 -0
  58. package/lib/domain/services/device-fingerprint/canvas.d.ts +10 -0
  59. package/lib/domain/services/device-fingerprint/canvas.js +33 -0
  60. package/lib/domain/services/device-fingerprint/display.d.ts +49 -0
  61. package/lib/domain/services/device-fingerprint/display.js +88 -0
  62. package/lib/domain/services/device-fingerprint/hash.d.ts +14 -0
  63. package/lib/domain/services/device-fingerprint/hash.js +60 -0
  64. package/lib/domain/services/device-fingerprint/index.d.ts +8 -0
  65. package/lib/domain/services/device-fingerprint/index.js +24 -0
  66. package/lib/domain/services/device-fingerprint/navigator.d.ts +110 -0
  67. package/lib/domain/services/device-fingerprint/navigator.js +213 -0
  68. package/lib/domain/services/device-fingerprint/pointer-capability.d.ts +14 -0
  69. package/lib/domain/services/device-fingerprint/pointer-capability.js +42 -0
  70. package/lib/domain/services/device-fingerprint/storage.d.ts +44 -0
  71. package/lib/domain/services/device-fingerprint/storage.js +64 -0
  72. package/lib/domain/services/device-fingerprint/utils.d.ts +42 -0
  73. package/lib/domain/services/device-fingerprint/utils.js +95 -0
  74. package/lib/domain/services/device-intelligence.d.ts +10 -0
  75. package/lib/domain/services/device-intelligence.js +59 -0
  76. package/lib/domain/services/single-script-injection/checkpoint-scheduler.d.ts +37 -0
  77. package/lib/domain/services/single-script-injection/checkpoint-scheduler.js +94 -0
  78. package/lib/domain/services/single-script-injection/index.d.ts +3 -0
  79. package/lib/domain/services/single-script-injection/index.js +19 -0
  80. package/lib/domain/services/single-script-injection/response-delivery.d.ts +47 -0
  81. package/lib/domain/services/single-script-injection/response-delivery.js +115 -0
  82. package/lib/domain/services/single-script-injection/schedule-store.d.ts +69 -0
  83. package/lib/domain/services/single-script-injection/schedule-store.js +146 -0
  84. package/lib/domain/services/snapshot-store.d.ts +19 -0
  85. package/lib/domain/services/snapshot-store.js +36 -0
  86. package/lib/domain/services/spa-navigation.d.ts +15 -0
  87. package/lib/domain/services/spa-navigation.js +40 -0
  88. package/lib/index.d.ts +19 -0
  89. package/lib/index.js +27 -0
  90. package/lib/infra/cache/index.d.ts +3 -0
  91. package/lib/infra/cache/index.js +19 -0
  92. package/lib/infra/cache/local-storage-adapter.d.ts +8 -0
  93. package/lib/infra/cache/local-storage-adapter.js +14 -0
  94. package/lib/infra/cache/session-storage-adapter.d.ts +8 -0
  95. package/lib/infra/cache/session-storage-adapter.js +14 -0
  96. package/lib/infra/cache/web-storage-adapter.d.ts +13 -0
  97. package/lib/infra/cache/web-storage-adapter.js +33 -0
  98. package/lib/infra/http/axios-http-client.d.ts +4 -0
  99. package/lib/infra/http/axios-http-client.js +39 -0
  100. package/lib/validation/builder.d.ts +43 -0
  101. package/lib/validation/builder.js +85 -0
  102. package/lib/validation/composite.d.ts +13 -0
  103. package/lib/validation/composite.js +23 -0
  104. package/lib/validation/errors/index.d.ts +2 -0
  105. package/lib/validation/errors/index.js +18 -0
  106. package/lib/validation/errors/invalid-field-error.d.ts +7 -0
  107. package/lib/validation/errors/invalid-field-error.js +14 -0
  108. package/lib/validation/errors/required-field-error.d.ts +3 -0
  109. package/lib/validation/errors/required-field-error.js +10 -0
  110. package/lib/validation/index.d.ts +5 -0
  111. package/lib/validation/index.js +21 -0
  112. package/lib/validation/protocols/index.d.ts +1 -0
  113. package/lib/validation/protocols/index.js +17 -0
  114. package/lib/validation/protocols/validator.d.ts +11 -0
  115. package/lib/validation/protocols/validator.js +2 -0
  116. package/lib/validation/validators/behavioural-signal.d.ts +27 -0
  117. package/lib/validation/validators/behavioural-signal.js +56 -0
  118. package/lib/validation/validators/country-code.d.ts +14 -0
  119. package/lib/validation/validators/country-code.js +24 -0
  120. package/lib/validation/validators/global-function.d.ts +14 -0
  121. package/lib/validation/validators/global-function.js +29 -0
  122. package/lib/validation/validators/index.d.ts +9 -0
  123. package/lib/validation/validators/index.js +25 -0
  124. package/lib/validation/validators/interpolated-template.d.ts +14 -0
  125. package/lib/validation/validators/interpolated-template.js +28 -0
  126. package/lib/validation/validators/json-object.d.ts +14 -0
  127. package/lib/validation/validators/json-object.js +33 -0
  128. package/lib/validation/validators/language-code.d.ts +13 -0
  129. package/lib/validation/validators/language-code.js +23 -0
  130. package/lib/validation/validators/positive-number.d.ts +13 -0
  131. package/lib/validation/validators/positive-number.js +24 -0
  132. package/lib/validation/validators/required-string.d.ts +10 -0
  133. package/lib/validation/validators/required-string.js +19 -0
  134. package/lib/validation/validators/schedule-record.d.ts +26 -0
  135. package/lib/validation/validators/schedule-record.js +33 -0
  136. package/package.json +51 -0
@@ -0,0 +1,44 @@
1
+ export declare class Storage {
2
+ /**
3
+ * Returns an object with properties indicating the availability of different storage types.
4
+ *
5
+ * The returned object has the following properties:
6
+ * - `sessionStorage`: Whether session storage is available.
7
+ * - `localStorage`: Whether local storage is available.
8
+ * - `indexedDB`: Whether IndexedDB is available.
9
+ *
10
+ * @returns {object} An object with properties indicating the availability of different storage types.
11
+ * @example
12
+ * const storageProperties = getStorageProperties();
13
+ * console.log(storageProperties);
14
+ * // Output: { sessionStorage: true, localStorage: true, indexedDB: true }
15
+ */
16
+ getStorageProperties(): {
17
+ sessionStorage: boolean;
18
+ localStorage: boolean;
19
+ indexedDB: boolean;
20
+ };
21
+ /**
22
+ * Checks if local storage is available.
23
+ *
24
+ * This function returns `true` if local storage is available, and `false` otherwise.
25
+ * Note that if a `SecurityError` is thrown when trying to access `window.localStorage`,
26
+ * it means that local storage exists, but is not accessible due to security restrictions.
27
+ * @returns {boolean} Whether local storage is available.
28
+ * @example
29
+ * const hasLocalStorage = hasLocalStorage(); // true if local storage is available, false otherwise
30
+ */
31
+ private _hasLocalStorage;
32
+ /**
33
+ * Checks if session storage is available.
34
+ *
35
+ * This function returns `true` if session storage is available, and `false` otherwise.
36
+ * Note that if a `SecurityError` is thrown when trying to access `window.sessionStorage`,
37
+ * it means that session storage exists, but is not accessible due to security restrictions.
38
+ *
39
+ * @returns {boolean} Whether session storage is available.
40
+ * @example
41
+ * const hasSessionStorage = hasSessionStorage(); // true if session storage is available, false otherwise
42
+ */
43
+ private _hasSessionStorage;
44
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Storage = void 0;
4
+ class Storage {
5
+ /**
6
+ * Returns an object with properties indicating the availability of different storage types.
7
+ *
8
+ * The returned object has the following properties:
9
+ * - `sessionStorage`: Whether session storage is available.
10
+ * - `localStorage`: Whether local storage is available.
11
+ * - `indexedDB`: Whether IndexedDB is available.
12
+ *
13
+ * @returns {object} An object with properties indicating the availability of different storage types.
14
+ * @example
15
+ * const storageProperties = getStorageProperties();
16
+ * console.log(storageProperties);
17
+ * // Output: { sessionStorage: true, localStorage: true, indexedDB: true }
18
+ */
19
+ getStorageProperties() {
20
+ return {
21
+ sessionStorage: this._hasSessionStorage(),
22
+ localStorage: this._hasLocalStorage(),
23
+ indexedDB: !!window.indexedDB,
24
+ };
25
+ }
26
+ /**
27
+ * Checks if local storage is available.
28
+ *
29
+ * This function returns `true` if local storage is available, and `false` otherwise.
30
+ * Note that if a `SecurityError` is thrown when trying to access `window.localStorage`,
31
+ * it means that local storage exists, but is not accessible due to security restrictions.
32
+ * @returns {boolean} Whether local storage is available.
33
+ * @example
34
+ * const hasLocalStorage = hasLocalStorage(); // true if local storage is available, false otherwise
35
+ */
36
+ _hasLocalStorage() {
37
+ try {
38
+ return !!window.localStorage;
39
+ }
40
+ catch (_a) {
41
+ return true; // SecurityError when referencing it means it exists
42
+ }
43
+ }
44
+ /**
45
+ * Checks if session storage is available.
46
+ *
47
+ * This function returns `true` if session storage is available, and `false` otherwise.
48
+ * Note that if a `SecurityError` is thrown when trying to access `window.sessionStorage`,
49
+ * it means that session storage exists, but is not accessible due to security restrictions.
50
+ *
51
+ * @returns {boolean} Whether session storage is available.
52
+ * @example
53
+ * const hasSessionStorage = hasSessionStorage(); // true if session storage is available, false otherwise
54
+ */
55
+ _hasSessionStorage() {
56
+ try {
57
+ return !!window.sessionStorage;
58
+ }
59
+ catch (_a) {
60
+ return true; // SecurityError when referencing it means it exists
61
+ }
62
+ }
63
+ }
64
+ exports.Storage = Storage;
@@ -0,0 +1,42 @@
1
+ import { NetworkTimes } from "../../protocols/services/device-fingerprint/utils";
2
+ export declare class Utils {
3
+ /**
4
+ * Gets the timezone offset of the current browser.
5
+ *
6
+ * @returns {number} The timezone offset in hours.
7
+ *
8
+ * @example
9
+ * const timezoneOffset = getTimezoneOffset();
10
+ * console.log(timezoneOffset); // Output: -5 or 3
11
+ */
12
+ getTimezoneOffset(): number;
13
+ /**
14
+ * Checks if touch events are supported in the current browser.
15
+ *
16
+ * @returns {boolean} True if touch events are supported, false otherwise.
17
+ *
18
+ * @example
19
+ * const touchSupported = getTouchSupport();
20
+ * console.log(touchSupported); // Output: true or false
21
+ */
22
+ getTouchSupport(): boolean;
23
+ /**
24
+ * Gets network timing data for the current page load.
25
+ *
26
+ * @returns {NetworkTimes} An object containing network timing data.
27
+ *
28
+ * @example
29
+ * const networkTimes = getNetworkTime();
30
+ * console.log(networkTimes);
31
+ * // Output:
32
+ * // {
33
+ * // networkTime: 1.234,
34
+ * // dnsLookupTime: 0.123,
35
+ * // tcpConnectionTime: 0.234,
36
+ * // serverResponseTime: 0.345,
37
+ * // pageDownloadTime: 0.456,
38
+ * // browserTime: 1.567
39
+ * // }
40
+ */
41
+ getNetworkTime(): NetworkTimes;
42
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Utils = void 0;
4
+ class Utils {
5
+ /**
6
+ * Gets the timezone offset of the current browser.
7
+ *
8
+ * @returns {number} The timezone offset in hours.
9
+ *
10
+ * @example
11
+ * const timezoneOffset = getTimezoneOffset();
12
+ * console.log(timezoneOffset); // Output: -5 or 3
13
+ */
14
+ getTimezoneOffset() {
15
+ const dtDate = new Date();
16
+ return -dtDate.getTimezoneOffset() / 60;
17
+ }
18
+ /**
19
+ * Checks if touch events are supported in the current browser.
20
+ *
21
+ * @returns {boolean} True if touch events are supported, false otherwise.
22
+ *
23
+ * @example
24
+ * const touchSupported = getTouchSupport();
25
+ * console.log(touchSupported); // Output: true or false
26
+ */
27
+ getTouchSupport() {
28
+ try {
29
+ if (typeof navigator !== 'undefined' && typeof navigator.maxTouchPoints === 'number'
30
+ && navigator.maxTouchPoints > 0) {
31
+ return true;
32
+ }
33
+ if (typeof window !== 'undefined' && 'ontouchstart' in window) {
34
+ return true;
35
+ }
36
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'function'
37
+ && window.matchMedia('(any-pointer: coarse)').matches) {
38
+ return true;
39
+ }
40
+ return typeof document !== 'undefined' && !!document.createEvent('TouchEvent');
41
+ }
42
+ catch (_a) {
43
+ return false;
44
+ }
45
+ }
46
+ /**
47
+ * Gets network timing data for the current page load.
48
+ *
49
+ * @returns {NetworkTimes} An object containing network timing data.
50
+ *
51
+ * @example
52
+ * const networkTimes = getNetworkTime();
53
+ * console.log(networkTimes);
54
+ * // Output:
55
+ * // {
56
+ * // networkTime: 1.234,
57
+ * // dnsLookupTime: 0.123,
58
+ * // tcpConnectionTime: 0.234,
59
+ * // serverResponseTime: 0.345,
60
+ * // pageDownloadTime: 0.456,
61
+ * // browserTime: 1.567
62
+ * // }
63
+ */
64
+ getNetworkTime() {
65
+ try {
66
+ const navigationTiming = performance.getEntriesByType('navigation')[0];
67
+ const networkTime = navigationTiming.responseEnd - navigationTiming.fetchStart;
68
+ const dnsLookupTime = navigationTiming.domainLookupEnd - navigationTiming.domainLookupStart;
69
+ const tcpConnectionTime = navigationTiming.connectEnd - navigationTiming.connectStart;
70
+ const serverResponseTime = navigationTiming.responseStart - navigationTiming.requestStart;
71
+ const pageDownloadTime = navigationTiming.responseEnd - navigationTiming.responseStart;
72
+ const browserTime = navigationTiming.loadEventEnd - navigationTiming.fetchStart;
73
+ return {
74
+ networkTime: Number((networkTime / 1000).toFixed(3)),
75
+ dnsLookupTime: Number((dnsLookupTime / 1000).toFixed(3)),
76
+ tcpConnectionTime: Number((tcpConnectionTime / 1000).toFixed(3)),
77
+ serverResponseTime: Number((serverResponseTime / 1000).toFixed(3)),
78
+ pageDownloadTime: Number((pageDownloadTime / 1000).toFixed(3)),
79
+ browserTime: Number((browserTime / 1000).toFixed(3))
80
+ };
81
+ }
82
+ catch (err) {
83
+ console.error("Failed to retrieve network timing data:", err);
84
+ return {
85
+ networkTime: 0,
86
+ dnsLookupTime: 0,
87
+ tcpConnectionTime: 0,
88
+ serverResponseTime: 0,
89
+ pageDownloadTime: 0,
90
+ browserTime: 0
91
+ };
92
+ }
93
+ }
94
+ }
95
+ exports.Utils = Utils;
@@ -0,0 +1,10 @@
1
+ import { DeviceIdentifierConfig } from "../protocols/services/device-identifier";
2
+ import { HttpClient, HttpMethod } from "../protocols/http/http-client";
3
+ import { DeviceIntelligenceHTTPRequest } from "../protocols/services/device-intelligence";
4
+ export declare class DeviceIntelligenceService implements DeviceIntelligenceHTTPRequest {
5
+ private httpClient;
6
+ private baseUrl;
7
+ private token;
8
+ constructor(httpClient: HttpClient, baseUrl: string, token: string);
9
+ performRequest(patch: string, method: HttpMethod, config?: DeviceIdentifierConfig, data?: any): Promise<any>;
10
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DeviceIntelligenceService = void 0;
13
+ const crosscutting_1 = require("../models/crosscutting");
14
+ class DeviceIntelligenceService {
15
+ constructor(httpClient, baseUrl, token) {
16
+ this.httpClient = httpClient;
17
+ this.baseUrl = baseUrl || '';
18
+ this.token = token || '';
19
+ }
20
+ performRequest(patch_1, method_1) {
21
+ return __awaiter(this, arguments, void 0, function* (patch, method, config = {}, data) {
22
+ var _a, _b;
23
+ try {
24
+ const { token = '', env = 'staging' } = config;
25
+ const missingTransactionId = 'transactionId' in (data !== null && data !== void 0 ? data : {}) && !data.transactionId;
26
+ if (missingTransactionId || (!config.token && !this.token)) {
27
+ throw new Error('TransactionId or Authentication Token missing');
28
+ }
29
+ const isProductionEnv = env.toLowerCase() === 'production';
30
+ if (isProductionEnv) {
31
+ this.baseUrl = crosscutting_1.PURESCORE_INTELLIGENCE_BASE_URL.production;
32
+ }
33
+ const response = yield this.httpClient.request({
34
+ url: `${this.baseUrl}${patch}`,
35
+ method,
36
+ body: data,
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ Authorization: `Bearer ${token || this.token}`
40
+ },
41
+ });
42
+ if (!response.body) {
43
+ throw new Error(`Empty response with status: ${response.statusCode}`);
44
+ }
45
+ return { statusCode: response.statusCode, body: response.body };
46
+ }
47
+ catch (error) {
48
+ const errorResponse = {
49
+ statusCode: (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status,
50
+ message: error.message,
51
+ body: (_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.data,
52
+ };
53
+ console.error('Error performing Device Intelligence request:', errorResponse);
54
+ return errorResponse;
55
+ }
56
+ });
57
+ }
58
+ }
59
+ exports.DeviceIntelligenceService = DeviceIntelligenceService;
@@ -0,0 +1,37 @@
1
+ import { ScheduleRecord } from '../../protocols/services/single-script-injection/auto-init';
2
+ import { ScheduleStore } from './schedule-store';
3
+ /**
4
+ * How often the scheduler asks "is a checkpoint due yet?".
5
+ *
6
+ * Polling rather than a `setTimeout` per checkpoint because the schedule is
7
+ * shared state that another page load may have advanced: a timer armed on this
8
+ * page would not know that a checkpoint had already been delivered elsewhere.
9
+ */
10
+ export declare const TICK_MS = 5000;
11
+ type CheckpointHandler = (n: number, record: ScheduleRecord) => Promise<void>;
12
+ /**
13
+ * Drives the Device-Intelligence calls off the schedule record.
14
+ *
15
+ * Every tick it resolves the next outstanding checkpoint and fires it if its due
16
+ * time has passed; otherwise it keeps waiting. Once every checkpoint of the
17
+ * transaction has been delivered the scheduler stops itself, capping the
18
+ * transaction at `CHECKPOINT_COUNT`.
19
+ */
20
+ export declare class CheckpointScheduler {
21
+ private readonly store;
22
+ private readonly onCheckpoint;
23
+ private timer;
24
+ private inFlight;
25
+ constructor(store: ScheduleStore, onCheckpoint: CheckpointHandler);
26
+ /**
27
+ * Resumes (or starts) the schedule and begins polling. The first tick runs
28
+ * immediately so a checkpoint already overdue is not delayed another `TICK_MS`.
29
+ */
30
+ start(): ScheduleRecord;
31
+ stop(): void;
32
+ isRunning(): boolean;
33
+ /** Fires a tick without letting its promise escape as an unhandled rejection. */
34
+ private runTick;
35
+ private tick;
36
+ }
37
+ export {};
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CheckpointScheduler = exports.TICK_MS = void 0;
13
+ /**
14
+ * How often the scheduler asks "is a checkpoint due yet?".
15
+ *
16
+ * Polling rather than a `setTimeout` per checkpoint because the schedule is
17
+ * shared state that another page load may have advanced: a timer armed on this
18
+ * page would not know that a checkpoint had already been delivered elsewhere.
19
+ */
20
+ exports.TICK_MS = 5000;
21
+ /**
22
+ * Drives the Device-Intelligence calls off the schedule record.
23
+ *
24
+ * Every tick it resolves the next outstanding checkpoint and fires it if its due
25
+ * time has passed; otherwise it keeps waiting. Once every checkpoint of the
26
+ * transaction has been delivered the scheduler stops itself, capping the
27
+ * transaction at `CHECKPOINT_COUNT`.
28
+ */
29
+ class CheckpointScheduler {
30
+ constructor(store, onCheckpoint) {
31
+ this.store = store;
32
+ this.onCheckpoint = onCheckpoint;
33
+ this.timer = null;
34
+ this.inFlight = false;
35
+ }
36
+ /**
37
+ * Resumes (or starts) the schedule and begins polling. The first tick runs
38
+ * immediately so a checkpoint already overdue is not delayed another `TICK_MS`.
39
+ */
40
+ start() {
41
+ this.stop();
42
+ const record = this.store.resumeOrCreate();
43
+ this.runTick();
44
+ this.timer = setInterval(() => this.runTick(), exports.TICK_MS);
45
+ return record;
46
+ }
47
+ stop() {
48
+ if (this.timer !== null) {
49
+ clearInterval(this.timer);
50
+ this.timer = null;
51
+ }
52
+ }
53
+ isRunning() {
54
+ return this.timer !== null;
55
+ }
56
+ /** Fires a tick without letting its promise escape as an unhandled rejection. */
57
+ runTick() {
58
+ this.tick().catch(error => console.error('Error in Device-Intelligence checkpoint tick:', error));
59
+ }
60
+ tick() {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ // A call already in flight owns the next checkpoint; a second tick must not
63
+ // fire it again while the request is still resolving.
64
+ if (this.inFlight)
65
+ return;
66
+ const record = this.store.resumeOrCreate();
67
+ const next = record.checkpoints.find(c => c.n > record.sent);
68
+ if (!next) {
69
+ // Nothing left, and nothing can appear: the LOI checkpoints are added
70
+ // before the schedule starts.
71
+ this.stop();
72
+ return;
73
+ }
74
+ if (new Date().getTime() < next.dueAt)
75
+ return;
76
+ this.inFlight = true;
77
+ try {
78
+ yield this.onCheckpoint(next.n, record);
79
+ // Persisted only after the call resolves, so a failed request leaves the
80
+ // checkpoint outstanding and the next tick retries it.
81
+ this.store.markSent(next.n);
82
+ }
83
+ catch (error) {
84
+ // Swallowed on purpose: a rejected checkpoint must not surface as an
85
+ // unhandled rejection on the buyer's survey page.
86
+ console.error(`Error delivering Device-Intelligence checkpoint ${next.n}:`, error);
87
+ }
88
+ finally {
89
+ this.inFlight = false;
90
+ }
91
+ });
92
+ }
93
+ }
94
+ exports.CheckpointScheduler = CheckpointScheduler;
@@ -0,0 +1,3 @@
1
+ export * from './checkpoint-scheduler';
2
+ export * from './response-delivery';
3
+ export * from './schedule-store';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./checkpoint-scheduler"), exports);
18
+ __exportStar(require("./response-delivery"), exports);
19
+ __exportStar(require("./schedule-store"), exports);
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Name of the custom event carrying the Device-Intelligence response.
3
+ *
4
+ * The `ps:` prefix namespaces it so it cannot collide with an event the buyer's
5
+ * own survey platform dispatches.
6
+ */
7
+ export declare const PS_RESULT_EVENT = "ps:purescore:result";
8
+ /**
9
+ * Global the last response is also exposed on, for buyers who prefer reading it
10
+ * directly rather than listening.
11
+ */
12
+ export declare const PS_GLOBAL = "psPureScore";
13
+ /**
14
+ * Hands the Device-Intelligence response back to the buyer.
15
+ *
16
+ * Once the Device-Identifier owns the call it also owns the response, so it has
17
+ * to push it out. Three channels carry the same object and the buyer picks
18
+ * whichever suits their platform:
19
+ *
20
+ * - a `ps:purescore:result` CustomEvent on `window` (any number of listeners);
21
+ * - a global function named on the tag via `data-callback`;
22
+ * - `window.psPureScore.lastResult`, for code that would rather read than listen.
23
+ */
24
+ export declare class ResponseDeliveryService {
25
+ private readonly callbackName?;
26
+ constructor(callbackName?: string | undefined);
27
+ /**
28
+ * Delivers a response that has just arrived, on every channel.
29
+ */
30
+ deliver(response: Record<string, any>): void;
31
+ /**
32
+ * Re-emits a response that was produced on an earlier page (the replay buffer).
33
+ *
34
+ * Because the checkpoints now fire on the schedule rather than at a point the
35
+ * buyer chose, the call and the buyer's code are no longer guaranteed to be on
36
+ * the same page. The global is published synchronously — it is a read, so it
37
+ * has to be there before the buyer's code runs — while the event and the
38
+ * callback are deferred until the document has finished parsing, giving a
39
+ * listener or function declared further down the page a chance to exist.
40
+ */
41
+ replay(response: Record<string, any>): void;
42
+ private publishGlobal;
43
+ private dispatch;
44
+ private invokeCallback;
45
+ private buildEvent;
46
+ private whenDocumentReady;
47
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseDeliveryService = exports.PS_GLOBAL = exports.PS_RESULT_EVENT = void 0;
4
+ const validation_1 = require("../../../validation");
5
+ /**
6
+ * Name of the custom event carrying the Device-Intelligence response.
7
+ *
8
+ * The `ps:` prefix namespaces it so it cannot collide with an event the buyer's
9
+ * own survey platform dispatches.
10
+ */
11
+ exports.PS_RESULT_EVENT = 'ps:purescore:result';
12
+ /**
13
+ * Global the last response is also exposed on, for buyers who prefer reading it
14
+ * directly rather than listening.
15
+ */
16
+ exports.PS_GLOBAL = 'psPureScore';
17
+ /**
18
+ * Hands the Device-Intelligence response back to the buyer.
19
+ *
20
+ * Once the Device-Identifier owns the call it also owns the response, so it has
21
+ * to push it out. Three channels carry the same object and the buyer picks
22
+ * whichever suits their platform:
23
+ *
24
+ * - a `ps:purescore:result` CustomEvent on `window` (any number of listeners);
25
+ * - a global function named on the tag via `data-callback`;
26
+ * - `window.psPureScore.lastResult`, for code that would rather read than listen.
27
+ */
28
+ class ResponseDeliveryService {
29
+ constructor(callbackName) {
30
+ this.callbackName = callbackName;
31
+ }
32
+ /**
33
+ * Delivers a response that has just arrived, on every channel.
34
+ */
35
+ deliver(response) {
36
+ if (typeof window === 'undefined')
37
+ return;
38
+ this.publishGlobal(response);
39
+ this.dispatch(response);
40
+ this.invokeCallback(response);
41
+ }
42
+ /**
43
+ * Re-emits a response that was produced on an earlier page (the replay buffer).
44
+ *
45
+ * Because the checkpoints now fire on the schedule rather than at a point the
46
+ * buyer chose, the call and the buyer's code are no longer guaranteed to be on
47
+ * the same page. The global is published synchronously — it is a read, so it
48
+ * has to be there before the buyer's code runs — while the event and the
49
+ * callback are deferred until the document has finished parsing, giving a
50
+ * listener or function declared further down the page a chance to exist.
51
+ */
52
+ replay(response) {
53
+ if (typeof window === 'undefined')
54
+ return;
55
+ this.publishGlobal(response);
56
+ this.whenDocumentReady(() => {
57
+ this.dispatch(response);
58
+ this.invokeCallback(response);
59
+ });
60
+ }
61
+ publishGlobal(response) {
62
+ var _a;
63
+ try {
64
+ const globals = (_a = window[exports.PS_GLOBAL]) !== null && _a !== void 0 ? _a : {};
65
+ globals.lastResult = response;
66
+ window[exports.PS_GLOBAL] = globals;
67
+ }
68
+ catch ( /* never let delivery bookkeeping break the survey page */_b) { /* never let delivery bookkeeping break the survey page */ }
69
+ }
70
+ dispatch(response) {
71
+ try {
72
+ window.dispatchEvent(this.buildEvent(response));
73
+ }
74
+ catch (error) {
75
+ console.error('Error dispatching PureScore result event:', error);
76
+ }
77
+ }
78
+ invokeCallback(response) {
79
+ if (!this.callbackName)
80
+ return;
81
+ const error = new validation_1.GlobalFunction(this.callbackName, 'data-callback').validate();
82
+ if (error) {
83
+ console.error(`PureScore callback: ${error.message}`);
84
+ return;
85
+ }
86
+ const fn = window[this.callbackName];
87
+ try {
88
+ fn(response);
89
+ }
90
+ catch (error) {
91
+ console.error(`Error in PureScore callback "${this.callbackName}":`, error);
92
+ }
93
+ }
94
+ buildEvent(response) {
95
+ try {
96
+ return new CustomEvent(exports.PS_RESULT_EVENT, { detail: response });
97
+ }
98
+ catch (_a) {
99
+ // Older browsers where CustomEvent is not constructible.
100
+ const event = document.createEvent('CustomEvent');
101
+ event.initCustomEvent(exports.PS_RESULT_EVENT, false, false, response);
102
+ return event;
103
+ }
104
+ }
105
+ whenDocumentReady(run) {
106
+ if (typeof document === 'undefined' || document.readyState !== 'loading') {
107
+ // Already parsed: still defer by a macrotask so an inline listener placed
108
+ // right after the tag is registered before the replay fires.
109
+ setTimeout(run, 0);
110
+ return;
111
+ }
112
+ document.addEventListener('DOMContentLoaded', () => run(), { once: true });
113
+ }
114
+ }
115
+ exports.ResponseDeliveryService = ResponseDeliveryService;