@sentientui/core 0.16.5 → 0.16.7
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-C5CJIBEL.mjs +2 -0
- package/dist/chunk-C5CJIBEL.mjs.map +1 -0
- 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 +0 -8
- package/dist/index-graph.d.ts +0 -8
- 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.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -3
- package/dist/chunk-VJZDW3BH.mjs +0 -2
- package/dist/chunk-VJZDW3BH.mjs.map +0 -1
package/dist/index-graph.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as b,d as v}from"./chunk-CD2A55US.mjs";import{h as T,j as N}from"./chunk-C5CJIBEL.mjs";import{d as D,e as G,f as k,g as $,h as j}from"./chunk-L5TA3FAB.mjs";import{a as y,b as I}from"./chunk-TMCGHANO.mjs";var L=new Set(["SECTION","ARTICLE","MAIN","DIV"]),U="h1, h2, h3",A=30,K=1500,F={scan:async()=>({nodes:[],edges:[],scannedAt:0}),observe:()=>{},getProminenceScore:()=>0,destroy:()=>{}};function x(e,t,n){return n<=t?0:Math.max(0,Math.min(1,(e-t)/(n-t)))}function q(e){var t,n,i;try{let p=e;for(let s of Object.keys(p)){if(!s.startsWith("__reactFiber")&&!s.startsWith("__reactInternalInstance"))continue;let r=p[s],c=(i=(t=r==null?void 0:r.type)==null?void 0:t.displayName)!=null?i:(n=r==null?void 0:r.type)==null?void 0:n.name;if(c&&c.length>1)return c}}catch(p){}}function z(e){let t={};for(let n of Array.from(e.attributes))n.name.startsWith("data-")&&(t[n.name]=n.value);return t}var _=new Set(b);function B(e){let t=e.getAttribute("data-sentient-type");if(t&&_.has(t))return t;let n=e.getAttribute("role");return n&&_.has(n)?n:v(e)}function H(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)&4294967295;return(t>>>0).toString(16).padStart(8,"0")}function J(e){let t=[],n=e;for(;n;){let i=n.parentElement;if(!i){t.push(n.tagName.toLowerCase());break}let p=Array.prototype.indexOf.call(i.children,n);t.push(`${n.tagName.toLowerCase()}[${p}]`),n=i}return t.reverse().join("/")}function V(e){var n;let t=(n=e.getAttribute("data-sentient-id"))!=null?n:e.getAttribute("id");return t||`${e.tagName.toLowerCase()}-${H(J(e))}`}function Y(e){let t=0,n=e.parentElement;for(;n;)t++,n=n.parentElement;return t}function C(e,t){var i,p,s;let n=e.querySelector(U);return{componentId:V(e),semanticType:B(e),ariaLabel:(i=e.getAttribute("aria-label"))!=null?i:void 0,headingText:(s=(p=n==null?void 0:n.textContent)==null?void 0:p.trim())!=null?s:void 0,isAboveFold:e.getBoundingClientRect().top<window.innerHeight,prominenceScore:t(e),depth:Y(e),reactComponentName:q(e),dataAttributes:z(e)}}function O(e){var s;let t=[],n=new Set,i="__root__",p=new Map;for(let[r,c]of e){let a=r.parentElement,d=i;for(;a;){if(e.has(a)){d=e.get(a);let l=e.get(r),g=`${d}->${l}`;!n.has(g)&&d!==l&&(n.add(g),t.push({fromComponentId:d,toComponentId:l,weight:.6}));break}a=a.parentElement}let u=(s=p.get(d))!=null?s:[];u.push(r),p.set(d,u)}for(let r of p.values()){if(r.length<2)continue;let c=r.length>A?r.slice(0,A):r;for(let a=0;a<c.length;a++)for(let d=a+1;d<c.length;d++){if(t.length>=K)return t;let u=e.get(c[a]),l=e.get(c[d]);if(u===l)continue;let g=`${u}->${l}::sib`,o=`${l}->${u}::sib`;n.has(g)||(n.add(g),t.push({fromComponentId:u,toComponentId:l,weight:.3})),n.has(o)||(n.add(o),t.push({fromComponentId:l,toComponentId:u,weight:.3}))}}return t}function W(e){let t=[],n=new Set,i=new Map;return document.querySelectorAll("[data-sentient-id]").forEach(r=>{if(r instanceof Element&&!n.has(r)){n.add(r);let c=C(r,e);t.push(c),i.set(r,c.componentId)}}),document.querySelectorAll("section, article, main, aside").forEach(r=>{if(!(r instanceof Element)||n.has(r))return;let c=r.hasAttribute("aria-label"),a=r.hasAttribute("data-sentient-id");if(!c&&!a)return;n.add(r);let d=C(r,e);t.push(d),i.set(r,d.componentId)}),{nodes:t,edges:O(i),elementToId:i}}function M(){if(typeof window=="undefined")return F;let e=null,t=0,n=null,i=new Map,p=a=>{try{let d=window.getComputedStyle(a),u=parseFloat(d.fontSize)||12,l=parseFloat(d.zIndex)||0,g=a.getBoundingClientRect(),o=Math.max(g.top,0),m=window.innerHeight||1,S=1/(o/m+1),f=x(u,12,48)*.4+S*.4+x(l,0,100)*.2;return Math.max(0,Math.min(1,f))}catch(d){return .5}};return{scan:()=>new Promise(a=>{let d=()=>{let{nodes:u,edges:l,elementToId:g}=W(p);i.clear();for(let[o,m]of g)i.set(o,m);a({nodes:u,edges:l,scannedAt:Date.now()})};try{typeof requestIdleCallback=="function"?t=requestIdleCallback(d,{timeout:100}):d()}catch(u){d()}}),observe:a=>{n=a;try{e=new MutationObserver(d=>{let u=[],l=new Set;for(let o of d)o.type==="childList"&&o.addedNodes.forEach(m=>{if(!(m instanceof Element)||!L.has(m.tagName))return;let S=m.hasAttribute("data-sentient-id"),f=m.hasAttribute("aria-label");if(!S&&!f)return;let h=C(m,p);u.push(h),l.add(h.componentId),i.set(m,h.componentId)});if(u.length===0||!n)return;for(let o of[...i.keys()])o.isConnected||i.delete(o);let g=O(i).filter(o=>l.has(o.fromComponentId)||l.has(o.toComponentId));n({nodes:u,edges:g,addedAt:Date.now()})}),e.observe(document.body,{childList:!0,subtree:!0})}catch(d){}},getProminenceScore:p,destroy:()=>{if(e&&(e.disconnect(),e=null),t&&typeof cancelIdleCallback=="function")try{cancelIdleCallback(t)}catch(a){}t=0,n=null,i.clear()}}}var w="_snt_graph_nodes",R="_snt_graph_edges",Q={pricing:["features","faq"],features:["pricing"],faq:["pricing"],social_proof:["cta"],cta:["social_proof","hero","trust"],hero:["cta"],comparison:["pricing"],trust:["cta"]};function X(e){var t;return(t=Q[e])!=null?t:[]}function Z(e,t){try{let n=localStorage.getItem(e);return n?JSON.parse(n):t}catch(n){return t}}function ee(e,t){try{localStorage.setItem(e,JSON.stringify(t))}catch(n){}}var te=new Set(["pricing","hero","social_proof","cta","features","faq","comparison","trust","navigation","generic"]);function ne(e){return te.has(e)?e:"generic"}function oe(e,t,n){let i=`${e}:${t}:${n.join(",")}`,p=5381;for(let s=0;s<i.length;s++)p=(p<<5)+p+i.charCodeAt(s)&4294967295;return(p>>>0).toString(16).padStart(8,"0")}function P(e){let t=new Map,n=new Map,i=()=>{typeof window!="undefined"&&ee(w,[...t.values()])},p=s=>{var r;try{let c=JSON.parse(s);t.clear();for(let a of(r=c.pageNodes)!=null?r:[])t.set(a.componentId,a)}catch(c){}};if(typeof window!="undefined"){let s=Z(w,[]);for(let r of s)t.set(r.componentId,r);try{localStorage.removeItem(R)}catch(r){}}return{addPageNode(s){t.set(s.componentId,s),i()},addStructuralEdge(s){let r=`${s.fromComponentId}->${s.toComponentId}`;n.set(r,s)},syncOnce(){var r,c;if(!(e!=null&&e.syncUrl)||typeof window=="undefined")return;let s=[...t.values()];if(s.length!==0)try{let a=new Map;for(let o of s){let m=(r=a.get(o.semanticType))!=null?r:[];m.push(o),a.set(o.semanticType,m)}let d=[],u=new Set;for(let o of s)for(let m of X(o.semanticType)){let S=(c=a.get(m))!=null?c:[];for(let f of S){if(f.componentId===o.componentId)continue;let h=`semantic:${o.componentId}->${f.componentId}`;u.has(h)||(u.add(h),d.push({fromComponentId:o.componentId,toComponentId:f.componentId,type:"semantic",weight:.4,confidence:.9}))}}let l=new Set(s.map(o=>o.componentId));for(let o of n.values()){if(!l.has(o.fromComponentId)||!l.has(o.toComponentId))continue;let m=`structural:${o.fromComponentId}->${o.toComponentId}`;u.has(m)||(u.add(m),d.push({fromComponentId:o.fromComponentId,toComponentId:o.toComponentId,type:"structural",weight:o.weight,confidence:1}))}let g=I(y(y({pageUrl:window.location.href},e.sessionId?{sessionId:e.sessionId}:{}),e.projectId?{projectId:e.projectId}:{}),{nodes:s.map(o=>{let m=ne(o.semanticType);return{componentId:o.componentId,semanticType:m,answers:o.answers,contentHash:oe(o.componentId,m,o.answers),prominenceScore:o.prominenceScore,depthInPage:o.depth}}),edges:d});fetch(e.syncUrl,{method:"POST",keepalive:!0,headers:y({"Content-Type":"application/json"},e.apiKey?{Authorization:`Bearer ${e.apiKey}`}:{}),body:JSON.stringify(g)}).catch(()=>{})}catch(a){}},snapshot(){return{pageNodes:[...t.values()],capturedAt:Date.now()}},serialize(){return JSON.stringify({pageNodes:[...t.values()]})},restore:p,destroy(){if(typeof window!="undefined")try{localStorage.removeItem(w),localStorage.removeItem(R)}catch(s){}}}}var re="https://api.sentient-ui.com/v1/events";function se(){try{let e=document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);return e?decodeURIComponent(e[1]):void 0}catch(e){return}}var E=new Map;function me(e){var l;let t=N(e),n=e.respectDoNotTrack!==!1&&T(),i=e.consent===!1||n;if(!e.graph||!e.apiKey||i||typeof window=="undefined")return t;let p=E.get(e.apiKey);if(p)try{p()}catch(g){}let s=M(),r=(l=e.ingestUrl)!=null?l:re,c=P({syncUrl:r.replace(/\/events\/?$/,"/graph/sync"),apiKey:e.apiKey,projectId:e.apiKey,sessionId:se()});s.scan().then(g=>{for(let o of g.nodes)c.addPageNode({id:o.componentId,componentId:o.componentId,semanticType:o.semanticType,answers:o.headingText?[o.headingText]:[],prominenceScore:o.prominenceScore,depth:o.depth});for(let o of g.edges)c.addStructuralEdge(o);c.syncOnce()});let a=null,d=()=>{a!==null&&clearTimeout(a),a=setTimeout(()=>{a=null,c.syncOnce()},500)};s.observe(g=>{for(let o of g.nodes)c.addPageNode({id:o.componentId,componentId:o.componentId,semanticType:o.semanticType,answers:o.headingText?[o.headingText]:[],prominenceScore:o.prominenceScore,depth:o.depth});for(let o of g.edges)c.addStructuralEdge(o);d()});let u=()=>{a!==null&&(clearTimeout(a),a=null),s.destroy(),c.destroy(),E.get(e.apiKey)===u&&E.delete(e.apiKey)};return E.set(e.apiKey,u),I(y({},t),{getGraph:()=>c.snapshot(),dispose:()=>{u(),t.dispose()},destroy:()=>{u(),t.destroy()}})}export{j as deriveSessionSegment,D as detectDeviceClass,$ as detectTimeOfDay,G as detectTrafficSource,me as init,k as referrerDomainFromReferer};
|
|
2
2
|
//# sourceMappingURL=index-graph.mjs.map
|
package/dist/index-graph.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scanner.ts","../src/graph.ts","../src/index-graph.ts"],"sourcesContent":["/** Reads the rendered DOM to build the page-side context graph. */\n\nimport { classifySection, SEMANTIC_TYPES, type SemanticType } from './engagement/classify';\n\nexport type ScannedNode = {\n componentId: string;\n semanticType: string;\n ariaLabel?: string;\n headingText?: string;\n isAboveFold: boolean;\n prominenceScore: number;\n depth: number;\n reactComponentName?: string;\n dataAttributes: Record<string, string>;\n};\n\nexport type StructuralEdge = {\n fromComponentId: string;\n toComponentId: string;\n /** 0.6 for direct parent → child, 0.3 for sibling (both directions emitted). */\n weight: number;\n};\n\nexport type ScanResult = {\n nodes: ScannedNode[];\n edges: StructuralEdge[];\n scannedAt: number;\n};\n\nexport type ContentAddedEvent = {\n nodes: ScannedNode[];\n edges: StructuralEdge[];\n addedAt: number;\n};\n\nexport type DOMScanner = {\n scan(): Promise<ScanResult>;\n observe(onContentAdded: (event: ContentAddedEvent) => void): void;\n getProminenceScore(element: Element): number;\n destroy(): void;\n};\n\nconst OBSERVE_TAGS = new Set(['SECTION', 'ARTICLE', 'MAIN', 'DIV']);\nconst HEADING_SELECTOR = 'h1, h2, h3';\n\nconst SSR_SCANNER: DOMScanner = {\n scan: async () => ({ nodes: [], edges: [], scannedAt: 0 }),\n observe: () => undefined,\n getProminenceScore: () => 0,\n destroy: () => undefined,\n};\n\nfunction normalize(value: number, min: number, max: number): number {\n if (max <= min) return 0;\n return Math.max(0, Math.min(1, (value - min) / (max - min)));\n}\n\nfunction readReactComponentName(element: Element): string | undefined {\n try {\n const record = element as unknown as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n if (!key.startsWith('__reactFiber') && !key.startsWith('__reactInternalInstance')) {\n continue;\n }\n const fiber = record[key] as { type?: { name?: string; displayName?: string } };\n const name = fiber?.type?.displayName ?? fiber?.type?.name;\n if (name && name.length > 1) {\n return name;\n }\n }\n } catch {\n /* ignore */\n }\n return undefined;\n}\n\nfunction extractDataAttributes(element: Element): Record<string, string> {\n const attrs: Record<string, string> = {};\n for (const attr of Array.from(element.attributes)) {\n if (attr.name.startsWith('data-')) {\n attrs[attr.name] = attr.value;\n }\n }\n return attrs;\n}\n\nconst SEMANTIC_SET: ReadonlySet<string> = new Set(SEMANTIC_TYPES);\n\n// Explicit tag wins → role → heuristic → generic. Every output is normalized to\n// the graph_nodes enum: an out-of-vocabulary data-sentient-type/role falls\n// through to the heuristic instead of being emitted raw (raw values violated\n// the graph_nodes CHECK constraint on insert).\nfunction inferSemanticType(element: Element): SemanticType {\n const explicit = element.getAttribute('data-sentient-type');\n if (explicit && SEMANTIC_SET.has(explicit)) return explicit as SemanticType;\n const role = element.getAttribute('role');\n if (role && SEMANTIC_SET.has(role)) return role as SemanticType;\n return classifySection(element);\n}\n\nfunction componentIdFor(element: Element): string {\n return (\n element.getAttribute('data-sentient-id') ??\n element.getAttribute('id') ??\n element.tagName.toLowerCase()\n );\n}\n\nfunction depthOf(element: Element): number {\n let depth = 0;\n let current: Element | null = element.parentElement;\n while (current) {\n depth++;\n current = current.parentElement;\n }\n return depth;\n}\n\nfunction scanElement(\n element: Element,\n getProminenceScore: (el: Element) => number,\n): ScannedNode {\n const heading = element.querySelector(HEADING_SELECTOR);\n return {\n componentId: componentIdFor(element),\n semanticType: inferSemanticType(element),\n ariaLabel: element.getAttribute('aria-label') ?? undefined,\n headingText: heading?.textContent?.trim() ?? undefined,\n isAboveFold: element.getBoundingClientRect().top < window.innerHeight,\n prominenceScore: getProminenceScore(element),\n depth: depthOf(element),\n reactComponentName: readReactComponentName(element),\n dataAttributes: extractDataAttributes(element),\n };\n}\n\n/**\n * Detects structural relationships between scanned component elements:\n * - parent → child (direct ancestor link, weight 0.6)\n * - sibling ↔ sibling (share nearest component ancestor, weight 0.3, bidirectional)\n * A pair appears at most once per direction.\n */\nfunction detectStructuralEdges(elementToId: Map<Element, string>): StructuralEdge[] {\n const edges: StructuralEdge[] = [];\n const seen = new Set<string>();\n const ROOT = '__root__';\n\n // Parent → child: nearest component ancestor only.\n const groups = new Map<string, Element[]>();\n for (const [el, _id] of elementToId) {\n let ancestor: Element | null = el.parentElement;\n let groupKey = ROOT;\n while (ancestor) {\n if (elementToId.has(ancestor)) {\n groupKey = elementToId.get(ancestor)!;\n const childId = elementToId.get(el)!;\n const key = `${groupKey}->${childId}`;\n if (!seen.has(key) && groupKey !== childId) {\n seen.add(key);\n edges.push({ fromComponentId: groupKey, toComponentId: childId, weight: 0.6 });\n }\n break;\n }\n ancestor = ancestor.parentElement;\n }\n const siblings = groups.get(groupKey) ?? [];\n siblings.push(el);\n groups.set(groupKey, siblings);\n }\n\n // Sibling ↔ sibling: same ancestor group.\n for (const sibs of groups.values()) {\n if (sibs.length < 2) continue;\n for (let i = 0; i < sibs.length; i++) {\n for (let j = i + 1; j < sibs.length; j++) {\n const aId = elementToId.get(sibs[i]!)!;\n const bId = elementToId.get(sibs[j]!)!;\n if (aId === bId) continue;\n const fwd = `${aId}->${bId}::sib`;\n const rev = `${bId}->${aId}::sib`;\n if (!seen.has(fwd)) {\n seen.add(fwd);\n edges.push({ fromComponentId: aId, toComponentId: bId, weight: 0.3 });\n }\n if (!seen.has(rev)) {\n seen.add(rev);\n edges.push({ fromComponentId: bId, toComponentId: aId, weight: 0.3 });\n }\n }\n }\n }\n\n return edges;\n}\n\nfunction collectNodesAndEdges(\n getProminenceScore: (el: Element) => number,\n): { nodes: ScannedNode[]; edges: StructuralEdge[] } {\n const nodes: ScannedNode[] = [];\n const seen = new Set<Element>();\n const elementToId = new Map<Element, string>();\n\n const registered = document.querySelectorAll('[data-sentient-id]');\n registered.forEach((el) => {\n if (el instanceof Element && !seen.has(el)) {\n seen.add(el);\n const node = scanElement(el, getProminenceScore);\n nodes.push(node);\n elementToId.set(el, node.componentId);\n }\n });\n\n const structural = document.querySelectorAll('section, article, main, aside');\n structural.forEach((el) => {\n if (!(el instanceof Element) || seen.has(el)) return;\n const hasAria = el.hasAttribute('aria-label');\n const hasSentientId = el.hasAttribute('data-sentient-id');\n if (!hasAria && !hasSentientId) return;\n seen.add(el);\n const node = scanElement(el, getProminenceScore);\n nodes.push(node);\n elementToId.set(el, node.componentId);\n });\n\n return { nodes, edges: detectStructuralEdges(elementToId) };\n}\n\n/**\n * Creates a DOM scanner that uses idle callbacks and mutation observation.\n */\nexport function createDOMScanner(): DOMScanner {\n if (typeof window === 'undefined') {\n return SSR_SCANNER;\n }\n\n let observer: MutationObserver | null = null;\n let idleCallbackId = 0;\n let contentCallback: ((event: ContentAddedEvent) => void) | null = null;\n\n const getProminenceScore = (element: Element): number => {\n try {\n const styles = window.getComputedStyle(element);\n const fontSize = parseFloat(styles.fontSize) || 12;\n const zIndex = parseFloat(styles.zIndex) || 0;\n const rect = element.getBoundingClientRect();\n const distanceFromTop = Math.max(rect.top, 0);\n const viewportHeight = window.innerHeight || 1;\n const inverseDistance = 1 / (distanceFromTop / viewportHeight + 1);\n\n const score =\n normalize(fontSize, 12, 48) * 0.4 +\n normalize(inverseDistance, 0, 1) * 0.4 +\n normalize(zIndex, 0, 100) * 0.2;\n\n return Math.max(0, Math.min(1, score));\n } catch {\n return 0.5;\n }\n };\n\n const scan = (): Promise<ScanResult> =>\n new Promise((resolve) => {\n const run = (): void => {\n const { nodes, edges } = collectNodesAndEdges(getProminenceScore);\n resolve({ nodes, edges, scannedAt: Date.now() });\n };\n\n try {\n if (typeof requestIdleCallback === 'function') {\n idleCallbackId = requestIdleCallback(run, { timeout: 100 });\n } else {\n run();\n }\n } catch {\n run();\n }\n });\n\n const observe = (onContentAdded: (event: ContentAddedEvent) => void): void => {\n contentCallback = onContentAdded;\n try {\n observer = new MutationObserver((mutations) => {\n const added: ScannedNode[] = [];\n const addedElementToId = new Map<Element, string>();\n for (const mutation of mutations) {\n if (mutation.type !== 'childList') continue;\n mutation.addedNodes.forEach((node) => {\n if (!(node instanceof Element)) return;\n if (!OBSERVE_TAGS.has(node.tagName)) return;\n const hasId = node.hasAttribute('data-sentient-id');\n const hasAria = node.hasAttribute('aria-label');\n if (!hasId && !hasAria) return;\n const scanned = scanElement(node, getProminenceScore);\n added.push(scanned);\n addedElementToId.set(node, scanned.componentId);\n });\n }\n if (added.length > 0 && contentCallback) {\n contentCallback({\n nodes: added,\n edges: detectStructuralEdges(addedElementToId),\n addedAt: Date.now(),\n });\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n } catch {\n /* ignore */\n }\n };\n\n const destroy = (): void => {\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (idleCallbackId && typeof cancelIdleCallback === 'function') {\n try {\n cancelIdleCallback(idleCallbackId);\n } catch {\n /* ignore */\n }\n }\n idleCallbackId = 0;\n contentCallback = null;\n };\n\n return {\n scan,\n observe,\n getProminenceScore,\n destroy,\n };\n}\n","/** In-memory context graph with persistence and backend sync. */\n\nexport type PageNode = {\n id: string;\n componentId: string;\n semanticType: string;\n answers: string[];\n prominenceScore: number;\n depth: number;\n};\n\nexport type GraphSnapshot = {\n pageNodes: PageNode[];\n capturedAt: number;\n};\n\nexport type GraphConfig = {\n syncUrl?: string;\n apiKey?: string;\n projectId?: string;\n sessionId?: string;\n};\n\nexport type StructuralEdge = {\n fromComponentId: string;\n toComponentId: string;\n weight: number;\n};\n\nexport type GraphClient = {\n addPageNode(node: PageNode): void;\n /** Record a DOM-derived parent/child or sibling relationship between two components. */\n addStructuralEdge(edge: StructuralEdge): void;\n /** One-shot batch sync of all current page nodes to the backend. */\n syncOnce(): void;\n snapshot(): GraphSnapshot;\n serialize(): string;\n restore(data: string): void;\n destroy(): void;\n};\n\nconst NODES_KEY = '_snt_graph_nodes';\n// _snt_graph_edges was written by earlier builds but never synced to the backend.\n// We still read and clear any leftover key on init/destroy so old clients don't\n// accumulate stale data, but we no longer write it.\nconst STALE_EDGES_KEY = '_snt_graph_edges';\n\nconst SEMANTIC_NEIGHBOURS: Record<string, string[]> = {\n pricing: ['features', 'faq'],\n features: ['pricing'],\n faq: ['pricing'],\n social_proof: ['cta'],\n cta: ['social_proof', 'hero', 'trust'],\n hero: ['cta'],\n comparison: ['pricing'],\n trust: ['cta'],\n};\n\nfunction neighboursFor(semanticType: string): string[] {\n return SEMANTIC_NEIGHBOURS[semanticType] ?? [];\n}\n\nfunction readStorage<T>(key: string, fallback: T): T {\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return fallback;\n return JSON.parse(raw) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction writeStorage(key: string, value: unknown): void {\n try {\n localStorage.setItem(key, JSON.stringify(value));\n } catch {\n /* ignore */\n }\n}\n\nconst VALID_SEMANTIC_TYPES = new Set([\n 'pricing', 'hero', 'social_proof', 'cta', 'features',\n 'faq', 'comparison', 'trust', 'navigation', 'generic',\n]);\n\nfunction toValidSemanticType(type: string): string {\n return VALID_SEMANTIC_TYPES.has(type) ? type : 'generic';\n}\n\nfunction contentHashOf(componentId: string, semanticType: string, answers: string[]): string {\n const input = `${componentId}:${semanticType}:${answers.join(',')}`;\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) & 0xffffffff;\n }\n return (h >>> 0).toString(16).padStart(8, '0');\n}\n\n/**\n * Creates an in-memory graph client with optional persistence and sync.\n */\nexport function createGraphClient(config?: GraphConfig): GraphClient {\n const pageNodes = new Map<string, PageNode>();\n const structuralEdges = new Map<string, StructuralEdge>();\n\n const persist = (): void => {\n if (typeof window === 'undefined') return;\n writeStorage(NODES_KEY, [...pageNodes.values()]);\n };\n\n const restore = (data: string): void => {\n try {\n const parsed = JSON.parse(data) as { pageNodes?: PageNode[] };\n pageNodes.clear();\n for (const node of parsed.pageNodes ?? []) {\n pageNodes.set(node.componentId, node);\n }\n } catch {\n /* ignore corrupt state */\n }\n };\n\n if (typeof window !== 'undefined') {\n const storedNodes = readStorage<PageNode[]>(NODES_KEY, []);\n for (const node of storedNodes) {\n pageNodes.set(node.componentId, node);\n }\n // Clear any stale edge data written by older SDK versions.\n try { localStorage.removeItem(STALE_EDGES_KEY); } catch { /* ignore */ }\n }\n\n return {\n addPageNode(node: PageNode): void {\n pageNodes.set(node.componentId, node);\n persist();\n },\n\n addStructuralEdge(edge: StructuralEdge): void {\n const key = `${edge.fromComponentId}->${edge.toComponentId}`;\n structuralEdges.set(key, edge);\n },\n\n syncOnce(): void {\n if (!config?.syncUrl || typeof window === 'undefined') return;\n const nodes = [...pageNodes.values()];\n if (nodes.length === 0) return;\n try {\n // Build semantic edges from the SEMANTIC_NEIGHBOURS map. Each node emits\n // an edge to every present sibling that matches one of its neighbour types.\n // Weight matches propagate()'s 0.4 attention factor; confidence is high\n // because the mapping is curated, not inferred.\n const nodesByType = new Map<string, PageNode[]>();\n for (const n of nodes) {\n const list = nodesByType.get(n.semanticType) ?? [];\n list.push(n);\n nodesByType.set(n.semanticType, list);\n }\n const edges: Array<{\n fromComponentId: string;\n toComponentId: string;\n type: 'semantic' | 'structural';\n weight: number;\n confidence: number;\n }> = [];\n const seen = new Set<string>();\n for (const source of nodes) {\n for (const neighbourType of neighboursFor(source.semanticType)) {\n const targets = nodesByType.get(neighbourType) ?? [];\n for (const target of targets) {\n if (target.componentId === source.componentId) continue;\n const key = `semantic:${source.componentId}->${target.componentId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n edges.push({\n fromComponentId: source.componentId,\n toComponentId: target.componentId,\n type: 'semantic',\n weight: 0.4,\n confidence: 0.9,\n });\n }\n }\n }\n\n // Structural edges from DOM relationships, recorded during scan.\n // Only emit when both endpoints are present in this page's node set —\n // a structural edge to/from a node that no longer exists would dangle.\n const componentIds = new Set(nodes.map((n) => n.componentId));\n for (const edge of structuralEdges.values()) {\n if (!componentIds.has(edge.fromComponentId) || !componentIds.has(edge.toComponentId)) continue;\n const key = `structural:${edge.fromComponentId}->${edge.toComponentId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n edges.push({\n fromComponentId: edge.fromComponentId,\n toComponentId: edge.toComponentId,\n type: 'structural',\n weight: edge.weight,\n confidence: 1.0,\n });\n }\n\n const payload = {\n pageUrl: window.location.href,\n nodes: nodes.map((n) => {\n const semanticType = toValidSemanticType(n.semanticType);\n return {\n componentId: n.componentId,\n semanticType,\n answers: n.answers,\n contentHash: contentHashOf(n.componentId, semanticType, n.answers),\n prominenceScore: n.prominenceScore,\n depthInPage: n.depth,\n };\n }),\n edges,\n };\n fetch(config.syncUrl, {\n method: 'POST',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n },\n body: JSON.stringify(payload),\n }).catch(() => undefined);\n } catch {\n /* ignore */\n }\n },\n\n snapshot(): GraphSnapshot {\n return {\n pageNodes: [...pageNodes.values()],\n capturedAt: Date.now(),\n };\n },\n\n serialize(): string {\n return JSON.stringify({ pageNodes: [...pageNodes.values()] });\n },\n\n restore,\n\n destroy(): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.removeItem(NODES_KEY);\n localStorage.removeItem(STALE_EDGES_KEY);\n } catch {\n /* ignore */\n }\n },\n };\n}\n","/**\n * Graph-capable entry point for @sentientui/core.\n *\n * Import from `@sentientui/core/graph` when you need DOM graph scanning and\n * page-structure sync. This entry pulls in `scanner.ts` and `graph.ts` at\n * build time, giving bundlers a real tree-shaking boundary. Standard A/B tests\n * should use `@sentientui/core` (the lean entry) instead.\n */\n\n// Re-export everything from the lean entry except `init`, which we override below.\nexport {\n detectDeviceClass,\n detectTrafficSource,\n detectTimeOfDay,\n deriveSessionSegment,\n referrerDomainFromReferer,\n} from './index.js';\n// SSR preload helpers moved to `@sentientui/core/server` in 0.6.0.\nexport type {\n SentientConfig,\n AssignResult,\n SentientClient,\n} from './index.js';\nexport type {\n SessionConfig,\n SessionManager,\n EventType,\n SentientEvent,\n QueueConfig,\n Assignment,\n} from './index.js';\n// EventQueue/AssignmentCache are no longer on the lean barrel — source them from\n// their own modules so the `/graph` subpath keeps exposing them unchanged.\nexport type { EventQueue } from './queue.js';\nexport type { AssignmentCache } from './cache.js';\n// Scanner + graph types (live in this entry only).\nexport type {\n ScannedNode,\n ScanResult,\n ContentAddedEvent,\n DOMScanner,\n} from './scanner.js';\nexport type {\n PageNode,\n GraphSnapshot,\n GraphConfig,\n GraphClient,\n} from './graph.js';\n\nimport { init as initLean, isDoNotTrackEnabled, type SentientConfig, type SentientClient } from './index.js';\n\nconst DEFAULT_INGEST_URL = 'https://api.sentient-ui.com/v1/events';\nimport { createDOMScanner } from './scanner.js';\nimport { createGraphClient, type PageNode } from './graph.js';\n\nexport type GraphSentientConfig = SentientConfig & {\n /**\n * Enable DOM graph scanning and page-structure sync. Wires a MutationObserver\n * and a localStorage-backed graph. When `false` (default) this entry behaves\n * identically to `@sentientui/core`.\n */\n graph?: boolean;\n};\n\nfunction readSntUid(): string | undefined {\n try {\n const m = document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);\n return m ? decodeURIComponent(m[1]) : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Graph-capable variant of `init()`. Identical to the lean `init` when\n * `config.graph` is `false` (or omitted). When `config.graph: true`, mounts\n * a DOM scanner + graph client and enables `client.getGraph()`.\n *\n * Import from `@sentientui/core/graph` — do not call the lean `init` alongside\n * this function as that would initialise two clients.\n */\nexport function init(config: GraphSentientConfig): SentientClient {\n const client = initLean(config);\n\n // Mirror initLean's opt-out gate: a DNT/GPC visitor (or consent:false) must\n // not get the DOM scanner + graph sync, which POST page-structure beacons and\n // read `_snt_uid` — tracking that bypasses the lean client's own gating, even\n // under `preConsentBehavior: 'statistical_winner'` (audit P1).\n const dntBlocked = config.respectDoNotTrack !== false && isDoNotTrackEnabled();\n const gated = config.consent === false || dntBlocked;\n\n // Keyless zero-network contract: with no api key there is nothing to feed —\n // the scanner must never mount and /v1/graph/sync must never fire.\n if (!config.graph || !config.apiKey || gated || typeof window === 'undefined') return client;\n\n const domScanner = createDOMScanner();\n const resolvedIngestUrl = config.ingestUrl ?? DEFAULT_INGEST_URL;\n const graphClient = createGraphClient({\n syncUrl: resolvedIngestUrl.replace(/\\/events\\/?$/, '/graph/sync'),\n apiKey: config.apiKey,\n projectId: config.apiKey,\n sessionId: readSntUid(),\n });\n\n // Restore persisted page-node state from a previous page load.\n try {\n const nodesRaw = localStorage.getItem('_snt_graph_nodes');\n if (nodesRaw) {\n graphClient.restore(\n JSON.stringify({ pageNodes: JSON.parse(nodesRaw) as PageNode[] }),\n );\n }\n } catch {\n /* best-effort */\n }\n\n void domScanner.scan().then((result) => {\n for (const node of result.nodes) {\n graphClient.addPageNode({\n id: node.componentId,\n componentId: node.componentId,\n semanticType: node.semanticType,\n answers: node.headingText ? [node.headingText] : [],\n prominenceScore: node.prominenceScore,\n depth: node.depth,\n });\n }\n for (const edge of result.edges) {\n graphClient.addStructuralEdge(edge);\n }\n graphClient.syncOnce();\n });\n\n let syncDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n const debouncedSync = (): void => {\n if (syncDebounceTimer !== null) clearTimeout(syncDebounceTimer);\n syncDebounceTimer = setTimeout(() => {\n syncDebounceTimer = null;\n graphClient.syncOnce();\n }, 500);\n };\n\n domScanner.observe((event) => {\n for (const node of event.nodes) {\n graphClient.addPageNode({\n id: node.componentId,\n componentId: node.componentId,\n semanticType: node.semanticType,\n answers: node.headingText ? [node.headingText] : [],\n prominenceScore: node.prominenceScore,\n depth: node.depth,\n });\n }\n for (const edge of event.edges) {\n graphClient.addStructuralEdge(edge);\n }\n debouncedSync();\n });\n\n return {\n ...client,\n getGraph: () => graphClient.snapshot(),\n dispose: () => {\n if (syncDebounceTimer !== null) clearTimeout(syncDebounceTimer);\n domScanner.destroy();\n graphClient.destroy();\n client.dispose();\n },\n destroy: () => {\n if (syncDebounceTimer !== null) clearTimeout(syncDebounceTimer);\n domScanner.destroy();\n graphClient.destroy();\n client.destroy();\n },\n };\n}\n"],"mappings":"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","names":["OBSERVE_TAGS","HEADING_SELECTOR","SSR_SCANNER","normalize","value","min","max","readReactComponentName","element","_a","_b","_c","record","key","fiber","name","e","extractDataAttributes","attrs","attr","SEMANTIC_SET","SEMANTIC_TYPES","inferSemanticType","explicit","role","classifySection","componentIdFor","depthOf","depth","current","scanElement","getProminenceScore","heading","detectStructuralEdges","elementToId","edges","seen","ROOT","groups","el","_id","ancestor","groupKey","childId","siblings","sibs","i","j","aId","bId","fwd","rev","collectNodesAndEdges","nodes","node","hasAria","hasSentientId","createDOMScanner","observer","idleCallbackId","contentCallback","styles","fontSize","zIndex","rect","distanceFromTop","viewportHeight","inverseDistance","score","resolve","run","onContentAdded","mutations","added","addedElementToId","mutation","hasId","scanned","NODES_KEY","STALE_EDGES_KEY","SEMANTIC_NEIGHBOURS","neighboursFor","semanticType","_a","readStorage","key","fallback","raw","e","writeStorage","value","VALID_SEMANTIC_TYPES","toValidSemanticType","type","contentHashOf","componentId","answers","input","h","i","createGraphClient","config","pageNodes","structuralEdges","persist","restore","data","parsed","node","storedNodes","edge","_b","nodes","nodesByType","n","list","edges","seen","source","neighbourType","targets","target","componentIds","payload","__spreadValues","DEFAULT_INGEST_URL","readSntUid","m","init","config","_a","client","dntBlocked","isDoNotTrackEnabled","gated","domScanner","createDOMScanner","resolvedIngestUrl","graphClient","createGraphClient","nodesRaw","e","result","node","edge","syncDebounceTimer","debouncedSync","event","__spreadProps","__spreadValues"]}
|
|
1
|
+
{"version":3,"sources":["../src/scanner.ts","../src/graph.ts","../src/index-graph.ts"],"sourcesContent":["/** Reads the rendered DOM to build the page-side context graph. */\n\nimport { classifySection, SEMANTIC_TYPES, type SemanticType } from './engagement/classify';\n\nexport type ScannedNode = {\n componentId: string;\n semanticType: string;\n ariaLabel?: string;\n headingText?: string;\n isAboveFold: boolean;\n prominenceScore: number;\n depth: number;\n reactComponentName?: string;\n dataAttributes: Record<string, string>;\n};\n\nexport type StructuralEdge = {\n fromComponentId: string;\n toComponentId: string;\n /** 0.6 for direct parent → child, 0.3 for sibling (both directions emitted). */\n weight: number;\n};\n\nexport type ScanResult = {\n nodes: ScannedNode[];\n edges: StructuralEdge[];\n scannedAt: number;\n};\n\nexport type ContentAddedEvent = {\n nodes: ScannedNode[];\n edges: StructuralEdge[];\n addedAt: number;\n};\n\nexport type DOMScanner = {\n scan(): Promise<ScanResult>;\n observe(onContentAdded: (event: ContentAddedEvent) => void): void;\n getProminenceScore(element: Element): number;\n destroy(): void;\n};\n\nconst OBSERVE_TAGS = new Set(['SECTION', 'ARTICLE', 'MAIN', 'DIV']);\nconst HEADING_SELECTOR = 'h1, h2, h3';\n\n// Sibling detection is O(n²) per group and emits two edges per pair, so a page\n// with hundreds of co-located components (e.g. a 200-cell product grid) would\n// otherwise emit tens of thousands of low-signal sibling edges. We cap the\n// sibling fan-out per group and the total structural edges per detection pass.\n// The total stays well under the server's 2000-edge-per-sync limit, leaving room\n// for semantic edges. Parent→child edges (higher signal) are emitted first, so\n// the cap sheds sibling edges before it ever touches them.\nconst MAX_SIBLINGS_PER_GROUP = 30;\nconst MAX_STRUCTURAL_EDGES = 1500;\n\nconst SSR_SCANNER: DOMScanner = {\n scan: async () => ({ nodes: [], edges: [], scannedAt: 0 }),\n observe: () => undefined,\n getProminenceScore: () => 0,\n destroy: () => undefined,\n};\n\nfunction normalize(value: number, min: number, max: number): number {\n if (max <= min) return 0;\n return Math.max(0, Math.min(1, (value - min) / (max - min)));\n}\n\nfunction readReactComponentName(element: Element): string | undefined {\n try {\n const record = element as unknown as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n if (!key.startsWith('__reactFiber') && !key.startsWith('__reactInternalInstance')) {\n continue;\n }\n const fiber = record[key] as { type?: { name?: string; displayName?: string } };\n const name = fiber?.type?.displayName ?? fiber?.type?.name;\n if (name && name.length > 1) {\n return name;\n }\n }\n } catch {\n /* ignore */\n }\n return undefined;\n}\n\nfunction extractDataAttributes(element: Element): Record<string, string> {\n const attrs: Record<string, string> = {};\n for (const attr of Array.from(element.attributes)) {\n if (attr.name.startsWith('data-')) {\n attrs[attr.name] = attr.value;\n }\n }\n return attrs;\n}\n\nconst SEMANTIC_SET: ReadonlySet<string> = new Set(SEMANTIC_TYPES);\n\n// Explicit tag wins → role → heuristic → generic. Every output is normalized to\n// the graph_nodes enum: an out-of-vocabulary data-sentient-type/role falls\n// through to the heuristic instead of being emitted raw (raw values violated\n// the graph_nodes CHECK constraint on insert).\nfunction inferSemanticType(element: Element): SemanticType {\n const explicit = element.getAttribute('data-sentient-type');\n if (explicit && SEMANTIC_SET.has(explicit)) return explicit as SemanticType;\n const role = element.getAttribute('role');\n if (role && SEMANTIC_SET.has(role)) return role as SemanticType;\n return classifySection(element);\n}\n\n// djb2 over a string → 8-hex-char digest. Stable and collision-resistant enough\n// to disambiguate co-located components that declare no id of their own.\nfunction shortHash(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) & 0xffffffff;\n }\n return (h >>> 0).toString(16).padStart(8, '0');\n}\n\n// A structural path (tag + sibling index at each level up to the root) uniquely\n// and stably identifies an element's DOM position, so two id-less sections don't\n// hash to the same value the way a bare tagName would.\nfunction domPathSignature(element: Element): string {\n const parts: string[] = [];\n let current: Element | null = element;\n while (current) {\n const parent: Element | null = current.parentElement;\n if (!parent) {\n parts.push(current.tagName.toLowerCase());\n break;\n }\n const index = Array.prototype.indexOf.call(parent.children, current);\n parts.push(`${current.tagName.toLowerCase()}[${index}]`);\n current = parent;\n }\n return parts.reverse().join('/');\n}\n\n// Prefer an author-declared id. When none exists, synthesize a stable, unique id\n// from the element's DOM path — the old `tagName.toLowerCase()` fallback gave\n// every id-less <section> the same \"section\" id, so a second such node silently\n// overwrote the first in the componentId-keyed graph Map (node loss).\nfunction componentIdFor(element: Element): string {\n const declared =\n element.getAttribute('data-sentient-id') ?? element.getAttribute('id');\n if (declared) return declared;\n return `${element.tagName.toLowerCase()}-${shortHash(domPathSignature(element))}`;\n}\n\nfunction depthOf(element: Element): number {\n let depth = 0;\n let current: Element | null = element.parentElement;\n while (current) {\n depth++;\n current = current.parentElement;\n }\n return depth;\n}\n\nfunction scanElement(\n element: Element,\n getProminenceScore: (el: Element) => number,\n): ScannedNode {\n const heading = element.querySelector(HEADING_SELECTOR);\n return {\n componentId: componentIdFor(element),\n semanticType: inferSemanticType(element),\n ariaLabel: element.getAttribute('aria-label') ?? undefined,\n headingText: heading?.textContent?.trim() ?? undefined,\n isAboveFold: element.getBoundingClientRect().top < window.innerHeight,\n prominenceScore: getProminenceScore(element),\n depth: depthOf(element),\n reactComponentName: readReactComponentName(element),\n dataAttributes: extractDataAttributes(element),\n };\n}\n\n/**\n * Detects structural relationships between scanned component elements:\n * - parent → child (direct ancestor link, weight 0.6)\n * - sibling ↔ sibling (share nearest component ancestor, weight 0.3, bidirectional)\n * A pair appears at most once per direction.\n */\nfunction detectStructuralEdges(elementToId: Map<Element, string>): StructuralEdge[] {\n const edges: StructuralEdge[] = [];\n const seen = new Set<string>();\n const ROOT = '__root__';\n\n // Parent → child: nearest component ancestor only.\n const groups = new Map<string, Element[]>();\n for (const [el, _id] of elementToId) {\n let ancestor: Element | null = el.parentElement;\n let groupKey = ROOT;\n while (ancestor) {\n if (elementToId.has(ancestor)) {\n groupKey = elementToId.get(ancestor)!;\n const childId = elementToId.get(el)!;\n const key = `${groupKey}->${childId}`;\n if (!seen.has(key) && groupKey !== childId) {\n seen.add(key);\n edges.push({ fromComponentId: groupKey, toComponentId: childId, weight: 0.6 });\n }\n break;\n }\n ancestor = ancestor.parentElement;\n }\n const siblings = groups.get(groupKey) ?? [];\n siblings.push(el);\n groups.set(groupKey, siblings);\n }\n\n // Sibling ↔ sibling: same ancestor group.\n for (const sibs of groups.values()) {\n if (sibs.length < 2) continue;\n // Cap the fan-out of any single group before the O(n²) pairing.\n const capped = sibs.length > MAX_SIBLINGS_PER_GROUP ? sibs.slice(0, MAX_SIBLINGS_PER_GROUP) : sibs;\n for (let i = 0; i < capped.length; i++) {\n for (let j = i + 1; j < capped.length; j++) {\n if (edges.length >= MAX_STRUCTURAL_EDGES) return edges;\n const aId = elementToId.get(capped[i]!)!;\n const bId = elementToId.get(capped[j]!)!;\n if (aId === bId) continue;\n const fwd = `${aId}->${bId}::sib`;\n const rev = `${bId}->${aId}::sib`;\n if (!seen.has(fwd)) {\n seen.add(fwd);\n edges.push({ fromComponentId: aId, toComponentId: bId, weight: 0.3 });\n }\n if (!seen.has(rev)) {\n seen.add(rev);\n edges.push({ fromComponentId: bId, toComponentId: aId, weight: 0.3 });\n }\n }\n }\n }\n\n return edges;\n}\n\nfunction collectNodesAndEdges(\n getProminenceScore: (el: Element) => number,\n): { nodes: ScannedNode[]; edges: StructuralEdge[]; elementToId: Map<Element, string> } {\n const nodes: ScannedNode[] = [];\n const seen = new Set<Element>();\n const elementToId = new Map<Element, string>();\n\n const registered = document.querySelectorAll('[data-sentient-id]');\n registered.forEach((el) => {\n if (el instanceof Element && !seen.has(el)) {\n seen.add(el);\n const node = scanElement(el, getProminenceScore);\n nodes.push(node);\n elementToId.set(el, node.componentId);\n }\n });\n\n const structural = document.querySelectorAll('section, article, main, aside');\n structural.forEach((el) => {\n if (!(el instanceof Element) || seen.has(el)) return;\n const hasAria = el.hasAttribute('aria-label');\n const hasSentientId = el.hasAttribute('data-sentient-id');\n if (!hasAria && !hasSentientId) return;\n seen.add(el);\n const node = scanElement(el, getProminenceScore);\n nodes.push(node);\n elementToId.set(el, node.componentId);\n });\n\n return { nodes, edges: detectStructuralEdges(elementToId), elementToId };\n}\n\n/**\n * Creates a DOM scanner that uses idle callbacks and mutation observation.\n */\nexport function createDOMScanner(): DOMScanner {\n if (typeof window === 'undefined') {\n return SSR_SCANNER;\n }\n\n let observer: MutationObserver | null = null;\n let idleCallbackId = 0;\n let contentCallback: ((event: ContentAddedEvent) => void) | null = null;\n // Element→componentId for every node registered so far (initial scan + prior\n // mutations). The MutationObserver detects edges against this whole set — not\n // just the nodes in the current mutation — so a child inserted under an\n // already-scanned parent still gets its parent→child edge.\n const knownElementToId = new Map<Element, string>();\n\n const getProminenceScore = (element: Element): number => {\n try {\n const styles = window.getComputedStyle(element);\n const fontSize = parseFloat(styles.fontSize) || 12;\n const zIndex = parseFloat(styles.zIndex) || 0;\n const rect = element.getBoundingClientRect();\n const distanceFromTop = Math.max(rect.top, 0);\n const viewportHeight = window.innerHeight || 1;\n const inverseDistance = 1 / (distanceFromTop / viewportHeight + 1);\n\n // inverseDistance is already in (0, 1] by construction, so it needs no\n // further normalization — only fontSize and zIndex are rescaled.\n const score =\n normalize(fontSize, 12, 48) * 0.4 +\n inverseDistance * 0.4 +\n normalize(zIndex, 0, 100) * 0.2;\n\n return Math.max(0, Math.min(1, score));\n } catch {\n return 0.5;\n }\n };\n\n const scan = (): Promise<ScanResult> =>\n new Promise((resolve) => {\n const run = (): void => {\n const { nodes, edges, elementToId } = collectNodesAndEdges(getProminenceScore);\n // Seed the known-element registry so the observer can resolve parents that\n // were registered in this scan when later children are inserted.\n knownElementToId.clear();\n for (const [el, id] of elementToId) knownElementToId.set(el, id);\n resolve({ nodes, edges, scannedAt: Date.now() });\n };\n\n try {\n if (typeof requestIdleCallback === 'function') {\n idleCallbackId = requestIdleCallback(run, { timeout: 100 });\n } else {\n run();\n }\n } catch {\n run();\n }\n });\n\n const observe = (onContentAdded: (event: ContentAddedEvent) => void): void => {\n contentCallback = onContentAdded;\n try {\n observer = new MutationObserver((mutations) => {\n const added: ScannedNode[] = [];\n const addedIds = new Set<string>();\n for (const mutation of mutations) {\n if (mutation.type !== 'childList') continue;\n mutation.addedNodes.forEach((node) => {\n if (!(node instanceof Element)) return;\n if (!OBSERVE_TAGS.has(node.tagName)) return;\n const hasId = node.hasAttribute('data-sentient-id');\n const hasAria = node.hasAttribute('aria-label');\n if (!hasId && !hasAria) return;\n const scanned = scanElement(node, getProminenceScore);\n added.push(scanned);\n addedIds.add(scanned.componentId);\n knownElementToId.set(node, scanned.componentId);\n });\n }\n if (added.length === 0 || !contentCallback) return;\n // Drop elements no longer in the document so removed nodes don't dangle\n // and the map stays bounded.\n for (const el of [...knownElementToId.keys()]) {\n if (!el.isConnected) knownElementToId.delete(el);\n }\n // Detect over the FULL known set so a child inserted under an already-\n // scanned parent still gets its parent→child edge, then surface only the\n // edges that touch a newly-added node (existing edges were already emitted).\n const edges = detectStructuralEdges(knownElementToId).filter(\n (e) => addedIds.has(e.fromComponentId) || addedIds.has(e.toComponentId),\n );\n contentCallback({ nodes: added, edges, addedAt: Date.now() });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n } catch {\n /* ignore */\n }\n };\n\n const destroy = (): void => {\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (idleCallbackId && typeof cancelIdleCallback === 'function') {\n try {\n cancelIdleCallback(idleCallbackId);\n } catch {\n /* ignore */\n }\n }\n idleCallbackId = 0;\n contentCallback = null;\n knownElementToId.clear();\n };\n\n return {\n scan,\n observe,\n getProminenceScore,\n destroy,\n };\n}\n","/** In-memory context graph with persistence and backend sync. */\n\nexport type PageNode = {\n id: string;\n componentId: string;\n semanticType: string;\n answers: string[];\n prominenceScore: number;\n depth: number;\n};\n\nexport type GraphSnapshot = {\n pageNodes: PageNode[];\n capturedAt: number;\n};\n\nexport type GraphConfig = {\n syncUrl?: string;\n apiKey?: string;\n projectId?: string;\n sessionId?: string;\n};\n\nexport type StructuralEdge = {\n fromComponentId: string;\n toComponentId: string;\n weight: number;\n};\n\nexport type GraphClient = {\n addPageNode(node: PageNode): void;\n /** Record a DOM-derived parent/child or sibling relationship between two components. */\n addStructuralEdge(edge: StructuralEdge): void;\n /** One-shot batch sync of all current page nodes to the backend. */\n syncOnce(): void;\n snapshot(): GraphSnapshot;\n serialize(): string;\n restore(data: string): void;\n destroy(): void;\n};\n\nconst NODES_KEY = '_snt_graph_nodes';\n// _snt_graph_edges was written by earlier builds but never synced to the backend.\n// We still read and clear any leftover key on init/destroy so old clients don't\n// accumulate stale data, but we no longer write it.\nconst STALE_EDGES_KEY = '_snt_graph_edges';\n\nconst SEMANTIC_NEIGHBOURS: Record<string, string[]> = {\n pricing: ['features', 'faq'],\n features: ['pricing'],\n faq: ['pricing'],\n social_proof: ['cta'],\n cta: ['social_proof', 'hero', 'trust'],\n hero: ['cta'],\n comparison: ['pricing'],\n trust: ['cta'],\n};\n\nfunction neighboursFor(semanticType: string): string[] {\n return SEMANTIC_NEIGHBOURS[semanticType] ?? [];\n}\n\nfunction readStorage<T>(key: string, fallback: T): T {\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return fallback;\n return JSON.parse(raw) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction writeStorage(key: string, value: unknown): void {\n try {\n localStorage.setItem(key, JSON.stringify(value));\n } catch {\n /* ignore */\n }\n}\n\nconst VALID_SEMANTIC_TYPES = new Set([\n 'pricing', 'hero', 'social_proof', 'cta', 'features',\n 'faq', 'comparison', 'trust', 'navigation', 'generic',\n]);\n\nfunction toValidSemanticType(type: string): string {\n return VALID_SEMANTIC_TYPES.has(type) ? type : 'generic';\n}\n\nfunction contentHashOf(componentId: string, semanticType: string, answers: string[]): string {\n const input = `${componentId}:${semanticType}:${answers.join(',')}`;\n let h = 5381;\n for (let i = 0; i < input.length; i++) {\n h = ((h << 5) + h + input.charCodeAt(i)) & 0xffffffff;\n }\n return (h >>> 0).toString(16).padStart(8, '0');\n}\n\n/**\n * Creates an in-memory graph client with optional persistence and sync.\n */\nexport function createGraphClient(config?: GraphConfig): GraphClient {\n const pageNodes = new Map<string, PageNode>();\n const structuralEdges = new Map<string, StructuralEdge>();\n\n const persist = (): void => {\n if (typeof window === 'undefined') return;\n writeStorage(NODES_KEY, [...pageNodes.values()]);\n };\n\n const restore = (data: string): void => {\n try {\n const parsed = JSON.parse(data) as { pageNodes?: PageNode[] };\n pageNodes.clear();\n for (const node of parsed.pageNodes ?? []) {\n pageNodes.set(node.componentId, node);\n }\n } catch {\n /* ignore corrupt state */\n }\n };\n\n if (typeof window !== 'undefined') {\n const storedNodes = readStorage<PageNode[]>(NODES_KEY, []);\n for (const node of storedNodes) {\n pageNodes.set(node.componentId, node);\n }\n // Clear any stale edge data written by older SDK versions.\n try { localStorage.removeItem(STALE_EDGES_KEY); } catch { /* ignore */ }\n }\n\n return {\n addPageNode(node: PageNode): void {\n pageNodes.set(node.componentId, node);\n persist();\n },\n\n addStructuralEdge(edge: StructuralEdge): void {\n const key = `${edge.fromComponentId}->${edge.toComponentId}`;\n structuralEdges.set(key, edge);\n },\n\n syncOnce(): void {\n if (!config?.syncUrl || typeof window === 'undefined') return;\n const nodes = [...pageNodes.values()];\n if (nodes.length === 0) return;\n try {\n // Build semantic edges from the SEMANTIC_NEIGHBOURS map. Each node emits\n // an edge to every present sibling that matches one of its neighbour types.\n // Weight matches propagate()'s 0.4 attention factor; confidence is high\n // because the mapping is curated, not inferred.\n const nodesByType = new Map<string, PageNode[]>();\n for (const n of nodes) {\n const list = nodesByType.get(n.semanticType) ?? [];\n list.push(n);\n nodesByType.set(n.semanticType, list);\n }\n const edges: Array<{\n fromComponentId: string;\n toComponentId: string;\n type: 'semantic' | 'structural';\n weight: number;\n confidence: number;\n }> = [];\n const seen = new Set<string>();\n for (const source of nodes) {\n for (const neighbourType of neighboursFor(source.semanticType)) {\n const targets = nodesByType.get(neighbourType) ?? [];\n for (const target of targets) {\n if (target.componentId === source.componentId) continue;\n const key = `semantic:${source.componentId}->${target.componentId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n edges.push({\n fromComponentId: source.componentId,\n toComponentId: target.componentId,\n type: 'semantic',\n weight: 0.4,\n confidence: 0.9,\n });\n }\n }\n }\n\n // Structural edges from DOM relationships, recorded during scan.\n // Only emit when both endpoints are present in this page's node set —\n // a structural edge to/from a node that no longer exists would dangle.\n const componentIds = new Set(nodes.map((n) => n.componentId));\n for (const edge of structuralEdges.values()) {\n if (!componentIds.has(edge.fromComponentId) || !componentIds.has(edge.toComponentId)) continue;\n const key = `structural:${edge.fromComponentId}->${edge.toComponentId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n edges.push({\n fromComponentId: edge.fromComponentId,\n toComponentId: edge.toComponentId,\n type: 'structural',\n weight: edge.weight,\n confidence: 1.0,\n });\n }\n\n const payload = {\n pageUrl: window.location.href,\n // Visitor/project attribution. The /graph/sync handler ignores unknown\n // top-level fields (Fastify additionalProperties + Zod strips extras),\n // so these ride along harmlessly and let beacons carry attribution.\n ...(config.sessionId ? { sessionId: config.sessionId } : {}),\n ...(config.projectId ? { projectId: config.projectId } : {}),\n nodes: nodes.map((n) => {\n const semanticType = toValidSemanticType(n.semanticType);\n return {\n componentId: n.componentId,\n semanticType,\n answers: n.answers,\n contentHash: contentHashOf(n.componentId, semanticType, n.answers),\n prominenceScore: n.prominenceScore,\n depthInPage: n.depth,\n };\n }),\n edges,\n };\n fetch(config.syncUrl, {\n method: 'POST',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n },\n body: JSON.stringify(payload),\n }).catch(() => undefined);\n } catch {\n /* ignore */\n }\n },\n\n snapshot(): GraphSnapshot {\n return {\n pageNodes: [...pageNodes.values()],\n capturedAt: Date.now(),\n };\n },\n\n serialize(): string {\n return JSON.stringify({ pageNodes: [...pageNodes.values()] });\n },\n\n restore,\n\n destroy(): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.removeItem(NODES_KEY);\n localStorage.removeItem(STALE_EDGES_KEY);\n } catch {\n /* ignore */\n }\n },\n };\n}\n","/**\n * Graph-capable entry point for @sentientui/core.\n *\n * Import from `@sentientui/core/graph` when you need DOM graph scanning and\n * page-structure sync. This entry pulls in `scanner.ts` and `graph.ts` at\n * build time, giving bundlers a real tree-shaking boundary. Standard A/B tests\n * should use `@sentientui/core` (the lean entry) instead.\n */\n\n// Re-export everything from the lean entry except `init`, which we override below.\nexport {\n detectDeviceClass,\n detectTrafficSource,\n detectTimeOfDay,\n deriveSessionSegment,\n referrerDomainFromReferer,\n} from './index.js';\n// SSR preload helpers moved to `@sentientui/core/server` in 0.6.0.\nexport type {\n SentientConfig,\n AssignResult,\n SentientClient,\n} from './index.js';\nexport type {\n SessionConfig,\n SessionManager,\n EventType,\n SentientEvent,\n QueueConfig,\n Assignment,\n} from './index.js';\n// EventQueue/AssignmentCache are no longer on the lean barrel — source them from\n// their own modules so the `/graph` subpath keeps exposing them unchanged.\nexport type { EventQueue } from './queue.js';\nexport type { AssignmentCache } from './cache.js';\n// Scanner + graph types (live in this entry only).\nexport type {\n ScannedNode,\n ScanResult,\n ContentAddedEvent,\n DOMScanner,\n} from './scanner.js';\nexport type {\n PageNode,\n GraphSnapshot,\n GraphConfig,\n GraphClient,\n} from './graph.js';\n\nimport { init as initLean, isDoNotTrackEnabled, type SentientConfig, type SentientClient } from './index.js';\n\nconst DEFAULT_INGEST_URL = 'https://api.sentient-ui.com/v1/events';\nimport { createDOMScanner } from './scanner.js';\nimport { createGraphClient } from './graph.js';\n\nexport type GraphSentientConfig = SentientConfig & {\n /**\n * Enable DOM graph scanning and page-structure sync. Wires a MutationObserver\n * and a localStorage-backed graph. When `false` (default) this entry behaves\n * identically to `@sentientui/core`.\n */\n graph?: boolean;\n};\n\nfunction readSntUid(): string | undefined {\n try {\n const m = document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);\n return m ? decodeURIComponent(m[1]) : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Graph-capable variant of `init()`. Identical to the lean `init` when\n * `config.graph` is `false` (or omitted). When `config.graph: true`, mounts\n * a DOM scanner + graph client and enables `client.getGraph()`.\n *\n * Import from `@sentientui/core/graph` — do not call the lean `init` alongside\n * this function as that would initialise two clients.\n */\n// Teardown for the graph resources (scanner + MutationObserver + debounce\n// timer + graph client) bound to each apiKey. initLean already disposes the\n// lean client's own timers/listeners on re-init, but it knows nothing about\n// these graph resources, so this entry tracks and tears them down itself —\n// otherwise an HMR / consent-toggle / provider-remount re-init would leak a\n// live MutationObserver and a pending sync timer per mount.\nconst _graphTeardowns = new Map<string, () => void>();\n\nexport function init(config: GraphSentientConfig): SentientClient {\n const client = initLean(config);\n\n // Mirror initLean's opt-out gate: a DNT/GPC visitor (or consent:false) must\n // not get the DOM scanner + graph sync, which POST page-structure beacons and\n // read `_snt_uid` — tracking that bypasses the lean client's own gating, even\n // under `preConsentBehavior: 'statistical_winner'` (audit P1).\n const dntBlocked = config.respectDoNotTrack !== false && isDoNotTrackEnabled();\n const gated = config.consent === false || dntBlocked;\n\n // Keyless zero-network contract: with no api key there is nothing to feed —\n // the scanner must never mount and /v1/graph/sync must never fire.\n if (!config.graph || !config.apiKey || gated || typeof window === 'undefined') return client;\n\n // A prior graph mount for this key is now superseded — tear it down first so\n // its observer/timer don't leak alongside the new mount's.\n const prevTeardown = _graphTeardowns.get(config.apiKey);\n if (prevTeardown) {\n try {\n prevTeardown();\n } catch {\n /* teardown must never throw on re-init */\n }\n }\n\n const domScanner = createDOMScanner();\n const resolvedIngestUrl = config.ingestUrl ?? DEFAULT_INGEST_URL;\n const graphClient = createGraphClient({\n syncUrl: resolvedIngestUrl.replace(/\\/events\\/?$/, '/graph/sync'),\n apiKey: config.apiKey,\n projectId: config.apiKey,\n sessionId: readSntUid(),\n });\n\n // Persisted page-node state from a previous page load is restored by the graph\n // client's own constructor (it reads `_snt_graph_nodes` on creation). We no\n // longer re-read the key and call restore() here — that was a redundant second\n // load path that cleared and reloaded identical data.\n\n void domScanner.scan().then((result) => {\n for (const node of result.nodes) {\n graphClient.addPageNode({\n id: node.componentId,\n componentId: node.componentId,\n semanticType: node.semanticType,\n answers: node.headingText ? [node.headingText] : [],\n prominenceScore: node.prominenceScore,\n depth: node.depth,\n });\n }\n for (const edge of result.edges) {\n graphClient.addStructuralEdge(edge);\n }\n graphClient.syncOnce();\n });\n\n let syncDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n const debouncedSync = (): void => {\n if (syncDebounceTimer !== null) clearTimeout(syncDebounceTimer);\n syncDebounceTimer = setTimeout(() => {\n syncDebounceTimer = null;\n graphClient.syncOnce();\n }, 500);\n };\n\n domScanner.observe((event) => {\n for (const node of event.nodes) {\n graphClient.addPageNode({\n id: node.componentId,\n componentId: node.componentId,\n semanticType: node.semanticType,\n answers: node.headingText ? [node.headingText] : [],\n prominenceScore: node.prominenceScore,\n depth: node.depth,\n });\n }\n for (const edge of event.edges) {\n graphClient.addStructuralEdge(edge);\n }\n debouncedSync();\n });\n\n // Tears down only the graph resources; the caller pairs it with the lean\n // client's own dispose/destroy. Idempotent, and de-registers itself so a\n // later re-init or teardown can't run it twice on already-freed resources.\n const teardownGraph = (): void => {\n if (syncDebounceTimer !== null) {\n clearTimeout(syncDebounceTimer);\n syncDebounceTimer = null;\n }\n domScanner.destroy();\n graphClient.destroy();\n if (_graphTeardowns.get(config.apiKey) === teardownGraph) {\n _graphTeardowns.delete(config.apiKey);\n }\n };\n _graphTeardowns.set(config.apiKey, teardownGraph);\n\n return {\n ...client,\n getGraph: () => graphClient.snapshot(),\n dispose: () => {\n teardownGraph();\n client.dispose();\n },\n destroy: () => {\n teardownGraph();\n client.destroy();\n },\n };\n}\n"],"mappings":"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","names":["OBSERVE_TAGS","HEADING_SELECTOR","MAX_SIBLINGS_PER_GROUP","MAX_STRUCTURAL_EDGES","SSR_SCANNER","normalize","value","min","max","readReactComponentName","element","_a","_b","_c","record","key","fiber","name","e","extractDataAttributes","attrs","attr","SEMANTIC_SET","SEMANTIC_TYPES","inferSemanticType","explicit","role","classifySection","shortHash","input","h","i","domPathSignature","parts","current","parent","index","componentIdFor","declared","depthOf","depth","scanElement","getProminenceScore","heading","detectStructuralEdges","elementToId","edges","seen","ROOT","groups","el","_id","ancestor","groupKey","childId","siblings","sibs","capped","j","aId","bId","fwd","rev","collectNodesAndEdges","nodes","node","hasAria","hasSentientId","createDOMScanner","observer","idleCallbackId","contentCallback","knownElementToId","styles","fontSize","zIndex","rect","distanceFromTop","viewportHeight","inverseDistance","score","resolve","run","id","onContentAdded","mutations","added","addedIds","mutation","hasId","scanned","NODES_KEY","STALE_EDGES_KEY","SEMANTIC_NEIGHBOURS","neighboursFor","semanticType","_a","readStorage","key","fallback","raw","e","writeStorage","value","VALID_SEMANTIC_TYPES","toValidSemanticType","type","contentHashOf","componentId","answers","input","h","i","createGraphClient","config","pageNodes","structuralEdges","persist","restore","data","parsed","node","storedNodes","edge","_b","nodes","nodesByType","n","list","edges","seen","source","neighbourType","targets","target","componentIds","payload","__spreadProps","__spreadValues","DEFAULT_INGEST_URL","readSntUid","m","_graphTeardowns","init","config","_a","client","dntBlocked","isDoNotTrackEnabled","gated","prevTeardown","e","domScanner","createDOMScanner","resolvedIngestUrl","graphClient","createGraphClient","result","node","edge","syncDebounceTimer","debouncedSync","event","teardownGraph","__spreadProps","__spreadValues"]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var ze=Object.create;var se=Object.defineProperty,Ve=Object.defineProperties,qe=Object.getOwnPropertyDescriptor,Xe=Object.getOwnPropertyDescriptors,Ze=Object.getOwnPropertyNames,Oe=Object.getOwnPropertySymbols,et=Object.getPrototypeOf,Le=Object.prototype.hasOwnProperty,tt=Object.prototype.propertyIsEnumerable;var Te=(e,t,n)=>t in e?se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,S=(e,t)=>{for(var n in t||(t={}))Le.call(t,n)&&Te(e,n,t[n]);if(Oe)for(var n of Oe(t))tt.call(t,n)&&Te(e,n,t[n]);return e},Q=(e,t)=>Ve(e,Xe(t));var nt=(e,t)=>{for(var n in t)se(e,n,{get:t[n],enumerable:!0})},Pe=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of Ze(t))!Le.call(e,l)&&l!==n&&se(e,l,{get:()=>t[l],enumerable:!(a=qe(t,l))||a.enumerable});return e};var ot=(e,t,n)=>(n=e!=null?ze(et(e)):{},Pe(t||!e||!e.__esModule?se(n,"default",{value:e,enumerable:!0}):n,e)),st=e=>Pe(se({},"__esModule",{value:!0}),e);var kt={};nt(kt,{LOCAL_MODE_BANNER:()=>Ce,PROD_KEYLESS_ERROR:()=>he,SNAPSHOT_STORAGE_KEY_PREFIX:()=>J,agentUaList:()=>xe,armOfResult:()=>fe,attachMicroSignalDetectors:()=>je,baselineResultFor:()=>z,baselineSlots:()=>Ge,deriveSessionSegment:()=>Ke,detectDeviceClass:()=>ie,detectTimeOfDay:()=>ce,detectTrafficSource:()=>ae,grantConsent:()=>Ct,init:()=>Ye,isDoNotTrackEnabled:()=>_e,matchedAgentToken:()=>Ie,readSnapshot:()=>me,referrerDomainFromReferer:()=>le,renderPrePaintScript:()=>Be,toWireSlot:()=>de,uaTokenMatch:()=>re,writeSnapshot:()=>V});module.exports=st(kt);var rt="_snt_uid";var Y="_snt_uid";function it(){try{if(typeof crypto!="undefined"&&typeof crypto.randomUUID=="function")return crypto.randomUUID()}catch(t){}let e=()=>Math.floor(Math.random()*4294967295).toString(16).padStart(8,"0");return`${e()}-${e()}-${e()}-${e()}`}function at(e){try{let t=document.cookie.match(new RegExp(`(?:^|; )${e}=([^;]*)`));return t?decodeURIComponent(t[1]):null}catch(t){return null}}function lt(e,t,n){try{document.cookie=`${e}=${encodeURIComponent(t)}; max-age=${n}; SameSite=strict; path=/`}catch(a){}}function ct(e){try{return localStorage.getItem(e)}catch(t){return null}}function dt(e,t){try{return localStorage.setItem(e,t),!0}catch(n){return!1}}function ut(e){try{return sessionStorage.getItem(e)}catch(t){return null}}function gt(e,t){try{return sessionStorage.setItem(e,t),!0}catch(n){return!1}}function pt(e){try{sessionStorage.removeItem(e)}catch(t){}}function ft(e){try{return document.cookie=`${e}_probe=1; max-age=1; SameSite=strict; path=/`,/(?:^|; )_snt_uid_probe=1/.test(document.cookie)||document.cookie.indexOf(`${e}_probe=1`)!==-1}catch(t){return!1}}function mt(e){try{localStorage.removeItem(e)}catch(t){}}function yt(e){try{document.cookie=`${e}=; max-age=0; SameSite=strict; path=/`}catch(t){}}var St={getSessionId:()=>null,isEphemeral:()=>!1,destroy:()=>{}};function ge(e){var c,g,f,w,E,P;if(typeof window=="undefined")return St;let t=(c=e==null?void 0:e.cookieName)!=null?c:rt,a=((g=e==null?void 0:e.cookieTTLDays)!=null?g:365)*24*60*60,l=(P=(E=(w=(f=at(t))!=null?f:ct(Y))!=null?w:ut(Y))!=null?E:e==null?void 0:e.ssrSessionId)!=null?P:it();lt(t,l,a);let i=dt(Y,l),d=ft(t),o=i?!1:gt(Y,l),s=!i&&!d&&!o;return{getSessionId:()=>l,isEphemeral:()=>s,destroy:()=>{l=null,yt(t),mt(Y),pt(Y)}}}function we(e){return`_snt_retry_${e.slice(0,12)}`}var ht={push:()=>{},flush:()=>{},destroy:()=>{}};function vt(e,t){try{let n=localStorage.getItem(t);if(!n)return[];let a=JSON.parse(n);return Array.isArray(a)?(localStorage.removeItem(t),a.slice(-e)):[]}catch(n){return[]}}function ve(e,t,n){try{let l=[...(()=>{try{let i=localStorage.getItem(n);if(!i)return[];let d=JSON.parse(i);return Array.isArray(d)?d:[]}catch(i){return[]}})(),...e].slice(-t);localStorage.setItem(n,JSON.stringify(l))}catch(a){}}function Me(e){var Z,ee,te;if(typeof window=="undefined")return ht;let t=(Z=e.flushIntervalMs)!=null?Z:5e3,n=(ee=e.maxBatchSize)!=null?ee:20,a=(te=e.maxRetrySize)!=null?te:100,l=e.ingestUrl,i=e.apiKey,d=we(i),o=[],s=new Set,c=[],g=p=>{for(let m of p)f.delete(m),!s.has(m)&&(s.add(m),c.push(m));for(;c.length>500;){let m=c.shift();m&&s.delete(m)}},f=new Set,w=p=>{s.has(p.id)||f.has(p.id)||(f.add(p.id),o.push(p))},E=p=>{for(let m of p)s.has(m.id)||(f.add(m.id),o.push(m))},P=vt(a,d);for(let p of P)w(p);let x=0,A=0,D=p=>{if(p.length===0)return;let m=JSON.stringify(p),U=p.map(r=>r.id),T;try{T=fetch(l,{method:"POST",keepalive:!0,body:m,headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`}})}catch(r){ve(p,a,d),E(p),A++,x=Date.now()+Math.min(6e4,1e3*2**Math.min(A,6));return}let K=r=>{if(r.ok||r.status>=400&&r.status<500&&r.status!==429){g(U),A=0,x=0;return}ve(p,a,d),E(p),A++,x=Date.now()+Math.min(6e4,1e3*2**Math.min(A,6))};T instanceof Promise?T.then(K).catch(()=>{ve(p,a,d),E(p),A++,x=Date.now()+Math.min(6e4,1e3*2**Math.min(A,6))}):K(T)},h=typeof TextEncoder!="undefined"?new TextEncoder:null,ue=p=>h?h.encode(p).length:p.length,$=p=>{let m=[],U=2;for(let T of p){let K=ue(JSON.stringify(T))+1;if(m.length>0&&U+K>57344||m.length>=n)break;m.push(T),U+=K}return m},M=()=>{try{if(Date.now()<x)return;for(;o.length>0&&!(Date.now()<x);){let p=o.filter(U=>!s.has(U.id));if(o.length=0,p.length===0)break;let m=$(p);if(m.length===0)break;m.length<p.length&&o.push(...p.slice(m.length)),D(m)}}catch(p){}},O=!0,W=null;W=setInterval(()=>{O&&M()},t);let N=()=>{document.visibilityState==="hidden"&&M()},X=()=>{M()};return document.addEventListener("visibilitychange",N),window.addEventListener("pagehide",X),{push(p){w(p),o.length>=n&&M()},flush:M,destroy(){O=!1,W!==null&&(clearInterval(W),W=null),document.removeEventListener("visibilitychange",N),window.removeEventListener("pagehide",X),M()}}}var Ee="_snt_asgn_";function pe(e,t){return`${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function wt(e,t){return`${Ee}${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function Ue(e){let t=e.slice(Ee.length),n=t.indexOf(":");if(n<0)return null;try{return{componentId:decodeURIComponent(t.slice(0,n)),segment:decodeURIComponent(t.slice(n+1))}}catch(a){return null}}function be(){try{let e=[];for(let t=0;t<localStorage.length;t++){let n=localStorage.key(t);n!=null&&n.startsWith(Ee)&&e.push(n)}return e}catch(e){return[]}}function Ne(e=18e5){let t=new Map,n=l=>l.assignedAt+(l.ttlMs&&l.ttlMs>0?l.ttlMs:e)<Date.now();return typeof window!="undefined"&&(()=>{for(let l of be())try{let i=localStorage.getItem(l);if(!i)continue;let d=JSON.parse(i);if(n(d)){localStorage.removeItem(l);continue}let o=Ue(l);if(!o)continue;t.set(pe(o.componentId,o.segment),d)}catch(i){}})(),{get(l,i){let d=t.get(pe(l,i));return d?n(d)?(t.delete(pe(l,i)),null):d:null},set(l,i,d){let o=pe(l,i);t.set(o,d);try{localStorage.setItem(wt(l,i),JSON.stringify(d))}catch(s){}},invalidate(l){let i=`${encodeURIComponent(l)}:`;for(let d of[...t.keys()])d.startsWith(i)&&t.delete(d);for(let d of be()){let o=Ue(d);if((o==null?void 0:o.componentId)===l)try{localStorage.removeItem(d)}catch(s){}}},clear(){t.clear();for(let l of be())try{localStorage.removeItem(l)}catch(i){}}}}var xe=["GPTBot","ChatGPT-User","OAI-SearchBot","ClaudeBot","Claude-User","Claude-SearchBot","PerplexityBot","Perplexity-User","Google-Extended","Applebot-Extended","Meta-ExternalAgent","Bytespider","CCBot","Amazonbot","cohere-ai","Diffbot"];function re(e){return Ie(e)!==null}function Ie(e){var n;if(!e)return null;let t=e.toLowerCase();return(n=xe.find(a=>t.includes(a.toLowerCase())))!=null?n:null}function ie(e){let t=e.toLowerCase();return/ipad|tablet|playbook|kindle|silk/.test(t)?"tablet":/mobi|iphone|ipod|android.*mobile|phone/.test(t)?"mobile":"desktop"}function ae(e,t){if(!e)return"direct";try{let n=new URL(e);if(t)try{if(new URL(t).host===n.host)return"direct"}catch(l){}let a=n.hostname.toLowerCase();return/(^|\.)(google|bing|duckduckgo|yahoo)\./.test(a)?"search":/(^|\.)(twitter\.com|x\.com|facebook\.com|linkedin\.com|reddit\.com|t\.co)$/.test(a)?"social":"referral"}catch(n){return"direct"}}function le(e){if(!e)return null;try{return new URL(e).hostname}catch(t){return null}}function ce(e){let t=e.getHours();return t<6?"night":t<12?"morning":t<18?"afternoon":"evening"}function Ke(e){let t=bt("__segment__",e);return`${t.deviceClass}:${t.trafficSource}`}function bt(e,t){var i,d,o,s,c,g,f;let n=(d=(i=t==null?void 0:t.userAgent)==null?void 0:i.trim())!=null?d:"",a=(s=(o=t==null?void 0:t.referer)==null?void 0:o.trim())!=null?s:"",l=(c=t==null?void 0:t.now)!=null?c:new Date;return{sessionId:e,ephemeral:!1,utmParams:(g=t==null?void 0:t.utmParams)!=null?g:{},deviceClass:n?ie(n):"desktop",trafficSource:a?ae(a,t==null?void 0:t.appOrigin):"direct",referrerDomain:le(a),timeOfDay:ce(l),dayOfWeek:(f=["sun","mon","tue","wed","thu","fri","sat"][l.getDay()])!=null?f:"sun",automation:(t==null?void 0:t.webdriver)===!0||re(n)}}var H=require("@sentientui/policy");function de(e){return S(S(S({id:e.id},e.arms?{arms:[...e.arms]}:{}),e.dims?{dims:Object.fromEntries(Object.entries(e.dims).map(([t,n])=>[t,[...n]]))}:{}),e.baseline!==void 0?{baseline:e.baseline}:{})}function z(e){let t=de(e);return(0,H.slotResultFor)(t,(0,H.slotBaselineArm)(t))}function Ge(e){let t={};for(let n of e)t[n.id]=z(n);return t}function fe(e){return typeof e=="string"?e:(0,H.canonicalArm)(e)}var J="_snt_snap:",Et=["low","medium","high"];function me(e){try{let t=localStorage.getItem(J+e);if(!t)return null;let n=JSON.parse(t);return!n||typeof n!="object"||n.v!==1||typeof n.persona!="string"||typeof n.band!="string"||!Et.includes(n.band)||typeof n.slots!="object"||n.slots===null||Array.isArray(n.slots)||!(n.layoutOrder===null||Array.isArray(n.layoutOrder))||typeof n.savedAt!="number"||!(n.slotConfig===void 0||typeof n.slotConfig=="object"&&n.slotConfig!==null&&!Array.isArray(n.slotConfig))?null:n}catch(t){return null}}function V(e,t){try{localStorage.setItem(J+e,JSON.stringify(t))}catch(n){}}function Be(e){return"(function(){try{var r=localStorage.getItem("+JSON.stringify(J+e).replace(/</g,"\\u003c")+');if(!r)return;var s=JSON.parse(r);if(!s||s.v!==1||typeof s.persona!=="string"||typeof s.band!=="string")return;var d=document.documentElement;if(d.hasAttribute("data-sentient-persona"))return;d.setAttribute("data-sentient-persona",s.persona);d.setAttribute("data-sentient-confidence",s.band);}catch(e){}})();'}var ke=require("@sentientui/policy");var Se=require("@sentientui/policy");var he="[sentient] No API key configured \u2014 nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development.",Ce="[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.",$e=!1,ye=!1;function xt(){var e;try{return(e=new URLSearchParams(window.location.search).get("sentient_persona"))!=null?e:void 0}catch(t){return}}function We(e){var o;let t=ge({ssrSessionId:e.ssrSessionId}),n=(o=t.getSessionId())!=null?o:"local",a=xt(),l=import("@sentientui/core/local").then(s=>{let c=s;return c.LOCAL_ENGINE_AVAILABLE?($e||($e=!0,console.info(Ce)),c):(ye||(ye=!0,console.error(he)),null)}).catch(()=>(ye||(ye=!0,console.error(he)),null)),i=null;function d(s){let c=document.documentElement;c.dataset.sentientPersona===void 0&&(c.dataset.sentientPersona=s.persona,c.dataset.sentientConfidence=(0,Se.confidenceBand)(s.confidence))}return{isLocal:!0,async decide(s){var f,w,E;let c=await l;if(!c)return null;let g=c.createLocalEngine({sessionId:n,forcedPersona:a}).decide(s);return i=Q(S({},g),{layoutOrder:(w=(f=g.layoutOrder)!=null?f:i==null?void 0:i.layoutOrder)!=null?w:null,slots:S(S({},(E=i==null?void 0:i.slots)!=null?E:{}),g.slots)}),V(e.apiKey||"local",{v:1,persona:i.persona,band:(0,Se.confidenceBand)(i.confidence),slots:i.slots,layoutOrder:i.layoutOrder,savedAt:Date.now()}),d(g),g},getSlotResult(s){var c,g,f;return(f=(g=i==null?void 0:i.slots[s])!=null?g:(c=e.initialSlots)==null?void 0:c[s])!=null?f:null},getPersona(){return i?{persona:i.persona,confidence:i.confidence,band:(0,Se.confidenceBand)(i.confidence)}:null},async assign(s,c){var w;let g=await l;return!g||!c||c.length===0?c!=null&&c[0]?{variantId:c[0],assignmentTtlMs:0}:null:{variantId:(w=g.createLocalEngine({sessionId:n,forcedPersona:a}).decide({components:[{id:s,variantIds:c}]}).assignments[s])!=null?w:c[0],assignmentTtlMs:0}},track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},getAssignment:()=>null,fetchWeights:()=>Promise.resolve([]),getGraph:()=>({pageNodes:[],capturedAt:0}),dispose:()=>{},destroy:()=>t.destroy()}}function je(e,t,n,a){let l=[];{let o=!1,s=[],c=()=>{if(o)return;let g=Date.now();for(s.push(g);s.length>0&&g-s[0]>500;)s.shift();s.length>=3&&(o=!0,e("rage_click"))};t.addEventListener("click",c),l.push(()=>t.removeEventListener("click",c))}{let i=!1,d=o=>{if(i||!(o.target instanceof Node)||!t.contains(o.target)&&t!==o.target)return;i=!0;let s=typeof window!="undefined"?window.getSelection():null,c=s?s.toString().length:0;e("text_copy",{selectionLength:c})};document.addEventListener("copy",d),l.push(()=>document.removeEventListener("copy",d))}{let i=!1,d=!1,o=null,s=()=>{o!==null&&(clearTimeout(o),o=null)},c=()=>{i||!d||(s(),o=setTimeout(()=>{!i&&d&&(i=!0,e("scroll_hesitation"))},3e3))},g=()=>{s(),c()},f=E=>{for(let P of E)d=P.intersectionRatio>.3,d?c():s()},w=new IntersectionObserver(f,{threshold:[.3]});w.observe(t),window.addEventListener("scroll",g,{passive:!0}),l.push(()=>{w.disconnect(),window.removeEventListener("scroll",g),s()})}if((a==null?void 0:a.tabLoss)!==!1){let i=!1,d=n!=null?n:Date.now(),o=()=>{if(i||document.visibilityState!=="hidden")return;let s=Date.now()-d;s<15e3&&(i=!0,e("tab_loss",{timeOnPage:s}))};document.addEventListener("visibilitychange",o),l.push(()=>document.removeEventListener("visibilitychange",o))}return()=>{for(let i of l)i()}}var Fe="https://api.sentient-ui.com/v1/events",C=new Map,Je=null;function Re(){try{if(typeof crypto!="undefined"&&typeof crypto.randomUUID=="function")return crypto.randomUUID()}catch(e){}return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}var q={track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},getAssignment:()=>null,assign:()=>Promise.resolve(null),decide:()=>Promise.resolve(null),getSlotResult:()=>null,getPersona:()=>null,fetchWeights:()=>Promise.resolve([]),getGraph:()=>({pageNodes:[],capturedAt:0}),dispose:()=>{},destroy:()=>{}};function It(){try{let e={},t=new URLSearchParams(window.location.search);for(let[n,a]of t)n.startsWith("utm_")&&(e[n]=a);return e}catch(e){return{}}}function Qe(e){return e.replace(/\/events\/?$/,"")}function _e(){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")}function Ct(e){var o;if(typeof window=="undefined")return;let t=e!=null?e:Je;if(!t){console.warn("[sentient] grantConsent() called before init()");return}let n=C.get(t);if(!n){console.warn("[sentient] grantConsent() called before init()");return}let{config:a,upgrade:l}=n;if(!l||a.respectDoNotTrack!==!1&&_e())return;let i=Ye(Q(S({},a),{consent:!0}));l(i);let d=(o=C.get(t))==null?void 0:o.dispose;C.set(t,{config:Q(S({},a),{consent:!0}),upgrade:null,dispose:d})}function Rt(e){var d;let t=Qe((d=e.ingestUrl)!=null?d:Fe),n={"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},a={track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},getAssignment:()=>null,fetchWeights:()=>Promise.resolve([]),async assign(o,s,c){try{let g=new URLSearchParams({componentId:o});for(let E of s!=null?s:[])g.append("variantIds[]",E);let f=await fetch(`${t}/winner?${g.toString()}`,{headers:n});return f.ok?{variantId:(await f.json()).variantId,assignmentTtlMs:0}:s!=null&&s[0]?{variantId:s[0],assignmentTtlMs:0}:null}catch(g){return s!=null&&s[0]?{variantId:s[0],assignmentTtlMs:0}:null}},decide:()=>Promise.resolve(null),getSlotResult:()=>null,getPersona:()=>null,getGraph:()=>({pageNodes:[],capturedAt:0}),dispose:()=>{},destroy:()=>{}},l={track:o=>a.track(o),goal:(o,s,c,g)=>a.goal(o,s,c,g),componentGoal:(o,s,c)=>a.componentGoal(o,s,c),identify:o=>a.identify(o),getAssignment:(o,s)=>a.getAssignment(o,s),assign:(o,s,c,g)=>a.assign(o,s,c,g),decide:o=>a.decide(o),getSlotResult:o=>a.getSlotResult(o),getPersona:()=>a.getPersona(),fetchWeights:()=>a.fetchWeights(),getGraph:()=>a.getGraph(),dispose:()=>a.dispose(),destroy:()=>a.destroy()};function i(o){a=o}return{proxy:l,setInner:i}}function Ye(e){var X,Z,ee,te,p,m,U,T,K;if(typeof window=="undefined")return q;Je=e.apiKey;let t=C.get(e.apiKey||"local");if(t!=null&&t.dispose)try{t.dispose()}catch(r){}let n=e.respectDoNotTrack!==!1&&_e(),a=e.consent===!1||n,l=typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_");if(e.localMode===!0||!l&&e.localMode!==!1)return a?(C.set(e.apiKey||"local",{config:e,upgrade:null}),q):(C.set(e.apiKey||"local",{config:e,upgrade:null}),We(e));if(a){if(e.preConsentBehavior==="statistical_winner"){if(!e.apiKey||!e.apiKey.startsWith("pk_"))return console.warn("[sentient] init() called with an invalid apiKey \u2014 expected a pk_ public key. SDK disabled."),q;let{proxy:r,setInner:u}=Rt(e);return C.set(e.apiKey,{config:e,upgrade:n?null:u}),r}return C.set(e.apiKey,{config:e,upgrade:null}),q}if(!e.apiKey||!e.apiKey.startsWith("pk_"))return console.warn("[sentient] init() called with an invalid apiKey \u2014 expected a pk_ public key. SDK disabled."),q;if(e.ingestUrl==="")return console.warn("[sentient] init() called with an empty ingestUrl. SDK disabled."),q;let i=(X=e.ingestUrl)!=null?X:Fe,d=Date.now(),o=ge({ssrSessionId:e.ssrSessionId}),s=Ne(),c=Me({ingestUrl:i,apiKey:e.apiKey}),g=Qe(i),f={"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},w=ie((Z=navigator.userAgent)!=null?Z:""),E=typeof window!="undefined"?window.location.origin:void 0,P=ae((ee=document.referrer)!=null?ee:"",E),x=(te=e.sessionSegment)!=null?te:`${w}:${P}`,A=new Map,D=new Map,h=null,ue=r=>{for(let u of r)D.has(u.id)||D.set(u.id,z(u))};if(e.initialSlots)for(let[r,u]of Object.entries(e.initialSlots))D.set(r,u);let $=me(e.apiKey);if($)for(let[r,u]of Object.entries($.slots))D.has(r)||D.set(r,u);let M={low:.15,medium:.5,high:.85};if(e.initialPersona)h=S({},e.initialPersona);else{let r=document.documentElement.dataset;r.sentientPersona?h={persona:r.sentientPersona,confidence:(m=M[(p=r.sentientConfidence)!=null?p:"low"])!=null?m:.15}:$&&(h={persona:$.persona,confidence:(U=M[$.band])!=null?U:.15})}if(e.initialAssignments)for(let[r,u]of Object.entries(e.initialAssignments))s.set(r,x,{variantId:u,assignedAt:Date.now(),segment:x,confidence:1});let O=Promise.resolve(),W=o.getSessionId();if(W){let r=le((T=document.referrer)!=null?T:""),u=S(S({sessionId:W,deviceClass:w,trafficSource:P,referrerDomain:r,utmParams:It(),timeOfDay:ce(new Date),dayOfWeek:["sun","mon","tue","wed","thu","fri","sat"][new Date().getDay()],ephemeral:o.isEphemeral(),automation:typeof navigator!="undefined"&&navigator.webdriver===!0||re((K=navigator.userAgent)!=null?K:"")},e.userId?{userId:e.userId}:{}),e.country?{country:e.country}:{});try{O=fetch(`${g}/sessions`,{method:"POST",keepalive:!0,body:JSON.stringify(u),headers:f}).then(y=>{y.status===402&&console.warn("[SentientUI] Session limit exceeded for this project. The bandit will stop learning until the limit resets. Upgrade at sentient-ui.com/pricing")}).catch(()=>{})}catch(y){}}e.debug&&(console.log("[sentient] initialized",{context:e.context}),window.__sentient={client:null,queue:c});let N={goal(r,u={},y=1,L=0){let I=o.getSessionId();if(!I)return;let b=Re();O.then(()=>{fetch(`${g}/goals`,{method:"POST",keepalive:!0,body:JSON.stringify({sessionId:I,name:r,metadata:u,weight:y,stepIndex:L,goalId:b}),headers:f}).catch(()=>{})})},componentGoal(r,u,y){var R,B,k;let L=o.getSessionId();if(!L)return;let I=s.get(r,x),b=I?null:(R=D.get(r))!=null?R:null;if(!I&&b===null){e.debug&&console.warn(`[sentient] componentGoal("${r}"): no assignment or slot decision yet \u2014 render its <Adaptive>/adaptive hook or call assign()/decide() before recording a goal.`);return}let j=I?I.variantId:fe(b),G={id:Re(),sessionId:L,projectId:e.apiKey,componentId:r,variantId:j,eventType:"goal_achieved",goalType:u,payload:S({reward:(B=y==null?void 0:y.reward)!=null?B:1},(k=y==null?void 0:y.metadata)!=null?k:{}),timestamp:Date.now(),timeInSession:Date.now()-d};e.debug&&console.log("[sentient] componentGoal",G),O.then(()=>c.push(G))},identify(r){let u=o.getSessionId();u&&O.then(()=>{fetch(`${g}/sessions`,{method:"POST",keepalive:!0,body:JSON.stringify({sessionId:u,userId:r,ephemeral:o.isEphemeral()}),headers:f}).catch(()=>{})})},track(r){let u=o.getSessionId();if(!u)return;let y=Q(S({},r),{id:Re(),sessionId:u,timestamp:Date.now(),timeInSession:Date.now()-d});e.debug&&console.log("[sentient] track",y),O.then(()=>c.push(y))},getAssignment(r,u){return s.get(r,u)},async assign(r,u,y,L){let I=o.getSessionId();if(!I)return null;let b=s.get(r,x);if(b&&(u!=null&&u.length||b.content!==void 0)){let R=b.ttlMs&&b.ttlMs>0?Math.max(0,b.assignedAt+b.ttlMs-Date.now()):0;return{variantId:b.variantId,assignmentTtlMs:R,content:b.content}}let j=A.get(r);if(j)return j;let G=(async()=>{await O;try{let R={sessionId:I,componentId:r,variantIds:u};L!==void 0?R.agentDataByVariant=L:y!==void 0&&(R.agentData=y);let B=await fetch(`${g}/assign`,{method:"POST",body:JSON.stringify(R),headers:f});if(!B.ok)return null;let k=await B.json();return s.set(r,x,S({variantId:k.variantId,assignedAt:Date.now(),segment:x,confidence:1,content:k.content},k.assignmentTtlMs&&k.assignmentTtlMs>0?{ttlMs:k.assignmentTtlMs}:{})),k}catch(R){return null}finally{A.delete(r)}})();return A.set(r,G),G},async decide(r){var L,I,b,j,G,R,B,k,Ae;let u=o.getSessionId();if(!u)return null;let y=(L=r.slots)!=null?L:[];await O;try{let F={sessionId:u};r.sections&&r.sections.length>0&&(F.sections=r.sections.map(_=>({id:_}))),F.components=(I=r.components)!=null?I:[],y.length>0&&(F.slots=y.map(de)),r.slotsFrom==="registry"&&(F.slotsFrom="registry"),r.v&&(F.v=r.v);let De=await fetch(`${g}/decide`,{method:"POST",body:JSON.stringify(F),headers:f});if(!De.ok)return ue(y),null;let v=await De.json(),ne={};for(let _ of y)ne[_.id]=(j=(b=v.slots)==null?void 0:b[_.id])!=null?j:z(_);if(v.slots)for(let[_,oe]of Object.entries(v.slots))_ in ne||(ne[_]=oe);for(let[_,oe]of Object.entries(ne))D.set(_,oe);let He=h!=null&&h.persona!=="unknown";v.persona&&!(v.persona==="unknown"&&He)?h={persona:v.persona,confidence:(G=v.confidence)!=null?G:0}:h||(h={persona:"unknown",confidence:0});for(let[_,oe]of Object.entries((R=v.assignments)!=null?R:{}))s.set(_,x,{variantId:oe,assignedAt:Date.now(),segment:x,confidence:1});return V(e.apiKey,S({v:1,persona:h.persona,band:(0,ke.confidenceBand)(h.confidence),slots:Object.fromEntries(D),layoutOrder:(B=v.layoutOrder)!=null?B:null,savedAt:Date.now()},v.slotConfig?{slotConfig:v.slotConfig}:{})),S(S(S({layoutOrder:(k=v.layoutOrder)!=null?k:null,assignments:(Ae=v.assignments)!=null?Ae:{},slots:ne,persona:h.persona,confidence:h.confidence},v.slotConfig?{slotConfig:v.slotConfig}:{}),v.goals?{goals:v.goals}:{}),v.sectionMap?{sectionMap:v.sectionMap}:{})}catch(F){return ue(y),null}},getSlotResult(r){var u;return(u=D.get(r))!=null?u:null},getPersona(){return h?{persona:h.persona,confidence:h.confidence,band:(0,ke.confidenceBand)(h.confidence)}:null},async fetchWeights(){var r;try{let u=await fetch(`${g}/weights`,{headers:f});return u.ok?(r=(await u.json()).components)!=null?r:[]:[]}catch(u){return[]}},getGraph(){return{pageNodes:[],capturedAt:0}},dispose(){var r;c.destroy(),((r=C.get(e.apiKey))==null?void 0:r.dispose)===N.dispose&&C.delete(e.apiKey),e.debug&&console.log("[sentient] disposed")},destroy(){var r;c.destroy(),o.destroy(),((r=C.get(e.apiKey))==null?void 0:r.dispose)===N.dispose&&C.delete(e.apiKey);try{localStorage.removeItem(J+e.apiKey),localStorage.removeItem(we(e.apiKey))}catch(u){}e.debug&&console.log("[sentient] destroyed")}};if(C.set(e.apiKey,{config:e,upgrade:null,dispose:N.dispose}),e.debug){let r=window;r.__sentient&&(r.__sentient.client=N)}return N}0&&(module.exports={LOCAL_MODE_BANNER,PROD_KEYLESS_ERROR,SNAPSHOT_STORAGE_KEY_PREFIX,agentUaList,armOfResult,attachMicroSignalDetectors,baselineResultFor,baselineSlots,deriveSessionSegment,detectDeviceClass,detectTimeOfDay,detectTrafficSource,grantConsent,init,isDoNotTrackEnabled,matchedAgentToken,readSnapshot,referrerDomainFromReferer,renderPrePaintScript,toWireSlot,uaTokenMatch,writeSnapshot});
|
|
1
|
+
"use strict";var ze=Object.create;var re=Object.defineProperty,qe=Object.defineProperties,Xe=Object.getOwnPropertyDescriptor,Ze=Object.getOwnPropertyDescriptors,et=Object.getOwnPropertyNames,Te=Object.getOwnPropertySymbols,tt=Object.getPrototypeOf,Pe=Object.prototype.hasOwnProperty,nt=Object.prototype.propertyIsEnumerable;var Le=(e,t,n)=>t in e?re(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,S=(e,t)=>{for(var n in t||(t={}))Pe.call(t,n)&&Le(e,n,t[n]);if(Te)for(var n of Te(t))nt.call(t,n)&&Le(e,n,t[n]);return e},Q=(e,t)=>qe(e,Ze(t));var ot=(e,t)=>{for(var n in t)re(e,n,{get:t[n],enumerable:!0})},Me=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let c of et(t))!Pe.call(e,c)&&c!==n&&re(e,c,{get:()=>t[c],enumerable:!(a=Xe(t,c))||a.enumerable});return e};var rt=(e,t,n)=>(n=e!=null?ze(tt(e)):{},Me(t||!e||!e.__esModule?re(n,"default",{value:e,enumerable:!0}):n,e)),st=e=>Me(re({},"__esModule",{value:!0}),e);var Dt={};ot(Dt,{LOCAL_MODE_BANNER:()=>Re,PROD_KEYLESS_ERROR:()=>ve,SNAPSHOT_STORAGE_KEY_PREFIX:()=>J,agentUaList:()=>Ie,armOfResult:()=>me,attachMicroSignalDetectors:()=>Fe,baselineResultFor:()=>Y,baselineSlots:()=>Be,deriveSessionSegment:()=>Ge,detectDeviceClass:()=>ie,detectTimeOfDay:()=>ce,detectTrafficSource:()=>ae,grantConsent:()=>At,init:()=>He,isDoNotTrackEnabled:()=>_e,matchedAgentToken:()=>Ce,readSnapshot:()=>ye,referrerDomainFromReferer:()=>le,renderPrePaintScript:()=>$e,toWireSlot:()=>de,uaTokenMatch:()=>se,writeSnapshot:()=>z});module.exports=st(Dt);function ge(){try{if(typeof crypto!="undefined"&&typeof crypto.randomUUID=="function")return crypto.randomUUID()}catch(e){}try{if(typeof crypto!="undefined"&&typeof crypto.getRandomValues=="function"){let e=new Uint8Array(16);crypto.getRandomValues(e),e[6]=e[6]&15|64,e[8]=e[8]&63|128;let t="";for(let n=0;n<16;n++)t+=e[n].toString(16).padStart(2,"0"),(n===3||n===5||n===7||n===9)&&(t+="-");return t}}catch(e){}return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}var it="_snt_uid",at=365,V="_snt_uid";function lt(){return ge()}function ct(e){try{let t=document.cookie.match(new RegExp(`(?:^|; )${e}=([^;]*)`));return t?decodeURIComponent(t[1]):null}catch(t){return null}}function dt(e,t,n){try{document.cookie=`${e}=${encodeURIComponent(t)}; max-age=${n}; SameSite=strict; path=/`}catch(a){}}function ut(e){try{return localStorage.getItem(e)}catch(t){return null}}function gt(e,t){try{return localStorage.setItem(e,t),!0}catch(n){return!1}}function pt(e){try{return sessionStorage.getItem(e)}catch(t){return null}}function ft(e,t){try{return sessionStorage.setItem(e,t),!0}catch(n){return!1}}function mt(e){try{sessionStorage.removeItem(e)}catch(t){}}function yt(e){try{return document.cookie=`${e}_probe=1; max-age=1; SameSite=strict; path=/`,document.cookie.indexOf(`${e}_probe=1`)!==-1}catch(t){return!1}}function St(e){try{localStorage.removeItem(e)}catch(t){}}function ht(e){try{document.cookie=`${e}=; max-age=0; SameSite=strict; path=/`}catch(t){}}var vt={getSessionId:()=>null,isEphemeral:()=>!1,destroy:()=>{}};function pe(e){var g,f,w,x,P,b;if(typeof window=="undefined")return vt;let t=(g=e==null?void 0:e.cookieName)!=null?g:it,a=((f=e==null?void 0:e.cookieTTLDays)!=null?f:at)*24*60*60,c=I=>I&&I.length>0?I:null,s=(b=(P=(x=(w=c(ct(t)))!=null?w:c(ut(V)))!=null?x:c(pt(V)))!=null?P:c(e==null?void 0:e.ssrSessionId))!=null?b:lt();dt(t,s,a);let l=gt(V,s),o=yt(t),r=l?!1:ft(V,s),d=!l&&!o&&!r;return{getSessionId:()=>s,isEphemeral:()=>d,destroy:()=>{s=null,ht(t),St(V),mt(V)}}}function be(e){return`_snt_retry_${e.slice(0,12)}`}var wt={push:()=>{},flush:()=>{},destroy:()=>{}};function bt(e,t){try{let n=localStorage.getItem(t);if(!n)return[];let a=JSON.parse(n);return Array.isArray(a)?(localStorage.removeItem(t),a.slice(-e)):[]}catch(n){return[]}}function we(e,t,n){try{let a=(()=>{try{let l=localStorage.getItem(n);if(!l)return[];let o=JSON.parse(l);return Array.isArray(o)?o:[]}catch(l){return[]}})(),c=new Map;for(let l of a)c.set(l.id,l);for(let l of e)c.set(l.id,l);let s=[...c.values()].slice(-t);localStorage.setItem(n,JSON.stringify(s))}catch(a){}}function Et(e,t){try{let n=localStorage.getItem(t);if(!n)return;let a=JSON.parse(n);if(!Array.isArray(a))return;let c=new Set(e),s=a.filter(l=>!c.has(l.id));if(s.length===a.length)return;s.length===0?localStorage.removeItem(t):localStorage.setItem(t,JSON.stringify(s))}catch(n){}}function Ne(e){var Z,ee,te;if(typeof window=="undefined")return wt;let t=(Z=e.flushIntervalMs)!=null?Z:5e3,n=(ee=e.maxBatchSize)!=null?ee:20,a=(te=e.maxRetrySize)!=null?te:100,c=e.ingestUrl,s=e.apiKey,l=be(s),o=[],r=new Set,d=[],g=p=>{for(let m of p)f.delete(m),!r.has(m)&&(r.add(m),d.push(m));for(;d.length>500;){let m=d.shift();m&&r.delete(m)}Et(p,l)},f=new Set,w=p=>{r.has(p.id)||f.has(p.id)||(f.add(p.id),o.push(p))},x=p=>{for(let m of p)r.has(m.id)||(f.add(m.id),o.push(m))},P=bt(a,l);for(let p of P)w(p);let b=0,I=0,D=p=>{if(p.length===0)return;let m=JSON.stringify(p),N=p.map(i=>i.id),T;try{T=fetch(c,{method:"POST",keepalive:!0,body:m,headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`}})}catch(i){we(p,a,l),x(p),I++,b=Date.now()+Math.min(6e4,1e3*2**Math.min(I,6));return}let K=i=>{if(i.ok||i.status>=400&&i.status<500&&i.status!==429){g(N),I=0,b=0;return}we(p,a,l),x(p),I++,b=Date.now()+Math.min(6e4,1e3*2**Math.min(I,6))};T instanceof Promise?T.then(K).catch(()=>{we(p,a,l),x(p),I++,b=Date.now()+Math.min(6e4,1e3*2**Math.min(I,6))}):K(T)},h=typeof TextEncoder!="undefined"?new TextEncoder:null,ue=p=>h?h.encode(p).length:p.length,$=p=>{let m=[],N=2;for(let T of p){let K=ue(JSON.stringify(T))+1;if(m.length>0&&N+K>57344||m.length>=n)break;m.push(T),N+=K}return m},M=()=>{try{if(Date.now()<b)return;for(;o.length>0&&!(Date.now()<b);){let p=o.filter(N=>!r.has(N.id));if(o.length=0,p.length===0)break;let m=$(p);if(m.length===0)break;m.length<p.length&&o.push(...p.slice(m.length)),D(m)}}catch(p){}},O=!0,W=null;W=setInterval(()=>{O&&M()},t);let U=()=>{document.visibilityState==="hidden"&&M()},X=()=>{M()};return document.addEventListener("visibilitychange",U),window.addEventListener("pagehide",X),{push(p){w(p),o.length>=n&&M()},flush:M,destroy(){O=!1,W!==null&&(clearInterval(W),W=null),document.removeEventListener("visibilitychange",U),window.removeEventListener("pagehide",X),M()}}}var xe="_snt_asgn_";function fe(e,t){return`${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function xt(e,t){return`${xe}${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function Ue(e){let t=e.slice(xe.length),n=t.indexOf(":");if(n<0)return null;try{return{componentId:decodeURIComponent(t.slice(0,n)),segment:decodeURIComponent(t.slice(n+1))}}catch(a){return null}}function Ee(){try{let e=[];for(let t=0;t<localStorage.length;t++){let n=localStorage.key(t);n!=null&&n.startsWith(xe)&&e.push(n)}return e}catch(e){return[]}}function Ke(e=18e5){let t=new Map,n=c=>c.assignedAt+(c.ttlMs&&c.ttlMs>0?c.ttlMs:e)<Date.now();return typeof window!="undefined"&&(()=>{for(let c of Ee())try{let s=localStorage.getItem(c);if(!s)continue;let l=JSON.parse(s);if(n(l)){localStorage.removeItem(c);continue}let o=Ue(c);if(!o)continue;t.set(fe(o.componentId,o.segment),l)}catch(s){}})(),{get(c,s){let l=t.get(fe(c,s));return l?n(l)?(t.delete(fe(c,s)),null):l:null},set(c,s,l){let o=fe(c,s);t.set(o,l);try{localStorage.setItem(xt(c,s),JSON.stringify(l))}catch(r){}},invalidate(c){let s=`${encodeURIComponent(c)}:`;for(let l of[...t.keys()])l.startsWith(s)&&t.delete(l);for(let l of Ee()){let o=Ue(l);if((o==null?void 0:o.componentId)===c)try{localStorage.removeItem(l)}catch(r){}}},clear(){t.clear();for(let c of Ee())try{localStorage.removeItem(c)}catch(s){}}}}var Ie=["GPTBot","ChatGPT-User","OAI-SearchBot","ClaudeBot","Claude-User","Claude-SearchBot","PerplexityBot","Perplexity-User","Google-Extended","Applebot-Extended","Meta-ExternalAgent","Bytespider","CCBot","Amazonbot","cohere-ai","Diffbot"];function se(e){return Ce(e)!==null}function Ce(e){var n;if(!e)return null;let t=e.toLowerCase();return(n=Ie.find(a=>t.includes(a.toLowerCase())))!=null?n:null}function ie(e){let t=e.toLowerCase();return/ipad|tablet|playbook|kindle|silk/.test(t)?"tablet":/mobi|iphone|ipod|android.*mobile|phone/.test(t)?"mobile":"desktop"}function ae(e,t){if(!e)return"direct";try{let n=new URL(e);if(t)try{if(new URL(t).host===n.host)return"direct"}catch(c){}let a=n.hostname.toLowerCase();return/(^|\.)(google|bing|duckduckgo|yahoo)\./.test(a)?"search":/(^|\.)(twitter\.com|x\.com|facebook\.com|linkedin\.com|reddit\.com|t\.co)$/.test(a)?"social":"referral"}catch(n){return"direct"}}function le(e){if(!e)return null;try{return new URL(e).hostname}catch(t){return null}}function ce(e){let t=e.getHours();return t<6?"night":t<12?"morning":t<18?"afternoon":"evening"}function Ge(e){let t=It("__segment__",e);return`${t.deviceClass}:${t.trafficSource}`}function It(e,t){var s,l,o,r,d,g,f;let n=(l=(s=t==null?void 0:t.userAgent)==null?void 0:s.trim())!=null?l:"",a=(r=(o=t==null?void 0:t.referer)==null?void 0:o.trim())!=null?r:"",c=(d=t==null?void 0:t.now)!=null?d:new Date;return{sessionId:e,ephemeral:!1,utmParams:(g=t==null?void 0:t.utmParams)!=null?g:{},deviceClass:n?ie(n):"desktop",trafficSource:a?ae(a,t==null?void 0:t.appOrigin):"direct",referrerDomain:le(a),timeOfDay:ce(c),dayOfWeek:(f=["sun","mon","tue","wed","thu","fri","sat"][c.getDay()])!=null?f:"sun",automation:(t==null?void 0:t.webdriver)===!0||se(n)}}var H=require("@sentientui/policy");function de(e){return S(S(S({id:e.id},e.arms?{arms:[...e.arms]}:{}),e.dims?{dims:Object.fromEntries(Object.entries(e.dims).map(([t,n])=>[t,[...n]]))}:{}),e.baseline!==void 0?{baseline:e.baseline}:{})}function Y(e){let t=de(e);return(0,H.slotResultFor)(t,(0,H.slotBaselineArm)(t))}function Be(e){let t={};for(let n of e)t[n.id]=Y(n);return t}function me(e){return typeof e=="string"?e:(0,H.canonicalArm)(e)}var J="_snt_snap:",Ct=["low","medium","high"];function ye(e){try{let t=localStorage.getItem(J+e);if(!t)return null;let n=JSON.parse(t);return!n||typeof n!="object"||n.v!==1||typeof n.persona!="string"||typeof n.band!="string"||!Ct.includes(n.band)||typeof n.slots!="object"||n.slots===null||Array.isArray(n.slots)||!(n.layoutOrder===null||Array.isArray(n.layoutOrder))||typeof n.savedAt!="number"||!(n.slotConfig===void 0||typeof n.slotConfig=="object"&&n.slotConfig!==null&&!Array.isArray(n.slotConfig))?null:n}catch(t){return null}}function z(e,t){try{localStorage.setItem(J+e,JSON.stringify(t))}catch(n){}}function $e(e){return"(function(){try{var r=localStorage.getItem("+JSON.stringify(J+e).replace(/</g,"\\u003c")+');if(!r)return;var s=JSON.parse(r);if(!s||s.v!==1||typeof s.persona!=="string"||typeof s.band!=="string")return;var d=document.documentElement;if(d.hasAttribute("data-sentient-persona"))return;d.setAttribute("data-sentient-persona",s.persona);d.setAttribute("data-sentient-confidence",s.band);}catch(e){}})();'}var Ae=require("@sentientui/policy");var he=require("@sentientui/policy");var ve="[sentient] No API key configured \u2014 nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development.",Re="[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.",We=!1,Se=!1;function Rt(){var e;try{return(e=new URLSearchParams(window.location.search).get("sentient_persona"))!=null?e:void 0}catch(t){return}}function je(e){var o;let t=pe({ssrSessionId:e.ssrSessionId}),n=(o=t.getSessionId())!=null?o:"local",a=Rt(),c=import("@sentientui/core/local").then(r=>{let d=r;return d.LOCAL_ENGINE_AVAILABLE?(We||(We=!0,console.info(Re)),d):(Se||(Se=!0,console.error(ve)),null)}).catch(()=>(Se||(Se=!0,console.error(ve)),null)),s=null;function l(r){let d=document.documentElement;d.dataset.sentientPersona===void 0&&(d.dataset.sentientPersona=r.persona,d.dataset.sentientConfidence=(0,he.confidenceBand)(r.confidence))}return{isLocal:!0,async decide(r){var f,w,x;let d=await c;if(!d)return null;let g=d.createLocalEngine({sessionId:n,forcedPersona:a}).decide(r);return s=Q(S({},g),{layoutOrder:(w=(f=g.layoutOrder)!=null?f:s==null?void 0:s.layoutOrder)!=null?w:null,slots:S(S({},(x=s==null?void 0:s.slots)!=null?x:{}),g.slots)}),z(e.apiKey||"local",{v:1,persona:s.persona,band:(0,he.confidenceBand)(s.confidence),slots:s.slots,layoutOrder:s.layoutOrder,savedAt:Date.now()}),l(g),g},getSlotResult(r){var d,g,f;return(f=(g=s==null?void 0:s.slots[r])!=null?g:(d=e.initialSlots)==null?void 0:d[r])!=null?f:null},getPersona(){return s?{persona:s.persona,confidence:s.confidence,band:(0,he.confidenceBand)(s.confidence)}:null},async assign(r,d){var w;let g=await c;return!g||!d||d.length===0?d!=null&&d[0]?{variantId:d[0],assignmentTtlMs:0}:null:{variantId:(w=g.createLocalEngine({sessionId:n,forcedPersona:a}).decide({components:[{id:r,variantIds:d}]}).assignments[r])!=null?w:d[0],assignmentTtlMs:0}},track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},getAssignment:()=>null,fetchWeights:()=>Promise.resolve([]),getGraph:()=>({pageNodes:[],capturedAt:0}),dispose:()=>{},destroy:()=>t.destroy()}}function Fe(e,t,n,a){let c=[];{let o=!1,r=[],d=()=>{if(o)return;let g=Date.now();for(r.push(g);r.length>0&&g-r[0]>500;)r.shift();r.length>=3&&(o=!0,e("rage_click"))};t.addEventListener("click",d),c.push(()=>t.removeEventListener("click",d))}{let s=!1,l=o=>{if(s||!(o.target instanceof Node)||!t.contains(o.target)&&t!==o.target)return;s=!0;let r=typeof window!="undefined"?window.getSelection():null,d=r?r.toString().length:0;e("text_copy",{selectionLength:d})};document.addEventListener("copy",l),c.push(()=>document.removeEventListener("copy",l))}{let s=!1,l=!1,o=null,r=()=>{o!==null&&(clearTimeout(o),o=null)},d=()=>{s||!l||(r(),o=setTimeout(()=>{!s&&l&&(s=!0,e("scroll_hesitation"))},3e3))},g=()=>{r(),d()},f=x=>{for(let P of x)l=P.intersectionRatio>.3,l?d():r()},w=new IntersectionObserver(f,{threshold:[.3]});w.observe(t),window.addEventListener("scroll",g,{passive:!0}),c.push(()=>{w.disconnect(),window.removeEventListener("scroll",g),r()})}if((a==null?void 0:a.tabLoss)!==!1){let s=!1,l=n!=null?n:Date.now(),o=()=>{if(s||document.visibilityState!=="hidden")return;let r=Date.now()-l;r<15e3&&(s=!0,e("tab_loss",{timeOnPage:r}))};document.addEventListener("visibilitychange",o),c.push(()=>document.removeEventListener("visibilitychange",o))}return()=>{for(let s of c)s()}}var Je="https://api.sentient-ui.com/v1/events",R=new Map,Qe=null;function ke(){return ge()}var q={track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},getAssignment:()=>null,assign:()=>Promise.resolve(null),decide:()=>Promise.resolve(null),getSlotResult:()=>null,getPersona:()=>null,fetchWeights:()=>Promise.resolve([]),getGraph:()=>({pageNodes:[],capturedAt:0}),dispose:()=>{},destroy:()=>{}};function kt(){try{let e={},t=new URLSearchParams(window.location.search);for(let[n,a]of t)n.startsWith("utm_")&&(e[n]=a);return e}catch(e){return{}}}function Ve(e){return e.replace(/\/events\/?$/,"")}function _e(){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")}function At(e){var o;if(typeof window=="undefined")return;let t=e!=null?e:Qe;if(!t){console.warn("[sentient] grantConsent() called before init()");return}let n=R.get(t);if(!n){console.warn("[sentient] grantConsent() called before init()");return}let{config:a,upgrade:c}=n;if(!c||a.respectDoNotTrack!==!1&&_e())return;let s=He(Q(S({},a),{consent:!0}));c(s);let l=(o=R.get(t))==null?void 0:o.dispose;R.set(t,{config:Q(S({},a),{consent:!0}),upgrade:null,dispose:l})}function _t(e){var l;let t=Ve((l=e.ingestUrl)!=null?l:Je),n={"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},a={track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},getAssignment:()=>null,fetchWeights:()=>Promise.resolve([]),async assign(o,r,d){try{let g=new URLSearchParams({componentId:o});for(let x of r!=null?r:[])g.append("variantIds[]",x);let f=await fetch(`${t}/winner?${g.toString()}`,{headers:n});return f.ok?{variantId:(await f.json()).variantId,assignmentTtlMs:0}:r!=null&&r[0]?{variantId:r[0],assignmentTtlMs:0}:null}catch(g){return r!=null&&r[0]?{variantId:r[0],assignmentTtlMs:0}:null}},decide:()=>Promise.resolve(null),getSlotResult:()=>null,getPersona:()=>null,getGraph:()=>({pageNodes:[],capturedAt:0}),dispose:()=>{},destroy:()=>{}},c={track:o=>a.track(o),goal:(o,r,d,g)=>a.goal(o,r,d,g),componentGoal:(o,r,d)=>a.componentGoal(o,r,d),identify:o=>a.identify(o),getAssignment:(o,r)=>a.getAssignment(o,r),assign:(o,r,d,g)=>a.assign(o,r,d,g),decide:o=>a.decide(o),getSlotResult:o=>a.getSlotResult(o),getPersona:()=>a.getPersona(),fetchWeights:()=>a.fetchWeights(),getGraph:()=>a.getGraph(),dispose:()=>a.dispose(),destroy:()=>a.destroy()};function s(o){a=o}return{proxy:c,setInner:s}}function He(e){var X,Z,ee,te,p,m,N,T,K;if(typeof window=="undefined")return q;Qe=e.apiKey;let t=R.get(e.apiKey||"local");if(t!=null&&t.dispose)try{t.dispose()}catch(i){}let n=e.respectDoNotTrack!==!1&&_e(),a=e.consent===!1||n,c=typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_");if(e.localMode===!0||!c&&e.localMode!==!1)return a?(R.set(e.apiKey||"local",{config:e,upgrade:null}),q):(R.set(e.apiKey||"local",{config:e,upgrade:null}),je(e));if(a){if(e.preConsentBehavior==="statistical_winner"){if(!e.apiKey||!e.apiKey.startsWith("pk_"))return console.warn("[sentient] init() called with an invalid apiKey \u2014 expected a pk_ public key. SDK disabled."),q;let{proxy:i,setInner:u}=_t(e);return R.set(e.apiKey,{config:e,upgrade:n?null:u}),i}return R.set(e.apiKey,{config:e,upgrade:null}),q}if(!e.apiKey||!e.apiKey.startsWith("pk_"))return console.warn("[sentient] init() called with an invalid apiKey \u2014 expected a pk_ public key. SDK disabled."),q;if(e.ingestUrl==="")return console.warn("[sentient] init() called with an empty ingestUrl. SDK disabled."),q;let s=(X=e.ingestUrl)!=null?X:Je,l=Date.now(),o=pe({ssrSessionId:e.ssrSessionId}),r=Ke(),d=Ne({ingestUrl:s,apiKey:e.apiKey}),g=Ve(s),f={"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},w=ie((Z=navigator.userAgent)!=null?Z:""),x=typeof window!="undefined"?window.location.origin:void 0,P=ae((ee=document.referrer)!=null?ee:"",x),b=(te=e.sessionSegment)!=null?te:`${w}:${P}`,I=new Map,D=new Map,h=null,ue=i=>{for(let u of i)D.has(u.id)||D.set(u.id,Y(u))};if(e.initialSlots)for(let[i,u]of Object.entries(e.initialSlots))D.set(i,u);let $=ye(e.apiKey);if($)for(let[i,u]of Object.entries($.slots))D.has(i)||D.set(i,u);let M={low:.15,medium:.5,high:.85};if(e.initialPersona)h=S({},e.initialPersona);else{let i=document.documentElement.dataset;i.sentientPersona?h={persona:i.sentientPersona,confidence:(m=M[(p=i.sentientConfidence)!=null?p:"low"])!=null?m:.15}:$&&(h={persona:$.persona,confidence:(N=M[$.band])!=null?N:.15})}if(e.initialAssignments)for(let[i,u]of Object.entries(e.initialAssignments))r.set(i,b,{variantId:u,assignedAt:Date.now(),segment:b,confidence:1});let O=Promise.resolve(),W=o.getSessionId();if(W){let i=le((T=document.referrer)!=null?T:""),u=S(S({sessionId:W,deviceClass:w,trafficSource:P,referrerDomain:i,utmParams:kt(),timeOfDay:ce(new Date),dayOfWeek:["sun","mon","tue","wed","thu","fri","sat"][new Date().getDay()],ephemeral:o.isEphemeral(),automation:typeof navigator!="undefined"&&navigator.webdriver===!0||se((K=navigator.userAgent)!=null?K:"")},e.userId?{userId:e.userId}:{}),e.country?{country:e.country}:{});try{O=fetch(`${g}/sessions`,{method:"POST",keepalive:!0,body:JSON.stringify(u),headers:f}).then(y=>{y.status===402&&console.warn("[SentientUI] Session limit exceeded for this project. The bandit will stop learning until the limit resets. Upgrade at sentient-ui.com/pricing")}).catch(()=>{})}catch(y){}}e.debug&&(console.log("[sentient] initialized",{context:e.context}),window.__sentient={client:null,queue:d});let U={goal(i,u={},y=1,L=0){let C=o.getSessionId();if(!C)return;let E=ke();O.then(()=>{fetch(`${g}/goals`,{method:"POST",keepalive:!0,body:JSON.stringify({sessionId:C,name:i,metadata:u,weight:y,stepIndex:L,goalId:E}),headers:f}).catch(()=>{})})},componentGoal(i,u,y){var k,B,A;let L=o.getSessionId();if(!L)return;let C=r.get(i,b),E=C?null:(k=D.get(i))!=null?k:null;if(!C&&E===null){e.debug&&console.warn(`[sentient] componentGoal("${i}"): no assignment or slot decision yet \u2014 render its <Adaptive>/adaptive hook or call assign()/decide() before recording a goal.`);return}let j=C?C.variantId:me(E),G={id:ke(),sessionId:L,projectId:e.apiKey,componentId:i,variantId:j,eventType:"goal_achieved",goalType:u,payload:S({reward:(B=y==null?void 0:y.reward)!=null?B:1},(A=y==null?void 0:y.metadata)!=null?A:{}),timestamp:Date.now(),timeInSession:Date.now()-l};e.debug&&console.log("[sentient] componentGoal",G),O.then(()=>d.push(G))},identify(i){let u=o.getSessionId();u&&O.then(()=>{fetch(`${g}/sessions`,{method:"POST",keepalive:!0,body:JSON.stringify({sessionId:u,userId:i,ephemeral:o.isEphemeral()}),headers:f}).catch(()=>{})})},track(i){let u=o.getSessionId();if(!u)return;let y=Q(S({},i),{id:ke(),sessionId:u,timestamp:Date.now(),timeInSession:Date.now()-l});e.debug&&console.log("[sentient] track",y),O.then(()=>d.push(y))},getAssignment(i,u){return r.get(i,u)},async assign(i,u,y,L){let C=o.getSessionId();if(!C)return null;let E=r.get(i,b);if(E&&(u!=null&&u.length||E.content!==void 0)){let k=E.ttlMs&&E.ttlMs>0?Math.max(0,E.assignedAt+E.ttlMs-Date.now()):0;return{variantId:E.variantId,assignmentTtlMs:k,content:E.content}}let j=I.get(i);if(j)return j;let G=(async()=>{await O;try{let k={sessionId:C,componentId:i,variantIds:u};L!==void 0?k.agentDataByVariant=L:y!==void 0&&(k.agentData=y);let B=await fetch(`${g}/assign`,{method:"POST",body:JSON.stringify(k),headers:f});if(!B.ok)return null;let A=await B.json();return r.set(i,b,S({variantId:A.variantId,assignedAt:Date.now(),segment:b,confidence:1,content:A.content},A.assignmentTtlMs&&A.assignmentTtlMs>0?{ttlMs:A.assignmentTtlMs}:{})),A}catch(k){return null}finally{I.delete(i)}})();return I.set(i,G),G},async decide(i){var L,C,E,j,G,k,B,A,De;let u=o.getSessionId();if(!u)return null;let y=(L=i.slots)!=null?L:[];await O;try{let F={sessionId:u};i.sections&&i.sections.length>0&&(F.sections=i.sections.map(_=>({id:_}))),F.components=(C=i.components)!=null?C:[],y.length>0&&(F.slots=y.map(de)),i.slotsFrom==="registry"&&(F.slotsFrom="registry"),i.v&&(F.v=i.v);let Oe=await fetch(`${g}/decide`,{method:"POST",body:JSON.stringify(F),headers:f});if(!Oe.ok)return ue(y),null;let v=await Oe.json(),ne={};for(let _ of y)ne[_.id]=(j=(E=v.slots)==null?void 0:E[_.id])!=null?j:Y(_);if(v.slots)for(let[_,oe]of Object.entries(v.slots))_ in ne||(ne[_]=oe);for(let[_,oe]of Object.entries(ne))D.set(_,oe);let Ye=h!=null&&h.persona!=="unknown";v.persona&&!(v.persona==="unknown"&&Ye)?h={persona:v.persona,confidence:(G=v.confidence)!=null?G:0}:h||(h={persona:"unknown",confidence:0});for(let[_,oe]of Object.entries((k=v.assignments)!=null?k:{}))r.set(_,b,{variantId:oe,assignedAt:Date.now(),segment:b,confidence:1});return z(e.apiKey,S({v:1,persona:h.persona,band:(0,Ae.confidenceBand)(h.confidence),slots:Object.fromEntries(D),layoutOrder:(B=v.layoutOrder)!=null?B:null,savedAt:Date.now()},v.slotConfig?{slotConfig:v.slotConfig}:{})),S(S(S({layoutOrder:(A=v.layoutOrder)!=null?A:null,assignments:(De=v.assignments)!=null?De:{},slots:ne,persona:h.persona,confidence:h.confidence},v.slotConfig?{slotConfig:v.slotConfig}:{}),v.goals?{goals:v.goals}:{}),v.sectionMap?{sectionMap:v.sectionMap}:{})}catch(F){return ue(y),null}},getSlotResult(i){var u;return(u=D.get(i))!=null?u:null},getPersona(){return h?{persona:h.persona,confidence:h.confidence,band:(0,Ae.confidenceBand)(h.confidence)}:null},async fetchWeights(){var i;try{let u=await fetch(`${g}/weights`,{headers:f});return u.ok?(i=(await u.json()).components)!=null?i:[]:[]}catch(u){return[]}},getGraph(){return{pageNodes:[],capturedAt:0}},dispose(){var i;d.destroy(),((i=R.get(e.apiKey))==null?void 0:i.dispose)===U.dispose&&R.delete(e.apiKey),e.debug&&console.log("[sentient] disposed")},destroy(){var i;d.destroy(),o.destroy(),((i=R.get(e.apiKey))==null?void 0:i.dispose)===U.dispose&&R.delete(e.apiKey);try{localStorage.removeItem(J+e.apiKey),localStorage.removeItem(be(e.apiKey))}catch(u){}e.debug&&console.log("[sentient] destroyed")}};if(R.set(e.apiKey,{config:e,upgrade:null,dispose:U.dispose}),e.debug){let i=window;i.__sentient&&(i.__sentient.client=U)}return U}0&&(module.exports={LOCAL_MODE_BANNER,PROD_KEYLESS_ERROR,SNAPSHOT_STORAGE_KEY_PREFIX,agentUaList,armOfResult,attachMicroSignalDetectors,baselineResultFor,baselineSlots,deriveSessionSegment,detectDeviceClass,detectTimeOfDay,detectTrafficSource,grantConsent,init,isDoNotTrackEnabled,matchedAgentToken,readSnapshot,referrerDomainFromReferer,renderPrePaintScript,toWireSlot,uaTokenMatch,writeSnapshot});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|