flowgrid-sdk 1.6.9 → 1.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.
@@ -298,11 +298,14 @@ class Identify extends transport_1.FlowGridTransport {
298
298
  const visitorId = resolveVisitorId();
299
299
  if (!this.webId || !visitorId)
300
300
  return;
301
- if (!captured.email && !captured.emailHash && !captured.firstName && !captured.lastName)
301
+ if (!captured.email && !captured.emailHash && !captured.firstName && !captured.lastName && !captured.phone)
302
302
  return;
303
303
  const traits = {
304
304
  email: captured.email ?? null,
305
305
  email_hash: captured.emailHash ?? null,
306
+ // Raw phone is only populated on an explicit form submit (consent);
307
+ // passive blur/input keeps phone hash-only.
308
+ phone: captured.phone ?? null,
306
309
  phone_hash: captured.phoneHash ?? null,
307
310
  first_name: captured.firstName ?? null,
308
311
  last_name: captured.lastName ?? null,
@@ -382,6 +385,31 @@ class Identify extends transport_1.FlowGridTransport {
382
385
  return;
383
386
  doc.querySelectorAll("input, textarea, select").forEach(attach);
384
387
  };
388
+ // Explicit submit is treated as consent — capture the RAW phone (the one
389
+ // identity field passive tracking keeps hash-only) so the CRM cascade can
390
+ // match by phone, then flush. All other fields are already captured passively.
391
+ const onSubmit = (e) => {
392
+ const form = e.target;
393
+ if (!form || form.tagName !== "FORM")
394
+ return;
395
+ if (EXCLUDED_PATH_RE.test(win.location.pathname))
396
+ return;
397
+ let phoneOnSubmit = false;
398
+ form.querySelectorAll("input, textarea, select").forEach((el) => {
399
+ const cls = classify(el);
400
+ if (!cls || "blocked" in cls || cls.trait !== "phone")
401
+ return;
402
+ const raw = (fieldEl(el).value || "").trim();
403
+ if (raw) {
404
+ captured.phone = raw;
405
+ phoneOnSubmit = true;
406
+ }
407
+ });
408
+ if (phoneOnSubmit)
409
+ sendIdentity();
410
+ };
411
+ doc.addEventListener("submit", onSubmit, true);
412
+ teardowns.push(() => doc.removeEventListener("submit", onSubmit, true));
385
413
  scanPage();
386
414
  let mo = null;
387
415
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"identify.js","sourceRoot":"","sources":["../../../../src/lib/features/analytics/identify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"identify.js","sourceRoot":"","sources":["../../../../src/lib/features/analytics/identify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Declarative, attribute-driven experiment tracking (no-code).
3
+ * @module features/core/declarativeExperiments
4
+ *
5
+ * @description
6
+ * Lets a non-technical user (WordPress / Wix / Squarespace marketer) wire
7
+ * experiment conversions, page-level goals, and exposures using ONLY HTML
8
+ * attributes — no JavaScript. It does not contain any experiment logic itself:
9
+ * it reads the visitor's already-assigned variant from the real engine
10
+ * (`Experiment` in `experiment.ts`) and calls its public tracking methods, so
11
+ * the deterministic assignment, anti-flicker, holdout and exposure semantics
12
+ * ("dynamic integrity") are untouched. This is purely the wiring layer.
13
+ *
14
+ * @attributes
15
+ * data-fg-goal="<experimentId>" Mark an element as a conversion trigger for
16
+ * that experiment. Use "*" for every experiment
17
+ * the visitor is currently bucketed into.
18
+ * data-fg-metric="signup" Metric name recorded (default "conversion").
19
+ * data-fg-value="49" Numeric value, e.g. order total (default 1).
20
+ * data-fg-on="click" Trigger: click (default) | load | submit | view.
21
+ * click — on element click
22
+ * load — once on page load (e.g. thank-you page)
23
+ * submit — on the element's (or nearest) form submit
24
+ * view — once when scrolled into view
25
+ * data-fg-event="<name>" Fire a generic `track(name)` event on the same
26
+ * trigger (page-level/interaction tracking). Can be
27
+ * combined with or used instead of data-fg-goal.
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <!-- count a click on the signup button as a conversion for the hero test -->
32
+ * <button data-fg-goal="homepage-hero-headline" data-fg-metric="signup">Start free</button>
33
+ *
34
+ * <!-- a thank-you page: count the visit as a conversion for every active test -->
35
+ * <body data-fg-goal="*" data-fg-on="load" data-fg-metric="purchase">
36
+ * ```
37
+ *
38
+ * Robust to dynamically-injected DOM: a MutationObserver re-scans on changes, so
39
+ * page builders and SPA route changes keep working with zero extra calls.
40
+ */
41
+ /** Minimal surface of the FlowGrid instance this layer depends on. */
42
+ export interface DeclarativeExperimentHost {
43
+ experiments: {
44
+ trackLocalConversion(experimentId: string, metricName?: string, value?: number): Promise<void> | void;
45
+ getAssignments(): Record<string, string>;
46
+ };
47
+ track(eventName: string, properties?: Record<string, unknown>): unknown;
48
+ }
49
+ /**
50
+ * Wire every `[data-fg-goal]` / `[data-fg-event]` element under `root` that
51
+ * isn't already wired, according to its trigger. Idempotent per element.
52
+ */
53
+ export declare function wireDeclarativeExperiments(host: DeclarativeExperimentHost): {
54
+ rescan: () => void;
55
+ flushLoad: () => void;
56
+ disconnect: () => void;
57
+ };
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Declarative, attribute-driven experiment tracking (no-code).
4
+ * @module features/core/declarativeExperiments
5
+ *
6
+ * @description
7
+ * Lets a non-technical user (WordPress / Wix / Squarespace marketer) wire
8
+ * experiment conversions, page-level goals, and exposures using ONLY HTML
9
+ * attributes — no JavaScript. It does not contain any experiment logic itself:
10
+ * it reads the visitor's already-assigned variant from the real engine
11
+ * (`Experiment` in `experiment.ts`) and calls its public tracking methods, so
12
+ * the deterministic assignment, anti-flicker, holdout and exposure semantics
13
+ * ("dynamic integrity") are untouched. This is purely the wiring layer.
14
+ *
15
+ * @attributes
16
+ * data-fg-goal="<experimentId>" Mark an element as a conversion trigger for
17
+ * that experiment. Use "*" for every experiment
18
+ * the visitor is currently bucketed into.
19
+ * data-fg-metric="signup" Metric name recorded (default "conversion").
20
+ * data-fg-value="49" Numeric value, e.g. order total (default 1).
21
+ * data-fg-on="click" Trigger: click (default) | load | submit | view.
22
+ * click — on element click
23
+ * load — once on page load (e.g. thank-you page)
24
+ * submit — on the element's (or nearest) form submit
25
+ * view — once when scrolled into view
26
+ * data-fg-event="<name>" Fire a generic `track(name)` event on the same
27
+ * trigger (page-level/interaction tracking). Can be
28
+ * combined with or used instead of data-fg-goal.
29
+ *
30
+ * @example
31
+ * ```html
32
+ * <!-- count a click on the signup button as a conversion for the hero test -->
33
+ * <button data-fg-goal="homepage-hero-headline" data-fg-metric="signup">Start free</button>
34
+ *
35
+ * <!-- a thank-you page: count the visit as a conversion for every active test -->
36
+ * <body data-fg-goal="*" data-fg-on="load" data-fg-metric="purchase">
37
+ * ```
38
+ *
39
+ * Robust to dynamically-injected DOM: a MutationObserver re-scans on changes, so
40
+ * page builders and SPA route changes keep working with zero extra calls.
41
+ */
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.wireDeclarativeExperiments = wireDeclarativeExperiments;
44
+ const WIRED_ATTR = "data-fg-wired";
45
+ const GOAL_ATTR = "data-fg-goal";
46
+ const EVENT_ATTR = "data-fg-event";
47
+ function parseTrigger(raw) {
48
+ switch ((raw || "").toLowerCase()) {
49
+ case "load": return "load";
50
+ case "submit": return "submit";
51
+ case "view": return "view";
52
+ default: return "click";
53
+ }
54
+ }
55
+ /** Resolve the experiment ids a `data-fg-goal` value targets. "*" = all active. */
56
+ function resolveExperimentIds(host, goal) {
57
+ const trimmed = goal.trim();
58
+ if (trimmed === "*") {
59
+ try {
60
+ return Object.keys(host.experiments.getAssignments());
61
+ }
62
+ catch {
63
+ return [];
64
+ }
65
+ }
66
+ // Allow a comma-separated list of ids for multi-experiment conversions.
67
+ return trimmed.split(",").map((s) => s.trim()).filter(Boolean);
68
+ }
69
+ /**
70
+ * Run the element's goal + event side effects once. `trackLocalConversion` is a
71
+ * safe no-op when the visitor isn't bucketed into a given experiment (control,
72
+ * holdout, or no running test), so firing for every resolved id is harmless.
73
+ */
74
+ function fire(host, el) {
75
+ const goal = el.getAttribute(GOAL_ATTR);
76
+ if (goal) {
77
+ const metric = el.getAttribute("data-fg-metric") || "conversion";
78
+ const rawValue = el.getAttribute("data-fg-value");
79
+ const value = rawValue != null && rawValue.trim() !== "" && Number.isFinite(Number(rawValue))
80
+ ? Number(rawValue)
81
+ : 1;
82
+ for (const id of resolveExperimentIds(host, goal)) {
83
+ try {
84
+ void host.experiments.trackLocalConversion(id, metric, value);
85
+ }
86
+ catch { /* ignore */ }
87
+ }
88
+ }
89
+ const eventName = el.getAttribute(EVENT_ATTR);
90
+ if (eventName) {
91
+ try {
92
+ host.track(eventName, { source: "declarative", trigger: el.getAttribute("data-fg-on") || "click" });
93
+ }
94
+ catch { /* ignore */ }
95
+ }
96
+ }
97
+ /**
98
+ * Wire every `[data-fg-goal]` / `[data-fg-event]` element under `root` that
99
+ * isn't already wired, according to its trigger. Idempotent per element.
100
+ */
101
+ function wireDeclarativeExperiments(host) {
102
+ if (typeof document === "undefined") {
103
+ return { rescan: () => { }, flushLoad: () => { }, disconnect: () => { } };
104
+ }
105
+ // Whether the engine has had a chance to resolve assignments. `load`/`view`
106
+ // goals discovered before this is true are deferred so a conversion is never
107
+ // recorded before the visitor is bucketed.
108
+ let assignmentsReady = false;
109
+ const pendingImmediate = [];
110
+ let viewObserver = null;
111
+ const fireOrDefer = (el) => {
112
+ if (assignmentsReady)
113
+ fire(host, el);
114
+ else
115
+ pendingImmediate.push(el);
116
+ };
117
+ const wireElement = (el) => {
118
+ if (el.hasAttribute(WIRED_ATTR))
119
+ return;
120
+ el.setAttribute(WIRED_ATTR, "");
121
+ const trigger = parseTrigger(el.getAttribute("data-fg-on"));
122
+ switch (trigger) {
123
+ case "click":
124
+ el.addEventListener("click", () => fire(host, el));
125
+ break;
126
+ case "submit": {
127
+ const form = el.tagName === "FORM" ? el : el.closest("form");
128
+ (form || el).addEventListener("submit", () => fire(host, el));
129
+ break;
130
+ }
131
+ case "view":
132
+ if (typeof IntersectionObserver !== "undefined") {
133
+ if (!viewObserver) {
134
+ viewObserver = new IntersectionObserver((entries, obs) => {
135
+ for (const entry of entries) {
136
+ if (entry.isIntersecting) {
137
+ obs.unobserve(entry.target);
138
+ fireOrDefer(entry.target);
139
+ }
140
+ }
141
+ }, { threshold: 0.5 });
142
+ }
143
+ viewObserver.observe(el);
144
+ }
145
+ else {
146
+ fireOrDefer(el); // no IO support — count it as seen
147
+ }
148
+ break;
149
+ case "load":
150
+ fireOrDefer(el);
151
+ break;
152
+ }
153
+ };
154
+ const scan = (root = document) => {
155
+ const sel = `[${GOAL_ATTR}]:not([${WIRED_ATTR}]),[${EVENT_ATTR}]:not([${WIRED_ATTR}])`;
156
+ root.querySelectorAll(sel).forEach(wireElement);
157
+ };
158
+ scan();
159
+ // Re-scan when the DOM changes (page builders, SPA navigation, lazy content).
160
+ const observer = typeof MutationObserver !== "undefined"
161
+ ? new MutationObserver((mutations) => {
162
+ for (const m of mutations) {
163
+ m.addedNodes.forEach((node) => {
164
+ if (node.nodeType === 1)
165
+ scan(node);
166
+ });
167
+ }
168
+ })
169
+ : null;
170
+ observer?.observe(document.documentElement, { childList: true, subtree: true });
171
+ return {
172
+ rescan: () => scan(),
173
+ /**
174
+ * Mark assignments as resolved and fire any `load`/`view` goals that were
175
+ * discovered before the engine had bucketed the visitor. Call once
176
+ * `initFromServer()` settles. Idempotent.
177
+ */
178
+ flushLoad: () => {
179
+ if (assignmentsReady)
180
+ return;
181
+ assignmentsReady = true;
182
+ const queued = pendingImmediate.splice(0, pendingImmediate.length);
183
+ for (const el of queued)
184
+ fire(host, el);
185
+ },
186
+ disconnect: () => {
187
+ try {
188
+ observer?.disconnect();
189
+ }
190
+ catch { /* ignore */ }
191
+ try {
192
+ viewObserver?.disconnect();
193
+ }
194
+ catch { /* ignore */ }
195
+ },
196
+ };
197
+ }
198
+ //# sourceMappingURL=declarativeExperiments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declarativeExperiments.js","sourceRoot":"","sources":["../../../../src/lib/features/core/declarativeExperiments.ts"],"names":[],"mappings":"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"}
@@ -239,6 +239,36 @@ export interface VariantResponse {
239
239
  variantId: string;
240
240
  assignedAt: string;
241
241
  }
242
+ /**
243
+ * A single declarative DOM change applied for an assigned variant — the no-code
244
+ * rendering primitive. The engine applies these on `init()` so a marketer can
245
+ * run a test (different headline, hidden banner, redirect to another page)
246
+ * without an engineer hand-writing `if (variant === "B")` branching.
247
+ */
248
+ export type VariantChange = {
249
+ type: 'redirect';
250
+ url: string;
251
+ } | {
252
+ type: 'text';
253
+ selector: string;
254
+ value: string;
255
+ } | {
256
+ type: 'html';
257
+ selector: string;
258
+ value: string;
259
+ } | {
260
+ type: 'hide';
261
+ selector: string;
262
+ } | {
263
+ type: 'style';
264
+ selector: string;
265
+ property: string;
266
+ value: string;
267
+ } | {
268
+ type: 'addClass';
269
+ selector: string;
270
+ value: string;
271
+ };
242
272
  /**
243
273
  * Local experiment variant definition used by the client-side
244
274
  * assignment engine (ported from sdk.js).
@@ -248,6 +278,15 @@ export interface ExperimentVariant {
248
278
  id: string;
249
279
  /** Traffic allocation weight */
250
280
  weight: number;
281
+ /** Optional human-readable label (shown in the dashboard). */
282
+ label?: string;
283
+ /**
284
+ * Split-URL / redirect test shortcut — visitors assigned this variant are
285
+ * sent to `redirectUrl`. Equivalent to a single `{ type: 'redirect' }` change.
286
+ */
287
+ redirectUrl?: string;
288
+ /** Declarative DOM changes applied when this variant is assigned. */
289
+ changes?: VariantChange[];
251
290
  }
252
291
  /**
253
292
  * Lightweight experiment config passed to `initExperiments()`.
@@ -432,6 +471,38 @@ export declare class Experiment extends FlowGridTransport {
432
471
  * @param experiments - Array of experiment configs to register
433
472
  */
434
473
  initExperiments(experiments: ExperimentInitConfig[]): Promise<void>;
474
+ private antiFlickerStyleEl;
475
+ private antiFlickerTimer;
476
+ /** Experiments whose assigned variant has already had its changes applied + exposure fired. */
477
+ private appliedExperiments;
478
+ /** Normalises a variant's `redirectUrl` shortcut + `changes` into one list. */
479
+ private variantChanges;
480
+ /** All non-redirect selectors across the passed configs — used for anti-flicker. */
481
+ private collectChangeSelectors;
482
+ private injectAntiFlicker;
483
+ private removeAntiFlicker;
484
+ private applyDomChange;
485
+ /**
486
+ * Apply the assigned variant's declarative changes for every registered
487
+ * experiment, then fire one exposure per experiment. Redirects take priority
488
+ * and short-circuit (the new page re-runs init). DOM changes wait for the
489
+ * document to be ready. Idempotent per experiment.
490
+ */
491
+ private applyAssignedChanges;
492
+ /**
493
+ * Manually (re-)apply the assigned variant's changes for one experiment —
494
+ * useful after client-side navigation re-renders the DOM.
495
+ */
496
+ applyVariant(experimentId: string): void;
497
+ /**
498
+ * Zero-config init: fetch this site's running experiments from the server and
499
+ * run them. This is what lets the no-build snippet run experiments with no
500
+ * author JS — the dashboard is the only place experiments are configured.
501
+ *
502
+ * Best-effort: a network/permission failure is a silent no-op (the page just
503
+ * shows its control experience), never a thrown error.
504
+ */
505
+ initFromServer(): Promise<void>;
435
506
  /**
436
507
  * Returns the locally assigned variant for an experiment.
437
508
  *
@@ -184,6 +184,13 @@ class Experiment extends transport_1.FlowGridTransport {
184
184
  this.experiments = {};
185
185
  /** Local variant assignments: { [experiment_id]: variant_id } */
186
186
  this.assignments = {};
187
+ // ---------------------------------------------------------------------------
188
+ // CLIENT-SIDE ENGINE — declarative variant rendering (no-code)
189
+ // ---------------------------------------------------------------------------
190
+ this.antiFlickerStyleEl = null;
191
+ this.antiFlickerTimer = null;
192
+ /** Experiments whose assigned variant has already had its changes applied + exposure fired. */
193
+ this.appliedExperiments = new Set();
187
194
  }
188
195
  // ---------------------------------------------------------------------------
189
196
  // CLIENT-SIDE ENGINE — SSR-safe persistence (localStorage + cookie mirror)
@@ -534,8 +541,163 @@ class Experiment extends transport_1.FlowGridTransport {
534
541
  */
535
542
  async initExperiments(experiments) {
536
543
  this.assignments = this.loadAssignments();
537
- if (experiments.length > 0) {
538
- await this.verifyExperiments(experiments);
544
+ // Anti-flicker: hide every element a variant might change *before* the
545
+ // (async) verify round-trip, so visitors never see the original flash to
546
+ // the variant. A safety timeout reveals everything even if init stalls.
547
+ const selectors = this.collectChangeSelectors(experiments);
548
+ if (selectors.length > 0)
549
+ this.injectAntiFlicker(selectors);
550
+ try {
551
+ if (experiments.length > 0) {
552
+ await this.verifyExperiments(experiments);
553
+ }
554
+ this.applyAssignedChanges();
555
+ }
556
+ finally {
557
+ this.removeAntiFlicker();
558
+ }
559
+ }
560
+ /** Normalises a variant's `redirectUrl` shortcut + `changes` into one list. */
561
+ variantChanges(variant) {
562
+ if (!variant)
563
+ return [];
564
+ const out = [];
565
+ if (variant.redirectUrl)
566
+ out.push({ type: 'redirect', url: variant.redirectUrl });
567
+ if (Array.isArray(variant.changes))
568
+ out.push(...variant.changes);
569
+ return out;
570
+ }
571
+ /** All non-redirect selectors across the passed configs — used for anti-flicker. */
572
+ collectChangeSelectors(experiments) {
573
+ const set = new Set();
574
+ for (const exp of experiments) {
575
+ for (const v of exp.variants) {
576
+ for (const c of this.variantChanges(v)) {
577
+ if (c.type !== 'redirect')
578
+ set.add(c.selector);
579
+ }
580
+ }
581
+ }
582
+ return Array.from(set);
583
+ }
584
+ injectAntiFlicker(selectors) {
585
+ if (typeof document === 'undefined' || this.antiFlickerStyleEl)
586
+ return;
587
+ try {
588
+ const style = document.createElement('style');
589
+ style.setAttribute('data-flowgrid-antiflicker', '');
590
+ style.textContent = `${selectors.join(',')}{visibility:hidden !important}`;
591
+ (document.head || document.documentElement).appendChild(style);
592
+ this.antiFlickerStyleEl = style;
593
+ // Never leave the page hidden — reveal after 4s no matter what.
594
+ this.antiFlickerTimer = setTimeout(() => this.removeAntiFlicker(), 4000);
595
+ }
596
+ catch { /* ignore */ }
597
+ }
598
+ removeAntiFlicker() {
599
+ if (this.antiFlickerTimer) {
600
+ clearTimeout(this.antiFlickerTimer);
601
+ this.antiFlickerTimer = null;
602
+ }
603
+ try {
604
+ this.antiFlickerStyleEl?.remove();
605
+ }
606
+ catch { /* ignore */ }
607
+ this.antiFlickerStyleEl = null;
608
+ }
609
+ applyDomChange(change) {
610
+ if (typeof document === 'undefined')
611
+ return;
612
+ const nodes = document.querySelectorAll(change.selector);
613
+ nodes.forEach((el) => {
614
+ switch (change.type) {
615
+ case 'text':
616
+ el.textContent = change.value;
617
+ break;
618
+ case 'html':
619
+ el.innerHTML = change.value;
620
+ break;
621
+ case 'hide':
622
+ el.style.display = 'none';
623
+ break;
624
+ case 'style':
625
+ el.style.setProperty(change.property, change.value);
626
+ break;
627
+ case 'addClass':
628
+ el.classList.add(...change.value.split(/\s+/).filter(Boolean));
629
+ break;
630
+ }
631
+ });
632
+ }
633
+ /**
634
+ * Apply the assigned variant's declarative changes for every registered
635
+ * experiment, then fire one exposure per experiment. Redirects take priority
636
+ * and short-circuit (the new page re-runs init). DOM changes wait for the
637
+ * document to be ready. Idempotent per experiment.
638
+ */
639
+ applyAssignedChanges() {
640
+ if (typeof window === 'undefined')
641
+ return;
642
+ for (const [experimentId, config] of Object.entries(this.experiments)) {
643
+ if (this.appliedExperiments.has(experimentId))
644
+ continue;
645
+ const variantId = this.assignments[experimentId];
646
+ if (!variantId)
647
+ continue;
648
+ const variant = config.variants.find((v) => v.id === variantId);
649
+ const changes = this.variantChanges(variant);
650
+ // Redirect first — if we're not already on the target, go there. The
651
+ // destination page's own init() handles exposure for the redirected view.
652
+ const redirect = changes.find((c) => c.type === 'redirect');
653
+ if (redirect) {
654
+ const target = new URL(redirect.url, window.location.href);
655
+ if (target.href !== window.location.href) {
656
+ this.appliedExperiments.add(experimentId);
657
+ this.trackLocalExposure(experimentId).catch(() => { });
658
+ window.location.replace(target.href);
659
+ return;
660
+ }
661
+ }
662
+ const domChanges = changes.filter((c) => c.type !== 'redirect');
663
+ const run = () => domChanges.forEach((c) => this.applyDomChange(c));
664
+ if (typeof document !== 'undefined' && document.readyState === 'loading') {
665
+ document.addEventListener('DOMContentLoaded', run, { once: true });
666
+ }
667
+ else {
668
+ run();
669
+ }
670
+ this.appliedExperiments.add(experimentId);
671
+ // Auto-fire exposure so no-code users get results without extra calls.
672
+ this.trackLocalExposure(experimentId).catch(() => { });
673
+ }
674
+ }
675
+ /**
676
+ * Manually (re-)apply the assigned variant's changes for one experiment —
677
+ * useful after client-side navigation re-renders the DOM.
678
+ */
679
+ applyVariant(experimentId) {
680
+ this.appliedExperiments.delete(experimentId);
681
+ this.applyAssignedChanges();
682
+ }
683
+ /**
684
+ * Zero-config init: fetch this site's running experiments from the server and
685
+ * run them. This is what lets the no-build snippet run experiments with no
686
+ * author JS — the dashboard is the only place experiments are configured.
687
+ *
688
+ * Best-effort: a network/permission failure is a silent no-op (the page just
689
+ * shows its control experience), never a thrown error.
690
+ */
691
+ async initFromServer() {
692
+ try {
693
+ const res = await fetch(`${this.endpoint}/api/v1/experiments/active?web_id=${encodeURIComponent(this.webId)}`);
694
+ const json = await res.json();
695
+ if (json?.ok && Array.isArray(json.data) && json.data.length > 0) {
696
+ await this.initExperiments(json.data);
697
+ }
698
+ }
699
+ catch {
700
+ /* offline, blocked, or no experiments — leave the control experience */
539
701
  }
540
702
  }
541
703
  /**