@appright/funnelshift 0.0.0-stage → 0.16.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/bin/funnel-kit.js +2 -0
- package/dist/anchors.d.ts +4 -0
- package/dist/anchors.js +94 -0
- package/dist/answers.d.ts +11 -0
- package/dist/answers.js +100 -0
- package/dist/attribution.d.ts +34 -0
- package/dist/attribution.js +237 -0
- package/dist/autotrack.d.ts +4 -0
- package/dist/autotrack.js +13 -0
- package/dist/backnav.d.ts +15 -0
- package/dist/backnav.js +73 -0
- package/dist/blocks/Choice.d.ts +19 -0
- package/dist/blocks/Choice.js +38 -0
- package/dist/blocks/Cta.d.ts +7 -0
- package/dist/blocks/Cta.js +8 -0
- package/dist/blocks/Hero.d.ts +10 -0
- package/dist/blocks/Hero.js +48 -0
- package/dist/blocks/MultiChoice.d.ts +13 -0
- package/dist/blocks/MultiChoice.js +47 -0
- package/dist/blocks/Section.d.ts +6 -0
- package/dist/blocks/Section.js +4 -0
- package/dist/bootstrap.d.ts +33 -0
- package/dist/bootstrap.js +19 -0
- package/dist/bucket.d.ts +13 -0
- package/dist/bucket.js +41 -0
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.js +18 -0
- package/dist/cli/build.d.ts +6 -0
- package/dist/cli/build.js +200 -0
- package/dist/cli/extract.d.ts +32 -0
- package/dist/cli/extract.js +253 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +40 -0
- package/dist/cli/init.d.ts +5 -0
- package/dist/cli/init.js +67 -0
- package/dist/cli/lint.d.ts +25 -0
- package/dist/cli/lint.js +535 -0
- package/dist/cli/upload.d.ts +32 -0
- package/dist/cli/upload.js +100 -0
- package/dist/clicks.d.ts +7 -0
- package/dist/clicks.js +102 -0
- package/dist/content.d.ts +7 -0
- package/dist/content.js +60 -0
- package/dist/context.d.ts +12 -0
- package/dist/context.js +52 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +90 -0
- package/dist/experiments.d.ts +4 -0
- package/dist/experiments.js +24 -0
- package/dist/exposure.d.ts +4 -0
- package/dist/exposure.js +35 -0
- package/dist/functions.d.ts +37 -0
- package/dist/functions.js +24 -0
- package/dist/funnel.d.ts +64 -0
- package/dist/funnel.js +433 -0
- package/dist/handoff.d.ts +8 -0
- package/dist/handoff.js +66 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +17 -0
- package/dist/nav.d.ts +19 -0
- package/dist/nav.js +14 -0
- package/dist/offer.d.ts +3 -0
- package/dist/offer.js +7 -0
- package/dist/pixel.d.ts +36 -0
- package/dist/pixel.js +173 -0
- package/dist/prerender.d.ts +2 -0
- package/dist/prerender.js +16 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +88 -0
- package/dist/sha256.d.ts +2 -0
- package/dist/sha256.js +65 -0
- package/dist/signals.d.ts +18 -0
- package/dist/signals.js +300 -0
- package/dist/tracker.d.ts +80 -0
- package/dist/tracker.js +446 -0
- package/dist/uuid.d.ts +1 -0
- package/dist/uuid.js +12 -0
- package/dist/vitals.d.ts +4 -0
- package/dist/vitals.js +104 -0
- package/package.json +29 -4
- package/src/blocks/blocks.css +364 -0
- package/templates/init/CLAUDE.md +10 -0
- package/templates/init/funnels/welcome/index.tsx +129 -0
- package/templates/init/gitignore +5 -0
- package/templates/init/package.json.tmpl +20 -0
- package/templates/init/theme.css +77 -0
- package/templates/init/tsconfig.json +7 -0
- package/README.md +0 -3
package/dist/signals.js
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// What the kit watches on a step by itself (kit 0.13.0, see autotrack.ts for the switches). One object per mounted funnel; the
|
|
2
|
+
// funnel calls newView() when a step comes on screen and activeMs() when it leaves one.
|
|
3
|
+
//
|
|
4
|
+
// $scroll {depth, ms} depth 25, 50, 75 or 100: the share of the page that has been in the window at the deepest. Each depth
|
|
5
|
+
// once per step view; a jump over several quarters sends each of them. Only on a page taller than the
|
|
6
|
+
// window, and only once the visitor scrolls (no scrolling, no event). ms: since the step came on screen.
|
|
7
|
+
// $section_view {section, ms} an element with data-section="<name>" was at least half in view (or fills half of the window, for a
|
|
8
|
+
// section taller than it) for one second without a break, in a visible tab. Once per section and view.
|
|
9
|
+
// $field_error {field, code} a field turned invalid: the browser's `invalid` event (a native validation) or aria-invalid going to
|
|
10
|
+
// "true" (a funnel's own). The field is its name; the code a short word (required, email_invalid, …).
|
|
11
|
+
// The typed value is never read. Not more than 3 per field and code, 20 per step view.
|
|
12
|
+
// active_ms the time this step was on screen with the tab visible and the window focused (activeMs()).
|
|
13
|
+
//
|
|
14
|
+
// All of it is passive: listeners never stop or change anything, and nothing here may throw into the page.
|
|
15
|
+
const QUARTERS = [25, 50, 75, 100];
|
|
16
|
+
const SCROLL_DELAY = 120;
|
|
17
|
+
const MIN_SCROLL = 50; // a page taller than the window by less than this does not scroll
|
|
18
|
+
const SECTION_DWELL = 1000;
|
|
19
|
+
const SECTION_SELECTOR = '[data-section]';
|
|
20
|
+
const SECTION_NAME = /[^a-z0-9_-]+/g;
|
|
21
|
+
const MAX_NAME = 64;
|
|
22
|
+
const MAX_PER_FIELD = 3;
|
|
23
|
+
const MAX_PER_VIEW = 20;
|
|
24
|
+
const MAX_SECTIONS_PER_VIEW = 20; // sections named in one step view; a page with more is marked with too many data-section
|
|
25
|
+
const CODE = /^[a-z][a-z0-9_]{0,31}$/;
|
|
26
|
+
const FIELD_TYPES_WITH_CODE = new Set(['email', 'tel', 'url', 'number', 'date']);
|
|
27
|
+
const THRESHOLDS = Array.from({ length: 21 }, (_, i) => i / 20);
|
|
28
|
+
// The name of a section as it is sent: lower case, anything but [a-z0-9_-] turned into _, at most 64 characters; '' for none.
|
|
29
|
+
export function sectionName(raw) {
|
|
30
|
+
const n = (raw ?? '').trim().toLowerCase().replace(SECTION_NAME, '_').replace(/^_+|_+$/g, '').slice(0, MAX_NAME);
|
|
31
|
+
return n;
|
|
32
|
+
}
|
|
33
|
+
// The key of a field: its name, else data-track, data-field, a plain id, else its type. Lower case, [a-z0-9_-].
|
|
34
|
+
export function fieldKey(el) {
|
|
35
|
+
const id = el.getAttribute('id') ?? '';
|
|
36
|
+
const raw = el.getAttribute('name') || el.getAttribute('data-track') || el.getAttribute('data-field') || (id && !id.startsWith(':') ? id : '')
|
|
37
|
+
|| el.getAttribute('type') || el.tagName.toLowerCase();
|
|
38
|
+
return sectionName(raw) || 'field';
|
|
39
|
+
}
|
|
40
|
+
// The error code of a field that is invalid: data-error-code, else the browser's validity state, else a guess from the field
|
|
41
|
+
// without ever looking at what was typed (only whether it is empty).
|
|
42
|
+
export function errorCode(el) {
|
|
43
|
+
const own = el.getAttribute('data-error-code') ?? '';
|
|
44
|
+
if (CODE.test(own))
|
|
45
|
+
return own;
|
|
46
|
+
const type = (el.getAttribute('type') ?? 'text').toLowerCase();
|
|
47
|
+
const v = el.validity;
|
|
48
|
+
if (v && !v.valid) {
|
|
49
|
+
if (v.valueMissing)
|
|
50
|
+
return 'required';
|
|
51
|
+
if (v.typeMismatch)
|
|
52
|
+
return FIELD_TYPES_WITH_CODE.has(type) ? `${type}_invalid` : 'invalid';
|
|
53
|
+
if (v.patternMismatch)
|
|
54
|
+
return FIELD_TYPES_WITH_CODE.has(type) ? `${type}_invalid` : 'pattern';
|
|
55
|
+
if (v.tooShort)
|
|
56
|
+
return 'too_short';
|
|
57
|
+
if (v.tooLong)
|
|
58
|
+
return 'too_long';
|
|
59
|
+
if (v.rangeUnderflow)
|
|
60
|
+
return 'too_small';
|
|
61
|
+
if (v.rangeOverflow)
|
|
62
|
+
return 'too_large';
|
|
63
|
+
if (v.stepMismatch)
|
|
64
|
+
return 'step_mismatch';
|
|
65
|
+
if (v.badInput)
|
|
66
|
+
return 'bad_input';
|
|
67
|
+
}
|
|
68
|
+
const value = el.value;
|
|
69
|
+
if (typeof value === 'string' && value === '' && el.matches('input, textarea, select'))
|
|
70
|
+
return 'required';
|
|
71
|
+
return FIELD_TYPES_WITH_CODE.has(type) ? `${type}_invalid` : 'invalid';
|
|
72
|
+
}
|
|
73
|
+
// The time the tab was visible and the window focused. Focus is taken for granted until a blur says otherwise (a webview may never
|
|
74
|
+
// report it), and a blur into an iframe (a card form) is not a leave.
|
|
75
|
+
class ActiveClock {
|
|
76
|
+
now;
|
|
77
|
+
acc = 0;
|
|
78
|
+
since;
|
|
79
|
+
focused = true;
|
|
80
|
+
listeners = [];
|
|
81
|
+
constructor(now) {
|
|
82
|
+
this.now = now;
|
|
83
|
+
this.since = this.active() ? now() : null;
|
|
84
|
+
const on = (t, type, fn) => { t.addEventListener(type, fn); this.listeners.push([t, type, fn]); };
|
|
85
|
+
on(document, 'visibilitychange', () => this.sync());
|
|
86
|
+
on(window, 'blur', () => { if (document.activeElement?.tagName === 'IFRAME')
|
|
87
|
+
return; this.focused = false; this.sync(); });
|
|
88
|
+
on(window, 'focus', () => { this.focused = true; this.sync(); });
|
|
89
|
+
on(window, 'pageshow', () => { this.focused = true; this.sync(); });
|
|
90
|
+
}
|
|
91
|
+
active() { return document.visibilityState !== 'hidden' && this.focused; }
|
|
92
|
+
sync() {
|
|
93
|
+
const a = this.active(), t = this.now();
|
|
94
|
+
if (a && this.since === null)
|
|
95
|
+
this.since = t;
|
|
96
|
+
else if (!a && this.since !== null) {
|
|
97
|
+
this.acc += t - this.since;
|
|
98
|
+
this.since = null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
reset() { this.acc = 0; this.since = this.active() ? this.now() : null; }
|
|
102
|
+
read() { return Math.max(0, Math.round(this.acc + (this.since !== null ? this.now() - this.since : 0))); }
|
|
103
|
+
off() { for (const [t, type, fn] of this.listeners)
|
|
104
|
+
t.removeEventListener(type, fn); this.listeners = []; }
|
|
105
|
+
}
|
|
106
|
+
export function installStepSignals(root, o) {
|
|
107
|
+
const now = o.now ?? Date.now;
|
|
108
|
+
const safe = (fn) => () => { try {
|
|
109
|
+
fn();
|
|
110
|
+
}
|
|
111
|
+
catch { /* analytics must never break the page */ } };
|
|
112
|
+
const clock = o.activeTime ? new ActiveClock(now) : null;
|
|
113
|
+
let viewStart = now();
|
|
114
|
+
let alive = true;
|
|
115
|
+
// ---- scroll depth ------------------------------------------------------------------------------------------------------------
|
|
116
|
+
let reached = 0;
|
|
117
|
+
let scrollTimer;
|
|
118
|
+
const measure = safe(() => {
|
|
119
|
+
scrollTimer = undefined;
|
|
120
|
+
const doc = document.documentElement;
|
|
121
|
+
const total = Math.max(doc.scrollHeight, document.body?.scrollHeight ?? 0);
|
|
122
|
+
const view = window.innerHeight || doc.clientHeight;
|
|
123
|
+
if (!(view > 0) || !(total > view + MIN_SCROLL))
|
|
124
|
+
return;
|
|
125
|
+
const pct = ((window.scrollY || doc.scrollTop || 0) + view) / total * 100;
|
|
126
|
+
for (const q of QUARTERS) {
|
|
127
|
+
if (q > reached && pct >= q - 1) {
|
|
128
|
+
reached = q;
|
|
129
|
+
o.track('$scroll', { depth: q, ms: Math.max(0, now() - viewStart) }, o.stepId());
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
const onScroll = () => { if (alive && scrollTimer === undefined)
|
|
134
|
+
scrollTimer = setTimeout(measure, SCROLL_DELAY); };
|
|
135
|
+
if (o.scroll)
|
|
136
|
+
window.addEventListener('scroll', onScroll, { passive: true });
|
|
137
|
+
// ---- sections ----------------------------------------------------------------------------------------------------------------
|
|
138
|
+
let io;
|
|
139
|
+
let mo;
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
let sectionsSent = 0;
|
|
142
|
+
const inView = new Set(); // half in view now, whatever the tab does
|
|
143
|
+
const timers = new Map();
|
|
144
|
+
const tabVisible = () => document.visibilityState !== 'hidden';
|
|
145
|
+
const clearTimer = (el) => { const t = timers.get(el); if (t !== undefined) {
|
|
146
|
+
clearTimeout(t);
|
|
147
|
+
timers.delete(el);
|
|
148
|
+
} };
|
|
149
|
+
const arm = (el) => {
|
|
150
|
+
if (timers.has(el) || !tabVisible())
|
|
151
|
+
return;
|
|
152
|
+
const name = sectionName(el.getAttribute('data-section'));
|
|
153
|
+
if (!name || seen.has(name))
|
|
154
|
+
return;
|
|
155
|
+
timers.set(el, setTimeout(safe(() => {
|
|
156
|
+
timers.delete(el);
|
|
157
|
+
if (!alive || seen.has(name) || !inView.has(el) || !tabVisible() || sectionsSent >= MAX_SECTIONS_PER_VIEW)
|
|
158
|
+
return;
|
|
159
|
+
seen.add(name);
|
|
160
|
+
sectionsSent++;
|
|
161
|
+
inView.delete(el);
|
|
162
|
+
io?.unobserve(el);
|
|
163
|
+
o.track('$section_view', { section: name, ms: Math.max(0, now() - viewStart) }, o.stepId());
|
|
164
|
+
}), SECTION_DWELL));
|
|
165
|
+
};
|
|
166
|
+
const watched = new Set();
|
|
167
|
+
const watch = (el) => {
|
|
168
|
+
if (io && !watched.has(el)) {
|
|
169
|
+
watched.add(el);
|
|
170
|
+
io.observe(el);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const scan = (from) => {
|
|
174
|
+
if (from instanceof Element && from.matches(SECTION_SELECTOR))
|
|
175
|
+
watch(from);
|
|
176
|
+
from.querySelectorAll(SECTION_SELECTOR).forEach(watch);
|
|
177
|
+
};
|
|
178
|
+
const startSections = () => {
|
|
179
|
+
if (!o.sections || typeof IntersectionObserver === 'undefined')
|
|
180
|
+
return;
|
|
181
|
+
io = new IntersectionObserver(entries => {
|
|
182
|
+
try {
|
|
183
|
+
for (const e of entries) {
|
|
184
|
+
const h = e.rootBounds?.height || window.innerHeight;
|
|
185
|
+
const half = e.isIntersecting && (e.intersectionRatio >= 0.5 || (h > 0 && e.intersectionRect.height >= h * 0.5));
|
|
186
|
+
if (half) {
|
|
187
|
+
inView.add(e.target);
|
|
188
|
+
arm(e.target);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
inView.delete(e.target);
|
|
192
|
+
clearTimer(e.target);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch { /* analytics must never break the page */ }
|
|
197
|
+
}, { threshold: THRESHOLDS });
|
|
198
|
+
scan(root);
|
|
199
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
200
|
+
mo = new MutationObserver(records => { try {
|
|
201
|
+
for (const r of records)
|
|
202
|
+
r.addedNodes.forEach(n => { if (n instanceof Element)
|
|
203
|
+
scan(n); });
|
|
204
|
+
}
|
|
205
|
+
catch { /* ignore */ } });
|
|
206
|
+
mo.observe(root, { childList: true, subtree: true });
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const stopSections = () => {
|
|
210
|
+
io?.disconnect();
|
|
211
|
+
mo?.disconnect();
|
|
212
|
+
io = undefined;
|
|
213
|
+
mo = undefined;
|
|
214
|
+
for (const t of timers.values())
|
|
215
|
+
clearTimeout(t);
|
|
216
|
+
timers.clear();
|
|
217
|
+
inView.clear();
|
|
218
|
+
watched.clear();
|
|
219
|
+
};
|
|
220
|
+
const onVisibility = () => {
|
|
221
|
+
if (document.visibilityState === 'hidden') {
|
|
222
|
+
for (const t of timers.values())
|
|
223
|
+
clearTimeout(t);
|
|
224
|
+
timers.clear();
|
|
225
|
+
}
|
|
226
|
+
else
|
|
227
|
+
for (const el of inView)
|
|
228
|
+
arm(el);
|
|
229
|
+
};
|
|
230
|
+
if (o.sections)
|
|
231
|
+
document.addEventListener('visibilitychange', onVisibility);
|
|
232
|
+
// ---- field errors ------------------------------------------------------------------------------------------------------------
|
|
233
|
+
const counts = new Map();
|
|
234
|
+
const lastAt = new Map();
|
|
235
|
+
let total = 0;
|
|
236
|
+
const reportField = (el) => {
|
|
237
|
+
if (!alive || el.matches('[type=hidden], :disabled'))
|
|
238
|
+
return;
|
|
239
|
+
const field = fieldKey(el), code = errorCode(el), key = field + '\u0000' + code;
|
|
240
|
+
const t = now(), n = counts.get(key) ?? 0;
|
|
241
|
+
if (total >= MAX_PER_VIEW || n >= MAX_PER_FIELD || t - (lastAt.get(key) ?? -1e9) < 1000)
|
|
242
|
+
return;
|
|
243
|
+
counts.set(key, n + 1);
|
|
244
|
+
lastAt.set(key, t);
|
|
245
|
+
total++;
|
|
246
|
+
o.track('$field_error', { field, code }, o.stepId());
|
|
247
|
+
};
|
|
248
|
+
const onInvalid = (e) => { try {
|
|
249
|
+
if (e.target instanceof Element)
|
|
250
|
+
reportField(e.target);
|
|
251
|
+
}
|
|
252
|
+
catch { /* ignore */ } };
|
|
253
|
+
let ariaObserver;
|
|
254
|
+
if (o.fieldErrors) {
|
|
255
|
+
root.addEventListener('invalid', onInvalid, true);
|
|
256
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
257
|
+
ariaObserver = new MutationObserver(records => {
|
|
258
|
+
try {
|
|
259
|
+
for (const r of records) {
|
|
260
|
+
const el = r.target;
|
|
261
|
+
if (r.type === 'attributes' && el instanceof Element && el.getAttribute('aria-invalid') === 'true' && r.oldValue !== 'true')
|
|
262
|
+
reportField(el);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch { /* ignore */ }
|
|
266
|
+
});
|
|
267
|
+
ariaObserver.observe(root, { attributes: true, attributeFilter: ['aria-invalid'], attributeOldValue: true, subtree: true });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
newView() {
|
|
272
|
+
viewStart = now();
|
|
273
|
+
reached = 0;
|
|
274
|
+
if (scrollTimer !== undefined) {
|
|
275
|
+
clearTimeout(scrollTimer);
|
|
276
|
+
scrollTimer = undefined;
|
|
277
|
+
}
|
|
278
|
+
stopSections();
|
|
279
|
+
seen.clear();
|
|
280
|
+
sectionsSent = 0;
|
|
281
|
+
startSections();
|
|
282
|
+
counts.clear();
|
|
283
|
+
lastAt.clear();
|
|
284
|
+
total = 0;
|
|
285
|
+
clock?.reset();
|
|
286
|
+
},
|
|
287
|
+
activeMs: () => clock?.read(),
|
|
288
|
+
off() {
|
|
289
|
+
alive = false;
|
|
290
|
+
if (scrollTimer !== undefined)
|
|
291
|
+
clearTimeout(scrollTimer);
|
|
292
|
+
window.removeEventListener('scroll', onScroll);
|
|
293
|
+
document.removeEventListener('visibilitychange', onVisibility);
|
|
294
|
+
stopSections();
|
|
295
|
+
root.removeEventListener('invalid', onInvalid, true);
|
|
296
|
+
ariaObserver?.disconnect();
|
|
297
|
+
clock?.off();
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Env } from './bootstrap.js';
|
|
2
|
+
import { type Attribution } from './attribution.js';
|
|
3
|
+
import { type BatchContext } from './context.js';
|
|
4
|
+
export type Base = {
|
|
5
|
+
funnel_id: string;
|
|
6
|
+
build_id: string;
|
|
7
|
+
release_id: string;
|
|
8
|
+
env: Env;
|
|
9
|
+
visitor_id: string;
|
|
10
|
+
url_path: string;
|
|
11
|
+
};
|
|
12
|
+
export type TrackerOptions = {
|
|
13
|
+
ingestUrl: string | null;
|
|
14
|
+
key: string;
|
|
15
|
+
base: Base;
|
|
16
|
+
attribution?: Partial<Attribution>;
|
|
17
|
+
fallbackUrl?: string | null;
|
|
18
|
+
project?: string;
|
|
19
|
+
primaryTimeoutMs?: number;
|
|
20
|
+
variants?: Record<string, string>;
|
|
21
|
+
context?: () => BatchContext;
|
|
22
|
+
geo?: string;
|
|
23
|
+
storage?: Storage;
|
|
24
|
+
session?: Storage;
|
|
25
|
+
fetchImpl?: typeof fetch;
|
|
26
|
+
beacon?: (url: string, body: string) => boolean;
|
|
27
|
+
maxBatch?: number;
|
|
28
|
+
intervalMs?: number;
|
|
29
|
+
now?: () => number;
|
|
30
|
+
};
|
|
31
|
+
export declare const MAX_USER_ID = 128;
|
|
32
|
+
export declare function validUserId(u: unknown): u is string;
|
|
33
|
+
export type FinalEvent = {
|
|
34
|
+
name: string;
|
|
35
|
+
props?: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
export type StopScope = 'tab' | 'project';
|
|
38
|
+
export declare function safeProps(p?: Record<string, unknown>): Record<string, string>;
|
|
39
|
+
export declare class Tracker {
|
|
40
|
+
private o;
|
|
41
|
+
private qkey;
|
|
42
|
+
private stopKey;
|
|
43
|
+
private projectStopKey;
|
|
44
|
+
private userKey;
|
|
45
|
+
private memUser;
|
|
46
|
+
private halted;
|
|
47
|
+
private isDegraded;
|
|
48
|
+
private nextProbe;
|
|
49
|
+
private lastFallback;
|
|
50
|
+
private fallbackSends;
|
|
51
|
+
private timer?;
|
|
52
|
+
private inflight;
|
|
53
|
+
private failures;
|
|
54
|
+
private retryAt;
|
|
55
|
+
private onHide;
|
|
56
|
+
private onVisibility;
|
|
57
|
+
constructor(o: TrackerOptions);
|
|
58
|
+
private sharedDegradedUntil;
|
|
59
|
+
private shareDegraded;
|
|
60
|
+
private projectStopped;
|
|
61
|
+
stopped(): boolean;
|
|
62
|
+
user(): string;
|
|
63
|
+
setUser(id: string): void;
|
|
64
|
+
clearUser(): void;
|
|
65
|
+
degraded(): boolean;
|
|
66
|
+
halt(final?: FinalEvent, scope?: StopScope): Promise<void>;
|
|
67
|
+
private context;
|
|
68
|
+
private post;
|
|
69
|
+
private queue;
|
|
70
|
+
private save;
|
|
71
|
+
private sessionId;
|
|
72
|
+
session(): string;
|
|
73
|
+
track(name: string, props?: Record<string, unknown>, stepId?: string, variants?: Record<string, string>): string;
|
|
74
|
+
flushSoon(): void;
|
|
75
|
+
private takeBatch;
|
|
76
|
+
flush(useBeacon?: boolean): Promise<void>;
|
|
77
|
+
idle(): Promise<void>;
|
|
78
|
+
start(): void;
|
|
79
|
+
stop(): void;
|
|
80
|
+
}
|