@sentientui/core 0.26.0 → 0.27.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/dist/chunk-TRBPPGFT.mjs +2 -0
- package/dist/chunk-TRBPPGFT.mjs.map +1 -0
- package/dist/{index-DubrRV6l.d.ts → index-B5b5LlRJ.d.cts} +26 -215
- package/dist/{index-Ce3IPLrF.d.cts → index-NqZbPgmm.d.ts} +26 -215
- package/dist/index-engagement.js +1 -1
- package/dist/index-engagement.js.map +1 -1
- package/dist/index-engagement.mjs +1 -1
- package/dist/index-graph.d.cts +4 -3
- package/dist/index-graph.d.ts +4 -3
- package/dist/index-graph.js +1 -1
- package/dist/index-graph.js.map +1 -1
- package/dist/index-graph.mjs +1 -1
- package/dist/index-graph.mjs.map +1 -1
- package/dist/index-local.d.cts +2 -2
- package/dist/index-local.d.ts +2 -2
- package/dist/index-server.d.cts +9 -2
- package/dist/index-server.d.ts +9 -2
- package/dist/index-server.js +1 -1
- package/dist/index-server.js.map +1 -1
- package/dist/index-server.mjs +1 -1
- package/dist/index-server.mjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/session-meta-dN92q19_.d.cts +378 -0
- package/dist/session-meta-dN92q19_.d.ts +378 -0
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/dist/chunk-RCN2SIB6.mjs +0 -2
- package/dist/chunk-RCN2SIB6.mjs.map +0 -1
- package/dist/session-meta-C-bMqVeq.d.cts +0 -130
- package/dist/session-meta-C-bMqVeq.d.ts +0 -130
|
@@ -1,135 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { W as SlotConfigEntry, V as SitePalette, X as SlotDeclInput, z as CompoundLocator } from './session-meta-dN92q19_.cjs';
|
|
2
2
|
import { SlotResult } from '@sentientui/policy';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Composition Blocks (spec: 2026-08-20-nocode-composition-variants-design.md §4).
|
|
6
|
-
*
|
|
7
|
-
* A bounded, TYPED component tree — never HTML — that a registry arm may carry
|
|
8
|
-
* (`published_config.arms[].blocks`). The vocabulary is the whitelist: every
|
|
9
|
-
* prop value is an enumerated token, validated server-side before publish
|
|
10
|
-
* (apps/api/src/domain/composition-blocks.ts) and rendered client-side through
|
|
11
|
-
* document.createElement + property assignment only. No innerHTML/outerHTML/
|
|
12
|
-
* insertAdjacentHTML exists anywhere on this path — the security property is
|
|
13
|
-
* preserved by never accepting HTML, not by sanitizing it, which is why there
|
|
14
|
-
* is no sanitizer to keep honest.
|
|
15
|
-
*
|
|
16
|
-
* Token lists live here (not in the API domain like SlotOps' mirrors) because
|
|
17
|
-
* three parties must agree byte-for-byte: the server validator, the snippet
|
|
18
|
-
* renderer, and eventually the React renderer (§11) — a drifted copy would let
|
|
19
|
-
* a published arm fail to render, which the fail-safe turns into an invisibly
|
|
20
|
-
* missing section, not an error.
|
|
21
|
-
*/
|
|
22
|
-
declare const BLOCK_GAPS: readonly ["none", "sm", "md", "lg"];
|
|
23
|
-
declare const BLOCK_ALIGNS: readonly ["start", "center", "end", "stretch"];
|
|
24
|
-
declare const BLOCK_JUSTIFIES: readonly ["start", "center", "end", "between"];
|
|
25
|
-
declare const BLOCK_SIZES: readonly ["sm", "md", "lg"];
|
|
26
|
-
declare const BLOCK_WEIGHTS: readonly ["normal", "medium", "bold"];
|
|
27
|
-
declare const BLOCK_TONES: readonly ["default", "muted", "accent"];
|
|
28
|
-
declare const BLOCK_EMPHASES: readonly ["primary", "secondary", "ghost"];
|
|
29
|
-
declare const BLOCK_TEXT_ALIGNS: readonly ["left", "center", "right"];
|
|
30
|
-
declare const BLOCK_RATIOS: readonly ["auto", "square", "landscape", "wide"];
|
|
31
|
-
declare const BLOCK_FITS: readonly ["cover", "contain"];
|
|
32
|
-
declare const BLOCK_GRID_COLUMNS: readonly [2, 3, 4];
|
|
33
|
-
declare const BLOCK_HEADING_LEVELS: readonly [2, 3, 4];
|
|
34
|
-
type BlockGap = (typeof BLOCK_GAPS)[number];
|
|
35
|
-
type BlockAlign = (typeof BLOCK_ALIGNS)[number];
|
|
36
|
-
type BlockJustify = (typeof BLOCK_JUSTIFIES)[number];
|
|
37
|
-
type BlockSize = (typeof BLOCK_SIZES)[number];
|
|
38
|
-
type BlockWeight = (typeof BLOCK_WEIGHTS)[number];
|
|
39
|
-
type BlockTone = (typeof BLOCK_TONES)[number];
|
|
40
|
-
type BlockEmphasis = (typeof BLOCK_EMPHASES)[number];
|
|
41
|
-
type BlockTextAlign = (typeof BLOCK_TEXT_ALIGNS)[number];
|
|
42
|
-
type BlockRatio = (typeof BLOCK_RATIOS)[number];
|
|
43
|
-
type BlockFit = (typeof BLOCK_FITS)[number];
|
|
44
|
-
/** Flex row/column container. */
|
|
45
|
-
type StackBlock = {
|
|
46
|
-
type: 'stack';
|
|
47
|
-
direction: 'row' | 'column';
|
|
48
|
-
children: BlockNode[];
|
|
49
|
-
gap?: BlockGap;
|
|
50
|
-
align?: BlockAlign;
|
|
51
|
-
justify?: BlockJustify;
|
|
52
|
-
wrap?: boolean;
|
|
53
|
-
};
|
|
54
|
-
/** 2–4 equal-column grid container. */
|
|
55
|
-
type GridBlock = {
|
|
56
|
-
type: 'grid';
|
|
57
|
-
columns: (typeof BLOCK_GRID_COLUMNS)[number];
|
|
58
|
-
children: BlockNode[];
|
|
59
|
-
gap?: BlockGap;
|
|
60
|
-
align?: BlockAlign;
|
|
61
|
-
};
|
|
62
|
-
/** Paragraph / label. */
|
|
63
|
-
type TextBlock = {
|
|
64
|
-
type: 'text';
|
|
65
|
-
value: string;
|
|
66
|
-
size?: BlockSize;
|
|
67
|
-
weight?: BlockWeight;
|
|
68
|
-
tone?: BlockTone;
|
|
69
|
-
align?: BlockTextAlign;
|
|
70
|
-
};
|
|
71
|
-
/** h2–h4 — never h1 (the page owns its h1). */
|
|
72
|
-
type HeadingBlock = {
|
|
73
|
-
type: 'heading';
|
|
74
|
-
value: string;
|
|
75
|
-
level: (typeof BLOCK_HEADING_LEVELS)[number];
|
|
76
|
-
size?: BlockSize;
|
|
77
|
-
align?: BlockTextAlign;
|
|
78
|
-
};
|
|
79
|
-
/** Link styled as a button. `tag` feeds agent legibility (agentDataByVariant). */
|
|
80
|
-
type ButtonBlock = {
|
|
81
|
-
type: 'button';
|
|
82
|
-
label: string;
|
|
83
|
-
href: string;
|
|
84
|
-
emphasis?: BlockEmphasis;
|
|
85
|
-
size?: BlockSize;
|
|
86
|
-
tag?: string;
|
|
87
|
-
};
|
|
88
|
-
/** Inline text link. */
|
|
89
|
-
type LinkBlock = {
|
|
90
|
-
type: 'link';
|
|
91
|
-
label: string;
|
|
92
|
-
href: string;
|
|
93
|
-
tag?: string;
|
|
94
|
-
};
|
|
95
|
-
/** Image. `alt` is required; empty only with an explicit `decorative: true`. */
|
|
96
|
-
type ImageBlock = {
|
|
97
|
-
type: 'image';
|
|
98
|
-
src: string;
|
|
99
|
-
alt: string;
|
|
100
|
-
decorative?: boolean;
|
|
101
|
-
ratio?: BlockRatio;
|
|
102
|
-
fit?: BlockFit;
|
|
103
|
-
};
|
|
104
|
-
/** Eyebrow / pill. */
|
|
105
|
-
type BadgeBlock = {
|
|
106
|
-
type: 'badge';
|
|
107
|
-
value: string;
|
|
108
|
-
tone?: BlockTone;
|
|
109
|
-
};
|
|
110
|
-
/** Vertical rhythm. */
|
|
111
|
-
type SpacerBlock = {
|
|
112
|
-
type: 'spacer';
|
|
113
|
-
size: BlockSize;
|
|
114
|
-
};
|
|
115
|
-
type BlockNode = StackBlock | GridBlock | TextBlock | HeadingBlock | ButtonBlock | LinkBlock | ImageBlock | BadgeBlock | SpacerBlock;
|
|
116
|
-
/** The derived site palette (spec §4 "Colour and type: derived, not chosen").
|
|
117
|
-
* Sampled by the on-site editor from the live page's own buttons — computed
|
|
118
|
-
* styles, so values are plain colors (rgb/hex), never var()/url() — validated
|
|
119
|
-
* server-side, stored per project, and served with the decision so injected
|
|
120
|
-
* blocks render in the merchant's own primary color and corner radius.
|
|
121
|
-
* Absent → the renderer's neutral inherit-first defaults. */
|
|
122
|
-
type SitePalette = {
|
|
123
|
-
primaryBg: string;
|
|
124
|
-
primaryText: string;
|
|
125
|
-
radius: string;
|
|
126
|
-
};
|
|
127
|
-
declare const MAX_BLOCK_NODES = 64;
|
|
128
|
-
declare const MAX_BLOCK_DEPTH = 5;
|
|
129
|
-
declare const MAX_BLOCK_CHILDREN = 12;
|
|
130
|
-
declare const MAX_BLOCK_ARMS = 4;
|
|
131
|
-
declare const MAX_BLOCK_TEXT_LEN = 500;
|
|
132
|
-
|
|
133
4
|
/** Manages anonymous session identity with cookie + localStorage layers. */
|
|
134
5
|
type SessionConfig = {
|
|
135
6
|
cookieName?: string;
|
|
@@ -250,90 +121,6 @@ type GraphClient = {
|
|
|
250
121
|
*/
|
|
251
122
|
declare function sanitizePageUrl(href: string): string;
|
|
252
123
|
|
|
253
|
-
/**
|
|
254
|
-
* Decision snapshot: the SPA / return-visit pre-paint source. Written after
|
|
255
|
-
* every successful decide; read by the inline pre-paint script (before any
|
|
256
|
-
* framework code runs) and by init() to seed slot/persona state.
|
|
257
|
-
*/
|
|
258
|
-
|
|
259
|
-
declare const SNAPSHOT_STORAGE_KEY_PREFIX = "_snt_snap:";
|
|
260
|
-
/** Versioned compound locator: resolve id → dataAttr → selector, then verify
|
|
261
|
-
* against fingerprint. Lets a slot survive DOM/markup drift. */
|
|
262
|
-
type CompoundLocator = {
|
|
263
|
-
v?: number;
|
|
264
|
-
id?: string;
|
|
265
|
-
dataAttr?: {
|
|
266
|
-
name: string;
|
|
267
|
-
value: string;
|
|
268
|
-
};
|
|
269
|
-
selector?: string;
|
|
270
|
-
urlMatch?: string;
|
|
271
|
-
fingerprint?: {
|
|
272
|
-
tag?: string;
|
|
273
|
-
text?: string;
|
|
274
|
-
};
|
|
275
|
-
semanticId?: string;
|
|
276
|
-
};
|
|
277
|
-
/** Bounded, declarative operations a registry arm may apply to its element.
|
|
278
|
-
* The style set is a fixed whitelist (validated server-side); no arbitrary CSS,
|
|
279
|
-
* HTML, or JS ever. `text` is applied via textContent; https-only URLs.
|
|
280
|
-
* moveBefore/moveAfter (exactly one) reposition the element relative to a
|
|
281
|
-
* uniquely-resolving sibling anchor — post-decide only, never pre-paint. */
|
|
282
|
-
type SlotOps = {
|
|
283
|
-
text?: string;
|
|
284
|
-
style?: Record<string, string>;
|
|
285
|
-
hidden?: boolean;
|
|
286
|
-
href?: string;
|
|
287
|
-
imageSrc?: string;
|
|
288
|
-
imageAlt?: string;
|
|
289
|
-
moveBefore?: CompoundLocator;
|
|
290
|
-
moveAfter?: CompoundLocator;
|
|
291
|
-
};
|
|
292
|
-
/** Registry-mode apply info per slot: where to apply and what to set. Stored so
|
|
293
|
-
* a returning visitor's pre-paint can reapply it. `target` is the Phase-2 bare
|
|
294
|
-
* selector; `locator` (Phase 3) is the compound locator, preferred when present. */
|
|
295
|
-
type SlotConfigEntry = {
|
|
296
|
-
kind: 'tokens' | 'arms';
|
|
297
|
-
target?: string;
|
|
298
|
-
locator?: CompoundLocator;
|
|
299
|
-
content?: string;
|
|
300
|
-
ops?: SlotOps;
|
|
301
|
-
/** Composition Blocks per arm — ALL arms, not just the served one, because
|
|
302
|
-
* Option-B rendering pre-paints every arm hidden and reveals the served one
|
|
303
|
-
* (spec §6). Holdout sessions receive the baseline arm's tree only, so the
|
|
304
|
-
* control group's DOM stays meaningful. Absent for non-composition slots. */
|
|
305
|
-
blocks?: Record<string, BlockNode>;
|
|
306
|
-
};
|
|
307
|
-
type DecisionSnapshot = {
|
|
308
|
-
v: 1;
|
|
309
|
-
persona: string;
|
|
310
|
-
band: 'low' | 'medium' | 'high';
|
|
311
|
-
slots: Record<string, SlotResult>;
|
|
312
|
-
layoutOrder: string[] | null;
|
|
313
|
-
savedAt: number;
|
|
314
|
-
slotConfig?: Record<string, SlotConfigEntry>;
|
|
315
|
-
/** Derived site palette for Composition Block rendering — cached so the
|
|
316
|
-
* pre-paint render already looks native (a palette that pops in post-decide
|
|
317
|
-
* would be its own flash). */
|
|
318
|
-
palette?: SitePalette;
|
|
319
|
-
};
|
|
320
|
-
/** Returns null on missing, corrupt, or wrong-version data — never throws. */
|
|
321
|
-
declare function readSnapshot(apiKey: string): DecisionSnapshot | null;
|
|
322
|
-
/** Best-effort persist — storage failures are swallowed. */
|
|
323
|
-
declare function writeSnapshot(apiKey: string, snap: DecisionSnapshot): void;
|
|
324
|
-
/**
|
|
325
|
-
* Inline pre-paint script (Rung 1a): reads the snapshot and sets
|
|
326
|
-
* `data-sentient-persona` / `data-sentient-confidence` on <html> before
|
|
327
|
-
* first paint. Single-writer: it never overwrites attributes already set.
|
|
328
|
-
*
|
|
329
|
-
* Safety properties (pinned by tests):
|
|
330
|
-
* - apiKey goes through JSON.stringify, then '<' is escaped to <, so a
|
|
331
|
-
* hostile key can neither break the JS string nor terminate the <script>.
|
|
332
|
-
* - Built by string concatenation and contains no backticks, so the output
|
|
333
|
-
* survives being embedded in template-literal-based renderers.
|
|
334
|
-
*/
|
|
335
|
-
declare function renderPrePaintScript(apiKey: string): string;
|
|
336
|
-
|
|
337
124
|
declare const PROD_KEYLESS_ERROR = "[sentient] No API key configured \u2014 nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development.";
|
|
338
125
|
declare const LOCAL_MODE_BANNER = "[sentient] Local mode \u2014 decisions are simulated on-device and nothing is sent over the network. Add an API key to learn from real traffic.";
|
|
339
126
|
|
|
@@ -445,6 +232,13 @@ type SentientConfig = {
|
|
|
445
232
|
* server-rendered markup on first paint.
|
|
446
233
|
*/
|
|
447
234
|
initialSlots?: Record<string, SlotResult>;
|
|
235
|
+
/**
|
|
236
|
+
* Registry slot config decided outside the browser (SSR). Seeds
|
|
237
|
+
* `getSlotConfig()` so server-rendered block/content arms survive hydration.
|
|
238
|
+
*/
|
|
239
|
+
initialSlotConfig?: Record<string, SlotConfigEntry>;
|
|
240
|
+
/** Site palette decided outside the browser (SSR). Seeds `getSitePalette()`. */
|
|
241
|
+
initialPalette?: SitePalette;
|
|
448
242
|
/**
|
|
449
243
|
* Persona decided during SSR. Takes priority over the html-attribute
|
|
450
244
|
* adoption and the local snapshot.
|
|
@@ -529,6 +323,14 @@ type DecideInput = {
|
|
|
529
323
|
* entirely on older deployments. Omit if the caller has no version to report.
|
|
530
324
|
*/
|
|
531
325
|
v?: string;
|
|
326
|
+
/**
|
|
327
|
+
* Snippet only: which inline pre-paint contract the install carries
|
|
328
|
+
* (`window.__sntPP.v`), or 0 for the two-tag install with no inline script.
|
|
329
|
+
* Sent as `pp` alongside `v`; the server persists it for the dashboard's
|
|
330
|
+
* install-health nudge and no serving behaviour depends on it. Additive —
|
|
331
|
+
* older deployments ignore it entirely.
|
|
332
|
+
*/
|
|
333
|
+
pp?: number;
|
|
532
334
|
};
|
|
533
335
|
type WeightEntry = {
|
|
534
336
|
variantId: string;
|
|
@@ -588,6 +390,15 @@ type SentientClient = {
|
|
|
588
390
|
decide(input: DecideInput): Promise<DecideOutcome | null>;
|
|
589
391
|
/** Slot result served this session (decide result, SSR seed, snapshot, or failure baseline). Null when unknown. */
|
|
590
392
|
getSlotResult(slotId: string): SlotResult | null;
|
|
393
|
+
/** Registry slot config served this session (content/ops/blocks for the slot).
|
|
394
|
+
* Null until a registry-mode decide, SSR seed, or snapshot provides it. */
|
|
395
|
+
getSlotConfig(slotId: string): SlotConfigEntry | null;
|
|
396
|
+
/** Report mounted AdaptiveSlot ids the server has no config for, so they
|
|
397
|
+
* auto-register as draft slots. Fire-and-forget, batched, deduped per
|
|
398
|
+
* client — never blocks rendering and never throws. */
|
|
399
|
+
reportSlots(slotIds: string[]): void;
|
|
400
|
+
/** Site palette served with registry block decisions. Null when absent. */
|
|
401
|
+
getSitePalette(): SitePalette | null;
|
|
591
402
|
/** Current persona estimate. Band is always `confidenceBand(confidence)`. Null when nothing is known yet. */
|
|
592
403
|
getPersona(): {
|
|
593
404
|
persona: string;
|
|
@@ -635,4 +446,4 @@ declare function grantConsent(apiKey?: string): void;
|
|
|
635
446
|
*/
|
|
636
447
|
declare function init(config: SentientConfig): SentientClient;
|
|
637
448
|
|
|
638
|
-
export { type
|
|
449
|
+
export { type AssignResult as A, type ComponentGoalOptions as C, type DecideInput as D, type EventQueue as E, type GoalDefinition as G, LEGACY_SESSION_COOKIE_NAME as L, type MicroSignalEmitter as M, PROD_KEYLESS_ERROR as P, type QueueConfig as Q, type SectionMapEntry as S, type WeightEntry as W, _registerConsentUpgradeInit as _, type Assignment as a, type AssignmentCache as b, type ComponentWeightEntry as c, type DecideOutcome as d, type EventType as e, type GoalOptions as f, type GraphClient as g, type GraphConfig as h, type GraphSnapshot as i, LOCAL_MODE_BANNER as j, type MicroSignalType as k, type PageNode as l, type SentientClient as m, type SentientConfig as n, type SentientEvent as o, type SessionConfig as p, type SessionManager as q, attachMicroSignalDetectors as r, grantConsent as s, init as t, isDoNotTrackEnabled as u, sanitizePageUrl as v, sessionCookieName as w };
|
|
@@ -1,135 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { W as SlotConfigEntry, V as SitePalette, X as SlotDeclInput, z as CompoundLocator } from './session-meta-dN92q19_.js';
|
|
2
2
|
import { SlotResult } from '@sentientui/policy';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Composition Blocks (spec: 2026-08-20-nocode-composition-variants-design.md §4).
|
|
6
|
-
*
|
|
7
|
-
* A bounded, TYPED component tree — never HTML — that a registry arm may carry
|
|
8
|
-
* (`published_config.arms[].blocks`). The vocabulary is the whitelist: every
|
|
9
|
-
* prop value is an enumerated token, validated server-side before publish
|
|
10
|
-
* (apps/api/src/domain/composition-blocks.ts) and rendered client-side through
|
|
11
|
-
* document.createElement + property assignment only. No innerHTML/outerHTML/
|
|
12
|
-
* insertAdjacentHTML exists anywhere on this path — the security property is
|
|
13
|
-
* preserved by never accepting HTML, not by sanitizing it, which is why there
|
|
14
|
-
* is no sanitizer to keep honest.
|
|
15
|
-
*
|
|
16
|
-
* Token lists live here (not in the API domain like SlotOps' mirrors) because
|
|
17
|
-
* three parties must agree byte-for-byte: the server validator, the snippet
|
|
18
|
-
* renderer, and eventually the React renderer (§11) — a drifted copy would let
|
|
19
|
-
* a published arm fail to render, which the fail-safe turns into an invisibly
|
|
20
|
-
* missing section, not an error.
|
|
21
|
-
*/
|
|
22
|
-
declare const BLOCK_GAPS: readonly ["none", "sm", "md", "lg"];
|
|
23
|
-
declare const BLOCK_ALIGNS: readonly ["start", "center", "end", "stretch"];
|
|
24
|
-
declare const BLOCK_JUSTIFIES: readonly ["start", "center", "end", "between"];
|
|
25
|
-
declare const BLOCK_SIZES: readonly ["sm", "md", "lg"];
|
|
26
|
-
declare const BLOCK_WEIGHTS: readonly ["normal", "medium", "bold"];
|
|
27
|
-
declare const BLOCK_TONES: readonly ["default", "muted", "accent"];
|
|
28
|
-
declare const BLOCK_EMPHASES: readonly ["primary", "secondary", "ghost"];
|
|
29
|
-
declare const BLOCK_TEXT_ALIGNS: readonly ["left", "center", "right"];
|
|
30
|
-
declare const BLOCK_RATIOS: readonly ["auto", "square", "landscape", "wide"];
|
|
31
|
-
declare const BLOCK_FITS: readonly ["cover", "contain"];
|
|
32
|
-
declare const BLOCK_GRID_COLUMNS: readonly [2, 3, 4];
|
|
33
|
-
declare const BLOCK_HEADING_LEVELS: readonly [2, 3, 4];
|
|
34
|
-
type BlockGap = (typeof BLOCK_GAPS)[number];
|
|
35
|
-
type BlockAlign = (typeof BLOCK_ALIGNS)[number];
|
|
36
|
-
type BlockJustify = (typeof BLOCK_JUSTIFIES)[number];
|
|
37
|
-
type BlockSize = (typeof BLOCK_SIZES)[number];
|
|
38
|
-
type BlockWeight = (typeof BLOCK_WEIGHTS)[number];
|
|
39
|
-
type BlockTone = (typeof BLOCK_TONES)[number];
|
|
40
|
-
type BlockEmphasis = (typeof BLOCK_EMPHASES)[number];
|
|
41
|
-
type BlockTextAlign = (typeof BLOCK_TEXT_ALIGNS)[number];
|
|
42
|
-
type BlockRatio = (typeof BLOCK_RATIOS)[number];
|
|
43
|
-
type BlockFit = (typeof BLOCK_FITS)[number];
|
|
44
|
-
/** Flex row/column container. */
|
|
45
|
-
type StackBlock = {
|
|
46
|
-
type: 'stack';
|
|
47
|
-
direction: 'row' | 'column';
|
|
48
|
-
children: BlockNode[];
|
|
49
|
-
gap?: BlockGap;
|
|
50
|
-
align?: BlockAlign;
|
|
51
|
-
justify?: BlockJustify;
|
|
52
|
-
wrap?: boolean;
|
|
53
|
-
};
|
|
54
|
-
/** 2–4 equal-column grid container. */
|
|
55
|
-
type GridBlock = {
|
|
56
|
-
type: 'grid';
|
|
57
|
-
columns: (typeof BLOCK_GRID_COLUMNS)[number];
|
|
58
|
-
children: BlockNode[];
|
|
59
|
-
gap?: BlockGap;
|
|
60
|
-
align?: BlockAlign;
|
|
61
|
-
};
|
|
62
|
-
/** Paragraph / label. */
|
|
63
|
-
type TextBlock = {
|
|
64
|
-
type: 'text';
|
|
65
|
-
value: string;
|
|
66
|
-
size?: BlockSize;
|
|
67
|
-
weight?: BlockWeight;
|
|
68
|
-
tone?: BlockTone;
|
|
69
|
-
align?: BlockTextAlign;
|
|
70
|
-
};
|
|
71
|
-
/** h2–h4 — never h1 (the page owns its h1). */
|
|
72
|
-
type HeadingBlock = {
|
|
73
|
-
type: 'heading';
|
|
74
|
-
value: string;
|
|
75
|
-
level: (typeof BLOCK_HEADING_LEVELS)[number];
|
|
76
|
-
size?: BlockSize;
|
|
77
|
-
align?: BlockTextAlign;
|
|
78
|
-
};
|
|
79
|
-
/** Link styled as a button. `tag` feeds agent legibility (agentDataByVariant). */
|
|
80
|
-
type ButtonBlock = {
|
|
81
|
-
type: 'button';
|
|
82
|
-
label: string;
|
|
83
|
-
href: string;
|
|
84
|
-
emphasis?: BlockEmphasis;
|
|
85
|
-
size?: BlockSize;
|
|
86
|
-
tag?: string;
|
|
87
|
-
};
|
|
88
|
-
/** Inline text link. */
|
|
89
|
-
type LinkBlock = {
|
|
90
|
-
type: 'link';
|
|
91
|
-
label: string;
|
|
92
|
-
href: string;
|
|
93
|
-
tag?: string;
|
|
94
|
-
};
|
|
95
|
-
/** Image. `alt` is required; empty only with an explicit `decorative: true`. */
|
|
96
|
-
type ImageBlock = {
|
|
97
|
-
type: 'image';
|
|
98
|
-
src: string;
|
|
99
|
-
alt: string;
|
|
100
|
-
decorative?: boolean;
|
|
101
|
-
ratio?: BlockRatio;
|
|
102
|
-
fit?: BlockFit;
|
|
103
|
-
};
|
|
104
|
-
/** Eyebrow / pill. */
|
|
105
|
-
type BadgeBlock = {
|
|
106
|
-
type: 'badge';
|
|
107
|
-
value: string;
|
|
108
|
-
tone?: BlockTone;
|
|
109
|
-
};
|
|
110
|
-
/** Vertical rhythm. */
|
|
111
|
-
type SpacerBlock = {
|
|
112
|
-
type: 'spacer';
|
|
113
|
-
size: BlockSize;
|
|
114
|
-
};
|
|
115
|
-
type BlockNode = StackBlock | GridBlock | TextBlock | HeadingBlock | ButtonBlock | LinkBlock | ImageBlock | BadgeBlock | SpacerBlock;
|
|
116
|
-
/** The derived site palette (spec §4 "Colour and type: derived, not chosen").
|
|
117
|
-
* Sampled by the on-site editor from the live page's own buttons — computed
|
|
118
|
-
* styles, so values are plain colors (rgb/hex), never var()/url() — validated
|
|
119
|
-
* server-side, stored per project, and served with the decision so injected
|
|
120
|
-
* blocks render in the merchant's own primary color and corner radius.
|
|
121
|
-
* Absent → the renderer's neutral inherit-first defaults. */
|
|
122
|
-
type SitePalette = {
|
|
123
|
-
primaryBg: string;
|
|
124
|
-
primaryText: string;
|
|
125
|
-
radius: string;
|
|
126
|
-
};
|
|
127
|
-
declare const MAX_BLOCK_NODES = 64;
|
|
128
|
-
declare const MAX_BLOCK_DEPTH = 5;
|
|
129
|
-
declare const MAX_BLOCK_CHILDREN = 12;
|
|
130
|
-
declare const MAX_BLOCK_ARMS = 4;
|
|
131
|
-
declare const MAX_BLOCK_TEXT_LEN = 500;
|
|
132
|
-
|
|
133
4
|
/** Manages anonymous session identity with cookie + localStorage layers. */
|
|
134
5
|
type SessionConfig = {
|
|
135
6
|
cookieName?: string;
|
|
@@ -250,90 +121,6 @@ type GraphClient = {
|
|
|
250
121
|
*/
|
|
251
122
|
declare function sanitizePageUrl(href: string): string;
|
|
252
123
|
|
|
253
|
-
/**
|
|
254
|
-
* Decision snapshot: the SPA / return-visit pre-paint source. Written after
|
|
255
|
-
* every successful decide; read by the inline pre-paint script (before any
|
|
256
|
-
* framework code runs) and by init() to seed slot/persona state.
|
|
257
|
-
*/
|
|
258
|
-
|
|
259
|
-
declare const SNAPSHOT_STORAGE_KEY_PREFIX = "_snt_snap:";
|
|
260
|
-
/** Versioned compound locator: resolve id → dataAttr → selector, then verify
|
|
261
|
-
* against fingerprint. Lets a slot survive DOM/markup drift. */
|
|
262
|
-
type CompoundLocator = {
|
|
263
|
-
v?: number;
|
|
264
|
-
id?: string;
|
|
265
|
-
dataAttr?: {
|
|
266
|
-
name: string;
|
|
267
|
-
value: string;
|
|
268
|
-
};
|
|
269
|
-
selector?: string;
|
|
270
|
-
urlMatch?: string;
|
|
271
|
-
fingerprint?: {
|
|
272
|
-
tag?: string;
|
|
273
|
-
text?: string;
|
|
274
|
-
};
|
|
275
|
-
semanticId?: string;
|
|
276
|
-
};
|
|
277
|
-
/** Bounded, declarative operations a registry arm may apply to its element.
|
|
278
|
-
* The style set is a fixed whitelist (validated server-side); no arbitrary CSS,
|
|
279
|
-
* HTML, or JS ever. `text` is applied via textContent; https-only URLs.
|
|
280
|
-
* moveBefore/moveAfter (exactly one) reposition the element relative to a
|
|
281
|
-
* uniquely-resolving sibling anchor — post-decide only, never pre-paint. */
|
|
282
|
-
type SlotOps = {
|
|
283
|
-
text?: string;
|
|
284
|
-
style?: Record<string, string>;
|
|
285
|
-
hidden?: boolean;
|
|
286
|
-
href?: string;
|
|
287
|
-
imageSrc?: string;
|
|
288
|
-
imageAlt?: string;
|
|
289
|
-
moveBefore?: CompoundLocator;
|
|
290
|
-
moveAfter?: CompoundLocator;
|
|
291
|
-
};
|
|
292
|
-
/** Registry-mode apply info per slot: where to apply and what to set. Stored so
|
|
293
|
-
* a returning visitor's pre-paint can reapply it. `target` is the Phase-2 bare
|
|
294
|
-
* selector; `locator` (Phase 3) is the compound locator, preferred when present. */
|
|
295
|
-
type SlotConfigEntry = {
|
|
296
|
-
kind: 'tokens' | 'arms';
|
|
297
|
-
target?: string;
|
|
298
|
-
locator?: CompoundLocator;
|
|
299
|
-
content?: string;
|
|
300
|
-
ops?: SlotOps;
|
|
301
|
-
/** Composition Blocks per arm — ALL arms, not just the served one, because
|
|
302
|
-
* Option-B rendering pre-paints every arm hidden and reveals the served one
|
|
303
|
-
* (spec §6). Holdout sessions receive the baseline arm's tree only, so the
|
|
304
|
-
* control group's DOM stays meaningful. Absent for non-composition slots. */
|
|
305
|
-
blocks?: Record<string, BlockNode>;
|
|
306
|
-
};
|
|
307
|
-
type DecisionSnapshot = {
|
|
308
|
-
v: 1;
|
|
309
|
-
persona: string;
|
|
310
|
-
band: 'low' | 'medium' | 'high';
|
|
311
|
-
slots: Record<string, SlotResult>;
|
|
312
|
-
layoutOrder: string[] | null;
|
|
313
|
-
savedAt: number;
|
|
314
|
-
slotConfig?: Record<string, SlotConfigEntry>;
|
|
315
|
-
/** Derived site palette for Composition Block rendering — cached so the
|
|
316
|
-
* pre-paint render already looks native (a palette that pops in post-decide
|
|
317
|
-
* would be its own flash). */
|
|
318
|
-
palette?: SitePalette;
|
|
319
|
-
};
|
|
320
|
-
/** Returns null on missing, corrupt, or wrong-version data — never throws. */
|
|
321
|
-
declare function readSnapshot(apiKey: string): DecisionSnapshot | null;
|
|
322
|
-
/** Best-effort persist — storage failures are swallowed. */
|
|
323
|
-
declare function writeSnapshot(apiKey: string, snap: DecisionSnapshot): void;
|
|
324
|
-
/**
|
|
325
|
-
* Inline pre-paint script (Rung 1a): reads the snapshot and sets
|
|
326
|
-
* `data-sentient-persona` / `data-sentient-confidence` on <html> before
|
|
327
|
-
* first paint. Single-writer: it never overwrites attributes already set.
|
|
328
|
-
*
|
|
329
|
-
* Safety properties (pinned by tests):
|
|
330
|
-
* - apiKey goes through JSON.stringify, then '<' is escaped to <, so a
|
|
331
|
-
* hostile key can neither break the JS string nor terminate the <script>.
|
|
332
|
-
* - Built by string concatenation and contains no backticks, so the output
|
|
333
|
-
* survives being embedded in template-literal-based renderers.
|
|
334
|
-
*/
|
|
335
|
-
declare function renderPrePaintScript(apiKey: string): string;
|
|
336
|
-
|
|
337
124
|
declare const PROD_KEYLESS_ERROR = "[sentient] No API key configured \u2014 nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development.";
|
|
338
125
|
declare const LOCAL_MODE_BANNER = "[sentient] Local mode \u2014 decisions are simulated on-device and nothing is sent over the network. Add an API key to learn from real traffic.";
|
|
339
126
|
|
|
@@ -445,6 +232,13 @@ type SentientConfig = {
|
|
|
445
232
|
* server-rendered markup on first paint.
|
|
446
233
|
*/
|
|
447
234
|
initialSlots?: Record<string, SlotResult>;
|
|
235
|
+
/**
|
|
236
|
+
* Registry slot config decided outside the browser (SSR). Seeds
|
|
237
|
+
* `getSlotConfig()` so server-rendered block/content arms survive hydration.
|
|
238
|
+
*/
|
|
239
|
+
initialSlotConfig?: Record<string, SlotConfigEntry>;
|
|
240
|
+
/** Site palette decided outside the browser (SSR). Seeds `getSitePalette()`. */
|
|
241
|
+
initialPalette?: SitePalette;
|
|
448
242
|
/**
|
|
449
243
|
* Persona decided during SSR. Takes priority over the html-attribute
|
|
450
244
|
* adoption and the local snapshot.
|
|
@@ -529,6 +323,14 @@ type DecideInput = {
|
|
|
529
323
|
* entirely on older deployments. Omit if the caller has no version to report.
|
|
530
324
|
*/
|
|
531
325
|
v?: string;
|
|
326
|
+
/**
|
|
327
|
+
* Snippet only: which inline pre-paint contract the install carries
|
|
328
|
+
* (`window.__sntPP.v`), or 0 for the two-tag install with no inline script.
|
|
329
|
+
* Sent as `pp` alongside `v`; the server persists it for the dashboard's
|
|
330
|
+
* install-health nudge and no serving behaviour depends on it. Additive —
|
|
331
|
+
* older deployments ignore it entirely.
|
|
332
|
+
*/
|
|
333
|
+
pp?: number;
|
|
532
334
|
};
|
|
533
335
|
type WeightEntry = {
|
|
534
336
|
variantId: string;
|
|
@@ -588,6 +390,15 @@ type SentientClient = {
|
|
|
588
390
|
decide(input: DecideInput): Promise<DecideOutcome | null>;
|
|
589
391
|
/** Slot result served this session (decide result, SSR seed, snapshot, or failure baseline). Null when unknown. */
|
|
590
392
|
getSlotResult(slotId: string): SlotResult | null;
|
|
393
|
+
/** Registry slot config served this session (content/ops/blocks for the slot).
|
|
394
|
+
* Null until a registry-mode decide, SSR seed, or snapshot provides it. */
|
|
395
|
+
getSlotConfig(slotId: string): SlotConfigEntry | null;
|
|
396
|
+
/** Report mounted AdaptiveSlot ids the server has no config for, so they
|
|
397
|
+
* auto-register as draft slots. Fire-and-forget, batched, deduped per
|
|
398
|
+
* client — never blocks rendering and never throws. */
|
|
399
|
+
reportSlots(slotIds: string[]): void;
|
|
400
|
+
/** Site palette served with registry block decisions. Null when absent. */
|
|
401
|
+
getSitePalette(): SitePalette | null;
|
|
591
402
|
/** Current persona estimate. Band is always `confidenceBand(confidence)`. Null when nothing is known yet. */
|
|
592
403
|
getPersona(): {
|
|
593
404
|
persona: string;
|
|
@@ -635,4 +446,4 @@ declare function grantConsent(apiKey?: string): void;
|
|
|
635
446
|
*/
|
|
636
447
|
declare function init(config: SentientConfig): SentientClient;
|
|
637
448
|
|
|
638
|
-
export { type
|
|
449
|
+
export { type AssignResult as A, type ComponentGoalOptions as C, type DecideInput as D, type EventQueue as E, type GoalDefinition as G, LEGACY_SESSION_COOKIE_NAME as L, type MicroSignalEmitter as M, PROD_KEYLESS_ERROR as P, type QueueConfig as Q, type SectionMapEntry as S, type WeightEntry as W, _registerConsentUpgradeInit as _, type Assignment as a, type AssignmentCache as b, type ComponentWeightEntry as c, type DecideOutcome as d, type EventType as e, type GoalOptions as f, type GraphClient as g, type GraphConfig as h, type GraphSnapshot as i, LOCAL_MODE_BANNER as j, type MicroSignalType as k, type PageNode as l, type SentientClient as m, type SentientConfig as n, type SentientEvent as o, type SessionConfig as p, type SessionManager as q, attachMicroSignalDetectors as r, grantConsent as s, init as t, isDoNotTrackEnabled as u, sanitizePageUrl as v, sessionCookieName as w };
|
package/dist/index-engagement.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var R=Object.defineProperty,le=Object.defineProperties,ce=Object.getOwnPropertyDescriptor,de=Object.getOwnPropertyDescriptors,ue=Object.getOwnPropertyNames,z=Object.getOwnPropertySymbols;var J=Object.prototype.hasOwnProperty,pe=Object.prototype.propertyIsEnumerable;var Y=(e,t,n)=>t in e?R(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,S=(e,t)=>{for(var n in t||(t={}))J.call(t,n)&&Y(e,n,t[n]);if(z)for(var n of z(t))pe.call(t,n)&&Y(e,n,t[n]);return e},_=(e,t)=>le(e,de(t));var ge=(e,t)=>{for(var n in t)R(e,n,{get:t[n],enumerable:!0})},fe=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ue(t))!J.call(e,o)&&o!==n&&R(e,o,{get:()=>t[o],enumerable:!(a=ce(t,o))||a.enumerable});return e};var me=e=>fe(R({},"__esModule",{value:!0}),e);var Ie={};ge(Ie,{SEMANTIC_TYPES:()=>x,classifyFeatures:()=>T,classifySection:()=>Z,featuresFromElement:()=>C,startEngagementCapture:()=>ie});module.exports=me(Ie);var x=["pricing","hero","social_proof","cta","features","faq","comparison","trust","navigation","generic"],ye={banner:"hero",navigation:"navigation",contentinfo:"footer"};function he(e){let t=e.ariaRole?ye[e.ariaRole.toLowerCase()]:void 0;if(t)return t;if(e.tag==="nav")return"navigation";if(e.tag==="footer")return"footer";if(e.tag==="header")return e.actionCount>=5?"navigation":"hero";let n=`${e.idClass} ${e.headingText}`.toLowerCase();return/\b(navbar|nav-bar|navigation|site-nav|main-nav|topbar|footer)\b/.test(n)?/footer/.test(n)?"footer":"navigation":/\b(hero|masthead|jumbotron)\b/i.test(e.idClass)?"hero":null}function Se(e){return e.actionCount>=1&&e.textLength>0&&e.textLength<200?"cta":"generic"}var we=[["pricing",/\b(pricing|price list|per month|\/mo|subscriptions?)\b|\bplans?\b(?=[^.]{0,40}(from|start|month|year|[$€£]))/i],["faq",/\bfaq\b|frequently asked|common questions?/i],["comparison",/\b(compare|comparison|versus)\b|\bvs\./i],["social_proof",/\b(reviews?|ratings?|testimonial|brands?|galler(y|ies)|logos)\b|trusted by|loved by|case stud|what our customers say/i],["trust",/\b(insurance|warrant(y|ies)|guarantees?|certifi|accredit|security|privacy|compliance|gdpr|encrypt)\b|why choose|about us|our team/i],["cta",/\b(book|booking|reserve|appointments?|newsletter|subscribe)\b|contact us|get in touch|opening hours/i],["features",/\b(features?|benefits?|capabilit|services?|repairs?|menus?|products?)\b|how it works|our process|what we (do|offer)|what you get/i]],O=[["pricing",/(?:[$€£]\s?\d[\d,.]*\s*(?:\/|per\s)\s*(?:mo|month|yr|year|seat|user))|(?:\b(?:starter|basic|pro|growth|premium|enterprise)\b[^.]{0,60}[$€£]\s?\d)/i],["social_proof",/(?:★{2,})|(?:\b\d(?:\.\d)?\s*(?:out of|\/)\s*5\b)|(?:\brated\b)|(?:["“][^"”]{20,160}["”]\s*[—–-]\s*[A-Z][a-z]+)/],["trust",/\b(?:money[- ]back guarantee|free returns?|returns? within|refund(?:s)? within|encrypted|soc ?2|iso ?27001|gdpr[- ]compliant|cancel anytime)\b/i],["comparison",/\b(?:vs|versus)\b\.?[^.!?]{0,80}\b(?:compare|comparison|plans?|features?|alternative)\b|\bhow (?:we|it) compares?\b/i]],X={navigation:"navigation",footer:"navigation",hero:"hero",cta:"cta",generic:"generic"};function be(e){var n;let t=e.querySelector("h1, h2, h3");return((n=t==null?void 0:t.textContent)!=null?n:"").slice(0,160)}function T(e){var o,i;let t=he(e);if(t)return{type:(o=X[t])!=null?o:"generic",strength:"strong"};let n=`${e.idClass} ${e.headingText}`.toLowerCase();for(let[d,s]of we)if(s.test(n))return{type:d,strength:"strong"};for(let[d,s]of O)if(s.test(e.bodyText))return{type:d,strength:"strong"};let a=Se(e);return{type:(i=X[a])!=null?i:"generic",strength:"weak"}}function C(e){var a,o;let t=((a=e.textContent)!=null?a:"").replace(/\s+/g," ").trim(),n=e.getAttribute("role");return S({tag:e.tagName.toLowerCase(),idClass:`${e.id} ${String((o=e.className)!=null?o:"")}`,headingText:be(e),bodyText:t.slice(0,2e3),actionCount:e.querySelectorAll('a, button, [role="button"]').length,textLength:t.length},n?{ariaRole:n}:{})}function Z(e){return T(C(e)).type}var re=require("@sentientui/policy");var ve=require("@sentientui/policy");function ee(e,t,n,a){let o=[];{let s=!1,l=[],f=()=>{if(s)return;let y=Date.now();for(l.push(y);l.length>0&&y-l[0]>500;)l.shift();l.length>=3&&(s=!0,e("rage_click"))};t.addEventListener("click",f),o.push(()=>t.removeEventListener("click",f))}{let i=!1,d=s=>{if(i||!(s.target instanceof Node)||!t.contains(s.target)&&t!==s.target)return;i=!0;let l=typeof window!="undefined"?window.getSelection():null,f=l?l.toString().length:0;e("text_copy",{selectionLength:f})};document.addEventListener("copy",d),o.push(()=>document.removeEventListener("copy",d))}{let i=!1,d=!1,s=null,l=()=>{s!==null&&(clearTimeout(s),s=null)},f=()=>{i||!d||(l(),s=setTimeout(()=>{!i&&d&&(i=!0,e("scroll_hesitation"))},3e3))},y=()=>{l(),f()},g=b=>{for(let k of b)d=k.intersectionRatio>.3,d?f():l()},h=new IntersectionObserver(g,{threshold:[.3]});h.observe(t),window.addEventListener("scroll",y,{passive:!0}),o.push(()=>{h.disconnect(),window.removeEventListener("scroll",y),l()})}if((a==null?void 0:a.tabLoss)!==!1){let i=!1,d=n!=null?n:Date.now(),s=()=>{if(i||document.visibilityState!=="hidden")return;let l=Date.now()-d;l<15e3&&(i=!0,e("tab_loss",{timeOnPage:l}))};document.addEventListener("visibilitychange",s),o.push(()=>document.removeEventListener("visibilitychange",s))}return()=>{for(let i of o)i()}}function te(){return typeof navigator!="undefined"&&navigator.globalPrivacyControl===!0?!0:[typeof navigator!="undefined"?navigator.doNotTrack:void 0,typeof window!="undefined"?window.doNotTrack:void 0,typeof navigator!="undefined"?navigator.msDoNotTrack:void 0].some(t=>t==="1"||t==="yes")}var Te=["data-sentient-id","data-testid","data-test","data-id","data-name","data-cy"];function P(e){var t;return((t=e.textContent)!=null?t:"").replace(/\s+/g," ").trim()}function Ce(e){return{tag:e.tagName.toLowerCase(),text:P(e).slice(0,40)}}function ne(e){return e.replace(/["\\\]]/g,"\\$&")}function E(e,t){try{return e.querySelectorAll(t).length===1}catch(n){return!1}}function oe(e,t){var d;let n=e.tagName.toLowerCase();if(!n)return null;let a=((d=e.getAttribute("class"))!=null?d:"").split(/\s+/).filter(s=>/^[a-zA-Z][\w-]*$/.test(s)),o=[n,...a.map(s=>`${n}.${s}`)];for(let s of o)if(E(t,s))return s;let i=e.parentElement;if(i&&i!==t){let s=oe(i,t);if(s){for(let g of o){let h=`${s} > ${g}`;if(E(t,h))return h}let l=Array.from(i.children).filter(g=>g.tagName.toLowerCase()===n),f=l.indexOf(e),y=l.some(g=>g!==e&&P(g)!==P(e));if(f>=0&&y){let g=`${s} > ${n}:nth-of-type(${f+1})`;if(E(t,g))return g}}}return null}function se(e,t){let n=Ce(e),a=e.getAttribute("id");if(a&&E(t,`#${ne(a)}`))return{v:1,id:a,fingerprint:n};for(let i of Te){let d=e.getAttribute(i);if(d&&E(t,`[${i}="${ne(d)}"]`))return{v:1,dataAttr:{name:i,value:d},fingerprint:n}}let o=oe(e,t);return o?{v:1,selector:o,fingerprint:n}:null}var Ee="section, header, footer, nav, main > div, [data-sentient-section]",ke=2e4;function Re(e){let t=Array.from(e.querySelectorAll(Ee)),n=t.filter(a=>t.filter(o=>o!==a&&a.contains(o)).length<2);return n.filter(a=>!n.some(o=>o!==a&&o.contains(a)))}function xe(e,t,n,a){try{fetch(`${t}/v1/section-map`,{method:"POST",keepalive:!0,headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify({pageUrl:n,sections:a})}).catch(()=>{})}catch(o){}}var I=()=>{};function ie(e,t){var N,L,$,K,G,F,W,j,B,U,H,q;let n=(N=t.doc)!=null?N:typeof document!="undefined"?document:void 0;if(!n||typeof IntersectionObserver=="undefined"||te()||!t.apiKey||!t.apiKey.startsWith("pk_"))return I;let a=((L=t.apiBase)!=null?L:"https://api.sentient-ui.com").replace(/\/+$/,"").replace(/\/v1$/,""),o=Re(n);if(o.length===0)return I;let i=new Map,d=[];for(let r of o){let c=r.getAttribute("data-sentient-type"),p=c&&x.includes(c)?c:null,u=C(r),v=(K=p!=null?p:($=t.typeOf)==null?void 0:$.call(t,r))!=null?K:T(u).type,w=se(r,n),V=w?`nc-${v}-${(0,re.fnv1a)(JSON.stringify({id:(G=w.id)!=null?G:null,dataAttr:(F=w.dataAttr)!=null?F:null,selector:(W=w.selector)!=null?W:null})).toString(36)}`:`nc-${v}`;i.set(r,V);let Q=O.filter(([,A])=>A.test(u.bodyText)).map(([A])=>A);d.push(_(S({componentId:V,semanticType:v,source:p?"markup":"auto"},w?{locator:w}:{}),{observation:S(S({tag:u.tag,idClass:u.idClass.slice(0,200),headingText:u.headingText,textLength:u.textLength,actionCount:u.actionCount},u.ariaRole?{ariaRole:u.ariaRole}:{}),Q.length>0?{patternFlags:Q}:{})}))}let s=(H=(U=(B=(j=n.defaultView)!=null?j:typeof window!="undefined"?window:void 0)==null?void 0:B.location)==null?void 0:U.pathname)!=null?H:"/";xe(t.apiKey,a,s,d);let l=new Map,f=r=>{let c=l.get(r);return c||(c={ms:0,scroll:0,enterAt:null,intersecting:!1},l.set(r,c)),c},y=new IntersectionObserver(r=>{for(let c of r){let p=i.get(c.target);if(!p)continue;let u=f(p);c.isIntersecting?(u.intersecting=!0,u.enterAt=Date.now(),c.intersectionRatio>u.scroll&&(u.scroll=c.intersectionRatio)):(u.intersecting=!1,u.enterAt!=null&&(u.ms+=Date.now()-u.enterAt,u.enterAt=null))}},{threshold:[0,.25,.5,.75,1]});for(let r of i.keys())y.observe(r);let g=()=>{let r=Date.now();for(let[c,p]of l)if(p.enterAt!=null&&(p.ms+=r-p.enterAt,p.enterAt=null),!(p.ms<=0)){try{e.track({projectId:t.apiKey,componentId:c,eventType:"dwell",payload:{dwell_time:Math.round(p.ms),scroll_depth:Number(p.scroll.toFixed(2))}})}catch(u){}p.ms=0}},h=()=>{if(n.hidden)g();else{let r=Date.now();for(let c of l.values())c.intersecting&&(c.enterAt=r)}},b=!1,k=r=>{if(g(),r!=null&&r.persisted){b=!0;return}try{y.disconnect()}catch(c){}},D=r=>{if(!(r!=null&&r.persisted)||!b)return;b=!1;let c=Date.now();for(let p of l.values())p.enterAt=p.intersecting&&!n.hidden?c:null};n.addEventListener("visibilitychange",h);let m=(q=n.defaultView)!=null?q:typeof window!="undefined"?window:void 0;m==null||m.addEventListener("pagehide",k),m==null||m.addEventListener("pageshow",D);let ae=setInterval(()=>{if(n.hidden||b)return;g();let r=Date.now();for(let c of l.values())c.intersecting&&(c.enterAt=r)},ke),M=[];return t.microSignals&&[...i.entries()].forEach(([r,c],p)=>{M.push(ee((u,v={})=>{try{e.track({projectId:t.apiKey,componentId:c,eventType:"micro_signal",payload:S({signalType:u},v)})}catch(w){}},r,void 0,{tabLoss:p===0}))}),()=>{g(),clearInterval(ae),n.removeEventListener("visibilitychange",h),m==null||m.removeEventListener("pagehide",k),m==null||m.removeEventListener("pageshow",D);for(let r of M)r();try{y.disconnect()}catch(r){}}}0&&(module.exports={SEMANTIC_TYPES,classifyFeatures,classifySection,featuresFromElement,startEngagementCapture});
|
|
1
|
+
"use strict";var R=Object.defineProperty,le=Object.defineProperties,ce=Object.getOwnPropertyDescriptor,de=Object.getOwnPropertyDescriptors,ue=Object.getOwnPropertyNames,Q=Object.getOwnPropertySymbols;var J=Object.prototype.hasOwnProperty,pe=Object.prototype.propertyIsEnumerable;var Y=(e,t,n)=>t in e?R(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,S=(e,t)=>{for(var n in t||(t={}))J.call(t,n)&&Y(e,n,t[n]);if(Q)for(var n of Q(t))pe.call(t,n)&&Y(e,n,t[n]);return e},P=(e,t)=>le(e,de(t));var ge=(e,t)=>{for(var n in t)R(e,n,{get:t[n],enumerable:!0})},fe=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ue(t))!J.call(e,o)&&o!==n&&R(e,o,{get:()=>t[o],enumerable:!(a=ce(t,o))||a.enumerable});return e};var me=e=>fe(R({},"__esModule",{value:!0}),e);var xe={};ge(xe,{SEMANTIC_TYPES:()=>I,classifyFeatures:()=>C,classifySection:()=>Z,featuresFromElement:()=>T,startEngagementCapture:()=>ie});module.exports=me(xe);var I=["pricing","hero","social_proof","cta","features","faq","comparison","trust","navigation","generic"],ye={banner:"hero",navigation:"navigation",contentinfo:"footer"};function he(e){let t=e.ariaRole?ye[e.ariaRole.toLowerCase()]:void 0;if(t)return t;if(e.tag==="nav")return"navigation";if(e.tag==="footer")return"footer";if(e.tag==="header")return e.actionCount>=5?"navigation":"hero";let n=`${e.idClass} ${e.headingText}`.toLowerCase();return/\b(navbar|nav-bar|navigation|site-nav|main-nav|topbar|footer)\b/.test(n)?/footer/.test(n)?"footer":"navigation":/\b(hero|masthead|jumbotron)\b/i.test(e.idClass)?"hero":null}function Se(e){return e.actionCount>=1&&e.textLength>0&&e.textLength<200?"cta":"generic"}var be=[["pricing",/\b(pricing|price list|per month|\/mo|subscriptions?)\b|\bplans?\b(?=[^.]{0,40}(from|start|month|year|[$€£]))/i],["faq",/\bfaq\b|frequently asked|common questions?/i],["comparison",/\b(compare|comparison|versus)\b|\bvs\./i],["social_proof",/\b(reviews?|ratings?|testimonial|brands?|galler(y|ies)|logos)\b|trusted by|loved by|case stud|what our customers say/i],["trust",/\b(insurance|warrant(y|ies)|guarantees?|certifi|accredit|security|privacy|compliance|gdpr|encrypt)\b|why choose|about us|our team/i],["cta",/\b(book|booking|reserve|appointments?|newsletter|subscribe)\b|contact us|get in touch|opening hours/i],["features",/\b(features?|benefits?|capabilit|services?|repairs?|menus?|products?)\b|how it works|our process|what we (do|offer)|what you get/i]],O=[["pricing",/(?:[$€£]\s?\d[\d,.]*\s*(?:\/|per\s)\s*(?:mo|month|yr|year|seat|user))|(?:\b(?:starter|basic|pro|growth|premium|enterprise)\b[^.]{0,60}[$€£]\s?\d)/i],["social_proof",/(?:★{2,})|(?:\b\d(?:\.\d)?\s*(?:out of|\/)\s*5\b)|(?:\brated\b)|(?:["“][^"”]{20,160}["”]\s*[—–-]\s*[A-Z][a-z]+)/],["trust",/\b(?:money[- ]back guarantee|free returns?|returns? within|refund(?:s)? within|encrypted|soc ?2|iso ?27001|gdpr[- ]compliant|cancel anytime)\b/i],["comparison",/\b(?:vs|versus)\b\.?[^.!?]{0,80}\b(?:compare|comparison|plans?|features?|alternative)\b|\bhow (?:we|it) compares?\b/i]],X={navigation:"navigation",footer:"navigation",hero:"hero",cta:"cta",generic:"generic"};function we(e){var n;let t=e.querySelector("h1, h2, h3");return((n=t==null?void 0:t.textContent)!=null?n:"").slice(0,160)}function C(e){var o,i;let t=he(e);if(t)return{type:(o=X[t])!=null?o:"generic",strength:"strong"};let n=`${e.idClass} ${e.headingText}`.toLowerCase();for(let[d,s]of be)if(s.test(n))return{type:d,strength:"strong"};for(let[d,s]of O)if(s.test(e.bodyText))return{type:d,strength:"strong"};let a=Se(e);return{type:(i=X[a])!=null?i:"generic",strength:"weak"}}function T(e){var a,o;let t=((a=e.textContent)!=null?a:"").replace(/\s+/g," ").trim(),n=e.getAttribute("role");return S({tag:e.tagName.toLowerCase(),idClass:`${e.id} ${String((o=e.className)!=null?o:"")}`,headingText:we(e),bodyText:t.slice(0,2e3),actionCount:e.querySelectorAll('a, button, [role="button"]').length,textLength:t.length},n?{ariaRole:n}:{})}function Z(e){return C(T(e)).type}var re=require("@sentientui/policy");var ve=require("@sentientui/policy");function ee(e,t,n,a){let o=[];{let s=!1,l=[],f=()=>{if(s)return;let y=Date.now();for(l.push(y);l.length>0&&y-l[0]>500;)l.shift();l.length>=3&&(s=!0,e("rage_click"))};t.addEventListener("click",f),o.push(()=>t.removeEventListener("click",f))}{let i=!1,d=s=>{if(i||!(s.target instanceof Node)||!t.contains(s.target)&&t!==s.target)return;i=!0;let l=typeof window!="undefined"?window.getSelection():null,f=l?l.toString().length:0;e("text_copy",{selectionLength:f})};document.addEventListener("copy",d),o.push(()=>document.removeEventListener("copy",d))}{let i=!1,d=!1,s=null,l=()=>{s!==null&&(clearTimeout(s),s=null)},f=()=>{i||!d||(l(),s=setTimeout(()=>{!i&&d&&(i=!0,e("scroll_hesitation"))},3e3))},y=()=>{l(),f()},g=w=>{for(let k of w)d=k.intersectionRatio>.3,d?f():l()},h=new IntersectionObserver(g,{threshold:[.3]});h.observe(t),window.addEventListener("scroll",y,{passive:!0}),o.push(()=>{h.disconnect(),window.removeEventListener("scroll",y),l()})}if((a==null?void 0:a.tabLoss)!==!1){let i=!1,d=n!=null?n:Date.now(),s=()=>{if(i||document.visibilityState!=="hidden")return;let l=Date.now()-d;l<15e3&&(i=!0,e("tab_loss",{timeOnPage:l}))};document.addEventListener("visibilitychange",s),o.push(()=>document.removeEventListener("visibilitychange",s))}return()=>{for(let i of o)i()}}function te(){return typeof navigator!="undefined"&&navigator.globalPrivacyControl===!0?!0:[typeof navigator!="undefined"?navigator.doNotTrack:void 0,typeof window!="undefined"?window.doNotTrack:void 0,typeof navigator!="undefined"?navigator.msDoNotTrack:void 0].some(t=>t==="1"||t==="yes")}var Ce=["data-sentient-id","data-testid","data-test","data-id","data-name","data-cy"];function _(e){var t;return((t=e.textContent)!=null?t:"").replace(/\s+/g," ").trim()}function Te(e){return{tag:e.tagName.toLowerCase(),text:_(e).slice(0,40)}}function ne(e){return e.replace(/["\\\]]/g,"\\$&")}function E(e,t){try{return e.querySelectorAll(t).length===1}catch(n){return!1}}function oe(e,t){var d;let n=e.tagName.toLowerCase();if(!n)return null;let a=((d=e.getAttribute("class"))!=null?d:"").split(/\s+/).filter(s=>/^[a-zA-Z][\w-]*$/.test(s)),o=[n,...a.map(s=>`${n}.${s}`)];for(let s of o)if(E(t,s))return s;let i=e.parentElement;if(i&&i!==t){let s=oe(i,t);if(s){for(let g of o){let h=`${s} > ${g}`;if(E(t,h))return h}let l=Array.from(i.children).filter(g=>g.tagName.toLowerCase()===n),f=l.indexOf(e),y=l.some(g=>g!==e&&_(g)!==_(e));if(f>=0&&y){let g=`${s} > ${n}:nth-of-type(${f+1})`;if(E(t,g))return g}}}return null}function se(e,t){let n=Te(e),a=e.getAttribute("id");if(a&&E(t,`#${ne(a)}`))return{v:1,id:a,fingerprint:n};for(let i of Ce){let d=e.getAttribute(i);if(d&&E(t,`[${i}="${ne(d)}"]`))return{v:1,dataAttr:{name:i,value:d},fingerprint:n}}let o=oe(e,t);return o?{v:1,selector:o,fingerprint:n}:null}var Ee="section, header, footer, nav, main > div, [data-sentient-section]",ke=2e4;function Re(e){let t=Array.from(e.querySelectorAll(Ee)),n=t.filter(a=>t.filter(o=>o!==a&&a.contains(o)).length<2);return n.filter(a=>!n.some(o=>o!==a&&o.contains(a)))}function Ie(e,t,n,a){try{fetch(`${t}/v1/section-map`,{method:"POST",keepalive:!0,headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify({pageUrl:n,sections:a})}).catch(()=>{})}catch(o){}}var x=()=>{};function ie(e,t){var N,L,$,K,G,j,F,W,B,U,H,q;let n=(N=t.doc)!=null?N:typeof document!="undefined"?document:void 0;if(!n||typeof IntersectionObserver=="undefined"||te()||!t.apiKey||!t.apiKey.startsWith("pk_"))return x;let a=((L=t.apiBase)!=null?L:"https://api.sentient-ui.com").replace(/\/+$/,"").replace(/\/v1$/,""),o=Re(n);if(o.length===0)return x;let i=new Map,d=[];for(let r of o){let c=r.getAttribute("data-sentient-type"),p=c&&I.includes(c)?c:null,u=T(r),v=(K=p!=null?p:($=t.typeOf)==null?void 0:$.call(t,r))!=null?K:C(u).type,b=se(r,n),z=b?`nc-${v}-${(0,re.fnv1a)(JSON.stringify({id:(G=b.id)!=null?G:null,dataAttr:(j=b.dataAttr)!=null?j:null,selector:(F=b.selector)!=null?F:null})).toString(36)}`:`nc-${v}`;i.set(r,z);let V=O.filter(([,A])=>A.test(u.bodyText)).map(([A])=>A);d.push(P(S({componentId:z,semanticType:v,source:p?"markup":"auto"},b?{locator:b}:{}),{observation:S(S({tag:u.tag,idClass:u.idClass.slice(0,200),headingText:u.headingText,textLength:u.textLength,actionCount:u.actionCount},u.ariaRole?{ariaRole:u.ariaRole}:{}),V.length>0?{patternFlags:V}:{})}))}let s=(H=(U=(B=(W=n.defaultView)!=null?W:typeof window!="undefined"?window:void 0)==null?void 0:B.location)==null?void 0:U.pathname)!=null?H:"/";Ie(t.apiKey,a,s,d);let l=new Map,f=r=>{let c=l.get(r);return c||(c={ms:0,scroll:0,enterAt:null,intersecting:!1},l.set(r,c)),c},y=new IntersectionObserver(r=>{for(let c of r){let p=i.get(c.target);if(!p)continue;let u=f(p);c.isIntersecting?(u.intersecting=!0,u.enterAt=Date.now(),c.intersectionRatio>u.scroll&&(u.scroll=c.intersectionRatio)):(u.intersecting=!1,u.enterAt!=null&&(u.ms+=Date.now()-u.enterAt,u.enterAt=null))}},{threshold:[0,.25,.5,.75,1]});for(let r of i.keys())y.observe(r);let g=()=>{let r=Date.now();for(let[c,p]of l)if(p.enterAt!=null&&(p.ms+=r-p.enterAt,p.enterAt=null),!(p.ms<=0)){try{e.track({projectId:t.apiKey,componentId:c,eventType:"dwell",payload:{dwell_time:Math.round(p.ms),scroll_depth:Number(p.scroll.toFixed(2))}})}catch(u){}p.ms=0}},h=()=>{if(n.hidden)g();else{let r=Date.now();for(let c of l.values())c.intersecting&&(c.enterAt=r)}},w=!1,k=r=>{if(g(),r!=null&&r.persisted){w=!0;return}try{y.disconnect()}catch(c){}},D=r=>{if(!(r!=null&&r.persisted)||!w)return;w=!1;let c=Date.now();for(let p of l.values())p.enterAt=p.intersecting&&!n.hidden?c:null};n.addEventListener("visibilitychange",h);let m=(q=n.defaultView)!=null?q:typeof window!="undefined"?window:void 0;m==null||m.addEventListener("pagehide",k),m==null||m.addEventListener("pageshow",D);let ae=setInterval(()=>{if(n.hidden||w)return;g();let r=Date.now();for(let c of l.values())c.intersecting&&(c.enterAt=r)},ke),M=[];return t.microSignals&&[...i.entries()].forEach(([r,c],p)=>{M.push(ee((u,v={})=>{try{e.track({projectId:t.apiKey,componentId:c,eventType:"micro_signal",payload:S({signalType:u},v)})}catch(b){}},r,void 0,{tabLoss:p===0}))}),()=>{g(),clearInterval(ae),n.removeEventListener("visibilitychange",h),m==null||m.removeEventListener("pagehide",k),m==null||m.removeEventListener("pageshow",D);for(let r of M)r();try{y.disconnect()}catch(r){}}}0&&(module.exports={SEMANTIC_TYPES,classifyFeatures,classifySection,featuresFromElement,startEngagementCapture});
|
|
2
2
|
//# sourceMappingURL=index-engagement.js.map
|