@qoretechnologies/reqraft 0.10.56 → 0.10.57-pr.127.g0a792ea

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 (157) hide show
  1. package/.claude/CLAUDE.md +1 -0
  2. package/README.md +20 -0
  3. package/design/TRACKING.md +290 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +5 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/tracking/browser/attach.d.ts +8 -0
  9. package/dist/tracking/browser/attach.d.ts.map +1 -0
  10. package/dist/tracking/browser/attach.js +182 -0
  11. package/dist/tracking/browser/attach.js.map +1 -0
  12. package/dist/tracking/browser/env.d.ts +14 -0
  13. package/dist/tracking/browser/env.d.ts.map +1 -0
  14. package/dist/tracking/browser/env.js +150 -0
  15. package/dist/tracking/browser/env.js.map +1 -0
  16. package/dist/tracking/core/consent.d.ts +21 -0
  17. package/dist/tracking/core/consent.d.ts.map +1 -0
  18. package/dist/tracking/core/consent.js +39 -0
  19. package/dist/tracking/core/consent.js.map +1 -0
  20. package/dist/tracking/core/engagement.d.ts +20 -0
  21. package/dist/tracking/core/engagement.d.ts.map +1 -0
  22. package/dist/tracking/core/engagement.js +52 -0
  23. package/dist/tracking/core/engagement.js.map +1 -0
  24. package/dist/tracking/core/experiments.d.ts +109 -0
  25. package/dist/tracking/core/experiments.d.ts.map +1 -0
  26. package/dist/tracking/core/experiments.js +294 -0
  27. package/dist/tracking/core/experiments.js.map +1 -0
  28. package/dist/tracking/core/hash.d.ts +16 -0
  29. package/dist/tracking/core/hash.d.ts.map +1 -0
  30. package/dist/tracking/core/hash.js +31 -0
  31. package/dist/tracking/core/hash.js.map +1 -0
  32. package/dist/tracking/core/ids.d.ts +6 -0
  33. package/dist/tracking/core/ids.d.ts.map +1 -0
  34. package/dist/tracking/core/ids.js +31 -0
  35. package/dist/tracking/core/ids.js.map +1 -0
  36. package/dist/tracking/core/observable.d.ts +12 -0
  37. package/dist/tracking/core/observable.d.ts.map +1 -0
  38. package/dist/tracking/core/observable.js +32 -0
  39. package/dist/tracking/core/observable.js.map +1 -0
  40. package/dist/tracking/core/queue.d.ts +47 -0
  41. package/dist/tracking/core/queue.d.ts.map +1 -0
  42. package/dist/tracking/core/queue.js +205 -0
  43. package/dist/tracking/core/queue.js.map +1 -0
  44. package/dist/tracking/core/sections.d.ts +54 -0
  45. package/dist/tracking/core/sections.d.ts.map +1 -0
  46. package/dist/tracking/core/sections.js +156 -0
  47. package/dist/tracking/core/sections.js.map +1 -0
  48. package/dist/tracking/core/storage.d.ts +15 -0
  49. package/dist/tracking/core/storage.d.ts.map +1 -0
  50. package/dist/tracking/core/storage.js +72 -0
  51. package/dist/tracking/core/storage.js.map +1 -0
  52. package/dist/tracking/core/tracker.d.ts +122 -0
  53. package/dist/tracking/core/tracker.d.ts.map +1 -0
  54. package/dist/tracking/core/tracker.js +390 -0
  55. package/dist/tracking/core/tracker.js.map +1 -0
  56. package/dist/tracking/core/types.d.ts +130 -0
  57. package/dist/tracking/core/types.d.ts.map +1 -0
  58. package/dist/tracking/core/types.js +69 -0
  59. package/dist/tracking/core/types.js.map +1 -0
  60. package/dist/tracking/core/utm.d.ts +6 -0
  61. package/dist/tracking/core/utm.d.ts.map +1 -0
  62. package/dist/tracking/core/utm.js +30 -0
  63. package/dist/tracking/core/utm.js.map +1 -0
  64. package/dist/tracking/index.d.ts +46 -0
  65. package/dist/tracking/index.d.ts.map +1 -0
  66. package/dist/tracking/index.js +91 -0
  67. package/dist/tracking/index.js.map +1 -0
  68. package/dist/tracking/markup.d.ts +12 -0
  69. package/dist/tracking/markup.d.ts.map +1 -0
  70. package/dist/tracking/markup.js +19 -0
  71. package/dist/tracking/markup.js.map +1 -0
  72. package/dist/tracking/react/Experiment.d.ts +23 -0
  73. package/dist/tracking/react/Experiment.d.ts.map +1 -0
  74. package/dist/tracking/react/Experiment.js +28 -0
  75. package/dist/tracking/react/Experiment.js.map +1 -0
  76. package/dist/tracking/react/TrackingProvider.d.ts +26 -0
  77. package/dist/tracking/react/TrackingProvider.d.ts.map +1 -0
  78. package/dist/tracking/react/TrackingProvider.js +45 -0
  79. package/dist/tracking/react/TrackingProvider.js.map +1 -0
  80. package/dist/tracking/react/hooks.d.ts +39 -0
  81. package/dist/tracking/react/hooks.d.ts.map +1 -0
  82. package/dist/tracking/react/hooks.js +96 -0
  83. package/dist/tracking/react/hooks.js.map +1 -0
  84. package/dist/tracking/react/index.d.ts +7 -0
  85. package/dist/tracking/react/index.d.ts.map +1 -0
  86. package/dist/tracking/react/index.js +17 -0
  87. package/dist/tracking/react/index.js.map +1 -0
  88. package/dist/tracking/testing.d.ts +40 -0
  89. package/dist/tracking/testing.d.ts.map +1 -0
  90. package/dist/tracking/testing.js +140 -0
  91. package/dist/tracking/testing.js.map +1 -0
  92. package/dist/tracking/ui/ExperimentCard.d.ts +55 -0
  93. package/dist/tracking/ui/ExperimentCard.d.ts.map +1 -0
  94. package/dist/tracking/ui/ExperimentCard.js +340 -0
  95. package/dist/tracking/ui/ExperimentCard.js.map +1 -0
  96. package/dist/tracking/ui/ExperimentsOverlay.d.ts +59 -0
  97. package/dist/tracking/ui/ExperimentsOverlay.d.ts.map +1 -0
  98. package/dist/tracking/ui/ExperimentsOverlay.js +359 -0
  99. package/dist/tracking/ui/ExperimentsOverlay.js.map +1 -0
  100. package/dist/tracking/ui/anchor.d.ts +107 -0
  101. package/dist/tracking/ui/anchor.d.ts.map +1 -0
  102. package/dist/tracking/ui/anchor.js +108 -0
  103. package/dist/tracking/ui/anchor.js.map +1 -0
  104. package/dist/tracking/ui/card.d.ts +121 -0
  105. package/dist/tracking/ui/card.d.ts.map +1 -0
  106. package/dist/tracking/ui/card.js +417 -0
  107. package/dist/tracking/ui/card.js.map +1 -0
  108. package/dist/tracking/ui/client.d.ts +42 -0
  109. package/dist/tracking/ui/client.d.ts.map +1 -0
  110. package/dist/tracking/ui/client.js +123 -0
  111. package/dist/tracking/ui/client.js.map +1 -0
  112. package/dist/tracking/ui/index.d.ts +20 -0
  113. package/dist/tracking/ui/index.d.ts.map +1 -0
  114. package/dist/tracking/ui/index.js +60 -0
  115. package/dist/tracking/ui/index.js.map +1 -0
  116. package/dist/tracking/ui/types.d.ts +120 -0
  117. package/dist/tracking/ui/types.d.ts.map +1 -0
  118. package/dist/tracking/ui/types.js +8 -0
  119. package/dist/tracking/ui/types.js.map +1 -0
  120. package/dist/tracking/ui/useExperimentsAdmin.d.ts +31 -0
  121. package/dist/tracking/ui/useExperimentsAdmin.d.ts.map +1 -0
  122. package/dist/tracking/ui/useExperimentsAdmin.js +136 -0
  123. package/dist/tracking/ui/useExperimentsAdmin.js.map +1 -0
  124. package/package.json +1 -1
  125. package/src/index.tsx +5 -0
  126. package/src/stories/tracking.tsx +206 -0
  127. package/src/tracking/browser/attach.ts +186 -0
  128. package/src/tracking/browser/env.ts +78 -0
  129. package/src/tracking/core/consent.ts +37 -0
  130. package/src/tracking/core/engagement.ts +47 -0
  131. package/src/tracking/core/experiments.ts +258 -0
  132. package/src/tracking/core/hash.ts +26 -0
  133. package/src/tracking/core/ids.ts +25 -0
  134. package/src/tracking/core/observable.ts +23 -0
  135. package/src/tracking/core/queue.ts +131 -0
  136. package/src/tracking/core/sections.ts +166 -0
  137. package/src/tracking/core/storage.ts +69 -0
  138. package/src/tracking/core/tracker.ts +417 -0
  139. package/src/tracking/core/types.ts +162 -0
  140. package/src/tracking/core/utm.ts +23 -0
  141. package/src/tracking/index.ts +72 -0
  142. package/src/tracking/markup.ts +17 -0
  143. package/src/tracking/react/Experiment.tsx +44 -0
  144. package/src/tracking/react/TrackingProvider.tsx +56 -0
  145. package/src/tracking/react/hooks.ts +106 -0
  146. package/src/tracking/react/index.ts +13 -0
  147. package/src/tracking/testing.ts +108 -0
  148. package/src/tracking/ui/ExperimentCard.stories.tsx +290 -0
  149. package/src/tracking/ui/ExperimentCard.tsx +581 -0
  150. package/src/tracking/ui/ExperimentsOverlay.stories.tsx +155 -0
  151. package/src/tracking/ui/ExperimentsOverlay.tsx +437 -0
  152. package/src/tracking/ui/anchor.ts +180 -0
  153. package/src/tracking/ui/card.ts +464 -0
  154. package/src/tracking/ui/client.ts +117 -0
  155. package/src/tracking/ui/index.ts +77 -0
  156. package/src/tracking/ui/types.ts +110 -0
  157. package/src/tracking/ui/useExperimentsAdmin.ts +103 -0
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
50
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
51
+ if (ar || !(i in from)) {
52
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
53
+ ar[i] = from[i];
54
+ }
55
+ }
56
+ return to.concat(ar || Array.prototype.slice.call(from));
57
+ };
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.EventQueue = exports.MAX_BACKLOG = exports.MAX_BATCH_BYTES = exports.MAX_EVENTS_PER_BATCH = void 0;
60
+ /** Collector limits (§4): at most 100 events and 64 KB per batch. We stay under both. */
61
+ exports.MAX_EVENTS_PER_BATCH = 100;
62
+ exports.MAX_BATCH_BYTES = 60 * 1024;
63
+ /** Events kept while the collector is unreachable; the oldest are dropped past this. */
64
+ exports.MAX_BACKLOG = 500;
65
+ var size = function (s) { return (typeof TextEncoder !== 'undefined' ? new TextEncoder().encode(s).length : s.length * 2); };
66
+ /**
67
+ * Batches events: sends every `flushIntervalMs`, as soon as `maxQueued` are waiting,
68
+ * and immediately (as a beacon) when the page is going away.
69
+ */
70
+ var EventQueue = /** @class */ (function () {
71
+ function EventQueue(o) {
72
+ this.o = o;
73
+ this.events = [];
74
+ this.timer = null;
75
+ this.sending = false;
76
+ }
77
+ Object.defineProperty(EventQueue.prototype, "length", {
78
+ get: function () {
79
+ return this.events.length;
80
+ },
81
+ enumerable: false,
82
+ configurable: true
83
+ });
84
+ EventQueue.prototype.push = function (event) {
85
+ this.events.push(event);
86
+ if (this.events.length > exports.MAX_BACKLOG)
87
+ this.events.splice(0, this.events.length - exports.MAX_BACKLOG);
88
+ if (this.events.length >= this.o.maxQueued)
89
+ void this.flush('fetch');
90
+ else
91
+ this.schedule();
92
+ };
93
+ /** Forget everything unsent (consent withdrawn). */
94
+ EventQueue.prototype.clear = function () {
95
+ this.events = [];
96
+ if (this.timer != null)
97
+ this.o.clearTimer(this.timer);
98
+ this.timer = null;
99
+ };
100
+ EventQueue.prototype.schedule = function () {
101
+ var _this = this;
102
+ if (this.timer != null)
103
+ return;
104
+ this.timer = this.o.setTimer(function () {
105
+ _this.timer = null;
106
+ void _this.flush('fetch');
107
+ }, this.o.flushIntervalMs);
108
+ };
109
+ /** Splits `events` into batches that fit the collector's limits. */
110
+ EventQueue.chunk = function (events, envelope, sentAt) {
111
+ var batches = [];
112
+ var current = [];
113
+ var bodyOf = function (evts) { return JSON.stringify(__assign(__assign({}, envelope), { sent_at: sentAt, events: evts })); };
114
+ for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
115
+ var e = events_1[_i];
116
+ var next = __spreadArray(__spreadArray([], current, true), [e], false);
117
+ if (current.length && (next.length > exports.MAX_EVENTS_PER_BATCH || size(bodyOf(next)) > exports.MAX_BATCH_BYTES)) {
118
+ batches.push(__assign(__assign({}, envelope), { sent_at: sentAt, events: current }));
119
+ current = [e];
120
+ }
121
+ else {
122
+ current = next;
123
+ }
124
+ }
125
+ if (current.length)
126
+ batches.push(__assign(__assign({}, envelope), { sent_at: sentAt, events: current }));
127
+ // A single event larger than the limit is dropped rather than rejected forever.
128
+ return batches.filter(function (b) { return b.events.length > 1 || size(JSON.stringify(b)) <= exports.MAX_BATCH_BYTES; });
129
+ };
130
+ EventQueue.prototype.flush = function () {
131
+ return __awaiter(this, arguments, void 0, function (mode) {
132
+ var envelope, pending, batches, failed, _i, batches_1, batch, ok, _a;
133
+ var _b, _c;
134
+ if (mode === void 0) { mode = 'fetch'; }
135
+ return __generator(this, function (_d) {
136
+ switch (_d.label) {
137
+ case 0:
138
+ if (this.timer != null) {
139
+ this.o.clearTimer(this.timer);
140
+ this.timer = null;
141
+ }
142
+ if (!this.events.length)
143
+ return [2 /*return*/];
144
+ // A fetch in flight owns the queue; a beacon (page going away) sends what is left now.
145
+ if (this.sending && mode === 'fetch') {
146
+ this.schedule();
147
+ return [2 /*return*/];
148
+ }
149
+ envelope = this.o.envelope();
150
+ if (!envelope) {
151
+ this.events = [];
152
+ return [2 /*return*/];
153
+ }
154
+ pending = this.events;
155
+ this.events = [];
156
+ batches = EventQueue.chunk(pending, envelope, new Date(this.o.now()).toISOString());
157
+ this.sending = true;
158
+ failed = [];
159
+ _d.label = 1;
160
+ case 1:
161
+ _d.trys.push([1, , 9, 10]);
162
+ _i = 0, batches_1 = batches;
163
+ _d.label = 2;
164
+ case 2:
165
+ if (!(_i < batches_1.length)) return [3 /*break*/, 8];
166
+ batch = batches_1[_i];
167
+ (_c = (_b = this.o).debug) === null || _c === void 0 ? void 0 : _c.call(_b, batch);
168
+ ok = false;
169
+ _d.label = 3;
170
+ case 3:
171
+ _d.trys.push([3, 5, , 6]);
172
+ return [4 /*yield*/, this.o.transport.send(JSON.stringify(batch), mode)];
173
+ case 4:
174
+ ok = _d.sent();
175
+ return [3 /*break*/, 6];
176
+ case 5:
177
+ _a = _d.sent();
178
+ ok = false;
179
+ return [3 /*break*/, 6];
180
+ case 6:
181
+ if (!ok)
182
+ failed.push.apply(failed, batch.events);
183
+ _d.label = 7;
184
+ case 7:
185
+ _i++;
186
+ return [3 /*break*/, 2];
187
+ case 8: return [3 /*break*/, 10];
188
+ case 9:
189
+ this.sending = false;
190
+ return [7 /*endfinally*/];
191
+ case 10:
192
+ if (failed.length) {
193
+ // Kept for the next flush, which the next event schedules (no retry loop against a
194
+ // collector that is down); event ids make a double delivery harmless.
195
+ this.events = __spreadArray(__spreadArray([], failed, true), this.events, true).slice(-exports.MAX_BACKLOG);
196
+ }
197
+ return [2 /*return*/];
198
+ }
199
+ });
200
+ });
201
+ };
202
+ return EventQueue;
203
+ }());
204
+ exports.EventQueue = EventQueue;
205
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../../src/tracking/core/queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Attention per section, as plain arithmetic over time (no DOM): the browser layer
3
+ * feeds it visibility changes from an IntersectionObserver and tab visibility, and
4
+ * asks it for the page summary.
5
+ *
6
+ * - `visible_ms`: time any part of the section was on screen while the tab was visible.
7
+ * - `seen`: the section was at least 50% visible for at least 1 s in one stretch — the
8
+ * attention definition the contract uses everywhere (§4). "50% visible" is 50% of
9
+ * the section *or* 50% of the viewport covered by it: a section taller than two
10
+ * screens can never show half of itself, and it would otherwise never count.
11
+ * - `first_seen_ms`: when that stretch began, measured from the start of the page view.
12
+ */
13
+ export declare const SEEN_RATIO = 0.5;
14
+ export declare const SEEN_MS = 1000;
15
+ export interface ISectionSummary {
16
+ id: string;
17
+ visible_ms: number;
18
+ seen: boolean;
19
+ first_seen_ms: number | null;
20
+ }
21
+ export declare class SectionClock {
22
+ private start;
23
+ private sections;
24
+ private tabVisible;
25
+ private seenListeners;
26
+ constructor(start: number);
27
+ /** A new page view: everything starts from zero at `now`. */
28
+ reset(now: number): void;
29
+ onSeen(listener: (id: string) => void): () => any;
30
+ isSeen: (id: string) => boolean;
31
+ private ensure;
32
+ /** Registers a section so it shows up in the summary even if it is never on screen. */
33
+ register(id: string, report?: boolean): void;
34
+ /** The section's effective visibility changed. */
35
+ update(id: string, ratio: number, now: number): void;
36
+ /** The tab became visible or hidden: time stops counting while hidden. */
37
+ setTabVisible(visible: boolean, now: number): void;
38
+ /** Promotes stretches that have lasted long enough to `seen`. Call ~every second. */
39
+ tick(now: number): void;
40
+ /** Closes the open stretches up to `now` (visible time, seen). */
41
+ private settle;
42
+ private tickOne;
43
+ /** Opens stretches for the current state. */
44
+ private arm;
45
+ /** The section most on screen now (ties: the lower one on the page, i.e. the later registered). */
46
+ current(): string | null;
47
+ summary(now: number): ISectionSummary[];
48
+ }
49
+ /**
50
+ * Effective visibility from an IntersectionObserver entry: the larger of the share
51
+ * of the section on screen and the share of the viewport the section fills.
52
+ */
53
+ export declare const effectiveRatio: (intersectionRatio: number, intersectionHeight: number, viewportHeight: number) => number;
54
+ //# sourceMappingURL=sections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../../../src/tracking/core/sections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,UAAU,MAAM,CAAC;AAC9B,eAAO,MAAM,OAAO,OAAO,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAeD,qBAAa,YAAY;IAKX,OAAO,CAAC,KAAK;IAJzB,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,aAAa,CAAmC;gBAEpC,KAAK,EAAE,MAAM;IAEjC,6DAA6D;IAC7D,KAAK,CAAC,GAAG,EAAE,MAAM;IAOjB,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI;IAKrC,MAAM,OAAQ,MAAM,aAA2C;IAE/D,OAAO,CAAC,MAAM;IASd,uFAAuF;IACvF,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,UAAO;IAIlC,kDAAkD;IAClD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAsB7C,0EAA0E;IAC1E,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM;IAO3C,qFAAqF;IACrF,IAAI,CAAC,GAAG,EAAE,MAAM;IAIhB,kEAAkE;IAClE,OAAO,CAAC,MAAM;IAOd,OAAO,CAAC,OAAO;IAQf,6CAA6C;IAC7C,OAAO,CAAC,GAAG;IAMX,mGAAmG;IACnG,OAAO,IAAI,MAAM,GAAG,IAAI;IAQxB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,EAAE;CAWxC;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,sBACN,MAAM,sBACL,MAAM,kBACV,MAAM,KACrB,MAIF,CAAC"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * Attention per section, as plain arithmetic over time (no DOM): the browser layer
4
+ * feeds it visibility changes from an IntersectionObserver and tab visibility, and
5
+ * asks it for the page summary.
6
+ *
7
+ * - `visible_ms`: time any part of the section was on screen while the tab was visible.
8
+ * - `seen`: the section was at least 50% visible for at least 1 s in one stretch — the
9
+ * attention definition the contract uses everywhere (§4). "50% visible" is 50% of
10
+ * the section *or* 50% of the viewport covered by it: a section taller than two
11
+ * screens can never show half of itself, and it would otherwise never count.
12
+ * - `first_seen_ms`: when that stretch began, measured from the start of the page view.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.effectiveRatio = exports.SectionClock = exports.SEEN_MS = exports.SEEN_RATIO = void 0;
16
+ exports.SEEN_RATIO = 0.5;
17
+ exports.SEEN_MS = 1000;
18
+ var SectionClock = /** @class */ (function () {
19
+ function SectionClock(start) {
20
+ var _this = this;
21
+ this.start = start;
22
+ this.sections = new Map();
23
+ this.tabVisible = true;
24
+ this.seenListeners = new Set();
25
+ this.isSeen = function (id) { var _a; return ((_a = _this.sections.get(id)) === null || _a === void 0 ? void 0 : _a.seenAt) != null; };
26
+ }
27
+ /** A new page view: everything starts from zero at `now`. */
28
+ SectionClock.prototype.reset = function (now) {
29
+ var _this = this;
30
+ this.start = now;
31
+ var ids = Array.from(this.sections.values()).map(function (s) { return [s.id, s.report]; });
32
+ this.sections.clear();
33
+ ids.forEach(function (_a) {
34
+ var id = _a[0], report = _a[1];
35
+ return _this.ensure(id, report);
36
+ });
37
+ };
38
+ SectionClock.prototype.onSeen = function (listener) {
39
+ var _this = this;
40
+ this.seenListeners.add(listener);
41
+ return function () { return void _this.seenListeners.delete(listener); };
42
+ };
43
+ SectionClock.prototype.ensure = function (id, report) {
44
+ if (report === void 0) { report = true; }
45
+ var s = this.sections.get(id);
46
+ if (!s) {
47
+ s = { id: id, ratio: 0, visibleMs: 0, visibleSince: null, halfSince: null, seenAt: null, firstSeenMs: null, report: report };
48
+ this.sections.set(id, s);
49
+ }
50
+ return s;
51
+ };
52
+ /** Registers a section so it shows up in the summary even if it is never on screen. */
53
+ SectionClock.prototype.register = function (id, report) {
54
+ var _a;
55
+ if (report === void 0) { report = true; }
56
+ (_a = this.ensure(id, report)).report || (_a.report = report);
57
+ };
58
+ /** The section's effective visibility changed. */
59
+ SectionClock.prototype.update = function (id, ratio, now) {
60
+ var s = this.ensure(id);
61
+ if (this.tabVisible) {
62
+ var wasVisible = s.ratio > 0;
63
+ var isVisible = ratio > 0;
64
+ if (wasVisible && !isVisible && s.visibleSince != null) {
65
+ s.visibleMs += Math.max(0, now - s.visibleSince);
66
+ s.visibleSince = null;
67
+ }
68
+ if (!wasVisible && isVisible)
69
+ s.visibleSince = now;
70
+ // A stretch at >= 50% continues through ratio changes above the line.
71
+ var wasHalf = s.ratio >= exports.SEEN_RATIO;
72
+ var isHalf = ratio >= exports.SEEN_RATIO;
73
+ if (wasHalf && !isHalf) {
74
+ this.tickOne(s, now);
75
+ s.halfSince = null;
76
+ }
77
+ if (!wasHalf && isHalf)
78
+ s.halfSince = now;
79
+ }
80
+ s.ratio = ratio;
81
+ };
82
+ /** The tab became visible or hidden: time stops counting while hidden. */
83
+ SectionClock.prototype.setTabVisible = function (visible, now) {
84
+ var _this = this;
85
+ if (visible === this.tabVisible)
86
+ return;
87
+ this.sections.forEach(function (s) { return _this.settle(s, now); });
88
+ this.tabVisible = visible;
89
+ this.sections.forEach(function (s) { return _this.arm(s, now); });
90
+ };
91
+ /** Promotes stretches that have lasted long enough to `seen`. Call ~every second. */
92
+ SectionClock.prototype.tick = function (now) {
93
+ var _this = this;
94
+ this.sections.forEach(function (s) { return _this.tickOne(s, now); });
95
+ };
96
+ /** Closes the open stretches up to `now` (visible time, seen). */
97
+ SectionClock.prototype.settle = function (s, now) {
98
+ if (s.visibleSince != null)
99
+ s.visibleMs += Math.max(0, now - s.visibleSince);
100
+ s.visibleSince = null;
101
+ this.tickOne(s, now);
102
+ s.halfSince = null;
103
+ };
104
+ SectionClock.prototype.tickOne = function (s, now) {
105
+ if (s.seenAt == null && s.halfSince != null && now - s.halfSince >= exports.SEEN_MS) {
106
+ s.seenAt = now;
107
+ s.firstSeenMs = Math.max(0, s.halfSince - this.start);
108
+ this.seenListeners.forEach(function (l) { return l(s.id); });
109
+ }
110
+ };
111
+ /** Opens stretches for the current state. */
112
+ SectionClock.prototype.arm = function (s, now) {
113
+ if (!this.tabVisible)
114
+ return;
115
+ if (s.ratio > 0)
116
+ s.visibleSince = now;
117
+ if (s.ratio >= exports.SEEN_RATIO)
118
+ s.halfSince = now;
119
+ };
120
+ /** The section most on screen now (ties: the lower one on the page, i.e. the later registered). */
121
+ SectionClock.prototype.current = function () {
122
+ var _a;
123
+ var best = null;
124
+ for (var _i = 0, _b = Array.from(this.sections.values()); _i < _b.length; _i++) {
125
+ var s = _b[_i];
126
+ if (s.report && s.ratio > 0 && (!best || s.ratio >= best.ratio))
127
+ best = s;
128
+ }
129
+ return (_a = best === null || best === void 0 ? void 0 : best.id) !== null && _a !== void 0 ? _a : null;
130
+ };
131
+ SectionClock.prototype.summary = function (now) {
132
+ this.tick(now);
133
+ return Array.from(this.sections.values())
134
+ .filter(function (s) { return s.report; })
135
+ .map(function (s) { return ({
136
+ id: s.id,
137
+ visible_ms: Math.round(s.visibleMs + (s.visibleSince != null ? Math.max(0, now - s.visibleSince) : 0)),
138
+ seen: s.seenAt != null,
139
+ first_seen_ms: s.firstSeenMs,
140
+ }); });
141
+ };
142
+ return SectionClock;
143
+ }());
144
+ exports.SectionClock = SectionClock;
145
+ /**
146
+ * Effective visibility from an IntersectionObserver entry: the larger of the share
147
+ * of the section on screen and the share of the viewport the section fills.
148
+ */
149
+ var effectiveRatio = function (intersectionRatio, intersectionHeight, viewportHeight) {
150
+ if (intersectionRatio <= 0)
151
+ return 0;
152
+ var cover = viewportHeight > 0 ? intersectionHeight / viewportHeight : 0;
153
+ return Math.min(1, Math.max(intersectionRatio, cover));
154
+ };
155
+ exports.effectiveRatio = effectiveRatio;
156
+ //# sourceMappingURL=sections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../../src/tracking/core/sections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Storage that never throws: private windows, blocked site data and sandboxed
3
+ * iframes make `localStorage` throw on access. The tracker then keeps its state in
4
+ * memory for the page's lifetime and the site behaves exactly as without consent.
5
+ */
6
+ export interface IStorage {
7
+ get(key: string): string | null;
8
+ set(key: string, value: string): void;
9
+ remove(key: string): void;
10
+ }
11
+ export declare const memoryStorage: () => IStorage;
12
+ export declare const safeStorage: (pick: () => Storage | undefined) => IStorage;
13
+ export declare const readJson: <T>(storage: IStorage, key: string) => T | null;
14
+ export declare const writeJson: (storage: IStorage, key: string, value: unknown) => void;
15
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/tracking/core/storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,QAAO,QAOhC,CAAC;AAEF,eAAO,MAAM,WAAW,SAAU,MAAM,OAAO,GAAG,SAAS,KAAG,QAoC7D,CAAC;AAEF,eAAO,MAAM,QAAQ,eAAgB,QAAQ,OAAO,MAAM,KAAG,CAAC,GAAG,IAQhE,CAAC;AAEF,eAAO,MAAM,SAAS,YAAa,QAAQ,OAAO,MAAM,SAAS,OAAO,SAA4C,CAAC"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeJson = exports.readJson = exports.safeStorage = exports.memoryStorage = void 0;
4
+ var memoryStorage = function () {
5
+ var data = new Map();
6
+ return {
7
+ get: function (k) { var _a; return (_a = data.get(k)) !== null && _a !== void 0 ? _a : null; },
8
+ set: function (k, v) { return void data.set(k, v); },
9
+ remove: function (k) { return void data.delete(k); },
10
+ };
11
+ };
12
+ exports.memoryStorage = memoryStorage;
13
+ var safeStorage = function (pick) {
14
+ var fallback = (0, exports.memoryStorage)();
15
+ var store = function () {
16
+ try {
17
+ return pick();
18
+ }
19
+ catch (_a) {
20
+ return undefined;
21
+ }
22
+ };
23
+ return {
24
+ get: function (k) {
25
+ try {
26
+ var s = store();
27
+ return s ? s.getItem(k) : fallback.get(k);
28
+ }
29
+ catch (_a) {
30
+ return fallback.get(k);
31
+ }
32
+ },
33
+ set: function (k, v) {
34
+ try {
35
+ var s = store();
36
+ if (s)
37
+ s.setItem(k, v);
38
+ else
39
+ fallback.set(k, v);
40
+ }
41
+ catch (_a) {
42
+ fallback.set(k, v);
43
+ }
44
+ },
45
+ remove: function (k) {
46
+ var _a;
47
+ fallback.remove(k);
48
+ try {
49
+ (_a = store()) === null || _a === void 0 ? void 0 : _a.removeItem(k);
50
+ }
51
+ catch (_b) {
52
+ /* ignore */
53
+ }
54
+ },
55
+ };
56
+ };
57
+ exports.safeStorage = safeStorage;
58
+ var readJson = function (storage, key) {
59
+ var raw = storage.get(key);
60
+ if (!raw)
61
+ return null;
62
+ try {
63
+ return JSON.parse(raw);
64
+ }
65
+ catch (_a) {
66
+ return null;
67
+ }
68
+ };
69
+ exports.readJson = readJson;
70
+ var writeJson = function (storage, key, value) { return storage.set(key, JSON.stringify(value)); };
71
+ exports.writeJson = writeJson;
72
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/tracking/core/storage.ts"],"names":[],"mappings":";;;AAWO,IAAM,aAAa,GAAG;IAC3B,IAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,OAAO;QACL,GAAG,EAAE,UAAC,CAAC,YAAK,OAAA,MAAA,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,mCAAI,IAAI,CAAA,EAAA;QAC/B,GAAG,EAAE,UAAC,CAAC,EAAE,CAAC,IAAK,OAAA,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAnB,CAAmB;QAClC,MAAM,EAAE,UAAC,CAAC,IAAK,OAAA,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAnB,CAAmB;KACnC,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,aAAa,iBAOxB;AAEK,IAAM,WAAW,GAAG,UAAC,IAA+B;IACzD,IAAM,QAAQ,GAAG,IAAA,qBAAa,GAAE,CAAC;IACjC,IAAM,KAAK,GAAG;QACZ,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;IACF,OAAO;QACL,GAAG,EAAE,UAAC,CAAC;YACL,IAAI,CAAC;gBACH,IAAM,CAAC,GAAG,KAAK,EAAE,CAAC;gBAClB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC5C,CAAC;YAAC,WAAM,CAAC;gBACP,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,GAAG,EAAE,UAAC,CAAC,EAAE,CAAC;YACR,IAAI,CAAC;gBACH,IAAM,CAAC,GAAG,KAAK,EAAE,CAAC;gBAClB,IAAI,CAAC;oBAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;;oBAClB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1B,CAAC;YAAC,WAAM,CAAC;gBACP,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QACD,MAAM,EAAE,UAAC,CAAC;;YACR,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACnB,IAAI,CAAC;gBACH,MAAA,KAAK,EAAE,0CAAE,UAAU,CAAC,CAAC,CAAC,CAAC;YACzB,CAAC;YAAC,WAAM,CAAC;gBACP,YAAY;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AApCW,QAAA,WAAW,eAoCtB;AAEK,IAAM,QAAQ,GAAG,UAAI,OAAiB,EAAE,GAAW;IACxD,IAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAC;IAC9B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AARW,QAAA,QAAQ,YAQnB;AAEK,IAAM,SAAS,GAAG,UAAC,OAAiB,EAAE,GAAW,EAAE,KAAc,IAAK,OAAA,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAvC,CAAuC,CAAC;AAAxG,QAAA,SAAS,aAA+F"}
@@ -0,0 +1,122 @@
1
+ import { ConsentStore } from './consent';
2
+ import { ExperimentStore, type IAssignContext, type IAssignment } from './experiments';
3
+ import { Observable } from './observable';
4
+ import { type ITransport } from './queue';
5
+ import { SectionClock } from './sections';
6
+ import { type IStorage } from './storage';
7
+ import { type ITrackingConfig, type TEventType, type TProps, type TStorageKeys, type TTrackingOptions } from './types';
8
+ /** What the page looks like right now (the browser layer reads it from `window`). */
9
+ export interface IPageInfo {
10
+ /** `https://example.com` */
11
+ origin: string;
12
+ path: string;
13
+ search: string;
14
+ title: string;
15
+ referrer: string;
16
+ lang: string;
17
+ viewport: [number, number];
18
+ device?: IAssignContext['device'];
19
+ }
20
+ /** Everything the tracker needs from its host; tests pass fakes. */
21
+ export interface ITrackerEnv {
22
+ local: IStorage;
23
+ session: IStorage;
24
+ transport: ITransport;
25
+ now: () => number;
26
+ setTimer: (fn: () => void, ms: number) => unknown;
27
+ clearTimer: (handle: unknown) => void;
28
+ page: () => IPageInfo;
29
+ fetchJson: (url: string, timeoutMs: number) => Promise<unknown>;
30
+ log?: (...args: unknown[]) => void;
31
+ }
32
+ /**
33
+ * The tracker: identity, consent, the event queue, page views and their summaries,
34
+ * experiment assignment and exposure. It has no DOM code of its own (see
35
+ * `browser/attach.ts`), so it runs unchanged in tests and in any web property.
36
+ * Everything product-specific (property, endpoints, storage prefix) is in `config`.
37
+ *
38
+ * Never throws into the page: every public method is wrapped.
39
+ */
40
+ export declare class Tracker {
41
+ private readonly env;
42
+ readonly consent: ConsentStore;
43
+ readonly experiments: ExperimentStore;
44
+ readonly sections: SectionClock;
45
+ private readonly engagement;
46
+ private readonly queue;
47
+ private pv;
48
+ private lastUrl;
49
+ private readonly firstTouchUtm;
50
+ private watches;
51
+ private started;
52
+ /** The current page view id (null without consent): the browser layer re-measures sections on change. */
53
+ readonly pageViewId: Observable<string>;
54
+ /** The storage keys under `config.storagePrefix`. */
55
+ readonly keys: TStorageKeys;
56
+ readonly config: ITrackingConfig;
57
+ constructor(options: TTrackingOptions, env: ITrackerEnv);
58
+ /** Runs `fn` and swallows any error: analytics never breaks the page. */
59
+ private safe;
60
+ private active;
61
+ /** The tracker's clock (the browser layer times sections with it). */
62
+ now: () => number;
63
+ /** The visitor id: exists only with consent. */
64
+ vid(): string | null;
65
+ /** The session id: a new one after `sessionTimeoutMs` without an event. */
66
+ private sid;
67
+ private envelope;
68
+ grant(): void;
69
+ /** Declines or withdraws: the visitor id and everything tied to it are deleted, nothing more is sent. */
70
+ deny(): void;
71
+ private onConsentChange;
72
+ /** Call once when the page has loaded: starts the first page view if consent was given earlier. */
73
+ start(): void;
74
+ /** A route change in a single-page app: closes the current page view and starts a new one. */
75
+ pageview(): void;
76
+ private beginPageView;
77
+ /**
78
+ * A cumulative summary of the page view. Sent when the tab is hidden (`final:
79
+ * false`, the visitor may come back) and when the page is left (`final: true`);
80
+ * the one with the highest `seq` for a `pv_id` is the complete one.
81
+ */
82
+ summary(final: boolean): void;
83
+ activity(): void;
84
+ scrolled(pct: number): void;
85
+ setTabVisible(visible: boolean): void;
86
+ /** The page is going away (`pagehide`). */
87
+ leave(): void;
88
+ flush(mode?: 'fetch' | 'beacon'): Promise<void>;
89
+ /** Queues an event of any type (nothing happens without consent). */
90
+ record(type: TEventType, props?: TProps): void;
91
+ heartbeat(): void;
92
+ click(props: {
93
+ target: string;
94
+ placement?: string | null;
95
+ label?: string | null;
96
+ href?: string | null;
97
+ }): void;
98
+ /** A conversion the server's goals can match (`signup-started`, …). */
99
+ goal(name: string, value?: number): void;
100
+ /** A named event with free-form props (`form-submitted`, `plan-picked`, …). */
101
+ custom(name: string, props?: TProps): void;
102
+ /**
103
+ * The variant for this visitor. Preview override first, then the running
104
+ * definition; the control whenever consent, the definitions or targeting say no.
105
+ */
106
+ decide(key: string, fallbackControl?: string): IAssignment;
107
+ /**
108
+ * Logs the exposure once per page view when the trigger section is seen (or at
109
+ * once for `trigger: null`). Returns an unsubscribe for when the variant unmounts.
110
+ */
111
+ watchExposure(assignment: IAssignment): () => void;
112
+ private onSectionSeen;
113
+ private expose;
114
+ /**
115
+ * Adds `qa_exp=key:variant,…` (experiments this visitor was exposed to; the server's
116
+ * sign-up flow reads this parameter, §5.4 of the contract) and the
117
+ * session's first-touch `utm_*` to a sign-up URL — nothing else, never the vid.
118
+ * Without consent the URL is returned unchanged.
119
+ */
120
+ decorateSignupUrl(url: string): string;
121
+ }
122
+ //# sourceMappingURL=tracker.d.ts.map