@sentientui/react 0.14.3 → 0.15.1
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/README.md +34 -17
- package/dist/devtools.js.map +1 -1
- package/dist/devtools.mjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/next/adaptive-root.d.ts +5 -2
- package/dist/next/adaptive-root.js +1 -1
- package/dist/next/adaptive-root.js.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/testing.mjs.map +1 -1
- package/llms.txt +4 -2
- package/package.json +3 -3
|
@@ -183,8 +183,11 @@ type PreloadComponent = {
|
|
|
183
183
|
variantIds: string[];
|
|
184
184
|
};
|
|
185
185
|
type AdaptiveRootProps = Omit<AdaptiveProviderProps, 'initialAssignments' | 'onAssignment' | 'initialSlots' | 'initialPersona'> & {
|
|
186
|
-
/**
|
|
187
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Components to assign server-side (SEO-safe). Optional — omit when the
|
|
188
|
+
* tree uses only slots/sections, or assigns client-side via hooks.
|
|
189
|
+
*/
|
|
190
|
+
components?: PreloadComponent[];
|
|
188
191
|
/**
|
|
189
192
|
* Declare page section IDs in their default order. When provided,
|
|
190
193
|
* AdaptiveRoot calls `/v1/decide` (single round trip) instead of
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
var ee=Object.defineProperty,te=Object.defineProperties;var ne=Object.getOwnPropertyDescriptors;var x=Object.getOwnPropertySymbols;var K=Object.prototype.hasOwnProperty,B=Object.prototype.propertyIsEnumerable;var U=(e,t,n)=>t in e?ee(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,m=(e,t)=>{for(var n in t||(t={}))K.call(t,n)&&U(e,n,t[n]);if(x)for(var n of x(t))B.call(t,n)&&U(e,n,t[n]);return e},v=(e,t)=>te(e,ne(t));var j=(e,t)=>{var n={};for(var r in e)K.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&x)for(var r of x(e))t.indexOf(r)<0&&B.call(e,r)&&(n[r]=e[r]);return n};import{deriveSessionSegment as ye}from"@sentientui/core";import{cookies as Se,headers as ve}from"next/headers";import{renderPrePaintScript as re}from"@sentientui/core";import{confidenceBand as se}from"@sentientui/policy";import{jsx as oe}from"react/jsx-runtime";function J(e){return JSON.stringify(e).replace(/</g,"\\u003c")}function ie(e){return e.persona?'(function(){try{var d=document.documentElement;if(d.hasAttribute("data-sentient-persona"))return;d.setAttribute("data-sentient-persona",'+J(e.persona.persona)+');d.setAttribute("data-sentient-confidence",'+J(se(e.persona.confidence))+");}catch(e){}})();":re(e.apiKey)}function T(e){return oe("script",{"data-sentient-persona-script":"",dangerouslySetInnerHTML:{__html:ie(e)}})}import{preloadAssignments as ae,readSessionCookie as de}from"@sentientui/core/server";import{preloadDecisions as Ee}from"@sentientui/core/server";function $(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function q(e,t){var s,o,i;let n=(i=(o=de(t.cookies))!=null?o:(s=t.createSessionId)==null?void 0:s.call(t))!=null?i:$();return{assignments:await ae(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,origin:t.origin,userAgent:t.userAgent,referer:t.referer,timeoutMs:t.timeoutMs}),sessionId:n}}async function V(e){var i,d,g,k,p,l,u,f,A,y;let{preloadDecisions:t,readSessionCookie:n}=await import("@sentientui/core/server"),r=(g=(d=n(e.cookies))!=null?d:(i=e.createSessionId)==null?void 0:i.call(e))!=null?g:$();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let w={layoutOrder:(k=e.sections)!=null?k:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:r};try{let S=await import("@sentientui/core/local");if(!S.LOCAL_ENGINE_AVAILABLE)return console.error("[sentient] No API key configured \u2014 nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development."),w;let a=S.createLocalEngine({sessionId:r}).decide({sections:e.sections,components:(p=e.components)!=null?p:[],slots:(l=e.slots)!=null?l:[]});return{layoutOrder:(f=(u=a.layoutOrder)!=null?u:e.sections)!=null?f:[],assignments:a.assignments,slots:a.slots,persona:a.persona,confidence:a.confidence,sessionId:r}}catch(S){return w}}let o=await t({sections:e.sections,components:(A=e.components)!=null?A:[],slots:(y=e.slots)!=null?y:[]},r,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,timeoutMs:e.timeoutMs});return v(m({},o),{sessionId:r})}import{AdaptiveRootClient as he}from"./adaptive-root-client.js";var ce=["page","blocks","layoutOrder"],H=new Map;function ge(e,t){H.set(e,t)}function pe(e){return H.get(e)}function I(e){var s,o;let t=(o=(s=e.content)!=null?s:pe(e.page))!=null?o:{},n={};for(let[i,d]of Object.entries(t))ce.includes(i)||(n[i]=d);let r=v(m({},n),{page:e.page,blocks:e.blocks});return e.layoutOrder&&(r.layoutOrder=e.layoutOrder),r}function W(e){return JSON.stringify(m({"@context":"https://schema.org","@type":"WebPage"},e)).replace(/</g,"\\u003c")}function X(e){let t=[];e.title&&t.push(`# ${e.title}`,""),e.summary&&t.push(String(e.summary),"");for(let[n,r]of Object.entries(e))["page","title","summary","blocks","layoutOrder"].includes(n)||t.push(`## ${n}`,"","```json",JSON.stringify(r,null,2),"```","");if(e.blocks.length>0){t.push("## blocks","");for(let n of e.blocks)t.push(`- **${n.id}** \u2192 variant \`${n.variant}\``),n.content!==void 0&&t.push(""," ```json",JSON.stringify(n.content,null,2)," ```");t.push("")}return t.join(`
|
|
2
2
|
`).trimEnd()+`
|
|
3
|
-
`}import{matchedAgentToken as le}from"@sentientui/core";function ue(e,t){return e.pathname.endsWith(".md")||t.toLowerCase().includes("text/markdown")}function me(e){return async t=>{var d;let n=new URL(t.url),r=(d=t.headers.get("accept"))!=null?d:"",s=t.headers.get("user-agent"),o=n.pathname.replace(/\.(md|json)$/,"");if(e.onRead)try{Promise.resolve(e.onRead({path:o,userAgent:s,botName:le(s!=null?s:"")})).catch(()=>{})}catch(g){}let i=await e.getFeed(t);return ue(n,r)?new Response(X(i),{headers:{"content-type":"text/markdown; charset=utf-8"}}):new Response(JSON.stringify(i),{headers:{"content-type":"application/json; charset=utf-8"}})}}import{matchedAgentToken as fe}from"@sentientui/core";function Ae(e){return async t=>{let n=t.headers.get("user-agent"),r=fe(n!=null?n:"");if(!r)return!1;try{let s=new URL(t.url).pathname;await Promise.resolve(e.onCrawler({path:s,userAgent:n,botName:r})).catch(()=>{})}catch(s){}return!0}}import{Fragment as Y,jsx as P,jsxs as z}from"react/jsx-runtime";var G="https://api.sentient-ui.com/v1";function Re(e){return Object.entries(e).map(([t,n])=>{var r;return{id:t,variant:typeof n=="string"?n:(r=n==null?void 0:n.variantId)!=null?r:""}})}async function Ve(e){var C,D,N,M,_;let F=e,{components:t,sections:n,slots:r,appOrigin:s,initialAssignments:o,ssrSessionId:i,timeoutMs:d,agentFeed:g,children:k}=F,p=j(F,["components","sections","slots","appOrigin","initialAssignments","ssrSessionId","timeoutMs","agentFeed","children"]),l=await ve(),u=l.get("host");!s&&process.env.NODE_ENV==="production"&&!u&&console.error("[SentientUI] AdaptiveRoot: Host header is absent and no appOrigin was provided. Pass appOrigin explicitly \u2014 the https://localhost fallback will likely fail allowed_origins validation.");let f=s!=null?s:process.env.NODE_ENV==="production"?`https://${u!=null?u:"localhost"}`:"http://localhost:3001",A=(C=l.get("user-agent"))!=null?C:void 0,y=(D=l.get("referer"))!=null?D:void 0,w=ye({userAgent:A,referer:y,appOrigin:f}),S=await Se(),a,h=null,O,R=null,b;if(o)a=o,b=i;else if(n&&n.length>0||r&&r.length>0){let c=await V({sections:n!=null?n:[],components:t,slots:r,cookies:S,apiKey:p.apiKey,baseUrl:G,origin:f,userAgent:A,referer:y,timeoutMs:d});a=c.assignments,h=c.layoutOrder,O=c.slots,R=c.persona!==void 0?{persona:c.persona,confidence:(N=c.confidence)!=null?N:0}:null,b=c.sessionId}else{let c=await q(t,{cookies:S,apiKey:p.apiKey,baseUrl:G,origin:f,userAgent:A,referer:y,timeoutMs:d});a=c.assignments,b=c.sessionId}let L=P(T,{apiKey:p.apiKey,persona:R}),E=P(he,v(m({},p),{initialAssignments:a,initialLayoutOrder:h,initialSlots:O,initialPersona:R!=null?R:void 0,sessionSegment:w,ssrSessionId:b,children:k}));if(!g)return z(Y,{children:[L,E]});let Q=(_=(M=g.path)!=null?M:l.get("x-pathname"))!=null?_:"/",Z=I({page:Q,blocks:Re(a),layoutOrder:h!=null?h:void 0,content:g.content});return z(Y,{children:[L,P("script",{type:"application/ld+json",dangerouslySetInnerHTML:{__html:W(Z)}}),E]})}export{Ve as AdaptiveRoot,I as buildAgentFeedFor,me as createAgentFeed,ge as defineAgentContent,Ae as sentientAgentMiddleware};
|
|
3
|
+
`}import{matchedAgentToken as le}from"@sentientui/core";function ue(e,t){return e.pathname.endsWith(".md")||t.toLowerCase().includes("text/markdown")}function me(e){return async t=>{var d;let n=new URL(t.url),r=(d=t.headers.get("accept"))!=null?d:"",s=t.headers.get("user-agent"),o=n.pathname.replace(/\.(md|json)$/,"");if(e.onRead)try{Promise.resolve(e.onRead({path:o,userAgent:s,botName:le(s!=null?s:"")})).catch(()=>{})}catch(g){}let i=await e.getFeed(t);return ue(n,r)?new Response(X(i),{headers:{"content-type":"text/markdown; charset=utf-8"}}):new Response(JSON.stringify(i),{headers:{"content-type":"application/json; charset=utf-8"}})}}import{matchedAgentToken as fe}from"@sentientui/core";function Ae(e){return async t=>{let n=t.headers.get("user-agent"),r=fe(n!=null?n:"");if(!r)return!1;try{let s=new URL(t.url).pathname;await Promise.resolve(e.onCrawler({path:s,userAgent:n,botName:r})).catch(()=>{})}catch(s){}return!0}}import{Fragment as Y,jsx as P,jsxs as z}from"react/jsx-runtime";var G="https://api.sentient-ui.com/v1";function Re(e){return Object.entries(e).map(([t,n])=>{var r;return{id:t,variant:typeof n=="string"?n:(r=n==null?void 0:n.variantId)!=null?r:""}})}async function Ve(e){var C,D,N,M,_;let F=e,{components:t=[],sections:n,slots:r,appOrigin:s,initialAssignments:o,ssrSessionId:i,timeoutMs:d,agentFeed:g,children:k}=F,p=j(F,["components","sections","slots","appOrigin","initialAssignments","ssrSessionId","timeoutMs","agentFeed","children"]),l=await ve(),u=l.get("host");!s&&process.env.NODE_ENV==="production"&&!u&&console.error("[SentientUI] AdaptiveRoot: Host header is absent and no appOrigin was provided. Pass appOrigin explicitly \u2014 the https://localhost fallback will likely fail allowed_origins validation.");let f=s!=null?s:process.env.NODE_ENV==="production"?`https://${u!=null?u:"localhost"}`:"http://localhost:3001",A=(C=l.get("user-agent"))!=null?C:void 0,y=(D=l.get("referer"))!=null?D:void 0,w=ye({userAgent:A,referer:y,appOrigin:f}),S=await Se(),a,h=null,O,R=null,b;if(o)a=o,b=i;else if(n&&n.length>0||r&&r.length>0){let c=await V({sections:n!=null?n:[],components:t,slots:r,cookies:S,apiKey:p.apiKey,baseUrl:G,origin:f,userAgent:A,referer:y,timeoutMs:d});a=c.assignments,h=c.layoutOrder,O=c.slots,R=c.persona!==void 0?{persona:c.persona,confidence:(N=c.confidence)!=null?N:0}:null,b=c.sessionId}else{let c=await q(t,{cookies:S,apiKey:p.apiKey,baseUrl:G,origin:f,userAgent:A,referer:y,timeoutMs:d});a=c.assignments,b=c.sessionId}let L=P(T,{apiKey:p.apiKey,persona:R}),E=P(he,v(m({},p),{initialAssignments:a,initialLayoutOrder:h,initialSlots:O,initialPersona:R!=null?R:void 0,sessionSegment:w,ssrSessionId:b,children:k}));if(!g)return z(Y,{children:[L,E]});let Q=(_=(M=g.path)!=null?M:l.get("x-pathname"))!=null?_:"/",Z=I({page:Q,blocks:Re(a),layoutOrder:h!=null?h:void 0,content:g.content});return z(Y,{children:[L,P("script",{type:"application/ld+json",dangerouslySetInnerHTML:{__html:W(Z)}}),E]})}export{Ve as AdaptiveRoot,I as buildAgentFeedFor,me as createAgentFeed,ge as defineAgentContent,Ae as sentientAgentMiddleware};
|
|
4
4
|
//# sourceMappingURL=adaptive-root.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/next/adaptive-root.tsx","../../src/persona-script.tsx","../../src/server.ts","../../src/agent-feed.ts","../../src/next/agent-feed-route.ts","../../src/next/agent-middleware.ts"],"sourcesContent":["import { deriveSessionSegment } from '@sentientui/core';\nimport type { SlotDeclInput, SlotResult } from '@sentientui/core';\nimport { cookies, headers } from 'next/headers';\nimport type { ReactNode } from 'react';\nimport type { AdaptiveProviderProps } from '../provider.js';\nimport { SentientPersonaScript } from '../persona-script.js';\nimport {\n loadAdaptiveAssignments,\n loadAdaptiveDecision,\n type ServerAssignments,\n} from '../server.js';\nimport { AdaptiveRootClient } from './adaptive-root-client.js';\nimport { buildAgentFeed, renderAgentJsonLdBody, type AgentBlock } from '../agent-feed.js';\n\nexport { createAgentFeed } from './agent-feed-route.js';\nexport type { AgentFeedRouteConfig, AgentFeedReadEntry } from './agent-feed-route.js';\nexport { sentientAgentMiddleware } from './agent-middleware.js';\nexport type { SentientAgentMiddlewareConfig, CrawlerRequestEntry } from './agent-middleware.js';\nexport { defineAgentContent, buildAgentFeed as buildAgentFeedFor } from '../agent-feed.js';\nexport type { AgentFeed } from '../agent-feed.js';\n\nconst DEFAULT_API_BASE_URL = 'https://api.sentient-ui.com/v1';\n\nexport type PreloadComponent = { id: string; variantIds: string[] };\n\nexport type AdaptiveRootProps = Omit<\n AdaptiveProviderProps,\n 'initialAssignments' | 'onAssignment' | 'initialSlots' | 'initialPersona'\n> & {\n /** Components to assign server-side (SEO-safe). */\n components: PreloadComponent[];\n /**\n * Declare page section IDs in their default order. When provided,\n * AdaptiveRoot calls `/v1/decide` (single round trip) instead of\n * individual `/v1/assign` calls, and `useLayoutOrder()` returns the\n * persona-specific order on first render.\n *\n * @example sections={['hero', 'pricing', 'features', 'social_proof']}\n */\n sections?: string[];\n /**\n * Adaptive-slot declarations used by `useAdaptiveTokens` / `AdaptiveGroup`\n * in this tree. Declaring them here decides them in the same SSR\n * round trip, so their values serialize into the server HTML.\n */\n slots?: SlotDeclInput[];\n /** App origin — must be in the project's `allowed_origins`. */\n appOrigin?: string;\n /** Override: when set no network fetch is made. Useful for tests. */\n initialAssignments?: ServerAssignments;\n /**\n * Milliseconds to wait for the API before rendering default variants.\n * Defaults to 1000. The hot path typically returns in well under 150 ms;\n * the full 1 s budget is only reached on a cold start or an API\n * geographically distant from your SSR host. Lower it if your API is\n * co-located and warm.\n */\n timeoutMs?: number;\n /**\n * When set, AdaptiveRoot emits a server-rendered inline JSON-LD block\n * describing the page's winning variants, layout order, and developer-supplied\n * content — readable by passive AI crawlers (which do not run JS). Invisible to\n * humans (a JSON-LD script renders no visible DOM). Omit to emit nothing.\n */\n agentFeed?: {\n /** Page path for the feed. Falls back to the `x-pathname` request header, then '/'. */\n path?: string;\n /** Structured page content. Falls back to the `defineAgentContent` registry for this path. */\n content?: Record<string, unknown>;\n };\n children: ReactNode;\n};\n\n/** Build agent blocks from SSR assignments (Record<id, variantId | { variantId }>). */\nfunction assignmentsToBlocks(assignments: ServerAssignments): AgentBlock[] {\n return Object.entries(assignments as Record<string, unknown>).map(([id, v]) => ({\n id,\n variant: typeof v === 'string' ? v : ((v as { variantId?: string })?.variantId ?? ''),\n }));\n}\n\n/**\n * Next.js Server Component that resolves variant assignments (and optionally\n * section layout order) server-side for zero layout shift on first paint.\n *\n * When `sections` is provided, a single `POST /v1/decide` call returns both\n * the persona-specific section order and all component assignments.\n * Without `sections`, individual `/v1/assign` calls are made per component.\n *\n * @example\n * // app/page.tsx — with section layout\n * import { AdaptiveRoot } from '@sentientui/react/next';\n *\n * export default async function Page() {\n * return (\n * <AdaptiveRoot\n * apiKey={process.env.NEXT_PUBLIC_SENTIENT_API_KEY!}\n * context=\"landing\"\n * sections={['hero', 'pricing', 'features', 'social_proof']}\n * components={[\n * { id: 'hero_cta', variantIds: ['default', 'accent'] },\n * ]}\n * >\n * <HeroSection />\n * <PricingSection />\n * <FeaturesSection />\n * <SocialProofSection />\n * </AdaptiveRoot>\n * );\n * }\n */\nexport async function AdaptiveRoot(props: AdaptiveRootProps): Promise<JSX.Element> {\n const {\n components,\n sections,\n slots,\n appOrigin,\n initialAssignments: initialAssignmentsOverride,\n ssrSessionId: ssrSessionIdProp,\n timeoutMs,\n agentFeed,\n children,\n ...providerProps\n } = props;\n\n const headerStore = await headers();\n const host = headerStore.get('host');\n if (!appOrigin && process.env.NODE_ENV === 'production' && !host) {\n console.error(\n '[SentientUI] AdaptiveRoot: Host header is absent and no appOrigin was provided. ' +\n 'Pass appOrigin explicitly — the https://localhost fallback will likely fail allowed_origins validation.',\n );\n }\n const resolvedOrigin = appOrigin ??\n (process.env.NODE_ENV === 'production'\n ? `https://${host ?? 'localhost'}`\n : 'http://localhost:3001');\n const userAgent = headerStore.get('user-agent') ?? undefined;\n const referer = headerStore.get('referer') ?? undefined;\n const sessionSegment = deriveSessionSegment({ userAgent, referer, appOrigin: resolvedOrigin });\n const cookieStore = await cookies();\n\n let initialAssignments: ServerAssignments;\n let initialLayoutOrder: string[] | null = null;\n let initialSlots: Record<string, SlotResult> | undefined;\n let initialPersona: { persona: string; confidence: number } | null = null;\n let ssrSessionId: string | undefined;\n\n if (initialAssignmentsOverride) {\n initialAssignments = initialAssignmentsOverride;\n ssrSessionId = ssrSessionIdProp;\n } else if ((sections && sections.length > 0) || (slots && slots.length > 0)) {\n const decision = await loadAdaptiveDecision({\n sections: sections ?? [],\n components,\n slots,\n cookies: cookieStore,\n apiKey: providerProps.apiKey,\n baseUrl: DEFAULT_API_BASE_URL,\n origin: resolvedOrigin,\n userAgent,\n referer,\n timeoutMs,\n });\n initialAssignments = decision.assignments;\n initialLayoutOrder = decision.layoutOrder;\n initialSlots = decision.slots;\n initialPersona =\n decision.persona !== undefined\n ? { persona: decision.persona, confidence: decision.confidence ?? 0 }\n : null;\n ssrSessionId = decision.sessionId;\n } else {\n const result = await loadAdaptiveAssignments(components, {\n cookies: cookieStore,\n apiKey: providerProps.apiKey,\n baseUrl: DEFAULT_API_BASE_URL,\n origin: resolvedOrigin,\n userAgent,\n referer,\n timeoutMs,\n });\n initialAssignments = result.assignments;\n ssrSessionId = result.sessionId;\n }\n\n // Single-writer inline script — ALWAYS the first child, before any markup\n // that CSS keyed on the persona attributes could style.\n const personaScript = (\n <SentientPersonaScript apiKey={providerProps.apiKey} persona={initialPersona} />\n );\n\n const client = (\n <AdaptiveRootClient\n {...providerProps}\n initialAssignments={initialAssignments}\n initialLayoutOrder={initialLayoutOrder}\n initialSlots={initialSlots}\n initialPersona={initialPersona ?? undefined}\n sessionSegment={sessionSegment}\n ssrSessionId={ssrSessionId}\n >\n {children}\n </AdaptiveRootClient>\n );\n\n if (!agentFeed) {\n return (\n <>\n {personaScript}\n {client}\n </>\n );\n }\n\n // Server-rendered inline JSON-LD for AI crawlers. Emitted only on the server\n // path so passive crawlers (no JS) see it in the raw HTML. The body escapes\n // '<' so page content cannot break out of the <script> element.\n const path = agentFeed.path ?? headerStore.get('x-pathname') ?? '/';\n const feed = buildAgentFeed({\n page: path,\n blocks: assignmentsToBlocks(initialAssignments),\n layoutOrder: initialLayoutOrder ?? undefined,\n content: agentFeed.content,\n });\n\n return (\n <>\n {personaScript}\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: renderAgentJsonLdBody(feed) }}\n />\n {client}\n </>\n );\n}\n","import { renderPrePaintScript } from '@sentientui/core';\nimport { confidenceBand } from '@sentientui/policy';\n\nexport type SentientPersonaScriptProps = {\n /** Publishable API key — selects the localStorage snapshot in the fallback path. */\n apiKey: string;\n /**\n * SSR-decided persona (from `loadAdaptiveDecision`). When present the\n * script embeds the literal values; when absent it reads the local\n * decision snapshot (SPA / return-visit path).\n */\n persona?: { persona: string; confidence: number } | null;\n};\n\n/** JSON string literal that is also safe inside an inline <script> element. */\nfunction inlineJsString(value: string): string {\n return JSON.stringify(value).replace(/</g, '\\\\u003c');\n}\n\n/** Exported for tests. Builds the inline JS (concatenation only — no backticks). */\nexport function personaScriptBody(props: SentientPersonaScriptProps): string {\n if (props.persona) {\n return (\n '(function(){try{var d=document.documentElement;' +\n 'if(d.hasAttribute(\"data-sentient-persona\"))return;' +\n 'd.setAttribute(\"data-sentient-persona\",' + inlineJsString(props.persona.persona) + ');' +\n 'd.setAttribute(\"data-sentient-confidence\",' + inlineJsString(confidenceBand(props.persona.confidence)) + ');' +\n '}catch(e){}})();'\n );\n }\n return renderPrePaintScript(props.apiKey);\n}\n\n/**\n * Single writer of the Rung-1a `<html>` attributes\n * (`data-sentient-persona`, `data-sentient-confidence`), executed pre-paint.\n *\n * `AdaptiveRoot` renders this automatically as its first child. For Pages\n * Router / Remix, render it yourself in `_document` / the root layout.\n *\n * IMPORTANT (install docs): add `suppressHydrationWarning` to your `<html>`\n * element — this script mutates documentElement before React hydrates it\n * (the same pattern next-themes uses). The client SDK adopts the attributes\n * as truth and never rewrites them mid-session.\n */\nexport function SentientPersonaScript(props: SentientPersonaScriptProps): JSX.Element {\n return (\n <script\n data-sentient-persona-script=\"\"\n dangerouslySetInnerHTML={{ __html: personaScriptBody(props) }}\n />\n );\n}\n","/**\n * Server-only helpers for Next.js / SSR. No React or DOM APIs.\n */\nimport {\n preloadAssignments,\n readSessionCookie,\n type ServerAssignConfig,\n type ServerAssignments,\n} from '@sentientui/core/server';\n\nexport { preloadAssignments, readSessionCookie };\nexport type { ServerAssignConfig, ServerAssignments };\n\n/** Return value of `loadAdaptiveAssignments` — includes the session ID used for SSR. */\nexport type LoadAdaptiveAssignmentsResult = {\n assignments: ServerAssignments;\n /** The session ID used for SSR assignment. Pass as `ssrSessionId` to `<AdaptiveProvider>`. */\n sessionId: string;\n};\n\nexport type LoadAdaptiveAssignmentsOptions = {\n /** Next.js `cookies()` return value, or any object with `get(name)`. */\n cookies: { get(name: string): { value: string } | undefined };\n apiKey: string;\n baseUrl: string;\n /** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */\n createSessionId?: () => string;\n /** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */\n origin?: string;\n /** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */\n userAgent?: string;\n /** From Next.js `headers().get('referer')`. */\n referer?: string;\n /** Milliseconds to wait for the API before returning default variants. Defaults to 1000 (typical decide is well under 150 ms; the full budget is only reached on a cold start or a distant API). */\n timeoutMs?: number;\n};\n\nfunction defaultSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Fetches bandit assignments on the server for SEO-safe HTML.\n * Pass `assignments` as `initialAssignments` and `sessionId` as `ssrSessionId`\n * on `<AdaptiveProvider>` so the client adopts the same session on first visit.\n */\nexport async function loadAdaptiveAssignments(\n components: Array<{ id: string; variantIds: string[] }>,\n options: LoadAdaptiveAssignmentsOptions,\n): Promise<LoadAdaptiveAssignmentsResult> {\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n const assignments = await preloadAssignments(components, sessionId, {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n timeoutMs: options.timeoutMs,\n });\n\n return { assignments, sessionId };\n}\n\nexport { preloadDecisions } from '@sentientui/core/server';\nexport type { DecideResult, SlotDeclInput, SlotResult } from '@sentientui/core/server';\n\n/** Return value of `loadAdaptiveDecision` — includes the session ID used for SSR. */\nexport type LoadAdaptiveDecisionResult = import('@sentientui/core/server').DecideResult & {\n sessionId: string;\n};\n\nexport type LoadAdaptiveDecisionOptions = LoadAdaptiveAssignmentsOptions & {\n /**\n * Section IDs in default order. Passed to /v1/decide as the candidate\n * layout. Optional since 0.13.0 — slot-only pages may omit it (at least\n * one of `sections`/`components`/`slots` must be non-empty).\n */\n sections?: string[];\n /** Components to assign in the same decide call. */\n components?: Array<{ id: string; variantIds?: string[] }>;\n /** Adaptive-slot declarations (useAdaptiveTokens / AdaptiveGroup) to decide server-side. */\n slots?: import('@sentientui/core/server').SlotDeclInput[];\n};\n\n/**\n * SSR helper for pages with a declared section layout and/or adaptive slots.\n * Calls `/v1/decide` instead of multiple `/v1/assign` round trips.\n * Pass `sessionId` as `ssrSessionId` on `<AdaptiveProvider>` so the client\n * adopts the same session on first visit.\n *\n * Keyless: with no valid `pk_` key this never fetches (no timeout burn).\n * Under the `development` export condition the decision is computed by the\n * deterministic local engine with the same sessionId the client will adopt —\n * server and client agree by construction. In production the engine resolves\n * to a stub and defaults are returned with one console.error.\n */\nexport async function loadAdaptiveDecision(\n options: LoadAdaptiveDecisionOptions,\n): Promise<LoadAdaptiveDecisionResult> {\n const { preloadDecisions, readSessionCookie } = await import('@sentientui/core/server');\n\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n const keyValid = typeof options.apiKey === 'string' && options.apiKey.startsWith('pk_');\n if (!keyValid) {\n const fallback: LoadAdaptiveDecisionResult = {\n layoutOrder: options.sections ?? [],\n assignments: {},\n slots: {},\n persona: 'unknown',\n confidence: 0,\n sessionId,\n };\n try {\n const mod = (await import('@sentientui/core/local')) as unknown as {\n LOCAL_ENGINE_AVAILABLE: boolean;\n createLocalEngine(opts: { sessionId: string }): {\n decide(input: {\n sections?: string[];\n components?: Array<{ id: string; variantIds?: string[] }>;\n slots?: LoadAdaptiveDecisionOptions['slots'];\n }): {\n layoutOrder: string[] | null;\n assignments: Record<string, string>;\n slots: Record<string, string | Record<string, string>>;\n persona: string;\n confidence: number;\n };\n };\n };\n if (!mod.LOCAL_ENGINE_AVAILABLE) {\n // Pinned message — must byte-match PROD_KEYLESS_ERROR in @sentientui/core.\n console.error(\n '[sentient] No API key configured — nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development.',\n );\n return fallback;\n }\n const outcome = mod.createLocalEngine({ sessionId }).decide({\n sections: options.sections,\n components: options.components ?? [],\n slots: options.slots ?? [],\n });\n return {\n layoutOrder: outcome.layoutOrder ?? options.sections ?? [],\n assignments: outcome.assignments,\n slots: outcome.slots,\n persona: outcome.persona,\n confidence: outcome.confidence,\n sessionId,\n };\n } catch {\n return fallback;\n }\n }\n\n const result = await preloadDecisions(\n {\n sections: options.sections,\n components: options.components ?? [],\n slots: options.slots ?? [],\n },\n sessionId,\n {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n timeoutMs: options.timeoutMs,\n },\n );\n\n return { ...result, sessionId };\n}\n","/**\n * Agent-readable content feed. Merges SDK-known data (winning variants, layout\n * order) with developer-supplied page content, and renders it either as a\n * server-rendered inline JSON-LD block (read by passive AI crawlers, which do\n * not run JS) or as Markdown (for agents that content-negotiate `text/markdown`).\n *\n * No React or DOM APIs — safe to import in server components, route handlers,\n * and middleware.\n */\n\nexport type AgentBlock = {\n /** Component ID. */\n id: string;\n /** Winning variant ID currently served. */\n variant: string;\n /** Agent-readable data attached to the served variant, if any. */\n content?: unknown;\n};\n\nexport type AgentFeed = {\n page: string;\n title?: string;\n summary?: string;\n layoutOrder?: string[];\n blocks: AgentBlock[];\n /** Developer-supplied extra fields (products, specs, arbitrary JSON). */\n [key: string]: unknown;\n};\n\n/** Fields the SDK owns — developer content can never overwrite these. */\nconst RESERVED_FIELDS = ['page', 'blocks', 'layoutOrder'] as const;\n\nconst registry = new Map<string, Record<string, unknown>>();\n\n/**\n * Register page-level structured content the SDK can't infer (title, summary,\n * product fields, arbitrary JSON), keyed by page path. Call at module load.\n */\nexport function defineAgentContent(page: string, content: Record<string, unknown>): void {\n registry.set(page, content);\n}\n\n/** Look up registered content for a page. */\nexport function getAgentContent(page: string): Record<string, unknown> | undefined {\n return registry.get(page);\n}\n\n/** Clear the registry — intended for tests. */\nexport function clearAgentContent(): void {\n registry.clear();\n}\n\n/**\n * Merge SDK-known data with developer-supplied content into a single feed.\n * Developer content fills in title/summary/etc. but can never overwrite the\n * SDK-authoritative fields (`page`, `blocks`, `layoutOrder`).\n */\nexport function buildAgentFeed(input: {\n page: string;\n blocks: AgentBlock[];\n layoutOrder?: string[];\n content?: Record<string, unknown>;\n}): AgentFeed {\n const supplied = input.content ?? getAgentContent(input.page) ?? {};\n const safe: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(supplied)) {\n if (!(RESERVED_FIELDS as readonly string[]).includes(k)) safe[k] = v;\n }\n const feed: AgentFeed = {\n ...safe,\n page: input.page,\n blocks: input.blocks,\n };\n if (input.layoutOrder) feed.layoutOrder = input.layoutOrder;\n return feed;\n}\n\n/**\n * Render the feed as a server-rendered inline JSON-LD `<script>` string. `<` is\n * escaped to `<` so embedded content cannot break out of the script\n * element. MUST be emitted on the server — passive crawlers never run client JS.\n */\nexport function renderAgentJsonLd(feed: AgentFeed): string {\n return `<script type=\"application/ld+json\">${renderAgentJsonLdBody(feed)}</script>`;\n}\n\n/**\n * The escaped JSON-LD body only (no `<script>` wrapper). For React server\n * components, inject via `<script type=\"application/ld+json\"\n * dangerouslySetInnerHTML={{ __html: renderAgentJsonLdBody(feed) }} />`.\n */\nexport function renderAgentJsonLdBody(feed: AgentFeed): string {\n return JSON.stringify({ '@context': 'https://schema.org', '@type': 'WebPage', ...feed })\n .replace(/</g, '\\\\u003c');\n}\n\n/** Render the feed as Markdown for agents that negotiate `text/markdown`. */\nexport function renderAgentMarkdown(feed: AgentFeed): string {\n const lines: string[] = [];\n if (feed.title) lines.push(`# ${feed.title}`, '');\n if (feed.summary) lines.push(String(feed.summary), '');\n\n for (const [k, v] of Object.entries(feed)) {\n if (['page', 'title', 'summary', 'blocks', 'layoutOrder'].includes(k)) continue;\n lines.push(`## ${k}`, '', '```json', JSON.stringify(v, null, 2), '```', '');\n }\n\n if (feed.blocks.length > 0) {\n lines.push('## blocks', '');\n for (const b of feed.blocks) {\n lines.push(`- **${b.id}** → variant \\`${b.variant}\\``);\n if (b.content !== undefined) {\n lines.push('', ' ```json', JSON.stringify(b.content, null, 2), ' ```');\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n').trimEnd() + '\\n';\n}\n","/**\n * `createAgentFeed` — a framework-standard Route Handler (Web `Request` →\n * `Response`) that serves the agent-readable feed via HTTP content negotiation:\n * `text/markdown` (Accept header or `.md` URL) → Markdown, otherwise JSON.\n *\n * This is the secondary channel of the agent-readable design — for agents that\n * *ask* (coding agents, agents the customer controls, future crawlers). The\n * primary channel is the server-rendered inline JSON-LD from `<AdaptiveRoot>`.\n *\n * Every fetch is reported to `onRead` (best-effort) so it can be logged to\n * `crawler_requests` and counted in the dashboard traffic breakdown.\n */\nimport { matchedAgentToken } from '@sentientui/core';\nimport { renderAgentMarkdown, type AgentFeed } from '../agent-feed.js';\n\nexport type AgentFeedReadEntry = {\n path: string;\n userAgent: string | null;\n botName: string | null;\n};\n\nexport type AgentFeedRouteConfig = {\n /** Resolve the feed for a request (winning variants + layout + dev content). */\n getFeed: (request: Request) => Promise<AgentFeed> | AgentFeed;\n /** Best-effort per-fetch hook — log to `crawler_requests` here. Never awaited into the response. */\n onRead?: (entry: AgentFeedReadEntry) => void | Promise<void>;\n};\n\nfunction wantsMarkdown(url: URL, accept: string): boolean {\n return url.pathname.endsWith('.md') || accept.toLowerCase().includes('text/markdown');\n}\n\nexport function createAgentFeed(\n config: AgentFeedRouteConfig,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const accept = request.headers.get('accept') ?? '';\n const userAgent = request.headers.get('user-agent');\n // Strip the .md/.json suffix so the feed path matches the page path.\n const path = url.pathname.replace(/\\.(md|json)$/, '');\n\n if (config.onRead) {\n try {\n void Promise.resolve(\n config.onRead({ path, userAgent, botName: matchedAgentToken(userAgent ?? '') }),\n ).catch(() => {});\n } catch {\n /* logging must never break the response */\n }\n }\n\n const feed = await config.getFeed(request);\n\n if (wantsMarkdown(url, accept)) {\n return new Response(renderAgentMarkdown(feed), {\n headers: { 'content-type': 'text/markdown; charset=utf-8' },\n });\n }\n return new Response(JSON.stringify(feed), {\n headers: { 'content-type': 'application/json; charset=utf-8' },\n });\n };\n}\n","/**\n * `sentientAgentMiddleware` — additive-discovery middleware. Detects known AI\n * crawler / agent user-agents on page requests and reports them so they can be\n * logged to `crawler_requests` (the only way to observe passive crawlers, which\n * run no JS and never create a session). It NEVER changes the response — the\n * caller composes it into their Next.js middleware and returns `NextResponse.next()`.\n *\n * export async function middleware(request: NextRequest) {\n * await logCrawler(request); // sentientAgentMiddleware instance\n * return NextResponse.next();\n * }\n */\nimport { matchedAgentToken } from '@sentientui/core';\n\nexport type CrawlerRequestEntry = {\n path: string;\n userAgent: string | null;\n botName: string;\n};\n\nexport type SentientAgentMiddlewareConfig = {\n /** Best-effort sink — persist to `crawler_requests` here. Failures are swallowed. */\n onCrawler: (entry: CrawlerRequestEntry) => void | Promise<void>;\n};\n\nexport function sentientAgentMiddleware(\n config: SentientAgentMiddlewareConfig,\n): (request: Request) => Promise<boolean> {\n return async (request: Request): Promise<boolean> => {\n const userAgent = request.headers.get('user-agent');\n const botName = matchedAgentToken(userAgent ?? '');\n if (!botName) return false;\n\n try {\n const path = new URL(request.url).pathname;\n await Promise.resolve(config.onCrawler({ path, userAgent, botName })).catch(() => {});\n } catch {\n /* detection/logging must never break the request */\n }\n return true;\n };\n}\n"],"mappings":"qlBAAA,OAAS,wBAAAA,OAA4B,mBAErC,OAAS,WAAAC,GAAS,WAAAC,OAAe,eCFjC,OAAS,wBAAAC,OAA4B,mBACrC,OAAS,kBAAAC,OAAsB,qBA8C3B,cAAAC,OAAA,oBAhCJ,SAASC,EAAeC,EAAuB,CAC7C,OAAO,KAAK,UAAUA,CAAK,EAAE,QAAQ,KAAM,SAAS,CACtD,CAGO,SAASC,GAAkBC,EAA2C,CAC3E,OAAIA,EAAM,QAEN,2IAE4CH,EAAeG,EAAM,QAAQ,OAAO,EAAI,+CACrCH,EAAeF,GAAeK,EAAM,QAAQ,UAAU,CAAC,EAAI,qBAIvGN,GAAqBM,EAAM,MAAM,CAC1C,CAcO,SAASC,EAAsBD,EAAgD,CACpF,OACEJ,GAAC,UACC,+BAA6B,GAC7B,wBAAyB,CAAE,OAAQG,GAAkBC,CAAK,CAAE,EAC9D,CAEJ,CCjDA,OACE,sBAAAE,GACA,qBAAAC,OAGK,0BA8DP,OAAS,oBAAAC,OAAwB,0BAjCjC,SAASC,GAA2B,CAClC,OAAI,OAAO,QAAW,aAAe,OAAO,OAAO,YAAe,WACzD,OAAO,WAAW,EAEpB,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,CAAC,EACrE,CAOA,eAAsBC,EACpBC,EACAC,EACwC,CApD1C,IAAAC,EAAAC,EAAAC,EAqDE,IAAMC,GACJD,GAAAD,EAAAG,GAAkBL,EAAQ,OAAO,IAAjC,KAAAE,GACAD,EAAAD,EAAQ,kBAAR,YAAAC,EAAA,KAAAD,KADA,KAAAG,EAEAN,EAAiB,EAWnB,MAAO,CAAE,YATW,MAAMS,GAAmBP,EAAYK,EAAW,CAClE,OAAQJ,EAAQ,OAChB,QAASA,EAAQ,QACjB,OAAQA,EAAQ,OAChB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,QACjB,UAAWA,EAAQ,SACrB,CAAC,EAEqB,UAAAI,CAAU,CAClC,CAmCA,eAAsBG,EACpBP,EACqC,CAzGvC,IAAAC,EAAAC,EAAAC,EAAAK,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EA0GE,GAAM,CAAE,iBAAAC,EAAkB,kBAAAV,CAAkB,EAAI,KAAM,QAAO,yBAAyB,EAEhFD,GACJD,GAAAD,EAAAG,EAAkBL,EAAQ,OAAO,IAAjC,KAAAE,GACAD,EAAAD,EAAQ,kBAAR,YAAAC,EAAA,KAAAD,KADA,KAAAG,EAEAN,EAAiB,EAGnB,GAAI,EADa,OAAOG,EAAQ,QAAW,UAAYA,EAAQ,OAAO,WAAW,KAAK,GACvE,CACb,IAAMgB,EAAuC,CAC3C,aAAaR,EAAAR,EAAQ,WAAR,KAAAQ,EAAoB,CAAC,EAClC,YAAa,CAAC,EACd,MAAO,CAAC,EACR,QAAS,UACT,WAAY,EACZ,UAAAJ,CACF,EACA,GAAI,CACF,IAAMa,EAAO,KAAM,QAAO,wBAAwB,EAgBlD,GAAI,CAACA,EAAI,uBAEP,eAAQ,MACN,mJACF,EACOD,EAET,IAAME,EAAUD,EAAI,kBAAkB,CAAE,UAAAb,CAAU,CAAC,EAAE,OAAO,CAC1D,SAAUJ,EAAQ,SAClB,YAAYS,EAAAT,EAAQ,aAAR,KAAAS,EAAsB,CAAC,EACnC,OAAOC,EAAAV,EAAQ,QAAR,KAAAU,EAAiB,CAAC,CAC3B,CAAC,EACD,MAAO,CACL,aAAaE,GAAAD,EAAAO,EAAQ,cAAR,KAAAP,EAAuBX,EAAQ,WAA/B,KAAAY,EAA2C,CAAC,EACzD,YAAaM,EAAQ,YACrB,MAAOA,EAAQ,MACf,QAASA,EAAQ,QACjB,WAAYA,EAAQ,WACpB,UAAAd,CACF,CACF,OAAQe,EAAA,CACN,OAAOH,CACT,CACF,CAEA,IAAMI,EAAS,MAAML,EACnB,CACE,SAAUf,EAAQ,SAClB,YAAYa,EAAAb,EAAQ,aAAR,KAAAa,EAAsB,CAAC,EACnC,OAAOC,EAAAd,EAAQ,QAAR,KAAAc,EAAiB,CAAC,CAC3B,EACAV,EACA,CACE,OAAQJ,EAAQ,OAChB,QAASA,EAAQ,QACjB,OAAQA,EAAQ,OAChB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,QACjB,UAAWA,EAAQ,SACrB,CACF,EAEA,OAAOqB,EAAAC,EAAA,GAAKF,GAAL,CAAa,UAAAhB,CAAU,EAChC,CF5KA,OAAS,sBAAAmB,OAA0B,4BGmBnC,IAAMC,GAAkB,CAAC,OAAQ,SAAU,aAAa,EAElDC,EAAW,IAAI,IAMd,SAASC,GAAmBC,EAAcC,EAAwC,CACvFH,EAAS,IAAIE,EAAMC,CAAO,CAC5B,CAGO,SAASC,GAAgBF,EAAmD,CACjF,OAAOF,EAAS,IAAIE,CAAI,CAC1B,CAYO,SAASG,EAAeC,EAKjB,CA9Dd,IAAAC,EAAAC,EA+DE,IAAMC,GAAWD,GAAAD,EAAAD,EAAM,UAAN,KAAAC,EAAiBG,GAAgBJ,EAAM,IAAI,IAA3C,KAAAE,EAAgD,CAAC,EAC5DG,EAAgC,CAAC,EACvC,OAAW,CAACC,EAAGC,CAAC,IAAK,OAAO,QAAQJ,CAAQ,EACpCK,GAAsC,SAASF,CAAC,IAAGD,EAAKC,CAAC,EAAIC,GAErE,IAAME,EAAkBC,EAAAC,EAAA,GACnBN,GADmB,CAEtB,KAAML,EAAM,KACZ,OAAQA,EAAM,MAChB,GACA,OAAIA,EAAM,cAAaS,EAAK,YAAcT,EAAM,aACzCS,CACT,CAgBO,SAASG,EAAsBC,EAAyB,CAC7D,OAAO,KAAK,UAAUC,EAAA,CAAE,WAAY,qBAAsB,QAAS,WAAcD,EAAM,EACpF,QAAQ,KAAM,SAAS,CAC5B,CAGO,SAASE,EAAoBF,EAAyB,CAC3D,IAAMG,EAAkB,CAAC,EACrBH,EAAK,OAAOG,EAAM,KAAK,KAAKH,EAAK,KAAK,GAAI,EAAE,EAC5CA,EAAK,SAASG,EAAM,KAAK,OAAOH,EAAK,OAAO,EAAG,EAAE,EAErD,OAAW,CAACI,EAAGC,CAAC,IAAK,OAAO,QAAQL,CAAI,EAClC,CAAC,OAAQ,QAAS,UAAW,SAAU,aAAa,EAAE,SAASI,CAAC,GACpED,EAAM,KAAK,MAAMC,CAAC,GAAI,GAAI,UAAW,KAAK,UAAUC,EAAG,KAAM,CAAC,EAAG,MAAO,EAAE,EAG5E,GAAIL,EAAK,OAAO,OAAS,EAAG,CAC1BG,EAAM,KAAK,YAAa,EAAE,EAC1B,QAAWG,KAAKN,EAAK,OACnBG,EAAM,KAAK,OAAOG,EAAE,EAAE,uBAAkBA,EAAE,OAAO,IAAI,EACjDA,EAAE,UAAY,QAChBH,EAAM,KAAK,GAAI,YAAa,KAAK,UAAUG,EAAE,QAAS,KAAM,CAAC,EAAG,OAAO,EAG3EH,EAAM,KAAK,EAAE,CACf,CAEA,OAAOA,EAAM,KAAK;AAAA,CAAI,EAAE,QAAQ,EAAI;AAAA,CACtC,CC3GA,OAAS,qBAAAI,OAAyB,mBAgBlC,SAASC,GAAcC,EAAUC,EAAyB,CACxD,OAAOD,EAAI,SAAS,SAAS,KAAK,GAAKC,EAAO,YAAY,EAAE,SAAS,eAAe,CACtF,CAEO,SAASC,GACdC,EACyC,CACzC,MAAO,OAAOC,GAAwC,CAnCxD,IAAAC,EAoCI,IAAML,EAAM,IAAI,IAAII,EAAQ,GAAG,EACzBH,GAASI,EAAAD,EAAQ,QAAQ,IAAI,QAAQ,IAA5B,KAAAC,EAAiC,GAC1CC,EAAYF,EAAQ,QAAQ,IAAI,YAAY,EAE5CG,EAAOP,EAAI,SAAS,QAAQ,eAAgB,EAAE,EAEpD,GAAIG,EAAO,OACT,GAAI,CACG,QAAQ,QACXA,EAAO,OAAO,CAAE,KAAAI,EAAM,UAAAD,EAAW,QAASE,GAAkBF,GAAA,KAAAA,EAAa,EAAE,CAAE,CAAC,CAChF,EAAE,MAAM,IAAM,CAAC,CAAC,CAClB,OAAQG,EAAA,CAER,CAGF,IAAMC,EAAO,MAAMP,EAAO,QAAQC,CAAO,EAEzC,OAAIL,GAAcC,EAAKC,CAAM,EACpB,IAAI,SAASU,EAAoBD,CAAI,EAAG,CAC7C,QAAS,CAAE,eAAgB,8BAA+B,CAC5D,CAAC,EAEI,IAAI,SAAS,KAAK,UAAUA,CAAI,EAAG,CACxC,QAAS,CAAE,eAAgB,iCAAkC,CAC/D,CAAC,CACH,CACF,CCnDA,OAAS,qBAAAE,OAAyB,mBAa3B,SAASC,GACdC,EACwC,CACxC,MAAO,OAAOC,GAAuC,CACnD,IAAMC,EAAYD,EAAQ,QAAQ,IAAI,YAAY,EAC5CE,EAAUL,GAAkBI,GAAA,KAAAA,EAAa,EAAE,EACjD,GAAI,CAACC,EAAS,MAAO,GAErB,GAAI,CACF,IAAMC,EAAO,IAAI,IAAIH,EAAQ,GAAG,EAAE,SAClC,MAAM,QAAQ,QAAQD,EAAO,UAAU,CAAE,KAAAI,EAAM,UAAAF,EAAW,QAAAC,CAAQ,CAAC,CAAC,EAAE,MAAM,IAAM,CAAC,CAAC,CACtF,OAAQE,EAAA,CAER,CACA,MAAO,EACT,CACF,CLoJI,OAmBE,YAAAC,EAnBF,OAAAC,EAmBE,QAAAC,MAnBF,oBAxKJ,IAAMC,EAAuB,iCAqD7B,SAASC,GAAoBC,EAA8C,CACzE,OAAO,OAAO,QAAQA,CAAsC,EAAE,IAAI,CAAC,CAACC,EAAIC,CAAC,IAAG,CA3E9E,IAAAC,EA2EkF,OAC9E,GAAAF,EACA,QAAS,OAAOC,GAAM,SAAWA,GAAMC,EAAAD,GAAA,YAAAA,EAA8B,YAA9B,KAAAC,EAA2C,EACpF,EAAE,CACJ,CAgCA,eAAsBC,GAAaC,EAAgD,CA/GnF,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAgHE,IAWIP,EAAAE,EAVF,YAAAM,EACA,SAAAC,EACA,MAAAC,EACA,UAAAC,EACA,mBAAoBC,EACpB,aAAcC,EACd,UAAAC,EACA,UAAAC,EACA,SAAAC,CAzHJ,EA2HMhB,EADCiB,EAAAC,EACDlB,EADC,CATH,aACA,WACA,QACA,YACA,qBACA,eACA,YACA,YACA,aAIImB,EAAc,MAAMC,GAAQ,EAC5BC,EAAOF,EAAY,IAAI,MAAM,EAC/B,CAACR,GAAa,QAAQ,IAAI,WAAa,cAAgB,CAACU,GAC1D,QAAQ,MACN,8LAEF,EAEF,IAAMC,EAAiBX,GAAA,KAAAA,EACpB,QAAQ,IAAI,WAAa,aACtB,WAAWU,GAAA,KAAAA,EAAQ,WAAW,GAC9B,wBACAE,GAAYpB,EAAAgB,EAAY,IAAI,YAAY,IAA5B,KAAAhB,EAAiC,OAC7CqB,GAAUpB,EAAAe,EAAY,IAAI,SAAS,IAAzB,KAAAf,EAA8B,OACxCqB,EAAiBC,GAAqB,CAAE,UAAAH,EAAW,QAAAC,EAAS,UAAWF,CAAe,CAAC,EACvFK,EAAc,MAAMC,GAAQ,EAE9BC,EACAC,EAAsC,KACtCC,EACAC,EAAiE,KACjEC,EAEJ,GAAIrB,EACFiB,EAAqBjB,EACrBqB,EAAepB,UACLJ,GAAYA,EAAS,OAAS,GAAOC,GAASA,EAAM,OAAS,EAAI,CAC3E,IAAMwB,EAAW,MAAMC,EAAqB,CAC1C,SAAU1B,GAAA,KAAAA,EAAY,CAAC,EACvB,WAAAD,EACA,MAAAE,EACA,QAASiB,EACT,OAAQV,EAAc,OACtB,QAAStB,EACT,OAAQ2B,EACR,UAAAC,EACA,QAAAC,EACA,UAAAV,CACF,CAAC,EACDe,EAAqBK,EAAS,YAC9BJ,EAAqBI,EAAS,YAC9BH,EAAeG,EAAS,MACxBF,EACEE,EAAS,UAAY,OACjB,CAAE,QAASA,EAAS,QAAS,YAAY7B,EAAA6B,EAAS,aAAT,KAAA7B,EAAuB,CAAE,EAClE,KACN4B,EAAeC,EAAS,SAC1B,KAAO,CACL,IAAME,EAAS,MAAMC,EAAwB7B,EAAY,CACvD,QAASmB,EACT,OAAQV,EAAc,OACtB,QAAStB,EACT,OAAQ2B,EACR,UAAAC,EACA,QAAAC,EACA,UAAAV,CACF,CAAC,EACDe,EAAqBO,EAAO,YAC5BH,EAAeG,EAAO,SACxB,CAIA,IAAME,EACJ7C,EAAC8C,EAAA,CAAsB,OAAQtB,EAAc,OAAQ,QAASe,EAAgB,EAG1EQ,EACJ/C,EAACgD,GAAAC,EAAAC,EAAA,GACK1B,GADL,CAEC,mBAAoBY,EACpB,mBAAoBC,EACpB,aAAcC,EACd,eAAgBC,GAAA,KAAAA,EAAkB,OAClC,eAAgBP,EAChB,aAAcQ,EAEb,SAAAjB,GACH,EAGF,GAAI,CAACD,EACH,OACErB,EAAAF,EAAA,CACG,UAAA8C,EACAE,GACH,EAOJ,IAAMI,GAAOrC,GAAAD,EAAAS,EAAU,OAAV,KAAAT,EAAkBa,EAAY,IAAI,YAAY,IAA9C,KAAAZ,EAAmD,IAC1DsC,EAAOC,EAAe,CAC1B,KAAMF,EACN,OAAQhD,GAAoBiC,CAAkB,EAC9C,YAAaC,GAAA,KAAAA,EAAsB,OACnC,QAASf,EAAU,OACrB,CAAC,EAED,OACErB,EAAAF,EAAA,CACG,UAAA8C,EACD7C,EAAC,UACC,KAAK,sBACL,wBAAyB,CAAE,OAAQsD,EAAsBF,CAAI,CAAE,EACjE,EACCL,GACH,CAEJ","names":["deriveSessionSegment","cookies","headers","renderPrePaintScript","confidenceBand","jsx","inlineJsString","value","personaScriptBody","props","SentientPersonaScript","preloadAssignments","readSessionCookie","preloadDecisions","defaultSessionId","loadAdaptiveAssignments","components","options","_a","_b","_c","sessionId","readSessionCookie","preloadAssignments","loadAdaptiveDecision","_d","_e","_f","_g","_h","_i","_j","preloadDecisions","fallback","mod","outcome","e","result","__spreadProps","__spreadValues","AdaptiveRootClient","RESERVED_FIELDS","registry","defineAgentContent","page","content","getAgentContent","buildAgentFeed","input","_a","_b","supplied","getAgentContent","safe","k","v","RESERVED_FIELDS","feed","__spreadProps","__spreadValues","renderAgentJsonLdBody","feed","__spreadValues","renderAgentMarkdown","lines","k","v","b","matchedAgentToken","wantsMarkdown","url","accept","createAgentFeed","config","request","_a","userAgent","path","matchedAgentToken","e","feed","renderAgentMarkdown","matchedAgentToken","sentientAgentMiddleware","config","request","userAgent","botName","path","e","Fragment","jsx","jsxs","DEFAULT_API_BASE_URL","assignmentsToBlocks","assignments","id","v","_a","AdaptiveRoot","props","_b","_c","_d","_e","_f","components","sections","slots","appOrigin","initialAssignmentsOverride","ssrSessionIdProp","timeoutMs","agentFeed","children","providerProps","__objRest","headerStore","headers","host","resolvedOrigin","userAgent","referer","sessionSegment","deriveSessionSegment","cookieStore","cookies","initialAssignments","initialLayoutOrder","initialSlots","initialPersona","ssrSessionId","decision","loadAdaptiveDecision","result","loadAdaptiveAssignments","personaScript","SentientPersonaScript","client","AdaptiveRootClient","__spreadProps","__spreadValues","path","feed","buildAgentFeed","renderAgentJsonLdBody"]}
|
|
1
|
+
{"version":3,"sources":["../../src/next/adaptive-root.tsx","../../src/persona-script.tsx","../../src/server.ts","../../src/agent-feed.ts","../../src/next/agent-feed-route.ts","../../src/next/agent-middleware.ts"],"sourcesContent":["import { deriveSessionSegment } from '@sentientui/core';\nimport type { SlotDeclInput, SlotResult } from '@sentientui/core';\nimport { cookies, headers } from 'next/headers';\nimport type { ReactNode } from 'react';\nimport type { AdaptiveProviderProps } from '../provider.js';\nimport { SentientPersonaScript } from '../persona-script.js';\nimport {\n loadAdaptiveAssignments,\n loadAdaptiveDecision,\n type ServerAssignments,\n} from '../server.js';\nimport { AdaptiveRootClient } from './adaptive-root-client.js';\nimport { buildAgentFeed, renderAgentJsonLdBody, type AgentBlock } from '../agent-feed.js';\n\nexport { createAgentFeed } from './agent-feed-route.js';\nexport type { AgentFeedRouteConfig, AgentFeedReadEntry } from './agent-feed-route.js';\nexport { sentientAgentMiddleware } from './agent-middleware.js';\nexport type { SentientAgentMiddlewareConfig, CrawlerRequestEntry } from './agent-middleware.js';\nexport { defineAgentContent, buildAgentFeed as buildAgentFeedFor } from '../agent-feed.js';\nexport type { AgentFeed } from '../agent-feed.js';\n\nconst DEFAULT_API_BASE_URL = 'https://api.sentient-ui.com/v1';\n\nexport type PreloadComponent = { id: string; variantIds: string[] };\n\nexport type AdaptiveRootProps = Omit<\n AdaptiveProviderProps,\n 'initialAssignments' | 'onAssignment' | 'initialSlots' | 'initialPersona'\n> & {\n /**\n * Components to assign server-side (SEO-safe). Optional — omit when the\n * tree uses only slots/sections, or assigns client-side via hooks.\n */\n components?: PreloadComponent[];\n /**\n * Declare page section IDs in their default order. When provided,\n * AdaptiveRoot calls `/v1/decide` (single round trip) instead of\n * individual `/v1/assign` calls, and `useLayoutOrder()` returns the\n * persona-specific order on first render.\n *\n * @example sections={['hero', 'pricing', 'features', 'social_proof']}\n */\n sections?: string[];\n /**\n * Adaptive-slot declarations used by `useAdaptiveTokens` / `AdaptiveGroup`\n * in this tree. Declaring them here decides them in the same SSR\n * round trip, so their values serialize into the server HTML.\n */\n slots?: SlotDeclInput[];\n /** App origin — must be in the project's `allowed_origins`. */\n appOrigin?: string;\n /** Override: when set no network fetch is made. Useful for tests. */\n initialAssignments?: ServerAssignments;\n /**\n * Milliseconds to wait for the API before rendering default variants.\n * Defaults to 1000. The hot path typically returns in well under 150 ms;\n * the full 1 s budget is only reached on a cold start or an API\n * geographically distant from your SSR host. Lower it if your API is\n * co-located and warm.\n */\n timeoutMs?: number;\n /**\n * When set, AdaptiveRoot emits a server-rendered inline JSON-LD block\n * describing the page's winning variants, layout order, and developer-supplied\n * content — readable by passive AI crawlers (which do not run JS). Invisible to\n * humans (a JSON-LD script renders no visible DOM). Omit to emit nothing.\n */\n agentFeed?: {\n /** Page path for the feed. Falls back to the `x-pathname` request header, then '/'. */\n path?: string;\n /** Structured page content. Falls back to the `defineAgentContent` registry for this path. */\n content?: Record<string, unknown>;\n };\n children: ReactNode;\n};\n\n/** Build agent blocks from SSR assignments (Record<id, variantId | { variantId }>). */\nfunction assignmentsToBlocks(assignments: ServerAssignments): AgentBlock[] {\n return Object.entries(assignments as Record<string, unknown>).map(([id, v]) => ({\n id,\n variant: typeof v === 'string' ? v : ((v as { variantId?: string })?.variantId ?? ''),\n }));\n}\n\n/**\n * Next.js Server Component that resolves variant assignments (and optionally\n * section layout order) server-side for zero layout shift on first paint.\n *\n * When `sections` is provided, a single `POST /v1/decide` call returns both\n * the persona-specific section order and all component assignments.\n * Without `sections`, individual `/v1/assign` calls are made per component.\n *\n * @example\n * // app/page.tsx — with section layout\n * import { AdaptiveRoot } from '@sentientui/react/next';\n *\n * export default async function Page() {\n * return (\n * <AdaptiveRoot\n * apiKey={process.env.NEXT_PUBLIC_SENTIENT_API_KEY!}\n * context=\"landing\"\n * sections={['hero', 'pricing', 'features', 'social_proof']}\n * components={[\n * { id: 'hero_cta', variantIds: ['default', 'accent'] },\n * ]}\n * >\n * <HeroSection />\n * <PricingSection />\n * <FeaturesSection />\n * <SocialProofSection />\n * </AdaptiveRoot>\n * );\n * }\n */\nexport async function AdaptiveRoot(props: AdaptiveRootProps): Promise<JSX.Element> {\n const {\n components = [],\n sections,\n slots,\n appOrigin,\n initialAssignments: initialAssignmentsOverride,\n ssrSessionId: ssrSessionIdProp,\n timeoutMs,\n agentFeed,\n children,\n ...providerProps\n } = props;\n\n const headerStore = await headers();\n const host = headerStore.get('host');\n if (!appOrigin && process.env.NODE_ENV === 'production' && !host) {\n console.error(\n '[SentientUI] AdaptiveRoot: Host header is absent and no appOrigin was provided. ' +\n 'Pass appOrigin explicitly — the https://localhost fallback will likely fail allowed_origins validation.',\n );\n }\n const resolvedOrigin = appOrigin ??\n (process.env.NODE_ENV === 'production'\n ? `https://${host ?? 'localhost'}`\n : 'http://localhost:3001');\n const userAgent = headerStore.get('user-agent') ?? undefined;\n const referer = headerStore.get('referer') ?? undefined;\n const sessionSegment = deriveSessionSegment({ userAgent, referer, appOrigin: resolvedOrigin });\n const cookieStore = await cookies();\n\n let initialAssignments: ServerAssignments;\n let initialLayoutOrder: string[] | null = null;\n let initialSlots: Record<string, SlotResult> | undefined;\n let initialPersona: { persona: string; confidence: number } | null = null;\n let ssrSessionId: string | undefined;\n\n if (initialAssignmentsOverride) {\n initialAssignments = initialAssignmentsOverride;\n ssrSessionId = ssrSessionIdProp;\n } else if ((sections && sections.length > 0) || (slots && slots.length > 0)) {\n const decision = await loadAdaptiveDecision({\n sections: sections ?? [],\n components,\n slots,\n cookies: cookieStore,\n apiKey: providerProps.apiKey,\n baseUrl: DEFAULT_API_BASE_URL,\n origin: resolvedOrigin,\n userAgent,\n referer,\n timeoutMs,\n });\n initialAssignments = decision.assignments;\n initialLayoutOrder = decision.layoutOrder;\n initialSlots = decision.slots;\n initialPersona =\n decision.persona !== undefined\n ? { persona: decision.persona, confidence: decision.confidence ?? 0 }\n : null;\n ssrSessionId = decision.sessionId;\n } else {\n const result = await loadAdaptiveAssignments(components, {\n cookies: cookieStore,\n apiKey: providerProps.apiKey,\n baseUrl: DEFAULT_API_BASE_URL,\n origin: resolvedOrigin,\n userAgent,\n referer,\n timeoutMs,\n });\n initialAssignments = result.assignments;\n ssrSessionId = result.sessionId;\n }\n\n // Single-writer inline script — ALWAYS the first child, before any markup\n // that CSS keyed on the persona attributes could style.\n const personaScript = (\n <SentientPersonaScript apiKey={providerProps.apiKey} persona={initialPersona} />\n );\n\n const client = (\n <AdaptiveRootClient\n {...providerProps}\n initialAssignments={initialAssignments}\n initialLayoutOrder={initialLayoutOrder}\n initialSlots={initialSlots}\n initialPersona={initialPersona ?? undefined}\n sessionSegment={sessionSegment}\n ssrSessionId={ssrSessionId}\n >\n {children}\n </AdaptiveRootClient>\n );\n\n if (!agentFeed) {\n return (\n <>\n {personaScript}\n {client}\n </>\n );\n }\n\n // Server-rendered inline JSON-LD for AI crawlers. Emitted only on the server\n // path so passive crawlers (no JS) see it in the raw HTML. The body escapes\n // '<' so page content cannot break out of the <script> element.\n const path = agentFeed.path ?? headerStore.get('x-pathname') ?? '/';\n const feed = buildAgentFeed({\n page: path,\n blocks: assignmentsToBlocks(initialAssignments),\n layoutOrder: initialLayoutOrder ?? undefined,\n content: agentFeed.content,\n });\n\n return (\n <>\n {personaScript}\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: renderAgentJsonLdBody(feed) }}\n />\n {client}\n </>\n );\n}\n","import { renderPrePaintScript } from '@sentientui/core';\nimport { confidenceBand } from '@sentientui/policy';\n\nexport type SentientPersonaScriptProps = {\n /** Publishable API key — selects the localStorage snapshot in the fallback path. */\n apiKey: string;\n /**\n * SSR-decided persona (from `loadAdaptiveDecision`). When present the\n * script embeds the literal values; when absent it reads the local\n * decision snapshot (SPA / return-visit path).\n */\n persona?: { persona: string; confidence: number } | null;\n};\n\n/** JSON string literal that is also safe inside an inline <script> element. */\nfunction inlineJsString(value: string): string {\n return JSON.stringify(value).replace(/</g, '\\\\u003c');\n}\n\n/** Exported for tests. Builds the inline JS (concatenation only — no backticks). */\nexport function personaScriptBody(props: SentientPersonaScriptProps): string {\n if (props.persona) {\n return (\n '(function(){try{var d=document.documentElement;' +\n 'if(d.hasAttribute(\"data-sentient-persona\"))return;' +\n 'd.setAttribute(\"data-sentient-persona\",' + inlineJsString(props.persona.persona) + ');' +\n 'd.setAttribute(\"data-sentient-confidence\",' + inlineJsString(confidenceBand(props.persona.confidence)) + ');' +\n '}catch(e){}})();'\n );\n }\n return renderPrePaintScript(props.apiKey);\n}\n\n/**\n * Single writer of the Rung-1a `<html>` attributes\n * (`data-sentient-persona`, `data-sentient-confidence`), executed pre-paint.\n *\n * `AdaptiveRoot` renders this automatically as its first child. For Pages\n * Router / Remix, render it yourself in `_document` / the root layout.\n *\n * IMPORTANT (install docs): add `suppressHydrationWarning` to your `<html>`\n * element — this script mutates documentElement before React hydrates it\n * (the same pattern next-themes uses). The client SDK adopts the attributes\n * as truth and never rewrites them mid-session.\n */\nexport function SentientPersonaScript(props: SentientPersonaScriptProps): JSX.Element {\n return (\n <script\n data-sentient-persona-script=\"\"\n dangerouslySetInnerHTML={{ __html: personaScriptBody(props) }}\n />\n );\n}\n","/**\n * Server-only helpers for Next.js / SSR. No React or DOM APIs.\n */\nimport {\n preloadAssignments,\n readSessionCookie,\n type ServerAssignConfig,\n type ServerAssignments,\n} from '@sentientui/core/server';\n\nexport { preloadAssignments, readSessionCookie };\nexport type { ServerAssignConfig, ServerAssignments };\n\n/** Return value of `loadAdaptiveAssignments` — includes the session ID used for SSR. */\nexport type LoadAdaptiveAssignmentsResult = {\n assignments: ServerAssignments;\n /** The session ID used for SSR assignment. Pass as `ssrSessionId` to `<AdaptiveProvider>`. */\n sessionId: string;\n};\n\nexport type LoadAdaptiveAssignmentsOptions = {\n /** Next.js `cookies()` return value, or any object with `get(name)`. */\n cookies: { get(name: string): { value: string } | undefined };\n apiKey: string;\n baseUrl: string;\n /** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */\n createSessionId?: () => string;\n /** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */\n origin?: string;\n /** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */\n userAgent?: string;\n /** From Next.js `headers().get('referer')`. */\n referer?: string;\n /** Milliseconds to wait for the API before returning default variants. Defaults to 1000 (typical decide is well under 150 ms; the full budget is only reached on a cold start or a distant API). */\n timeoutMs?: number;\n};\n\nfunction defaultSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Fetches bandit assignments on the server for SEO-safe HTML.\n * Pass `assignments` as `initialAssignments` and `sessionId` as `ssrSessionId`\n * on `<AdaptiveProvider>` so the client adopts the same session on first visit.\n */\nexport async function loadAdaptiveAssignments(\n components: Array<{ id: string; variantIds: string[] }>,\n options: LoadAdaptiveAssignmentsOptions,\n): Promise<LoadAdaptiveAssignmentsResult> {\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n const assignments = await preloadAssignments(components, sessionId, {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n timeoutMs: options.timeoutMs,\n });\n\n return { assignments, sessionId };\n}\n\nexport { preloadDecisions } from '@sentientui/core/server';\nexport type { DecideResult, SlotDeclInput, SlotResult } from '@sentientui/core/server';\n\n/** Return value of `loadAdaptiveDecision` — includes the session ID used for SSR. */\nexport type LoadAdaptiveDecisionResult = import('@sentientui/core/server').DecideResult & {\n sessionId: string;\n};\n\nexport type LoadAdaptiveDecisionOptions = LoadAdaptiveAssignmentsOptions & {\n /**\n * Section IDs in default order. Passed to /v1/decide as the candidate\n * layout. Optional since 0.13.0 — slot-only pages may omit it (at least\n * one of `sections`/`components`/`slots` must be non-empty).\n */\n sections?: string[];\n /** Components to assign in the same decide call. */\n components?: Array<{ id: string; variantIds?: string[] }>;\n /** Adaptive-slot declarations (useAdaptiveTokens / AdaptiveGroup) to decide server-side. */\n slots?: import('@sentientui/core/server').SlotDeclInput[];\n};\n\n/**\n * SSR helper for pages with a declared section layout and/or adaptive slots.\n * Calls `/v1/decide` instead of multiple `/v1/assign` round trips.\n * Pass `sessionId` as `ssrSessionId` on `<AdaptiveProvider>` so the client\n * adopts the same session on first visit.\n *\n * Keyless: with no valid `pk_` key this never fetches (no timeout burn).\n * Under the `development` export condition the decision is computed by the\n * deterministic local engine with the same sessionId the client will adopt —\n * server and client agree by construction. In production the engine resolves\n * to a stub and defaults are returned with one console.error.\n */\nexport async function loadAdaptiveDecision(\n options: LoadAdaptiveDecisionOptions,\n): Promise<LoadAdaptiveDecisionResult> {\n const { preloadDecisions, readSessionCookie } = await import('@sentientui/core/server');\n\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n const keyValid = typeof options.apiKey === 'string' && options.apiKey.startsWith('pk_');\n if (!keyValid) {\n const fallback: LoadAdaptiveDecisionResult = {\n layoutOrder: options.sections ?? [],\n assignments: {},\n slots: {},\n persona: 'unknown',\n confidence: 0,\n sessionId,\n };\n try {\n const mod = (await import('@sentientui/core/local')) as unknown as {\n LOCAL_ENGINE_AVAILABLE: boolean;\n createLocalEngine(opts: { sessionId: string }): {\n decide(input: {\n sections?: string[];\n components?: Array<{ id: string; variantIds?: string[] }>;\n slots?: LoadAdaptiveDecisionOptions['slots'];\n }): {\n layoutOrder: string[] | null;\n assignments: Record<string, string>;\n slots: Record<string, string | Record<string, string>>;\n persona: string;\n confidence: number;\n };\n };\n };\n if (!mod.LOCAL_ENGINE_AVAILABLE) {\n // Pinned message — must byte-match PROD_KEYLESS_ERROR in @sentientui/core.\n console.error(\n '[sentient] No API key configured — nothing is being learned. Set NEXT_PUBLIC_SENTIENT_API_KEY or pass localMode: true for local development.',\n );\n return fallback;\n }\n const outcome = mod.createLocalEngine({ sessionId }).decide({\n sections: options.sections,\n components: options.components ?? [],\n slots: options.slots ?? [],\n });\n return {\n layoutOrder: outcome.layoutOrder ?? options.sections ?? [],\n assignments: outcome.assignments,\n slots: outcome.slots,\n persona: outcome.persona,\n confidence: outcome.confidence,\n sessionId,\n };\n } catch {\n return fallback;\n }\n }\n\n const result = await preloadDecisions(\n {\n sections: options.sections,\n components: options.components ?? [],\n slots: options.slots ?? [],\n },\n sessionId,\n {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n timeoutMs: options.timeoutMs,\n },\n );\n\n return { ...result, sessionId };\n}\n","/**\n * Agent-readable content feed. Merges SDK-known data (winning variants, layout\n * order) with developer-supplied page content, and renders it either as a\n * server-rendered inline JSON-LD block (read by passive AI crawlers, which do\n * not run JS) or as Markdown (for agents that content-negotiate `text/markdown`).\n *\n * No React or DOM APIs — safe to import in server components, route handlers,\n * and middleware.\n */\n\nexport type AgentBlock = {\n /** Component ID. */\n id: string;\n /** Winning variant ID currently served. */\n variant: string;\n /** Agent-readable data attached to the served variant, if any. */\n content?: unknown;\n};\n\nexport type AgentFeed = {\n page: string;\n title?: string;\n summary?: string;\n layoutOrder?: string[];\n blocks: AgentBlock[];\n /** Developer-supplied extra fields (products, specs, arbitrary JSON). */\n [key: string]: unknown;\n};\n\n/** Fields the SDK owns — developer content can never overwrite these. */\nconst RESERVED_FIELDS = ['page', 'blocks', 'layoutOrder'] as const;\n\nconst registry = new Map<string, Record<string, unknown>>();\n\n/**\n * Register page-level structured content the SDK can't infer (title, summary,\n * product fields, arbitrary JSON), keyed by page path. Call at module load.\n */\nexport function defineAgentContent(page: string, content: Record<string, unknown>): void {\n registry.set(page, content);\n}\n\n/** Look up registered content for a page. */\nexport function getAgentContent(page: string): Record<string, unknown> | undefined {\n return registry.get(page);\n}\n\n/** Clear the registry — intended for tests. */\nexport function clearAgentContent(): void {\n registry.clear();\n}\n\n/**\n * Merge SDK-known data with developer-supplied content into a single feed.\n * Developer content fills in title/summary/etc. but can never overwrite the\n * SDK-authoritative fields (`page`, `blocks`, `layoutOrder`).\n */\nexport function buildAgentFeed(input: {\n page: string;\n blocks: AgentBlock[];\n layoutOrder?: string[];\n content?: Record<string, unknown>;\n}): AgentFeed {\n const supplied = input.content ?? getAgentContent(input.page) ?? {};\n const safe: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(supplied)) {\n if (!(RESERVED_FIELDS as readonly string[]).includes(k)) safe[k] = v;\n }\n const feed: AgentFeed = {\n ...safe,\n page: input.page,\n blocks: input.blocks,\n };\n if (input.layoutOrder) feed.layoutOrder = input.layoutOrder;\n return feed;\n}\n\n/**\n * Render the feed as a server-rendered inline JSON-LD `<script>` string. `<` is\n * escaped to `<` so embedded content cannot break out of the script\n * element. MUST be emitted on the server — passive crawlers never run client JS.\n */\nexport function renderAgentJsonLd(feed: AgentFeed): string {\n return `<script type=\"application/ld+json\">${renderAgentJsonLdBody(feed)}</script>`;\n}\n\n/**\n * The escaped JSON-LD body only (no `<script>` wrapper). For React server\n * components, inject via `<script type=\"application/ld+json\"\n * dangerouslySetInnerHTML={{ __html: renderAgentJsonLdBody(feed) }} />`.\n */\nexport function renderAgentJsonLdBody(feed: AgentFeed): string {\n return JSON.stringify({ '@context': 'https://schema.org', '@type': 'WebPage', ...feed })\n .replace(/</g, '\\\\u003c');\n}\n\n/** Render the feed as Markdown for agents that negotiate `text/markdown`. */\nexport function renderAgentMarkdown(feed: AgentFeed): string {\n const lines: string[] = [];\n if (feed.title) lines.push(`# ${feed.title}`, '');\n if (feed.summary) lines.push(String(feed.summary), '');\n\n for (const [k, v] of Object.entries(feed)) {\n if (['page', 'title', 'summary', 'blocks', 'layoutOrder'].includes(k)) continue;\n lines.push(`## ${k}`, '', '```json', JSON.stringify(v, null, 2), '```', '');\n }\n\n if (feed.blocks.length > 0) {\n lines.push('## blocks', '');\n for (const b of feed.blocks) {\n lines.push(`- **${b.id}** → variant \\`${b.variant}\\``);\n if (b.content !== undefined) {\n lines.push('', ' ```json', JSON.stringify(b.content, null, 2), ' ```');\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n').trimEnd() + '\\n';\n}\n","/**\n * `createAgentFeed` — a framework-standard Route Handler (Web `Request` →\n * `Response`) that serves the agent-readable feed via HTTP content negotiation:\n * `text/markdown` (Accept header or `.md` URL) → Markdown, otherwise JSON.\n *\n * This is the secondary channel of the agent-readable design — for agents that\n * *ask* (coding agents, agents the customer controls, future crawlers). The\n * primary channel is the server-rendered inline JSON-LD from `<AdaptiveRoot>`.\n *\n * Every fetch is reported to `onRead` (best-effort) so it can be logged to\n * `crawler_requests` and counted in the dashboard traffic breakdown.\n */\nimport { matchedAgentToken } from '@sentientui/core';\nimport { renderAgentMarkdown, type AgentFeed } from '../agent-feed.js';\n\nexport type AgentFeedReadEntry = {\n path: string;\n userAgent: string | null;\n botName: string | null;\n};\n\nexport type AgentFeedRouteConfig = {\n /** Resolve the feed for a request (winning variants + layout + dev content). */\n getFeed: (request: Request) => Promise<AgentFeed> | AgentFeed;\n /** Best-effort per-fetch hook — log to `crawler_requests` here. Never awaited into the response. */\n onRead?: (entry: AgentFeedReadEntry) => void | Promise<void>;\n};\n\nfunction wantsMarkdown(url: URL, accept: string): boolean {\n return url.pathname.endsWith('.md') || accept.toLowerCase().includes('text/markdown');\n}\n\nexport function createAgentFeed(\n config: AgentFeedRouteConfig,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const accept = request.headers.get('accept') ?? '';\n const userAgent = request.headers.get('user-agent');\n // Strip the .md/.json suffix so the feed path matches the page path.\n const path = url.pathname.replace(/\\.(md|json)$/, '');\n\n if (config.onRead) {\n try {\n void Promise.resolve(\n config.onRead({ path, userAgent, botName: matchedAgentToken(userAgent ?? '') }),\n ).catch(() => {});\n } catch {\n /* logging must never break the response */\n }\n }\n\n const feed = await config.getFeed(request);\n\n if (wantsMarkdown(url, accept)) {\n return new Response(renderAgentMarkdown(feed), {\n headers: { 'content-type': 'text/markdown; charset=utf-8' },\n });\n }\n return new Response(JSON.stringify(feed), {\n headers: { 'content-type': 'application/json; charset=utf-8' },\n });\n };\n}\n","/**\n * `sentientAgentMiddleware` — additive-discovery middleware. Detects known AI\n * crawler / agent user-agents on page requests and reports them so they can be\n * logged to `crawler_requests` (the only way to observe passive crawlers, which\n * run no JS and never create a session). It NEVER changes the response — the\n * caller composes it into their Next.js middleware and returns `NextResponse.next()`.\n *\n * export async function middleware(request: NextRequest) {\n * await logCrawler(request); // sentientAgentMiddleware instance\n * return NextResponse.next();\n * }\n */\nimport { matchedAgentToken } from '@sentientui/core';\n\nexport type CrawlerRequestEntry = {\n path: string;\n userAgent: string | null;\n botName: string;\n};\n\nexport type SentientAgentMiddlewareConfig = {\n /** Best-effort sink — persist to `crawler_requests` here. Failures are swallowed. */\n onCrawler: (entry: CrawlerRequestEntry) => void | Promise<void>;\n};\n\nexport function sentientAgentMiddleware(\n config: SentientAgentMiddlewareConfig,\n): (request: Request) => Promise<boolean> {\n return async (request: Request): Promise<boolean> => {\n const userAgent = request.headers.get('user-agent');\n const botName = matchedAgentToken(userAgent ?? '');\n if (!botName) return false;\n\n try {\n const path = new URL(request.url).pathname;\n await Promise.resolve(config.onCrawler({ path, userAgent, botName })).catch(() => {});\n } catch {\n /* detection/logging must never break the request */\n }\n return true;\n };\n}\n"],"mappings":"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","names":["deriveSessionSegment","cookies","headers","renderPrePaintScript","confidenceBand","jsx","inlineJsString","value","personaScriptBody","props","SentientPersonaScript","preloadAssignments","readSessionCookie","preloadDecisions","defaultSessionId","loadAdaptiveAssignments","components","options","_a","_b","_c","sessionId","readSessionCookie","preloadAssignments","loadAdaptiveDecision","_d","_e","_f","_g","_h","_i","_j","preloadDecisions","fallback","mod","outcome","e","result","__spreadProps","__spreadValues","AdaptiveRootClient","RESERVED_FIELDS","registry","defineAgentContent","page","content","getAgentContent","buildAgentFeed","input","_a","_b","supplied","getAgentContent","safe","k","v","RESERVED_FIELDS","feed","__spreadProps","__spreadValues","renderAgentJsonLdBody","feed","__spreadValues","renderAgentMarkdown","lines","k","v","b","matchedAgentToken","wantsMarkdown","url","accept","createAgentFeed","config","request","_a","userAgent","path","matchedAgentToken","e","feed","renderAgentMarkdown","matchedAgentToken","sentientAgentMiddleware","config","request","userAgent","botName","path","e","Fragment","jsx","jsxs","DEFAULT_API_BASE_URL","assignmentsToBlocks","assignments","id","v","_a","AdaptiveRoot","props","_b","_c","_d","_e","_f","components","sections","slots","appOrigin","initialAssignmentsOverride","ssrSessionIdProp","timeoutMs","agentFeed","children","providerProps","__objRest","headerStore","headers","host","resolvedOrigin","userAgent","referer","sessionSegment","deriveSessionSegment","cookieStore","cookies","initialAssignments","initialLayoutOrder","initialSlots","initialPersona","ssrSessionId","decision","loadAdaptiveDecision","result","loadAdaptiveAssignments","personaScript","SentientPersonaScript","client","AdaptiveRootClient","__spreadProps","__spreadValues","path","feed","buildAgentFeed","renderAgentJsonLdBody"]}
|
package/dist/testing.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
"use strict";var _e=Object.create;var P=Object.defineProperty,we=Object.defineProperties,Se=Object.getOwnPropertyDescriptor,be=Object.getOwnPropertyDescriptors,Re=Object.getOwnPropertyNames,q=Object.getOwnPropertySymbols,he=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var Q=(e,t,n)=>t in e?P(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,k=(e,t)=>{for(var n in t||(t={}))Y.call(t,n)&&Q(e,n,t[n]);if(q)for(var n of q(t))xe.call(t,n)&&Q(e,n,t[n]);return e},Z=(e,t)=>we(e,be(t));var Ce=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},ee=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Re(t))!Y.call(e,r)&&r!==n&&P(e,r,{get:()=>t[r],enumerable:!(i=Se(t,r))||i.enumerable});return e};var Ae=(e,t,n)=>(n=e!=null?_e(he(e)):{},ee(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),Pe=e=>ee(P({},"__esModule",{value:!0}),e);var Fe={};Ce(Fe,{applyScenario:()=>M,clearSentientEvents:()=>ue,getSentientEvents:()=>D,hasFiredGoal:()=>ce,mockSentient:()=>fe,mockSentientCypress:()=>ve,renderWithSentient:()=>Me,resetScenario:()=>B,resolveScenario:()=>w,scenarioToHandlers:()=>pe,setupSentientTests:()=>Be});module.exports=Pe(Fe);var me=require("@testing-library/react");var g=require("react"),x=require("@sentientui/core");var ke=new Map,Ee=new Map;function te(e,t){ke.set(e,t);let n=Ee.get(e);if(n)for(let i of n)try{i(t)}catch(r){}}var Oe={on:!1,listeners:new Set};function ne(){if(typeof window=="undefined")return Oe;let e=window;return e.__sentient_preview||(e.__sentient_preview={on:!1,listeners:new Set}),e.__sentient_preview}function T(){return ne().on}function ie(e){let t=ne().listeners;return t.add(e),()=>{t.delete(e)}}function oe(e){return{isLocal:e.isLocal,track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},fetchWeights:()=>Promise.resolve([]),getAssignment:(t,n)=>e.getAssignment(t,n),assign:(t,n,i,r)=>e.assign(t,n,i,r),decide:()=>Promise.resolve(null),getSlotResult:t=>e.getSlotResult(t),getPersona:()=>e.getPersona(),getGraph:()=>e.getGraph(),destroy:()=>e.destroy()}}function re(e){typeof window!="undefined"&&(window.__sentient_devtools_config=e)}var Ie={components:new Map,slots:new Map,sections:[],listeners:new Set,version:0};function j(){if(typeof window=="undefined")return Ie;let e=window;return e.__sentient_registry||(e.__sentient_registry={components:new Map,slots:new Map,sections:[],listeners:new Set,version:0}),e.__sentient_registry}function We(){j().version+=1;for(let e of j().listeners)e()}function se(e){j().sections=[...e],We()}var le=require("react/jsx-runtime");function De(){var e,t;if(typeof window=="undefined")return"desktop:direct";try{let n=(0,x.detectDeviceClass)((e=navigator.userAgent)!=null?e:""),i=(0,x.detectTrafficSource)((t=document.referrer)!=null?t:"",window.location.origin);return`${n}:${i}`}catch(n){return"desktop:direct"}}var ae="https://api.sentient-ui.com/v1",Le=(0,g.createContext)({client:null,apiKey:"",initialAssignments:{},sessionSegment:"desktop:direct",ssrFallback:"first",onAssignment:void 0,initialLayoutOrder:null,initialSlots:{},initialPersona:null,apiBaseUrl:ae});function de(e){var m,y;let[t,n]=(0,g.useState)(null),[i]=(0,g.useState)(()=>{var o;return(o=e.sessionSegment)!=null?o:De()}),[r,s]=(0,g.useState)(T());(0,g.useEffect)(()=>ie(()=>s(T())),[]),(0,g.useEffect)(()=>{if(e.consent===!1&&!e.preConsentBehavior){n(d=>(d==null||d.destroy(),null));return}let o={apiKey:e.apiKey,context:e.context,debug:e.debug,initialAssignments:e.initialAssignments,sessionSegment:i,consent:e.consent,preConsentBehavior:e.preConsentBehavior,respectDoNotTrack:e.respectDoNotTrack,ssrSessionId:e.ssrSessionId,country:e.country,localMode:e.localMode,initialSlots:e.initialSlots,initialPersona:e.initialPersona,ingestUrl:e.apiBaseUrl?`${e.apiBaseUrl.replace(/\/$/,"")}/events`:void 0},c=!1,l=null;return e.enableGraph?import("@sentientui/core/graph").then(({init:d})=>{c||(l=d(Z(k({},o),{graph:!0})),n(l))}):(l=(0,x.init)(o),n(l)),()=>{c=!0,l==null||l.destroy()}},[e.consent]),(0,g.useEffect)(()=>{if(!t)return;let o=!1,c=async()=>{if(o)return;let d;try{d=await t.fetchWeights()}catch(_){return}if(!o)for(let _ of d){let I={componentId:_.componentId,updatedAt:_.updatedAt,variants:_.variants.map(b=>{var C;return{variantId:b.variantId,pulls:b.pulls,avgReward:(C=b.avgReward)!=null?C:0}})};te(_.componentId,I)}};c();let l=setInterval(()=>{c()},6e4);return()=>{o=!0,clearInterval(l)}},[t]);let v=(m=e.ssrFallback)!=null?m:"first",u=(y=e.apiBaseUrl)!=null?y:ae;(0,g.useEffect)(()=>{var o;typeof process!="undefined"&&((o=process.env)==null?void 0:o.NODE_ENV)==="production"||re({apiKey:e.apiKey,apiBaseUrl:u,isLocal:(t==null?void 0:t.isLocal)===!0})},[t,e.apiKey,u]),(0,g.useEffect)(()=>{e.initialLayoutOrder&&e.initialLayoutOrder.length>0&&se(e.initialLayoutOrder)},[e.initialLayoutOrder]);let a=(0,g.useMemo)(()=>t&&r?oe(t):t,[t,r]),p=(0,g.useMemo)(()=>{var o,c,l,d;return{client:a,apiKey:e.apiKey,initialAssignments:(o=e.initialAssignments)!=null?o:{},sessionSegment:i,ssrFallback:v,onAssignment:e.onAssignment,initialLayoutOrder:(c=e.initialLayoutOrder)!=null?c:null,initialSlots:(l=e.initialSlots)!=null?l:{},initialPersona:(d=e.initialPersona)!=null?d:null,apiBaseUrl:u}},[a,e.apiKey,e.initialAssignments,i,v,e.onAssignment,e.initialLayoutOrder,e.initialSlots,e.initialPersona,u]);return(0,le.jsx)(Le.Provider,{value:p,children:e.children})}function E(e){return e<.3?"low":e<.7?"medium":"high"}function M(e={}){var n,i,r;let t=window;if(t.__sentient_overrides=k({},(n=e.variants)!=null?n:{}),e.layout?t.__sentient_layout_override=e.layout:delete t.__sentient_layout_override,e.slots?t.__sentient_slot_overrides=k({},e.slots):delete t.__sentient_slot_overrides,e.persona){t.__sentient_persona_override={persona:e.persona,confidence:(i=e.confidence)!=null?i:1};try{let s=document.documentElement;s.setAttribute("data-sentient-persona",e.persona),s.setAttribute("data-sentient-confidence",E((r=e.confidence)!=null?r:1))}catch(s){}}else delete t.__sentient_persona_override}function B(){let e=window;delete e.__sentient_overrides,delete e.__sentient_layout_override,delete e.__sentient_slot_overrides,delete e.__sentient_persona_override;try{document.documentElement.removeAttribute("data-sentient-persona"),document.documentElement.removeAttribute("data-sentient-confidence")}catch(t){}}var O=require("msw");var F=[];function K(e){F.push(e)}function D(){return[...F]}function ue(){F.length=0}function ce(e,t){return e.some(n=>(n.eventType==="goal_achieved"||n.eventType==="goal")&&n.goalType===t)}function Te(e){var t;try{return new URL(e).pathname}catch(n){return(t=e.split("?")[0])!=null?t:e}}async function je(e,t){var i,r,s;let n=(i=e.api)==null?void 0:i[t];return n===void 0?null:n==="error"?{status:500}:typeof n=="number"?{status:n}:(n.delayMs&&await new Promise(v=>setTimeout(v,n.delayMs)),{status:(r=n.status)!=null?r:200,json:(s=n.body)!=null?s:{}})}async function w(e,t,n,i){var a,p,m,y,o,c,l,d,_,I,b,C,N,U,V,G,H,J,$,z,X;let r=Te(n);if(!r.includes("/v1/"))return null;let s="/v1/"+((a=r.split("/v1/")[1])!=null?a:""),v=await je(e,s);if(v)return v;let u=i?JSON.parse(i):{};if(s==="/v1/sessions")return{status:204};if(s==="/v1/events"){for(let f of u)K(f);return{status:204}}if(s==="/v1/goals")return K({eventType:"goal",goalType:u.name}),{status:204};if(s==="/v1/assign"){let f=u;return{status:200,json:{variantId:(o=(y=(p=e.variants)==null?void 0:p[f.componentId])!=null?y:(m=f.variantIds)==null?void 0:m[0])!=null?o:"control",assignmentTtlMs:6e4}}}if(s==="/v1/decide"){let f=u,S={layoutOrder:(l=e.layout)!=null?l:((c=f.sections)!=null?c:[]).map(R=>R.id),assignments:(d=e.variants)!=null?d:{},persona:(_=e.persona)!=null?_:"unknown",confidence:(I=e.confidence)!=null?I:1};if(f.slots&&f.slots.length>0){let R={};for(let h of f.slots)R[h.id]=(C=(b=e.slots)==null?void 0:b[h.id])!=null?C:ge(h);S.slots=R}return{status:200,json:S}}if(s==="/v1/explain"){let f=u,A=(U=e.layout)!=null?U:((N=f.sections)!=null?N:[]).map(W=>W.id),S=(G=(V=f.persona)!=null?V:e.persona)!=null?G:"unknown",R=(H=e.confidence)!=null?H:1,h={layoutOrder:A,assignments:(J=e.variants)!=null?J:{},persona:S,reasons:[],personaAttributes:{persona:S,confidence:E(R)}};if(f.slots&&f.slots.length>0){let W={};for(let L of f.slots)W[L.id]=(z=($=e.slots)==null?void 0:$[L.id])!=null?z:ge(L);h.slots=W}return{status:200,json:h}}return s==="/v1/weights"?{status:200,json:{components:Object.entries((X=e.weights)!=null?X:{}).map(([A,S])=>({componentId:A,updatedAt:0,variants:S}))}}:null}function ge(e){var n,i,r;if(e.arms)return typeof e.baseline=="string"?e.baseline:(n=e.arms[0])!=null?n:"baseline";let t={};for(let[s,v]of Object.entries((i=e.dims)!=null?i:{})){let u=typeof e.baseline=="object"&&e.baseline!==null?e.baseline[s]:void 0;t[s]=(r=u!=null?u:v[0])!=null?r:""}return t}function pe(e={}){return[O.http.all("*/v1/*",async({request:t})=>{let n=t.method==="GET"||t.method==="HEAD"?null:await t.text(),i=await w(e,t.method,t.url,n);if(i)return i.json===void 0?new O.HttpResponse(null,{status:i.status}):O.HttpResponse.json(i.json,{status:i.status})})]}async function fe(e,t={}){var i,r,s,v,u;let n={overrides:(i=t.variants)!=null?i:{},layout:(r=t.layout)!=null?r:null,slots:(s=t.slots)!=null?s:null,persona:(v=t.persona)!=null?v:null,confidence:(u=t.confidence)!=null?u:1};return await e.addInitScript(a=>{let p=window;if(p.__sentient_overrides=a.overrides,a.layout&&(p.__sentient_layout_override=a.layout),a.slots&&(p.__sentient_slot_overrides=a.slots),a.persona){p.__sentient_persona_override={persona:a.persona,confidence:a.confidence};try{let m=a.confidence<.3?"low":a.confidence<.7?"medium":"high";document.documentElement.setAttribute("data-sentient-persona",a.persona),document.documentElement.setAttribute("data-sentient-confidence",m)}catch(m){}}},n),await e.route("**/v1/**",async a=>{var y;let p=a.request(),m=await w(t,p.method(),p.url(),p.postData());if(!m)return a.continue();await a.fulfill({status:m.status,contentType:"application/json",body:JSON.stringify((y=m.json)!=null?y:{})})}),{events:()=>D()}}function ve(e,t={}){var u,a,p,m,y;let n=(u=t.variants)!=null?u:{},i=(a=t.layout)!=null?a:null,r=(p=t.slots)!=null?p:null,s=(m=t.persona)!=null?m:null,v=(y=t.confidence)!=null?y:1;e.on("window:before:load",o=>{var c,l;if(o.__sentient_overrides=n,i&&(o.__sentient_layout_override=i),r&&(o.__sentient_slot_overrides=r),s){o.__sentient_persona_override={persona:s,confidence:v};try{let d=o.document;(c=d==null?void 0:d.documentElement)==null||c.setAttribute("data-sentient-persona",s),(l=d==null?void 0:d.documentElement)==null||l.setAttribute("data-sentient-confidence",E(v))}catch(d){}}}),e.intercept("**/v1/**",async o=>{var l;let c=await w(t,o.method,o.url,o.body!=null?JSON.stringify(o.body):null);c&&o.reply({statusCode:c.status,body:(l=c.json)!=null?l:""})})}var ye=require("react/jsx-runtime");function Me(e,t={},n){return M(t),(0,me.render)((0,ye.jsx)(de,{apiKey:"pk_test",context:"saas",consent:!1,children:e}),n)}function Be(){var t;let e=globalThis;(t=e.afterEach)==null||t.call(e,()=>B())}0&&(module.exports={applyScenario,clearSentientEvents,getSentientEvents,hasFiredGoal,mockSentient,mockSentientCypress,renderWithSentient,resetScenario,resolveScenario,scenarioToHandlers,setupSentientTests});
|
|
2
|
+
"use strict";var _e=Object.create;var P=Object.defineProperty,we=Object.defineProperties,Se=Object.getOwnPropertyDescriptor,be=Object.getOwnPropertyDescriptors,Re=Object.getOwnPropertyNames,q=Object.getOwnPropertySymbols,he=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var Q=(e,t,n)=>t in e?P(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,k=(e,t)=>{for(var n in t||(t={}))Y.call(t,n)&&Q(e,n,t[n]);if(q)for(var n of q(t))xe.call(t,n)&&Q(e,n,t[n]);return e},Z=(e,t)=>we(e,be(t));var Ce=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},ee=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Re(t))!Y.call(e,r)&&r!==n&&P(e,r,{get:()=>t[r],enumerable:!(i=Se(t,r))||i.enumerable});return e};var Ae=(e,t,n)=>(n=e!=null?_e(he(e)):{},ee(t||!e||!e.__esModule?P(n,"default",{value:e,enumerable:!0}):n,e)),Pe=e=>ee(P({},"__esModule",{value:!0}),e);var Fe={};Ce(Fe,{applyScenario:()=>M,clearSentientEvents:()=>ue,getSentientEvents:()=>D,hasFiredGoal:()=>ce,mockSentient:()=>fe,mockSentientCypress:()=>ve,renderWithSentient:()=>Me,resetScenario:()=>B,resolveScenario:()=>w,scenarioToHandlers:()=>pe,setupSentientTests:()=>Be});module.exports=Pe(Fe);var me=require("@testing-library/react");var g=require("react"),x=require("@sentientui/core");var ke=new Map,Ee=new Map;function te(e,t){ke.set(e,t);let n=Ee.get(e);if(n)for(let i of n)try{i(t)}catch(r){}}var Oe={on:!1,listeners:new Set};function ne(){if(typeof window=="undefined")return Oe;let e=window;return e.__sentient_preview||(e.__sentient_preview={on:!1,listeners:new Set}),e.__sentient_preview}function T(){return ne().on}function ie(e){let t=ne().listeners;return t.add(e),()=>{t.delete(e)}}function oe(e){return{isLocal:e.isLocal,track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},fetchWeights:()=>Promise.resolve([]),getAssignment:(t,n)=>e.getAssignment(t,n),assign:(t,n,i,r)=>e.assign(t,n,i,r),decide:()=>Promise.resolve(null),getSlotResult:t=>e.getSlotResult(t),getPersona:()=>e.getPersona(),getGraph:()=>e.getGraph(),dispose:()=>e.dispose(),destroy:()=>e.destroy()}}function re(e){typeof window!="undefined"&&(window.__sentient_devtools_config=e)}var Ie={components:new Map,slots:new Map,sections:[],listeners:new Set,version:0};function j(){if(typeof window=="undefined")return Ie;let e=window;return e.__sentient_registry||(e.__sentient_registry={components:new Map,slots:new Map,sections:[],listeners:new Set,version:0}),e.__sentient_registry}function We(){j().version+=1;for(let e of j().listeners)e()}function se(e){j().sections=[...e],We()}var le=require("react/jsx-runtime");function De(){var e,t;if(typeof window=="undefined")return"desktop:direct";try{let n=(0,x.detectDeviceClass)((e=navigator.userAgent)!=null?e:""),i=(0,x.detectTrafficSource)((t=document.referrer)!=null?t:"",window.location.origin);return`${n}:${i}`}catch(n){return"desktop:direct"}}var ae="https://api.sentient-ui.com/v1",Le=(0,g.createContext)({client:null,apiKey:"",initialAssignments:{},sessionSegment:"desktop:direct",ssrFallback:"first",onAssignment:void 0,initialLayoutOrder:null,initialSlots:{},initialPersona:null,apiBaseUrl:ae});function de(e){var m,y;let[t,n]=(0,g.useState)(null),[i]=(0,g.useState)(()=>{var o;return(o=e.sessionSegment)!=null?o:De()}),[r,s]=(0,g.useState)(T());(0,g.useEffect)(()=>ie(()=>s(T())),[]),(0,g.useEffect)(()=>{if(e.consent===!1&&!e.preConsentBehavior){n(d=>(d==null||d.destroy(),null));return}let o={apiKey:e.apiKey,context:e.context,debug:e.debug,initialAssignments:e.initialAssignments,sessionSegment:i,consent:e.consent,preConsentBehavior:e.preConsentBehavior,respectDoNotTrack:e.respectDoNotTrack,ssrSessionId:e.ssrSessionId,country:e.country,localMode:e.localMode,initialSlots:e.initialSlots,initialPersona:e.initialPersona,ingestUrl:e.apiBaseUrl?`${e.apiBaseUrl.replace(/\/$/,"")}/events`:void 0},c=!1,l=null;return e.enableGraph?import("@sentientui/core/graph").then(({init:d})=>{c||(l=d(Z(k({},o),{graph:!0})),n(l))}):(l=(0,x.init)(o),n(l)),()=>{c=!0,l==null||l.dispose()}},[e.consent]),(0,g.useEffect)(()=>{if(!t)return;let o=!1,c=async()=>{if(o)return;let d;try{d=await t.fetchWeights()}catch(_){return}if(!o)for(let _ of d){let I={componentId:_.componentId,updatedAt:_.updatedAt,variants:_.variants.map(b=>{var C;return{variantId:b.variantId,pulls:b.pulls,avgReward:(C=b.avgReward)!=null?C:0}})};te(_.componentId,I)}};c();let l=setInterval(()=>{c()},6e4);return()=>{o=!0,clearInterval(l)}},[t]);let v=(m=e.ssrFallback)!=null?m:"first",u=(y=e.apiBaseUrl)!=null?y:ae;(0,g.useEffect)(()=>{var o;typeof process!="undefined"&&((o=process.env)==null?void 0:o.NODE_ENV)==="production"||re({apiKey:e.apiKey,apiBaseUrl:u,isLocal:(t==null?void 0:t.isLocal)===!0})},[t,e.apiKey,u]),(0,g.useEffect)(()=>{e.initialLayoutOrder&&e.initialLayoutOrder.length>0&&se(e.initialLayoutOrder)},[e.initialLayoutOrder]);let a=(0,g.useMemo)(()=>t&&r?oe(t):t,[t,r]),p=(0,g.useMemo)(()=>{var o,c,l,d;return{client:a,apiKey:e.apiKey,initialAssignments:(o=e.initialAssignments)!=null?o:{},sessionSegment:i,ssrFallback:v,onAssignment:e.onAssignment,initialLayoutOrder:(c=e.initialLayoutOrder)!=null?c:null,initialSlots:(l=e.initialSlots)!=null?l:{},initialPersona:(d=e.initialPersona)!=null?d:null,apiBaseUrl:u}},[a,e.apiKey,e.initialAssignments,i,v,e.onAssignment,e.initialLayoutOrder,e.initialSlots,e.initialPersona,u]);return(0,le.jsx)(Le.Provider,{value:p,children:e.children})}function E(e){return e<.3?"low":e<.7?"medium":"high"}function M(e={}){var n,i,r;let t=window;if(t.__sentient_overrides=k({},(n=e.variants)!=null?n:{}),e.layout?t.__sentient_layout_override=e.layout:delete t.__sentient_layout_override,e.slots?t.__sentient_slot_overrides=k({},e.slots):delete t.__sentient_slot_overrides,e.persona){t.__sentient_persona_override={persona:e.persona,confidence:(i=e.confidence)!=null?i:1};try{let s=document.documentElement;s.setAttribute("data-sentient-persona",e.persona),s.setAttribute("data-sentient-confidence",E((r=e.confidence)!=null?r:1))}catch(s){}}else delete t.__sentient_persona_override}function B(){let e=window;delete e.__sentient_overrides,delete e.__sentient_layout_override,delete e.__sentient_slot_overrides,delete e.__sentient_persona_override;try{document.documentElement.removeAttribute("data-sentient-persona"),document.documentElement.removeAttribute("data-sentient-confidence")}catch(t){}}var O=require("msw");var F=[];function K(e){F.push(e)}function D(){return[...F]}function ue(){F.length=0}function ce(e,t){return e.some(n=>(n.eventType==="goal_achieved"||n.eventType==="goal")&&n.goalType===t)}function Te(e){var t;try{return new URL(e).pathname}catch(n){return(t=e.split("?")[0])!=null?t:e}}async function je(e,t){var i,r,s;let n=(i=e.api)==null?void 0:i[t];return n===void 0?null:n==="error"?{status:500}:typeof n=="number"?{status:n}:(n.delayMs&&await new Promise(v=>setTimeout(v,n.delayMs)),{status:(r=n.status)!=null?r:200,json:(s=n.body)!=null?s:{}})}async function w(e,t,n,i){var a,p,m,y,o,c,l,d,_,I,b,C,N,U,V,G,H,J,$,z,X;let r=Te(n);if(!r.includes("/v1/"))return null;let s="/v1/"+((a=r.split("/v1/")[1])!=null?a:""),v=await je(e,s);if(v)return v;let u=i?JSON.parse(i):{};if(s==="/v1/sessions")return{status:204};if(s==="/v1/events"){for(let f of u)K(f);return{status:204}}if(s==="/v1/goals")return K({eventType:"goal",goalType:u.name}),{status:204};if(s==="/v1/assign"){let f=u;return{status:200,json:{variantId:(o=(y=(p=e.variants)==null?void 0:p[f.componentId])!=null?y:(m=f.variantIds)==null?void 0:m[0])!=null?o:"control",assignmentTtlMs:6e4}}}if(s==="/v1/decide"){let f=u,S={layoutOrder:(l=e.layout)!=null?l:((c=f.sections)!=null?c:[]).map(R=>R.id),assignments:(d=e.variants)!=null?d:{},persona:(_=e.persona)!=null?_:"unknown",confidence:(I=e.confidence)!=null?I:1};if(f.slots&&f.slots.length>0){let R={};for(let h of f.slots)R[h.id]=(C=(b=e.slots)==null?void 0:b[h.id])!=null?C:ge(h);S.slots=R}return{status:200,json:S}}if(s==="/v1/explain"){let f=u,A=(U=e.layout)!=null?U:((N=f.sections)!=null?N:[]).map(W=>W.id),S=(G=(V=f.persona)!=null?V:e.persona)!=null?G:"unknown",R=(H=e.confidence)!=null?H:1,h={layoutOrder:A,assignments:(J=e.variants)!=null?J:{},persona:S,reasons:[],personaAttributes:{persona:S,confidence:E(R)}};if(f.slots&&f.slots.length>0){let W={};for(let L of f.slots)W[L.id]=(z=($=e.slots)==null?void 0:$[L.id])!=null?z:ge(L);h.slots=W}return{status:200,json:h}}return s==="/v1/weights"?{status:200,json:{components:Object.entries((X=e.weights)!=null?X:{}).map(([A,S])=>({componentId:A,updatedAt:0,variants:S}))}}:null}function ge(e){var n,i,r;if(e.arms)return typeof e.baseline=="string"?e.baseline:(n=e.arms[0])!=null?n:"baseline";let t={};for(let[s,v]of Object.entries((i=e.dims)!=null?i:{})){let u=typeof e.baseline=="object"&&e.baseline!==null?e.baseline[s]:void 0;t[s]=(r=u!=null?u:v[0])!=null?r:""}return t}function pe(e={}){return[O.http.all("*/v1/*",async({request:t})=>{let n=t.method==="GET"||t.method==="HEAD"?null:await t.text(),i=await w(e,t.method,t.url,n);if(i)return i.json===void 0?new O.HttpResponse(null,{status:i.status}):O.HttpResponse.json(i.json,{status:i.status})})]}async function fe(e,t={}){var i,r,s,v,u;let n={overrides:(i=t.variants)!=null?i:{},layout:(r=t.layout)!=null?r:null,slots:(s=t.slots)!=null?s:null,persona:(v=t.persona)!=null?v:null,confidence:(u=t.confidence)!=null?u:1};return await e.addInitScript(a=>{let p=window;if(p.__sentient_overrides=a.overrides,a.layout&&(p.__sentient_layout_override=a.layout),a.slots&&(p.__sentient_slot_overrides=a.slots),a.persona){p.__sentient_persona_override={persona:a.persona,confidence:a.confidence};try{let m=a.confidence<.3?"low":a.confidence<.7?"medium":"high";document.documentElement.setAttribute("data-sentient-persona",a.persona),document.documentElement.setAttribute("data-sentient-confidence",m)}catch(m){}}},n),await e.route("**/v1/**",async a=>{var y;let p=a.request(),m=await w(t,p.method(),p.url(),p.postData());if(!m)return a.continue();await a.fulfill({status:m.status,contentType:"application/json",body:JSON.stringify((y=m.json)!=null?y:{})})}),{events:()=>D()}}function ve(e,t={}){var u,a,p,m,y;let n=(u=t.variants)!=null?u:{},i=(a=t.layout)!=null?a:null,r=(p=t.slots)!=null?p:null,s=(m=t.persona)!=null?m:null,v=(y=t.confidence)!=null?y:1;e.on("window:before:load",o=>{var c,l;if(o.__sentient_overrides=n,i&&(o.__sentient_layout_override=i),r&&(o.__sentient_slot_overrides=r),s){o.__sentient_persona_override={persona:s,confidence:v};try{let d=o.document;(c=d==null?void 0:d.documentElement)==null||c.setAttribute("data-sentient-persona",s),(l=d==null?void 0:d.documentElement)==null||l.setAttribute("data-sentient-confidence",E(v))}catch(d){}}}),e.intercept("**/v1/**",async o=>{var l;let c=await w(t,o.method,o.url,o.body!=null?JSON.stringify(o.body):null);c&&o.reply({statusCode:c.status,body:(l=c.json)!=null?l:""})})}var ye=require("react/jsx-runtime");function Me(e,t={},n){return M(t),(0,me.render)((0,ye.jsx)(de,{apiKey:"pk_test",context:"saas",consent:!1,children:e}),n)}function Be(){var t;let e=globalThis;(t=e.afterEach)==null||t.call(e,()=>B())}0&&(module.exports={applyScenario,clearSentientEvents,getSentientEvents,hasFiredGoal,mockSentient,mockSentientCypress,renderWithSentient,resetScenario,resolveScenario,scenarioToHandlers,setupSentientTests});
|
|
3
3
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/testing/index.tsx","../src/provider.tsx","../src/weights-store.ts","../src/preview-mode.ts","../src/devtools-config.ts","../src/devtools-registry.ts","../src/testing/scenario.ts","../src/testing/handlers.ts","../src/testing/events.ts","../src/testing/resolve.ts","../src/testing/playwright.ts","../src/testing/cypress.ts"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { render, type RenderOptions, type RenderResult } from '@testing-library/react';\nimport { AdaptiveProvider } from '../provider.js';\nimport { applyScenario, resetScenario, type SentientScenario } from './scenario.js';\n\nexport type { SentientScenario };\nexport { applyScenario, resetScenario };\nexport { scenarioToHandlers } from './handlers.js';\nexport { resolveScenario, type ResolvedResponse } from './resolve.js';\nexport { getSentientEvents, clearSentientEvents, hasFiredGoal, type CapturedEvent } from './events.js';\nexport type { ScenarioWeight, ScenarioApiOverride } from './scenario.js';\nexport { mockSentient } from './playwright.js';\nexport { mockSentientCypress } from './cypress.js';\n\n/**\n * Render `ui` under a SentientUI provider configured for tests: consent is off,\n * so the SDK never initialises a client and every <Adaptive> renders its control\n * variant with zero network. A scenario forces specific variants/layout.\n */\nexport function renderWithSentient(\n ui: ReactElement,\n scenario: SentientScenario = {},\n options?: RenderOptions,\n): RenderResult {\n applyScenario(scenario);\n return render(\n <AdaptiveProvider apiKey=\"pk_test\" context=\"saas\" consent={false}>\n {ui}\n </AdaptiveProvider>,\n options,\n );\n}\n\n/** Call in a test setup file to reset forced state after each test. */\nexport function setupSentientTests(): void {\n const g = globalThis as unknown as { afterEach?: (fn: () => void) => void };\n g.afterEach?.(() => resetScenario());\n}\n","'use client';\n\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport {\n detectDeviceClass,\n detectTrafficSource,\n init,\n type SentientClient,\n type SentientConfig,\n type SlotResult,\n} from '@sentientui/core';\nimport { update as updateWeightsStore, type ComponentWeights } from './weights-store.js';\nimport { getPreviewMode, subscribePreview, createPreviewClient } from './preview-mode.js';\nimport { subscribeOverridesChanged } from './override-events.js';\nimport { publishDevtoolsConfig } from './devtools-config.js';\nimport { registerSections } from './devtools-registry.js';\n\n/**\n * Mirrors the segment derivation inside core `init()` so the cache key used\n * by `useAssignment` always matches the key `assign()` writes under. Before\n * this, the context defaulted to 'desktop:direct' while core used the\n * detected segment — a systematic cache miss for every integration that\n * didn't pass `sessionSegment` explicitly.\n */\nfunction deriveDefaultSegment(): string {\n if (typeof window === 'undefined') return 'desktop:direct';\n try {\n const device = detectDeviceClass(navigator.userAgent ?? '');\n const source = detectTrafficSource(document.referrer ?? '', window.location.origin);\n return `${device}:${source}`;\n } catch {\n return 'desktop:direct';\n }\n}\n\nconst DEFAULT_API_BASE_URL = 'https://api.sentient-ui.com/v1';\n\n/** How to render adaptive slots during SSR when assignments are not preloaded. */\nexport type SsrFallback = 'first' | 'none';\n\ntype AdaptiveContextValue = {\n client: SentientClient | null;\n // The publishable API key (pk_…). Historically named `projectId` because the\n // API uses it as the project identifier on the wire, but it is the API key,\n // not the project UUID. Field renamed for clarity.\n apiKey: string;\n initialAssignments: Record<string, string>;\n sessionSegment: string;\n ssrFallback: SsrFallback;\n onAssignment: ((componentId: string, variantId: string) => void) | undefined;\n initialLayoutOrder: string[] | null;\n initialSlots: Record<string, SlotResult>;\n initialPersona: { persona: string; confidence: number } | null;\n apiBaseUrl: string;\n};\n\nconst AdaptiveContext = createContext<AdaptiveContextValue>({\n client: null,\n apiKey: '',\n initialAssignments: {},\n sessionSegment: 'desktop:direct',\n ssrFallback: 'first',\n onAssignment: undefined,\n initialLayoutOrder: null,\n initialSlots: {},\n initialPersona: null,\n apiBaseUrl: DEFAULT_API_BASE_URL,\n});\n\nexport type AdaptiveProviderProps = {\n apiKey: string;\n context: SentientConfig['context'];\n debug?: boolean;\n /**\n * SSR-preloaded assignments from `preloadAssignments()` / `loadAdaptiveAssignments()`.\n * Passed through to `useAssignment` as synchronous initial state so crawlers and\n * the first paint see real content (recommended for SEO).\n */\n initialAssignments?: Record<string, string>;\n /**\n * Bandit segment from SSR (`device:source`). Keeps cache, assign, and worker\n * weights on one row — must match `loadAdaptiveAssignments` / session upsert.\n */\n sessionSegment?: string;\n /**\n * When no `initialAssignments` exist for a component, `'first'` renders\n * `variantIds[0]` in server HTML (safe default for SEO). Use `'none'` only for\n * decorative slots marked `clientOnly`.\n * @default 'first'\n */\n ssrFallback?: SsrFallback;\n /**\n * Consent gate. When `false` the SDK is not initialised and no events are\n * sent. Flip to `true` (e.g. after the user accepts the cookie banner) to\n * initialise and begin tracking.\n */\n consent?: boolean;\n /**\n * Behavior before consent is granted. Pass `'statistical_winner'` to serve the\n * best-performing variant via `GET /v1/winner` with zero tracking while the\n * consent banner is showing. Requires `consent: false`.\n * @see SentientConfig.preConsentBehavior\n */\n preConsentBehavior?: 'statistical_winner' | 'control';\n /**\n * Honor the browser's Do Not Track signal. Defaults to `true`: when DNT is\n * enabled the SDK sets no cookies and sends no tracking data (overriding\n * `consent: true`). Set `false` to make your own consent gate authoritative.\n * @see SentientConfig.respectDoNotTrack\n */\n respectDoNotTrack?: boolean;\n /**\n * Called once per component the first time a variant is resolved for that\n * component in this session. Use to forward assignments to your own analytics\n * (Mixpanel, PostHog, Segment, etc.) without having to wrap `useAssignment`.\n */\n onAssignment?: (componentId: string, variantId: string) => void;\n /**\n * SSR-preloaded section order from `loadAdaptiveDecision()`.\n * Pass the `layoutOrder` field from `DecideResult`. When set,\n * `useLayoutOrder()` returns this on first render so there is no layout shift.\n */\n initialLayoutOrder?: string[] | null;\n /**\n * SSR-preloaded slot results from `loadAdaptiveDecision()` (the `slots`\n * field of its result). Guarantees `useAdaptiveTokens`/`AdaptiveGroup`\n * render the decided arm in server HTML — zero flicker, hydration-safe.\n */\n initialSlots?: Record<string, SlotResult>;\n /**\n * Persona decided during SSR (`persona` + `confidence` fields of\n * `loadAdaptiveDecision()`'s result). Adopted by the core client;\n * rendered into html attributes only by `SentientPersonaScript`.\n */\n initialPersona?: { persona: string; confidence: number };\n /**\n * Base URL of the Sentient API (no trailing slash). Read by the devtools\n * panel for /v1/explain and by future client helpers. Defaults to the\n * hosted API.\n */\n apiBaseUrl?: string;\n /**\n * Session ID generated during SSR (the `sessionId` field returned by\n * `loadAdaptiveAssignments` / `loadAdaptiveDecision`). When provided and no\n * existing session cookie or localStorage entry is found, the client adopts\n * this ID so events and goals are attributed to the same session the server\n * used for variant assignment.\n */\n ssrSessionId?: string;\n /**\n * ISO 3166-1 alpha-2 country code. Pass the value of the `CF-IPCountry`\n * header from your Next.js server component to populate country on landing\n * sessions without client-side geo lookup.\n */\n country?: string;\n /**\n * Keyless local mode. 'auto' (default) simulates decisions on-device in\n * development builds when no valid API key is configured; `true` forces the\n * local engine; `false` restores the silent keyless no-op.\n * @see SentientConfig.localMode\n */\n localMode?: 'auto' | boolean;\n /**\n * Enable DOM graph scanning + page-structure sync. When `true`, the provider\n * dynamically loads `@sentientui/core/graph` and uses its graph-capable\n * `init()` for the single client, so the SDK scans your page structure and\n * syncs it to power the dashboard graph page. Left off (default), the lean\n * bundle is used and the graph entry is never loaded.\n */\n enableGraph?: boolean;\n children: ReactNode;\n};\n\n/**\n * Initialises the Sentient core SDK in a useEffect (SSR-safe) and exposes the\n * client via React context. Re-initialises when `consent` changes.\n */\nexport function AdaptiveProvider(props: AdaptiveProviderProps): JSX.Element {\n const [client, setClient] = useState<SentientClient | null>(null);\n // Derived once per mount: identical to what core init() computes, so cache\n // reads (context segment) and cache writes (core segment) always agree.\n const [sessionSegment] = useState(() => props.sessionSegment ?? deriveDefaultSegment());\n // Devtools preview: when on, expose an event-suppressing client so previewing\n // variants/personas writes nothing. Off by default (inert in production).\n const [previewOn, setPreviewOn] = useState(getPreviewMode());\n useEffect(() => subscribePreview(() => setPreviewOn(getPreviewMode())), []);\n\n useEffect(() => {\n // When consent is explicitly false with no preConsentBehavior, tear down any existing client.\n if (props.consent === false && !props.preConsentBehavior) {\n setClient((prev: SentientClient | null) => {\n prev?.destroy();\n return null;\n });\n return;\n }\n\n const config = {\n apiKey: props.apiKey,\n context: props.context,\n debug: props.debug,\n initialAssignments: props.initialAssignments,\n sessionSegment,\n consent: props.consent,\n preConsentBehavior: props.preConsentBehavior,\n respectDoNotTrack: props.respectDoNotTrack,\n ssrSessionId: props.ssrSessionId,\n country: props.country,\n localMode: props.localMode,\n initialSlots: props.initialSlots,\n initialPersona: props.initialPersona,\n ingestUrl: props.apiBaseUrl ? `${props.apiBaseUrl.replace(/\\/$/, '')}/events` : undefined,\n };\n\n // Track the client created by this effect run so cleanup destroys exactly\n // the right one, and so a late-resolving dynamic import can bail if the\n // effect was already torn down (unmount / consent change).\n let cancelled = false;\n let created: SentientClient | null = null;\n\n if (props.enableGraph) {\n // Load the graph entry only when asked — keeps the DOM scanner out of the\n // lean bundle. The provider still creates ONE client (graph-capable).\n void import('@sentientui/core/graph').then(({ init: initGraph }) => {\n if (cancelled) return;\n created = initGraph({ ...config, graph: true });\n setClient(created);\n });\n } else {\n created = init(config);\n setClient(created);\n }\n\n return () => {\n cancelled = true;\n created?.destroy();\n };\n // Re-init when consent changes. Other props (incl. enableGraph) are\n // intentionally stable for a session.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.consent]);\n\n // Poll /v1/weights every 60 s so long-lived sessions see updated bandit weights\n // without a page reload. useAssignment subscribers react via weights-store.\n useEffect(() => {\n if (!client) return;\n let cancelled = false;\n const poll = async (): Promise<void> => {\n if (cancelled) return;\n let entries;\n try {\n entries = await client.fetchWeights();\n } catch {\n // Network/transient error: skip this cycle and retry on the next\n // interval. Swallowed deliberately so a failed poll never surfaces as\n // an unhandled rejection.\n return;\n }\n if (cancelled) return;\n for (const entry of entries) {\n const weights: ComponentWeights = {\n componentId: entry.componentId,\n updatedAt: entry.updatedAt,\n variants: entry.variants.map((v) => ({\n variantId: v.variantId,\n pulls: v.pulls,\n avgReward: v.avgReward ?? 0,\n })),\n };\n updateWeightsStore(entry.componentId, weights);\n }\n };\n void poll();\n const timerId = setInterval(() => void poll(), 60_000);\n return () => {\n cancelled = true;\n clearInterval(timerId);\n };\n }, [client]);\n\n const ssrFallback = props.ssrFallback ?? 'first';\n const apiBaseUrl = props.apiBaseUrl ?? DEFAULT_API_BASE_URL;\n\n // Publish devtools config through window: the /devtools entry is a separate\n // bundle and cannot read this provider's context instance. Dev-only.\n useEffect(() => {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return;\n publishDevtoolsConfig({\n apiKey: props.apiKey,\n apiBaseUrl,\n isLocal: client?.isLocal === true,\n });\n }, [client, props.apiKey, apiBaseUrl]);\n\n // Sections registry for devtools /v1/explain + local simulation.\n useEffect(() => {\n if (props.initialLayoutOrder && props.initialLayoutOrder.length > 0) {\n registerSections(props.initialLayoutOrder);\n }\n }, [props.initialLayoutOrder]);\n\n // The client exposed to consumers — wrapped to suppress events while previewing.\n const exposedClient = useMemo(\n () => (client && previewOn ? createPreviewClient(client) : client),\n [client, previewOn],\n );\n\n // Memoized so unrelated parent re-renders don't cascade through every\n // useSentient / useAssignment consumer via a fresh context object.\n const value = useMemo<AdaptiveContextValue>(\n () => ({\n client: exposedClient,\n apiKey: props.apiKey,\n initialAssignments: props.initialAssignments ?? {},\n sessionSegment,\n ssrFallback,\n onAssignment: props.onAssignment,\n initialLayoutOrder: props.initialLayoutOrder ?? null,\n initialSlots: props.initialSlots ?? {},\n initialPersona: props.initialPersona ?? null,\n apiBaseUrl,\n }),\n [\n exposedClient,\n props.apiKey,\n props.initialAssignments,\n sessionSegment,\n ssrFallback,\n props.onAssignment,\n props.initialLayoutOrder,\n props.initialSlots,\n props.initialPersona,\n apiBaseUrl,\n ],\n );\n\n return (\n <AdaptiveContext.Provider value={value}>\n {props.children}\n </AdaptiveContext.Provider>\n );\n}\n\n/**\n * Returns the SentientClient, or null until the provider has finished\n * initialising on the client.\n */\nexport function useSentient(): SentientClient | null {\n return useContext(AdaptiveContext).client;\n}\n\n/** Internal: publishable API key carried alongside the client. */\nexport function useAdaptiveApiKey(): string {\n return useContext(AdaptiveContext).apiKey;\n}\n\n/**\n * @deprecated Renamed to `useAdaptiveApiKey`. Kept as an alias so external\n * imports from earlier versions of this package keep working. Will be removed\n * in 1.0.0.\n */\nlet warnedProjectIdAlias = false;\nexport function useAdaptiveProjectId(): string {\n if (\n !warnedProjectIdAlias &&\n typeof process !== 'undefined' &&\n process.env?.NODE_ENV !== 'production'\n ) {\n warnedProjectIdAlias = true;\n console.warn(\n '[@sentientui/react] useAdaptiveProjectId is deprecated; use useAdaptiveApiKey. Will be removed in 1.0.0.',\n );\n }\n return useAdaptiveApiKey();\n}\n\n/** Internal: SSR-preloaded assignments for hydration-safe first render. */\nexport function useInitialAssignments(): Record<string, string> {\n return useContext(AdaptiveContext).initialAssignments;\n}\n\n/** Internal: bandit segment aligned with SSR session upsert. */\nexport function useSessionSegment(): string {\n return useContext(AdaptiveContext).sessionSegment;\n}\n\n/** Internal: SSR fallback strategy when a slot has no preloaded assignment. */\nexport function useSsrFallback(): SsrFallback {\n return useContext(AdaptiveContext).ssrFallback;\n}\n\n/** Internal: forwarding hook for consumer analytics integration. */\nexport function useOnAssignment(): ((componentId: string, variantId: string) => void) | undefined {\n return useContext(AdaptiveContext).onAssignment;\n}\n\n/**\n * Returns the persona-specific section order from SSR, or null when no\n * sections were declared on AdaptiveRoot or reliability is below threshold.\n * Devtools/testing can force it via `window.__sentient_layout_override`;\n * consumers re-render when the devtools notifies an override change.\n */\nexport function useLayoutOrder(): string[] | null {\n const contextOrder = useContext(AdaptiveContext).initialLayoutOrder;\n const override = useSyncExternalStore(\n subscribeOverridesChanged,\n () =>\n typeof window === 'undefined'\n ? null\n : ((window as unknown as { __sentient_layout_override?: string[] })\n .__sentient_layout_override ?? null),\n () => null,\n );\n return override ?? contextOrder;\n}\n\n/** Internal: SSR-preloaded slot results for hydration-safe first render. */\nexport function useInitialSlots(): Record<string, SlotResult> {\n return useContext(AdaptiveContext).initialSlots;\n}\n\n/** Internal: SSR-decided persona carried alongside the client. */\nexport function useInitialPersona(): { persona: string; confidence: number } | null {\n return useContext(AdaptiveContext).initialPersona;\n}\n\n/** Internal: configured API base URL (devtools fetches /v1/explain against this, never a relative URL). */\nexport function useAdaptiveApiBaseUrl(): string {\n return useContext(AdaptiveContext).apiBaseUrl;\n}\n","/** Per-component weights store with isolated subscriptions. */\n\nexport type VariantWeight = {\n variantId: string;\n pulls: number;\n avgReward: number;\n};\n\nexport type ComponentWeights = {\n componentId: string;\n variants: VariantWeight[];\n updatedAt: number;\n};\n\ntype Listener = (weights: ComponentWeights) => void;\n\nconst store = new Map<string, ComponentWeights>();\nconst listeners = new Map<string, Set<Listener>>();\n\n/**\n * Subscribes a listener to a single component. Returns an unsubscribe function.\n * Updates to other components never trigger this listener.\n */\nexport function subscribe(componentId: string, cb: Listener): () => void {\n let set = listeners.get(componentId);\n if (!set) {\n set = new Set();\n listeners.set(componentId, set);\n }\n set.add(cb);\n return () => {\n set!.delete(cb);\n if (set!.size === 0) listeners.delete(componentId);\n };\n}\n\n/**\n * Replaces the weights for a component and notifies only that component's\n * subscribers.\n */\nexport function update(componentId: string, weights: ComponentWeights): void {\n store.set(componentId, weights);\n const set = listeners.get(componentId);\n if (!set) return;\n for (const cb of set) {\n try {\n cb(weights);\n } catch {\n /* never throw to other listeners */\n }\n }\n}\n\n/**\n * Returns the latest known weights for a component, or null if none seen.\n */\nexport function getWeights(componentId: string): ComponentWeights | null {\n return store.get(componentId) ?? null;\n}\n\n/** Test-only: wipe the entire store. */\nexport function _resetWeightsStore(): void {\n store.clear();\n listeners.clear();\n}\n","import type { SentientClient } from '@sentientui/core';\n\ntype PreviewState = { on: boolean; listeners: Set<() => void> };\nconst ssrFallback: PreviewState = { on: false, listeners: new Set() };\n\n// Window-backed: the /devtools entry (a separate bundle) toggles preview mode\n// and the provider (main bundle) must observe it.\nfunction state(): PreviewState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_preview?: PreviewState };\n if (!w.__sentient_preview) w.__sentient_preview = { on: false, listeners: new Set() };\n return w.__sentient_preview;\n}\n\nexport function setPreviewMode(on: boolean): void {\n const s = state();\n if (s.on === on) return;\n s.on = on;\n for (const fn of s.listeners) fn();\n}\n\nexport function getPreviewMode(): boolean {\n return state().on;\n}\n\nexport function subscribePreview(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/**\n * Wraps a client so it writes nothing: reads pass through, all emitters no-op.\n * Used while previewing variants/personas so no `variant_assigned`, goal, or\n * session events are sent.\n */\nexport function createPreviewClient(inner: SentientClient): SentientClient {\n return {\n isLocal: inner.isLocal,\n track: () => undefined,\n goal: () => undefined,\n componentGoal: () => undefined,\n identify: () => undefined,\n fetchWeights: () => Promise.resolve([]),\n getAssignment: (componentId, segment) => inner.getAssignment(componentId, segment),\n assign: (componentId, variantIds, agentData, agentDataByVariant) =>\n inner.assign(componentId, variantIds, agentData, agentDataByVariant),\n // Reads pass through; decide is a write (slot decisions persist server-side)\n // so preview mode never issues it.\n decide: () => Promise.resolve(null),\n getSlotResult: (slotId) => inner.getSlotResult(slotId),\n getPersona: () => inner.getPersona(),\n getGraph: () => inner.getGraph(),\n destroy: () => inner.destroy(),\n };\n}\n","/** Provider → devtools config handoff. Window-backed: the /devtools entry is a\n * separate bundle and cannot share the provider's React context instance. */\nexport type DevtoolsConfig = {\n apiKey: string;\n apiBaseUrl: string;\n isLocal: boolean;\n};\n\ntype ConfigWindow = Window & { __sentient_devtools_config?: DevtoolsConfig };\n\nexport function publishDevtoolsConfig(config: DevtoolsConfig): void {\n if (typeof window === 'undefined') return;\n (window as ConfigWindow).__sentient_devtools_config = config;\n}\n\nexport function readDevtoolsConfig(): DevtoolsConfig | null {\n if (typeof window === 'undefined') return null;\n return (window as ConfigWindow).__sentient_devtools_config ?? null;\n}\n","export type RegisteredComponent = { id: string; variantIds: string[]; goal?: string };\nexport type RegisteredSlot = {\n id: string;\n arms?: string[];\n dims?: Record<string, readonly string[]>;\n};\n\ntype RegistryState = {\n components: Map<string, RegisteredComponent>;\n slots: Map<string, RegisteredSlot>;\n sections: string[];\n listeners: Set<() => void>;\n /** Bumped on every mutation so `useSyncExternalStore` can read a stable, comparable snapshot. */\n version: number;\n};\n\n// Shared through a window global: the main entry and the /devtools entry are\n// separate bundles, each with its own copy of this module — module-local\n// state would give the devtools an always-empty registry in published apps.\nconst ssrFallback: RegistryState = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n version: 0,\n};\n\nfunction state(): RegistryState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_registry?: RegistryState };\n if (!w.__sentient_registry) {\n w.__sentient_registry = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n version: 0,\n };\n }\n return w.__sentient_registry;\n}\n\nfunction emit(): void {\n // Bump BEFORE notifying so a useSyncExternalStore consumer re-reading its\n // snapshot inside the notification sees the new value and re-renders.\n state().version += 1;\n for (const fn of state().listeners) fn();\n}\n\n/** Register (or re-register) a component. Returns an unregister function. */\nexport function registerComponent(c: RegisteredComponent): () => void {\n state().components.set(c.id, c);\n emit();\n return () => {\n state().components.delete(c.id);\n emit();\n };\n}\n\n/** Register (or re-register) a slot declaration. Returns an unregister function. */\nexport function registerSlot(s: RegisteredSlot): () => void {\n state().slots.set(s.id, s);\n emit();\n return () => {\n state().slots.delete(s.id);\n emit();\n };\n}\n\n/** Register the page's declared section ids (from AdaptiveRoot/provider). */\nexport function registerSections(sections: string[]): void {\n state().sections = [...sections];\n emit();\n}\n\nexport function getRegistered(): RegisteredComponent[] {\n return [...state().components.values()];\n}\n\nexport function getRegisteredSlots(): RegisteredSlot[] {\n return [...state().slots.values()];\n}\n\nexport function getRegisteredSections(): string[] {\n return [...state().sections];\n}\n\nexport function subscribeRegistry(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/** Monotonic snapshot for `useSyncExternalStore` — changes on every registry mutation. */\nexport function getRegistryVersion(): number {\n return state().version;\n}\n","export type ScenarioWeight = { variantId: string; pulls: number; avgReward: number };\nexport type ScenarioApiOverride =\n | 'error'\n | number\n | { status?: number; body?: unknown; delayMs?: number };\n\nexport type SentientScenario = {\n variants?: Record<string, string>;\n layout?: string[];\n /** Forced persona (canonical PersonaKey). Also sets the persona html attributes. */\n persona?: string;\n /** Persona confidence 0–1; buckets to low/medium/high for the html attribute. Default 1. */\n confidence?: number;\n /** Forced slot results: slot id → arm id (arms slots) or per-dim values (token slots). */\n slots?: Record<string, string | Record<string, string>>;\n weights?: Record<string, ScenarioWeight[]>;\n api?: Record<string, ScenarioApiOverride>;\n};\n\ntype ScenarioWindow = {\n __sentient_overrides?: Record<string, string>;\n __sentient_layout_override?: string[];\n __sentient_slot_overrides?: Record<string, string | Record<string, string>>;\n __sentient_persona_override?: { persona: string; confidence?: number };\n};\n\n/**\n * Confidence → band. Cutoffs pinned to @sentientui/policy `confidenceBand`\n * (<0.3 low, <0.7 medium, else high). Duplicated (not imported) because the\n * Playwright init function is serialized into the page and cannot close\n * over imports — both copies are pinned by tests.\n */\nexport function confidenceBandOf(c: number): 'low' | 'medium' | 'high' {\n return c < 0.3 ? 'low' : c < 0.7 ? 'medium' : 'high';\n}\n\n/** Apply a scenario by setting the client-forcing globals the SDK reads. */\nexport function applyScenario(scenario: SentientScenario = {}): void {\n const w = window as unknown as ScenarioWindow;\n w.__sentient_overrides = { ...(scenario.variants ?? {}) };\n if (scenario.layout) w.__sentient_layout_override = scenario.layout;\n else delete w.__sentient_layout_override;\n if (scenario.slots) w.__sentient_slot_overrides = { ...scenario.slots };\n else delete w.__sentient_slot_overrides;\n if (scenario.persona) {\n w.__sentient_persona_override = {\n persona: scenario.persona,\n confidence: scenario.confidence ?? 1,\n };\n try {\n const d = document.documentElement;\n d.setAttribute('data-sentient-persona', scenario.persona);\n d.setAttribute('data-sentient-confidence', confidenceBandOf(scenario.confidence ?? 1));\n } catch {\n /* no DOM (node env) — the override globals still apply */\n }\n } else {\n delete w.__sentient_persona_override;\n }\n}\n\n/** Clear all forced state. */\nexport function resetScenario(): void {\n const w = window as unknown as ScenarioWindow;\n delete w.__sentient_overrides;\n delete w.__sentient_layout_override;\n delete w.__sentient_slot_overrides;\n delete w.__sentient_persona_override;\n try {\n document.documentElement.removeAttribute('data-sentient-persona');\n document.documentElement.removeAttribute('data-sentient-confidence');\n } catch {\n /* no DOM */\n }\n}\n","import { http, HttpResponse } from 'msw';\nimport type { RequestHandler } from 'msw';\nimport { resolveScenario } from './resolve.js';\nimport type { SentientScenario } from './scenario.js';\n\n/** Turn a scenario into MSW handlers stubbing every SDK endpoint + capturing events. */\nexport function scenarioToHandlers(scenario: SentientScenario = {}): RequestHandler[] {\n return [\n http.all('*/v1/*', async ({ request }) => {\n const bodyText =\n request.method === 'GET' || request.method === 'HEAD' ? null : await request.text();\n const r = await resolveScenario(scenario, request.method, request.url, bodyText);\n if (!r) return undefined; // not a stubbed route — let MSW handle passthrough\n if (r.json === undefined) return new HttpResponse(null, { status: r.status });\n return HttpResponse.json(r.json as object, { status: r.status });\n }),\n ];\n}\n","export type CapturedEvent = {\n eventType: string;\n goalType?: string;\n componentId?: string;\n variantId?: string;\n [k: string]: unknown;\n};\n\nconst captured: CapturedEvent[] = [];\n\nexport function recordEvent(e: CapturedEvent): void {\n captured.push(e);\n}\n\nexport function getSentientEvents(): CapturedEvent[] {\n return [...captured];\n}\n\nexport function clearSentientEvents(): void {\n captured.length = 0;\n}\n\n/** True if any captured event is a goal (component goal_achieved or named goal) with this name. */\nexport function hasFiredGoal(events: CapturedEvent[], goalName: string): boolean {\n return events.some(\n (e) => (e.eventType === 'goal_achieved' || e.eventType === 'goal') && e.goalType === goalName,\n );\n}\n","import { recordEvent, type CapturedEvent } from './events.js';\nimport { confidenceBandOf, type SentientScenario, type ScenarioApiOverride } from './scenario.js';\n\n/** A framework-agnostic resolved response. `json` undefined ⇒ empty body. */\nexport type ResolvedResponse = { status: number; json?: unknown };\n\nfunction pathOf(url: string): string {\n try { return new URL(url).pathname; } catch { return url.split('?')[0] ?? url; }\n}\n\nasync function apiOverride(scenario: SentientScenario, route: string): Promise<ResolvedResponse | null> {\n const o: ScenarioApiOverride | undefined = scenario.api?.[route];\n if (o === undefined) return null;\n if (o === 'error') return { status: 500 };\n if (typeof o === 'number') return { status: o };\n if (o.delayMs) await new Promise((r) => setTimeout(r, o.delayMs));\n return { status: o.status ?? 200, json: o.body ?? {} };\n}\n\n/**\n * Resolve a request against a scenario. Returns a response, or null for routes\n * outside `/v1/*` (let the caller pass through). Shared by the MSW handlers and\n * the Playwright/Cypress adapters so behaviour can't drift.\n */\nexport async function resolveScenario(\n scenario: SentientScenario,\n _method: string,\n url: string,\n bodyText: string | null,\n): Promise<ResolvedResponse | null> {\n const path = pathOf(url);\n if (!path.includes('/v1/')) return null;\n\n const route = '/v1/' + (path.split('/v1/')[1] ?? '');\n const override = await apiOverride(scenario, route);\n if (override) return override;\n\n const body = bodyText ? (JSON.parse(bodyText) as unknown) : {};\n\n if (route === '/v1/sessions') return { status: 204 };\n\n if (route === '/v1/events') {\n for (const e of body as CapturedEvent[]) recordEvent(e);\n return { status: 204 };\n }\n\n if (route === '/v1/goals') {\n recordEvent({ eventType: 'goal', goalType: (body as { name?: string }).name });\n return { status: 204 };\n }\n\n if (route === '/v1/assign') {\n const b = body as { componentId: string; variantIds?: string[] };\n const variantId = scenario.variants?.[b.componentId] ?? b.variantIds?.[0] ?? 'control';\n return { status: 200, json: { variantId, assignmentTtlMs: 60_000 } };\n }\n\n if (route === '/v1/decide') {\n const b = body as {\n sections?: { id: string }[];\n slots?: Array<{\n id: string;\n arms?: string[];\n dims?: Record<string, string[]>;\n baseline?: string | Record<string, string>;\n }>;\n };\n const layoutOrder = scenario.layout ?? (b.sections ?? []).map((s) => s.id);\n const json: Record<string, unknown> = {\n layoutOrder,\n assignments: scenario.variants ?? {},\n persona: scenario.persona ?? 'unknown',\n confidence: scenario.confidence ?? 1,\n };\n // Mirror the real server: the slots key exists ONLY when slots were requested.\n if (b.slots && b.slots.length > 0) {\n const slots: Record<string, unknown> = {};\n for (const decl of b.slots) {\n slots[decl.id] = scenario.slots?.[decl.id] ?? defaultSlotResult(decl);\n }\n json.slots = slots;\n }\n return { status: 200, json };\n }\n\n if (route === '/v1/explain') {\n const b = body as {\n sections?: { id: string }[];\n persona?: string;\n slots?: Array<{\n id: string;\n arms?: string[];\n dims?: Record<string, string[]>;\n baseline?: string | Record<string, string>;\n }>;\n };\n const layoutOrder = scenario.layout ?? (b.sections ?? []).map((s) => s.id);\n const persona = b.persona ?? scenario.persona ?? 'unknown';\n const confidence = scenario.confidence ?? 1;\n const json: Record<string, unknown> = {\n layoutOrder,\n assignments: scenario.variants ?? {},\n persona,\n reasons: [],\n personaAttributes: { persona, confidence: confidenceBandOf(confidence) },\n };\n if (b.slots && b.slots.length > 0) {\n const slots: Record<string, unknown> = {};\n for (const decl of b.slots) {\n slots[decl.id] = scenario.slots?.[decl.id] ?? defaultSlotResult(decl);\n }\n json.slots = slots;\n }\n return { status: 200, json };\n }\n\n if (route === '/v1/weights') {\n const components = Object.entries(scenario.weights ?? {}).map(([componentId, variants]) => ({ componentId, updatedAt: 0, variants }));\n return { status: 200, json: { components } };\n }\n\n return null;\n}\n\n/** Declared baseline of a slot: explicit `baseline`, else first arm / first value per dim. */\nfunction defaultSlotResult(decl: {\n arms?: string[];\n dims?: Record<string, string[]>;\n baseline?: string | Record<string, string>;\n}): string | Record<string, string> {\n if (decl.arms) {\n return typeof decl.baseline === 'string' ? decl.baseline : decl.arms[0] ?? 'baseline';\n }\n const out: Record<string, string> = {};\n for (const [dim, values] of Object.entries(decl.dims ?? {})) {\n const declared =\n typeof decl.baseline === 'object' && decl.baseline !== null ? decl.baseline[dim] : undefined;\n out[dim] = declared ?? values[0] ?? '';\n }\n return out;\n}\n","import { resolveScenario } from './resolve.js';\nimport { getSentientEvents, type CapturedEvent } from './events.js';\nimport type { SentientScenario } from './scenario.js';\n\ntype InitData = {\n overrides: Record<string, string>;\n layout: string[] | null;\n slots: Record<string, string | Record<string, string>> | null;\n persona: string | null;\n confidence: number;\n};\n\ntype PwRoute = {\n request(): { method(): string; url(): string; postData(): string | null };\n fulfill(r: { status: number; contentType?: string; body?: string }): Promise<void>;\n continue(): Promise<void>;\n};\n\n/** Structural subset of Playwright's `Page` — avoids a hard dependency on @playwright/test. */\ntype PwPage = {\n addInitScript(script: (arg: InitData) => void, arg: InitData): Promise<void>;\n route(url: string, handler: (route: PwRoute) => unknown): Promise<void>;\n};\n\n/**\n * Make a Playwright `page` serve a SentientUI scenario: forces\n * variants/layout/slots/persona before load (including the persona html\n * attributes) and stubs every `/v1/*` request from the scenario, capturing\n * posted events. Returns a handle exposing `.events()`.\n */\nexport async function mockSentient(\n page: PwPage,\n scenario: SentientScenario = {},\n): Promise<{ events: () => CapturedEvent[] }> {\n const initData: InitData = {\n overrides: scenario.variants ?? {},\n layout: scenario.layout ?? null,\n slots: scenario.slots ?? null,\n persona: scenario.persona ?? null,\n confidence: scenario.confidence ?? 1,\n };\n await page.addInitScript((data: InitData) => {\n const w = window as unknown as Record<string, unknown>;\n w.__sentient_overrides = data.overrides;\n if (data.layout) w.__sentient_layout_override = data.layout;\n if (data.slots) w.__sentient_slot_overrides = data.slots;\n if (data.persona) {\n w.__sentient_persona_override = { persona: data.persona, confidence: data.confidence };\n try {\n // Inline banding: this function is SERIALIZED into the page context,\n // so it cannot close over imports. Cutoffs pinned to policy\n // confidenceBand (<0.3 low, <0.7 medium, else high).\n const band = data.confidence < 0.3 ? 'low' : data.confidence < 0.7 ? 'medium' : 'high';\n document.documentElement.setAttribute('data-sentient-persona', data.persona);\n document.documentElement.setAttribute('data-sentient-confidence', band);\n } catch {\n /* document not ready — the SDK adopts the override globals instead */\n }\n }\n }, initData);\n\n await page.route('**/v1/**', async (route) => {\n const req = route.request();\n const resolved = await resolveScenario(scenario, req.method(), req.url(), req.postData());\n if (!resolved) return route.continue();\n await route.fulfill({\n status: resolved.status,\n contentType: 'application/json',\n body: JSON.stringify(resolved.json ?? {}),\n });\n });\n\n return { events: () => getSentientEvents() };\n}\n","import { resolveScenario } from './resolve.js';\nimport { confidenceBandOf, type SentientScenario } from './scenario.js';\n\ntype CyReq = {\n method: string;\n url: string;\n body: unknown;\n reply(r: { statusCode: number; body?: unknown }): void;\n};\n\n/** Structural subset of Cypress's `cy` — avoids a hard dependency on cypress. */\ntype Cy = {\n intercept(url: string, handler: (req: CyReq) => void | Promise<void>): unknown;\n on(event: string, cb: (win: Record<string, unknown>) => void): unknown;\n};\n\n/**\n * Make Cypress serve a SentientUI scenario: forces variants/layout/slots/persona\n * on the app window before load (including the persona html attributes) and\n * stubs every `/v1/*` request from the scenario. Call in a `beforeEach` before\n * `cy.visit`.\n *\n * Note: for event assertions in Cypress, alias the intercept (`cy.intercept(...).as('ev')`)\n * and `cy.wait('@ev')` — captured module state does not cross the browser/Node boundary.\n */\nexport function mockSentientCypress(cy: Cy, scenario: SentientScenario = {}): void {\n const overrides = scenario.variants ?? {};\n const layout = scenario.layout ?? null;\n const slots = scenario.slots ?? null;\n const persona = scenario.persona ?? null;\n const confidence = scenario.confidence ?? 1;\n\n cy.on('window:before:load', (win) => {\n win.__sentient_overrides = overrides;\n if (layout) win.__sentient_layout_override = layout;\n if (slots) win.__sentient_slot_overrides = slots;\n if (persona) {\n win.__sentient_persona_override = { persona, confidence };\n try {\n const doc = (win as { document?: Document }).document;\n doc?.documentElement?.setAttribute('data-sentient-persona', persona);\n doc?.documentElement?.setAttribute('data-sentient-confidence', confidenceBandOf(confidence));\n } catch {\n /* document not ready — the SDK adopts the override globals instead */\n }\n }\n });\n\n cy.intercept('**/v1/**', async (req) => {\n const resolved = await resolveScenario(\n scenario,\n req.method,\n req.url,\n req.body != null ? JSON.stringify(req.body) : null,\n );\n if (!resolved) return; // passthrough\n req.reply({ statusCode: resolved.status, body: (resolved.json ?? '') as unknown });\n });\n}\n"],"mappings":"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","names":["testing_exports","__export","applyScenario","clearSentientEvents","getSentientEvents","hasFiredGoal","mockSentient","mockSentientCypress","renderWithSentient","resetScenario","resolveScenario","scenarioToHandlers","setupSentientTests","__toCommonJS","import_react","import_react","import_core","store","listeners","update","componentId","weights","store","set","listeners","cb","e","ssrFallback","state","w","getPreviewMode","state","subscribePreview","fn","listeners","createPreviewClient","inner","componentId","segment","variantIds","agentData","agentDataByVariant","slotId","publishDevtoolsConfig","config","ssrFallback","state","w","emit","fn","registerSections","sections","state","emit","import_jsx_runtime","deriveDefaultSegment","_a","_b","device","source","e","DEFAULT_API_BASE_URL","AdaptiveContext","AdaptiveProvider","props","client","setClient","sessionSegment","previewOn","setPreviewOn","getPreviewMode","subscribePreview","prev","config","cancelled","created","initGraph","__spreadProps","__spreadValues","poll","entries","entry","weights","v","update","timerId","ssrFallback","apiBaseUrl","publishDevtoolsConfig","registerSections","exposedClient","createPreviewClient","value","_c","_d","confidenceBandOf","c","applyScenario","scenario","_a","_b","_c","w","__spreadValues","d","e","resetScenario","import_msw","captured","recordEvent","getSentientEvents","clearSentientEvents","hasFiredGoal","events","goalName","e","pathOf","url","_a","e","apiOverride","scenario","route","_b","_c","o","r","resolveScenario","_method","bodyText","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","_u","path","override","body","recordEvent","b","json","s","slots","decl","defaultSlotResult","layoutOrder","persona","confidence","confidenceBandOf","componentId","variants","out","dim","values","declared","scenarioToHandlers","scenario","request","bodyText","r","resolveScenario","mockSentient","page","scenario","_a","_b","_c","_d","_e","initData","data","w","band","e","route","req","resolved","resolveScenario","getSentientEvents","mockSentientCypress","cy","scenario","_a","_b","_c","_d","_e","overrides","layout","slots","persona","confidence","win","doc","confidenceBandOf","e","req","resolved","resolveScenario","import_jsx_runtime","renderWithSentient","ui","scenario","options","applyScenario","AdaptiveProvider","setupSentientTests","_a","g","resetScenario"]}
|
|
1
|
+
{"version":3,"sources":["../src/testing/index.tsx","../src/provider.tsx","../src/weights-store.ts","../src/preview-mode.ts","../src/devtools-config.ts","../src/devtools-registry.ts","../src/testing/scenario.ts","../src/testing/handlers.ts","../src/testing/events.ts","../src/testing/resolve.ts","../src/testing/playwright.ts","../src/testing/cypress.ts"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { render, type RenderOptions, type RenderResult } from '@testing-library/react';\nimport { AdaptiveProvider } from '../provider.js';\nimport { applyScenario, resetScenario, type SentientScenario } from './scenario.js';\n\nexport type { SentientScenario };\nexport { applyScenario, resetScenario };\nexport { scenarioToHandlers } from './handlers.js';\nexport { resolveScenario, type ResolvedResponse } from './resolve.js';\nexport { getSentientEvents, clearSentientEvents, hasFiredGoal, type CapturedEvent } from './events.js';\nexport type { ScenarioWeight, ScenarioApiOverride } from './scenario.js';\nexport { mockSentient } from './playwright.js';\nexport { mockSentientCypress } from './cypress.js';\n\n/**\n * Render `ui` under a SentientUI provider configured for tests: consent is off,\n * so the SDK never initialises a client and every <Adaptive> renders its control\n * variant with zero network. A scenario forces specific variants/layout.\n */\nexport function renderWithSentient(\n ui: ReactElement,\n scenario: SentientScenario = {},\n options?: RenderOptions,\n): RenderResult {\n applyScenario(scenario);\n return render(\n <AdaptiveProvider apiKey=\"pk_test\" context=\"saas\" consent={false}>\n {ui}\n </AdaptiveProvider>,\n options,\n );\n}\n\n/** Call in a test setup file to reset forced state after each test. */\nexport function setupSentientTests(): void {\n const g = globalThis as unknown as { afterEach?: (fn: () => void) => void };\n g.afterEach?.(() => resetScenario());\n}\n","'use client';\n\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport {\n detectDeviceClass,\n detectTrafficSource,\n init,\n type SentientClient,\n type SentientConfig,\n type SlotResult,\n} from '@sentientui/core';\nimport { update as updateWeightsStore, type ComponentWeights } from './weights-store.js';\nimport { getPreviewMode, subscribePreview, createPreviewClient } from './preview-mode.js';\nimport { subscribeOverridesChanged } from './override-events.js';\nimport { publishDevtoolsConfig } from './devtools-config.js';\nimport { registerSections } from './devtools-registry.js';\n\n/**\n * Mirrors the segment derivation inside core `init()` so the cache key used\n * by `useAssignment` always matches the key `assign()` writes under. Before\n * this, the context defaulted to 'desktop:direct' while core used the\n * detected segment — a systematic cache miss for every integration that\n * didn't pass `sessionSegment` explicitly.\n */\nfunction deriveDefaultSegment(): string {\n if (typeof window === 'undefined') return 'desktop:direct';\n try {\n const device = detectDeviceClass(navigator.userAgent ?? '');\n const source = detectTrafficSource(document.referrer ?? '', window.location.origin);\n return `${device}:${source}`;\n } catch {\n return 'desktop:direct';\n }\n}\n\nconst DEFAULT_API_BASE_URL = 'https://api.sentient-ui.com/v1';\n\n/** How to render adaptive slots during SSR when assignments are not preloaded. */\nexport type SsrFallback = 'first' | 'none';\n\ntype AdaptiveContextValue = {\n client: SentientClient | null;\n // The publishable API key (pk_…). Historically named `projectId` because the\n // API uses it as the project identifier on the wire, but it is the API key,\n // not the project UUID. Field renamed for clarity.\n apiKey: string;\n initialAssignments: Record<string, string>;\n sessionSegment: string;\n ssrFallback: SsrFallback;\n onAssignment: ((componentId: string, variantId: string) => void) | undefined;\n initialLayoutOrder: string[] | null;\n initialSlots: Record<string, SlotResult>;\n initialPersona: { persona: string; confidence: number } | null;\n apiBaseUrl: string;\n};\n\nconst AdaptiveContext = createContext<AdaptiveContextValue>({\n client: null,\n apiKey: '',\n initialAssignments: {},\n sessionSegment: 'desktop:direct',\n ssrFallback: 'first',\n onAssignment: undefined,\n initialLayoutOrder: null,\n initialSlots: {},\n initialPersona: null,\n apiBaseUrl: DEFAULT_API_BASE_URL,\n});\n\nexport type AdaptiveProviderProps = {\n apiKey: string;\n context: SentientConfig['context'];\n debug?: boolean;\n /**\n * SSR-preloaded assignments from `preloadAssignments()` / `loadAdaptiveAssignments()`.\n * Passed through to `useAssignment` as synchronous initial state so crawlers and\n * the first paint see real content (recommended for SEO).\n */\n initialAssignments?: Record<string, string>;\n /**\n * Bandit segment from SSR (`device:source`). Keeps cache, assign, and worker\n * weights on one row — must match `loadAdaptiveAssignments` / session upsert.\n */\n sessionSegment?: string;\n /**\n * When no `initialAssignments` exist for a component, `'first'` renders\n * `variantIds[0]` in server HTML (safe default for SEO). Use `'none'` only for\n * decorative slots marked `clientOnly`.\n * @default 'first'\n */\n ssrFallback?: SsrFallback;\n /**\n * Consent gate. When `false` the SDK is not initialised and no events are\n * sent. Flip to `true` (e.g. after the user accepts the cookie banner) to\n * initialise and begin tracking.\n */\n consent?: boolean;\n /**\n * Behavior before consent is granted. Pass `'statistical_winner'` to serve the\n * best-performing variant via `GET /v1/winner` with zero tracking while the\n * consent banner is showing. Requires `consent: false`.\n * @see SentientConfig.preConsentBehavior\n */\n preConsentBehavior?: 'statistical_winner' | 'control';\n /**\n * Honor the browser's Do Not Track signal. Defaults to `true`: when DNT is\n * enabled the SDK sets no cookies and sends no tracking data (overriding\n * `consent: true`). Set `false` to make your own consent gate authoritative.\n * @see SentientConfig.respectDoNotTrack\n */\n respectDoNotTrack?: boolean;\n /**\n * Called once per component the first time a variant is resolved for that\n * component in this session. Use to forward assignments to your own analytics\n * (Mixpanel, PostHog, Segment, etc.) without having to wrap `useAssignment`.\n */\n onAssignment?: (componentId: string, variantId: string) => void;\n /**\n * SSR-preloaded section order from `loadAdaptiveDecision()`.\n * Pass the `layoutOrder` field from `DecideResult`. When set,\n * `useLayoutOrder()` returns this on first render so there is no layout shift.\n */\n initialLayoutOrder?: string[] | null;\n /**\n * SSR-preloaded slot results from `loadAdaptiveDecision()` (the `slots`\n * field of its result). Guarantees `useAdaptiveTokens`/`AdaptiveGroup`\n * render the decided arm in server HTML — zero flicker, hydration-safe.\n */\n initialSlots?: Record<string, SlotResult>;\n /**\n * Persona decided during SSR (`persona` + `confidence` fields of\n * `loadAdaptiveDecision()`'s result). Adopted by the core client;\n * rendered into html attributes only by `SentientPersonaScript`.\n */\n initialPersona?: { persona: string; confidence: number };\n /**\n * Base URL of the Sentient API (no trailing slash). Read by the devtools\n * panel for /v1/explain and by future client helpers. Defaults to the\n * hosted API.\n */\n apiBaseUrl?: string;\n /**\n * Session ID generated during SSR (the `sessionId` field returned by\n * `loadAdaptiveAssignments` / `loadAdaptiveDecision`). When provided and no\n * existing session cookie or localStorage entry is found, the client adopts\n * this ID so events and goals are attributed to the same session the server\n * used for variant assignment.\n */\n ssrSessionId?: string;\n /**\n * ISO 3166-1 alpha-2 country code. Pass the value of the `CF-IPCountry`\n * header from your Next.js server component to populate country on landing\n * sessions without client-side geo lookup.\n */\n country?: string;\n /**\n * Keyless local mode. 'auto' (default) simulates decisions on-device in\n * development builds when no valid API key is configured; `true` forces the\n * local engine; `false` restores the silent keyless no-op.\n * @see SentientConfig.localMode\n */\n localMode?: 'auto' | boolean;\n /**\n * Enable DOM graph scanning + page-structure sync. When `true`, the provider\n * dynamically loads `@sentientui/core/graph` and uses its graph-capable\n * `init()` for the single client, so the SDK scans your page structure and\n * syncs it to power the dashboard graph page. Left off (default), the lean\n * bundle is used and the graph entry is never loaded.\n */\n enableGraph?: boolean;\n children: ReactNode;\n};\n\n/**\n * Initialises the Sentient core SDK in a useEffect (SSR-safe) and exposes the\n * client via React context. Re-initialises when `consent` changes.\n */\nexport function AdaptiveProvider(props: AdaptiveProviderProps): JSX.Element {\n const [client, setClient] = useState<SentientClient | null>(null);\n // Derived once per mount: identical to what core init() computes, so cache\n // reads (context segment) and cache writes (core segment) always agree.\n const [sessionSegment] = useState(() => props.sessionSegment ?? deriveDefaultSegment());\n // Devtools preview: when on, expose an event-suppressing client so previewing\n // variants/personas writes nothing. Off by default (inert in production).\n const [previewOn, setPreviewOn] = useState(getPreviewMode());\n useEffect(() => subscribePreview(() => setPreviewOn(getPreviewMode())), []);\n\n useEffect(() => {\n // When consent is explicitly false with no preConsentBehavior, tear down any existing client.\n if (props.consent === false && !props.preConsentBehavior) {\n setClient((prev: SentientClient | null) => {\n prev?.destroy();\n return null;\n });\n return;\n }\n\n const config = {\n apiKey: props.apiKey,\n context: props.context,\n debug: props.debug,\n initialAssignments: props.initialAssignments,\n sessionSegment,\n consent: props.consent,\n preConsentBehavior: props.preConsentBehavior,\n respectDoNotTrack: props.respectDoNotTrack,\n ssrSessionId: props.ssrSessionId,\n country: props.country,\n localMode: props.localMode,\n initialSlots: props.initialSlots,\n initialPersona: props.initialPersona,\n ingestUrl: props.apiBaseUrl ? `${props.apiBaseUrl.replace(/\\/$/, '')}/events` : undefined,\n };\n\n // Track the client created by this effect run so cleanup destroys exactly\n // the right one, and so a late-resolving dynamic import can bail if the\n // effect was already torn down (unmount / consent change).\n let cancelled = false;\n let created: SentientClient | null = null;\n\n if (props.enableGraph) {\n // Load the graph entry only when asked — keeps the DOM scanner out of the\n // lean bundle. The provider still creates ONE client (graph-capable).\n void import('@sentientui/core/graph').then(({ init: initGraph }) => {\n if (cancelled) return;\n created = initGraph({ ...config, graph: true });\n setClient(created);\n });\n } else {\n created = init(config);\n setClient(created);\n }\n\n return () => {\n cancelled = true;\n // dispose, not destroy: effect cleanup runs on unmount, StrictMode's\n // dev double-invoke, and consent re-init — the visitor identity must\n // survive all of those. Full destroy() happens only on the explicit\n // consent-revocation branch above.\n created?.dispose();\n };\n // Re-init when consent changes. Other props (incl. enableGraph) are\n // intentionally stable for a session.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props.consent]);\n\n // Poll /v1/weights every 60 s so long-lived sessions see updated bandit weights\n // without a page reload. useAssignment subscribers react via weights-store.\n useEffect(() => {\n if (!client) return;\n let cancelled = false;\n const poll = async (): Promise<void> => {\n if (cancelled) return;\n let entries;\n try {\n entries = await client.fetchWeights();\n } catch {\n // Network/transient error: skip this cycle and retry on the next\n // interval. Swallowed deliberately so a failed poll never surfaces as\n // an unhandled rejection.\n return;\n }\n if (cancelled) return;\n for (const entry of entries) {\n const weights: ComponentWeights = {\n componentId: entry.componentId,\n updatedAt: entry.updatedAt,\n variants: entry.variants.map((v) => ({\n variantId: v.variantId,\n pulls: v.pulls,\n avgReward: v.avgReward ?? 0,\n })),\n };\n updateWeightsStore(entry.componentId, weights);\n }\n };\n void poll();\n const timerId = setInterval(() => void poll(), 60_000);\n return () => {\n cancelled = true;\n clearInterval(timerId);\n };\n }, [client]);\n\n const ssrFallback = props.ssrFallback ?? 'first';\n const apiBaseUrl = props.apiBaseUrl ?? DEFAULT_API_BASE_URL;\n\n // Publish devtools config through window: the /devtools entry is a separate\n // bundle and cannot read this provider's context instance. Dev-only.\n useEffect(() => {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return;\n publishDevtoolsConfig({\n apiKey: props.apiKey,\n apiBaseUrl,\n isLocal: client?.isLocal === true,\n });\n }, [client, props.apiKey, apiBaseUrl]);\n\n // Sections registry for devtools /v1/explain + local simulation.\n useEffect(() => {\n if (props.initialLayoutOrder && props.initialLayoutOrder.length > 0) {\n registerSections(props.initialLayoutOrder);\n }\n }, [props.initialLayoutOrder]);\n\n // The client exposed to consumers — wrapped to suppress events while previewing.\n const exposedClient = useMemo(\n () => (client && previewOn ? createPreviewClient(client) : client),\n [client, previewOn],\n );\n\n // Memoized so unrelated parent re-renders don't cascade through every\n // useSentient / useAssignment consumer via a fresh context object.\n const value = useMemo<AdaptiveContextValue>(\n () => ({\n client: exposedClient,\n apiKey: props.apiKey,\n initialAssignments: props.initialAssignments ?? {},\n sessionSegment,\n ssrFallback,\n onAssignment: props.onAssignment,\n initialLayoutOrder: props.initialLayoutOrder ?? null,\n initialSlots: props.initialSlots ?? {},\n initialPersona: props.initialPersona ?? null,\n apiBaseUrl,\n }),\n [\n exposedClient,\n props.apiKey,\n props.initialAssignments,\n sessionSegment,\n ssrFallback,\n props.onAssignment,\n props.initialLayoutOrder,\n props.initialSlots,\n props.initialPersona,\n apiBaseUrl,\n ],\n );\n\n return (\n <AdaptiveContext.Provider value={value}>\n {props.children}\n </AdaptiveContext.Provider>\n );\n}\n\n/**\n * Returns the SentientClient, or null until the provider has finished\n * initialising on the client.\n */\nexport function useSentient(): SentientClient | null {\n return useContext(AdaptiveContext).client;\n}\n\n/** Internal: publishable API key carried alongside the client. */\nexport function useAdaptiveApiKey(): string {\n return useContext(AdaptiveContext).apiKey;\n}\n\n/**\n * @deprecated Renamed to `useAdaptiveApiKey`. Kept as an alias so external\n * imports from earlier versions of this package keep working. Will be removed\n * in 1.0.0.\n */\nlet warnedProjectIdAlias = false;\nexport function useAdaptiveProjectId(): string {\n if (\n !warnedProjectIdAlias &&\n typeof process !== 'undefined' &&\n process.env?.NODE_ENV !== 'production'\n ) {\n warnedProjectIdAlias = true;\n console.warn(\n '[@sentientui/react] useAdaptiveProjectId is deprecated; use useAdaptiveApiKey. Will be removed in 1.0.0.',\n );\n }\n return useAdaptiveApiKey();\n}\n\n/** Internal: SSR-preloaded assignments for hydration-safe first render. */\nexport function useInitialAssignments(): Record<string, string> {\n return useContext(AdaptiveContext).initialAssignments;\n}\n\n/** Internal: bandit segment aligned with SSR session upsert. */\nexport function useSessionSegment(): string {\n return useContext(AdaptiveContext).sessionSegment;\n}\n\n/** Internal: SSR fallback strategy when a slot has no preloaded assignment. */\nexport function useSsrFallback(): SsrFallback {\n return useContext(AdaptiveContext).ssrFallback;\n}\n\n/** Internal: forwarding hook for consumer analytics integration. */\nexport function useOnAssignment(): ((componentId: string, variantId: string) => void) | undefined {\n return useContext(AdaptiveContext).onAssignment;\n}\n\n/**\n * Returns the persona-specific section order from SSR, or null when no\n * sections were declared on AdaptiveRoot or reliability is below threshold.\n * Devtools/testing can force it via `window.__sentient_layout_override`;\n * consumers re-render when the devtools notifies an override change.\n */\nexport function useLayoutOrder(): string[] | null {\n const contextOrder = useContext(AdaptiveContext).initialLayoutOrder;\n const override = useSyncExternalStore(\n subscribeOverridesChanged,\n () =>\n typeof window === 'undefined'\n ? null\n : ((window as unknown as { __sentient_layout_override?: string[] })\n .__sentient_layout_override ?? null),\n () => null,\n );\n return override ?? contextOrder;\n}\n\n/** Internal: SSR-preloaded slot results for hydration-safe first render. */\nexport function useInitialSlots(): Record<string, SlotResult> {\n return useContext(AdaptiveContext).initialSlots;\n}\n\n/** Internal: SSR-decided persona carried alongside the client. */\nexport function useInitialPersona(): { persona: string; confidence: number } | null {\n return useContext(AdaptiveContext).initialPersona;\n}\n\n/** Internal: configured API base URL (devtools fetches /v1/explain against this, never a relative URL). */\nexport function useAdaptiveApiBaseUrl(): string {\n return useContext(AdaptiveContext).apiBaseUrl;\n}\n","/** Per-component weights store with isolated subscriptions. */\n\nexport type VariantWeight = {\n variantId: string;\n pulls: number;\n avgReward: number;\n};\n\nexport type ComponentWeights = {\n componentId: string;\n variants: VariantWeight[];\n updatedAt: number;\n};\n\ntype Listener = (weights: ComponentWeights) => void;\n\nconst store = new Map<string, ComponentWeights>();\nconst listeners = new Map<string, Set<Listener>>();\n\n/**\n * Subscribes a listener to a single component. Returns an unsubscribe function.\n * Updates to other components never trigger this listener.\n */\nexport function subscribe(componentId: string, cb: Listener): () => void {\n let set = listeners.get(componentId);\n if (!set) {\n set = new Set();\n listeners.set(componentId, set);\n }\n set.add(cb);\n return () => {\n set!.delete(cb);\n if (set!.size === 0) listeners.delete(componentId);\n };\n}\n\n/**\n * Replaces the weights for a component and notifies only that component's\n * subscribers.\n */\nexport function update(componentId: string, weights: ComponentWeights): void {\n store.set(componentId, weights);\n const set = listeners.get(componentId);\n if (!set) return;\n for (const cb of set) {\n try {\n cb(weights);\n } catch {\n /* never throw to other listeners */\n }\n }\n}\n\n/**\n * Returns the latest known weights for a component, or null if none seen.\n */\nexport function getWeights(componentId: string): ComponentWeights | null {\n return store.get(componentId) ?? null;\n}\n\n/** Test-only: wipe the entire store. */\nexport function _resetWeightsStore(): void {\n store.clear();\n listeners.clear();\n}\n","import type { SentientClient } from '@sentientui/core';\n\ntype PreviewState = { on: boolean; listeners: Set<() => void> };\nconst ssrFallback: PreviewState = { on: false, listeners: new Set() };\n\n// Window-backed: the /devtools entry (a separate bundle) toggles preview mode\n// and the provider (main bundle) must observe it.\nfunction state(): PreviewState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_preview?: PreviewState };\n if (!w.__sentient_preview) w.__sentient_preview = { on: false, listeners: new Set() };\n return w.__sentient_preview;\n}\n\nexport function setPreviewMode(on: boolean): void {\n const s = state();\n if (s.on === on) return;\n s.on = on;\n for (const fn of s.listeners) fn();\n}\n\nexport function getPreviewMode(): boolean {\n return state().on;\n}\n\nexport function subscribePreview(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/**\n * Wraps a client so it writes nothing: reads pass through, all emitters no-op.\n * Used while previewing variants/personas so no `variant_assigned`, goal, or\n * session events are sent.\n */\nexport function createPreviewClient(inner: SentientClient): SentientClient {\n return {\n isLocal: inner.isLocal,\n track: () => undefined,\n goal: () => undefined,\n componentGoal: () => undefined,\n identify: () => undefined,\n fetchWeights: () => Promise.resolve([]),\n getAssignment: (componentId, segment) => inner.getAssignment(componentId, segment),\n assign: (componentId, variantIds, agentData, agentDataByVariant) =>\n inner.assign(componentId, variantIds, agentData, agentDataByVariant),\n // Reads pass through; decide is a write (slot decisions persist server-side)\n // so preview mode never issues it.\n decide: () => Promise.resolve(null),\n getSlotResult: (slotId) => inner.getSlotResult(slotId),\n getPersona: () => inner.getPersona(),\n getGraph: () => inner.getGraph(),\n dispose: () => inner.dispose(),\n destroy: () => inner.destroy(),\n };\n}\n","/** Provider → devtools config handoff. Window-backed: the /devtools entry is a\n * separate bundle and cannot share the provider's React context instance. */\nexport type DevtoolsConfig = {\n apiKey: string;\n apiBaseUrl: string;\n isLocal: boolean;\n};\n\ntype ConfigWindow = Window & { __sentient_devtools_config?: DevtoolsConfig };\n\nexport function publishDevtoolsConfig(config: DevtoolsConfig): void {\n if (typeof window === 'undefined') return;\n (window as ConfigWindow).__sentient_devtools_config = config;\n}\n\nexport function readDevtoolsConfig(): DevtoolsConfig | null {\n if (typeof window === 'undefined') return null;\n return (window as ConfigWindow).__sentient_devtools_config ?? null;\n}\n","export type RegisteredComponent = { id: string; variantIds: string[]; goal?: string };\nexport type RegisteredSlot = {\n id: string;\n arms?: string[];\n dims?: Record<string, readonly string[]>;\n};\n\ntype RegistryState = {\n components: Map<string, RegisteredComponent>;\n slots: Map<string, RegisteredSlot>;\n sections: string[];\n listeners: Set<() => void>;\n /** Bumped on every mutation so `useSyncExternalStore` can read a stable, comparable snapshot. */\n version: number;\n};\n\n// Shared through a window global: the main entry and the /devtools entry are\n// separate bundles, each with its own copy of this module — module-local\n// state would give the devtools an always-empty registry in published apps.\nconst ssrFallback: RegistryState = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n version: 0,\n};\n\nfunction state(): RegistryState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_registry?: RegistryState };\n if (!w.__sentient_registry) {\n w.__sentient_registry = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n version: 0,\n };\n }\n return w.__sentient_registry;\n}\n\nfunction emit(): void {\n // Bump BEFORE notifying so a useSyncExternalStore consumer re-reading its\n // snapshot inside the notification sees the new value and re-renders.\n state().version += 1;\n for (const fn of state().listeners) fn();\n}\n\n/** Register (or re-register) a component. Returns an unregister function. */\nexport function registerComponent(c: RegisteredComponent): () => void {\n state().components.set(c.id, c);\n emit();\n return () => {\n state().components.delete(c.id);\n emit();\n };\n}\n\n/** Register (or re-register) a slot declaration. Returns an unregister function. */\nexport function registerSlot(s: RegisteredSlot): () => void {\n state().slots.set(s.id, s);\n emit();\n return () => {\n state().slots.delete(s.id);\n emit();\n };\n}\n\n/** Register the page's declared section ids (from AdaptiveRoot/provider). */\nexport function registerSections(sections: string[]): void {\n state().sections = [...sections];\n emit();\n}\n\nexport function getRegistered(): RegisteredComponent[] {\n return [...state().components.values()];\n}\n\nexport function getRegisteredSlots(): RegisteredSlot[] {\n return [...state().slots.values()];\n}\n\nexport function getRegisteredSections(): string[] {\n return [...state().sections];\n}\n\nexport function subscribeRegistry(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/** Monotonic snapshot for `useSyncExternalStore` — changes on every registry mutation. */\nexport function getRegistryVersion(): number {\n return state().version;\n}\n","export type ScenarioWeight = { variantId: string; pulls: number; avgReward: number };\nexport type ScenarioApiOverride =\n | 'error'\n | number\n | { status?: number; body?: unknown; delayMs?: number };\n\nexport type SentientScenario = {\n variants?: Record<string, string>;\n layout?: string[];\n /** Forced persona (canonical PersonaKey). Also sets the persona html attributes. */\n persona?: string;\n /** Persona confidence 0–1; buckets to low/medium/high for the html attribute. Default 1. */\n confidence?: number;\n /** Forced slot results: slot id → arm id (arms slots) or per-dim values (token slots). */\n slots?: Record<string, string | Record<string, string>>;\n weights?: Record<string, ScenarioWeight[]>;\n api?: Record<string, ScenarioApiOverride>;\n};\n\ntype ScenarioWindow = {\n __sentient_overrides?: Record<string, string>;\n __sentient_layout_override?: string[];\n __sentient_slot_overrides?: Record<string, string | Record<string, string>>;\n __sentient_persona_override?: { persona: string; confidence?: number };\n};\n\n/**\n * Confidence → band. Cutoffs pinned to @sentientui/policy `confidenceBand`\n * (<0.3 low, <0.7 medium, else high). Duplicated (not imported) because the\n * Playwright init function is serialized into the page and cannot close\n * over imports — both copies are pinned by tests.\n */\nexport function confidenceBandOf(c: number): 'low' | 'medium' | 'high' {\n return c < 0.3 ? 'low' : c < 0.7 ? 'medium' : 'high';\n}\n\n/** Apply a scenario by setting the client-forcing globals the SDK reads. */\nexport function applyScenario(scenario: SentientScenario = {}): void {\n const w = window as unknown as ScenarioWindow;\n w.__sentient_overrides = { ...(scenario.variants ?? {}) };\n if (scenario.layout) w.__sentient_layout_override = scenario.layout;\n else delete w.__sentient_layout_override;\n if (scenario.slots) w.__sentient_slot_overrides = { ...scenario.slots };\n else delete w.__sentient_slot_overrides;\n if (scenario.persona) {\n w.__sentient_persona_override = {\n persona: scenario.persona,\n confidence: scenario.confidence ?? 1,\n };\n try {\n const d = document.documentElement;\n d.setAttribute('data-sentient-persona', scenario.persona);\n d.setAttribute('data-sentient-confidence', confidenceBandOf(scenario.confidence ?? 1));\n } catch {\n /* no DOM (node env) — the override globals still apply */\n }\n } else {\n delete w.__sentient_persona_override;\n }\n}\n\n/** Clear all forced state. */\nexport function resetScenario(): void {\n const w = window as unknown as ScenarioWindow;\n delete w.__sentient_overrides;\n delete w.__sentient_layout_override;\n delete w.__sentient_slot_overrides;\n delete w.__sentient_persona_override;\n try {\n document.documentElement.removeAttribute('data-sentient-persona');\n document.documentElement.removeAttribute('data-sentient-confidence');\n } catch {\n /* no DOM */\n }\n}\n","import { http, HttpResponse } from 'msw';\nimport type { RequestHandler } from 'msw';\nimport { resolveScenario } from './resolve.js';\nimport type { SentientScenario } from './scenario.js';\n\n/** Turn a scenario into MSW handlers stubbing every SDK endpoint + capturing events. */\nexport function scenarioToHandlers(scenario: SentientScenario = {}): RequestHandler[] {\n return [\n http.all('*/v1/*', async ({ request }) => {\n const bodyText =\n request.method === 'GET' || request.method === 'HEAD' ? null : await request.text();\n const r = await resolveScenario(scenario, request.method, request.url, bodyText);\n if (!r) return undefined; // not a stubbed route — let MSW handle passthrough\n if (r.json === undefined) return new HttpResponse(null, { status: r.status });\n return HttpResponse.json(r.json as object, { status: r.status });\n }),\n ];\n}\n","export type CapturedEvent = {\n eventType: string;\n goalType?: string;\n componentId?: string;\n variantId?: string;\n [k: string]: unknown;\n};\n\nconst captured: CapturedEvent[] = [];\n\nexport function recordEvent(e: CapturedEvent): void {\n captured.push(e);\n}\n\nexport function getSentientEvents(): CapturedEvent[] {\n return [...captured];\n}\n\nexport function clearSentientEvents(): void {\n captured.length = 0;\n}\n\n/** True if any captured event is a goal (component goal_achieved or named goal) with this name. */\nexport function hasFiredGoal(events: CapturedEvent[], goalName: string): boolean {\n return events.some(\n (e) => (e.eventType === 'goal_achieved' || e.eventType === 'goal') && e.goalType === goalName,\n );\n}\n","import { recordEvent, type CapturedEvent } from './events.js';\nimport { confidenceBandOf, type SentientScenario, type ScenarioApiOverride } from './scenario.js';\n\n/** A framework-agnostic resolved response. `json` undefined ⇒ empty body. */\nexport type ResolvedResponse = { status: number; json?: unknown };\n\nfunction pathOf(url: string): string {\n try { return new URL(url).pathname; } catch { return url.split('?')[0] ?? url; }\n}\n\nasync function apiOverride(scenario: SentientScenario, route: string): Promise<ResolvedResponse | null> {\n const o: ScenarioApiOverride | undefined = scenario.api?.[route];\n if (o === undefined) return null;\n if (o === 'error') return { status: 500 };\n if (typeof o === 'number') return { status: o };\n if (o.delayMs) await new Promise((r) => setTimeout(r, o.delayMs));\n return { status: o.status ?? 200, json: o.body ?? {} };\n}\n\n/**\n * Resolve a request against a scenario. Returns a response, or null for routes\n * outside `/v1/*` (let the caller pass through). Shared by the MSW handlers and\n * the Playwright/Cypress adapters so behaviour can't drift.\n */\nexport async function resolveScenario(\n scenario: SentientScenario,\n _method: string,\n url: string,\n bodyText: string | null,\n): Promise<ResolvedResponse | null> {\n const path = pathOf(url);\n if (!path.includes('/v1/')) return null;\n\n const route = '/v1/' + (path.split('/v1/')[1] ?? '');\n const override = await apiOverride(scenario, route);\n if (override) return override;\n\n const body = bodyText ? (JSON.parse(bodyText) as unknown) : {};\n\n if (route === '/v1/sessions') return { status: 204 };\n\n if (route === '/v1/events') {\n for (const e of body as CapturedEvent[]) recordEvent(e);\n return { status: 204 };\n }\n\n if (route === '/v1/goals') {\n recordEvent({ eventType: 'goal', goalType: (body as { name?: string }).name });\n return { status: 204 };\n }\n\n if (route === '/v1/assign') {\n const b = body as { componentId: string; variantIds?: string[] };\n const variantId = scenario.variants?.[b.componentId] ?? b.variantIds?.[0] ?? 'control';\n return { status: 200, json: { variantId, assignmentTtlMs: 60_000 } };\n }\n\n if (route === '/v1/decide') {\n const b = body as {\n sections?: { id: string }[];\n slots?: Array<{\n id: string;\n arms?: string[];\n dims?: Record<string, string[]>;\n baseline?: string | Record<string, string>;\n }>;\n };\n const layoutOrder = scenario.layout ?? (b.sections ?? []).map((s) => s.id);\n const json: Record<string, unknown> = {\n layoutOrder,\n assignments: scenario.variants ?? {},\n persona: scenario.persona ?? 'unknown',\n confidence: scenario.confidence ?? 1,\n };\n // Mirror the real server: the slots key exists ONLY when slots were requested.\n if (b.slots && b.slots.length > 0) {\n const slots: Record<string, unknown> = {};\n for (const decl of b.slots) {\n slots[decl.id] = scenario.slots?.[decl.id] ?? defaultSlotResult(decl);\n }\n json.slots = slots;\n }\n return { status: 200, json };\n }\n\n if (route === '/v1/explain') {\n const b = body as {\n sections?: { id: string }[];\n persona?: string;\n slots?: Array<{\n id: string;\n arms?: string[];\n dims?: Record<string, string[]>;\n baseline?: string | Record<string, string>;\n }>;\n };\n const layoutOrder = scenario.layout ?? (b.sections ?? []).map((s) => s.id);\n const persona = b.persona ?? scenario.persona ?? 'unknown';\n const confidence = scenario.confidence ?? 1;\n const json: Record<string, unknown> = {\n layoutOrder,\n assignments: scenario.variants ?? {},\n persona,\n reasons: [],\n personaAttributes: { persona, confidence: confidenceBandOf(confidence) },\n };\n if (b.slots && b.slots.length > 0) {\n const slots: Record<string, unknown> = {};\n for (const decl of b.slots) {\n slots[decl.id] = scenario.slots?.[decl.id] ?? defaultSlotResult(decl);\n }\n json.slots = slots;\n }\n return { status: 200, json };\n }\n\n if (route === '/v1/weights') {\n const components = Object.entries(scenario.weights ?? {}).map(([componentId, variants]) => ({ componentId, updatedAt: 0, variants }));\n return { status: 200, json: { components } };\n }\n\n return null;\n}\n\n/** Declared baseline of a slot: explicit `baseline`, else first arm / first value per dim. */\nfunction defaultSlotResult(decl: {\n arms?: string[];\n dims?: Record<string, string[]>;\n baseline?: string | Record<string, string>;\n}): string | Record<string, string> {\n if (decl.arms) {\n return typeof decl.baseline === 'string' ? decl.baseline : decl.arms[0] ?? 'baseline';\n }\n const out: Record<string, string> = {};\n for (const [dim, values] of Object.entries(decl.dims ?? {})) {\n const declared =\n typeof decl.baseline === 'object' && decl.baseline !== null ? decl.baseline[dim] : undefined;\n out[dim] = declared ?? values[0] ?? '';\n }\n return out;\n}\n","import { resolveScenario } from './resolve.js';\nimport { getSentientEvents, type CapturedEvent } from './events.js';\nimport type { SentientScenario } from './scenario.js';\n\ntype InitData = {\n overrides: Record<string, string>;\n layout: string[] | null;\n slots: Record<string, string | Record<string, string>> | null;\n persona: string | null;\n confidence: number;\n};\n\ntype PwRoute = {\n request(): { method(): string; url(): string; postData(): string | null };\n fulfill(r: { status: number; contentType?: string; body?: string }): Promise<void>;\n continue(): Promise<void>;\n};\n\n/** Structural subset of Playwright's `Page` — avoids a hard dependency on @playwright/test. */\ntype PwPage = {\n addInitScript(script: (arg: InitData) => void, arg: InitData): Promise<void>;\n route(url: string, handler: (route: PwRoute) => unknown): Promise<void>;\n};\n\n/**\n * Make a Playwright `page` serve a SentientUI scenario: forces\n * variants/layout/slots/persona before load (including the persona html\n * attributes) and stubs every `/v1/*` request from the scenario, capturing\n * posted events. Returns a handle exposing `.events()`.\n */\nexport async function mockSentient(\n page: PwPage,\n scenario: SentientScenario = {},\n): Promise<{ events: () => CapturedEvent[] }> {\n const initData: InitData = {\n overrides: scenario.variants ?? {},\n layout: scenario.layout ?? null,\n slots: scenario.slots ?? null,\n persona: scenario.persona ?? null,\n confidence: scenario.confidence ?? 1,\n };\n await page.addInitScript((data: InitData) => {\n const w = window as unknown as Record<string, unknown>;\n w.__sentient_overrides = data.overrides;\n if (data.layout) w.__sentient_layout_override = data.layout;\n if (data.slots) w.__sentient_slot_overrides = data.slots;\n if (data.persona) {\n w.__sentient_persona_override = { persona: data.persona, confidence: data.confidence };\n try {\n // Inline banding: this function is SERIALIZED into the page context,\n // so it cannot close over imports. Cutoffs pinned to policy\n // confidenceBand (<0.3 low, <0.7 medium, else high).\n const band = data.confidence < 0.3 ? 'low' : data.confidence < 0.7 ? 'medium' : 'high';\n document.documentElement.setAttribute('data-sentient-persona', data.persona);\n document.documentElement.setAttribute('data-sentient-confidence', band);\n } catch {\n /* document not ready — the SDK adopts the override globals instead */\n }\n }\n }, initData);\n\n await page.route('**/v1/**', async (route) => {\n const req = route.request();\n const resolved = await resolveScenario(scenario, req.method(), req.url(), req.postData());\n if (!resolved) return route.continue();\n await route.fulfill({\n status: resolved.status,\n contentType: 'application/json',\n body: JSON.stringify(resolved.json ?? {}),\n });\n });\n\n return { events: () => getSentientEvents() };\n}\n","import { resolveScenario } from './resolve.js';\nimport { confidenceBandOf, type SentientScenario } from './scenario.js';\n\ntype CyReq = {\n method: string;\n url: string;\n body: unknown;\n reply(r: { statusCode: number; body?: unknown }): void;\n};\n\n/** Structural subset of Cypress's `cy` — avoids a hard dependency on cypress. */\ntype Cy = {\n intercept(url: string, handler: (req: CyReq) => void | Promise<void>): unknown;\n on(event: string, cb: (win: Record<string, unknown>) => void): unknown;\n};\n\n/**\n * Make Cypress serve a SentientUI scenario: forces variants/layout/slots/persona\n * on the app window before load (including the persona html attributes) and\n * stubs every `/v1/*` request from the scenario. Call in a `beforeEach` before\n * `cy.visit`.\n *\n * Note: for event assertions in Cypress, alias the intercept (`cy.intercept(...).as('ev')`)\n * and `cy.wait('@ev')` — captured module state does not cross the browser/Node boundary.\n */\nexport function mockSentientCypress(cy: Cy, scenario: SentientScenario = {}): void {\n const overrides = scenario.variants ?? {};\n const layout = scenario.layout ?? null;\n const slots = scenario.slots ?? null;\n const persona = scenario.persona ?? null;\n const confidence = scenario.confidence ?? 1;\n\n cy.on('window:before:load', (win) => {\n win.__sentient_overrides = overrides;\n if (layout) win.__sentient_layout_override = layout;\n if (slots) win.__sentient_slot_overrides = slots;\n if (persona) {\n win.__sentient_persona_override = { persona, confidence };\n try {\n const doc = (win as { document?: Document }).document;\n doc?.documentElement?.setAttribute('data-sentient-persona', persona);\n doc?.documentElement?.setAttribute('data-sentient-confidence', confidenceBandOf(confidence));\n } catch {\n /* document not ready — the SDK adopts the override globals instead */\n }\n }\n });\n\n cy.intercept('**/v1/**', async (req) => {\n const resolved = await resolveScenario(\n scenario,\n req.method,\n req.url,\n req.body != null ? JSON.stringify(req.body) : null,\n );\n if (!resolved) return; // passthrough\n req.reply({ statusCode: resolved.status, body: (resolved.json ?? '') as unknown });\n });\n}\n"],"mappings":"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","names":["testing_exports","__export","applyScenario","clearSentientEvents","getSentientEvents","hasFiredGoal","mockSentient","mockSentientCypress","renderWithSentient","resetScenario","resolveScenario","scenarioToHandlers","setupSentientTests","__toCommonJS","import_react","import_react","import_core","store","listeners","update","componentId","weights","store","set","listeners","cb","e","ssrFallback","state","w","getPreviewMode","state","subscribePreview","fn","listeners","createPreviewClient","inner","componentId","segment","variantIds","agentData","agentDataByVariant","slotId","publishDevtoolsConfig","config","ssrFallback","state","w","emit","fn","registerSections","sections","state","emit","import_jsx_runtime","deriveDefaultSegment","_a","_b","device","source","e","DEFAULT_API_BASE_URL","AdaptiveContext","AdaptiveProvider","props","client","setClient","sessionSegment","previewOn","setPreviewOn","getPreviewMode","subscribePreview","prev","config","cancelled","created","initGraph","__spreadProps","__spreadValues","poll","entries","entry","weights","v","update","timerId","ssrFallback","apiBaseUrl","publishDevtoolsConfig","registerSections","exposedClient","createPreviewClient","value","_c","_d","confidenceBandOf","c","applyScenario","scenario","_a","_b","_c","w","__spreadValues","d","e","resetScenario","import_msw","captured","recordEvent","getSentientEvents","clearSentientEvents","hasFiredGoal","events","goalName","e","pathOf","url","_a","e","apiOverride","scenario","route","_b","_c","o","r","resolveScenario","_method","bodyText","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","_u","path","override","body","recordEvent","b","json","s","slots","decl","defaultSlotResult","layoutOrder","persona","confidence","confidenceBandOf","componentId","variants","out","dim","values","declared","scenarioToHandlers","scenario","request","bodyText","r","resolveScenario","mockSentient","page","scenario","_a","_b","_c","_d","_e","initData","data","w","band","e","route","req","resolved","resolveScenario","getSentientEvents","mockSentientCypress","cy","scenario","_a","_b","_c","_d","_e","overrides","layout","slots","persona","confidence","win","doc","confidenceBandOf","e","req","resolved","resolveScenario","import_jsx_runtime","renderWithSentient","ui","scenario","options","applyScenario","AdaptiveProvider","setupSentientTests","_a","g","resetScenario"]}
|