@sentientui/react 0.25.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -257,6 +257,22 @@ type AdaptiveRootProps = Omit<AdaptiveProviderProps, 'initialAssignments' | 'onA
257
257
  slots?: SlotDeclInput[];
258
258
  /** App origin — must be in the project's `allowed_origins`. */
259
259
  appOrigin?: string;
260
+ /**
261
+ * The page's `searchParams` prop (or an equivalent query string /
262
+ * URLSearchParams). Server Components cannot read the request URL from
263
+ * `headers()`, so without this the SSR-minted session carries no `utm_*`
264
+ * params and no ad click IDs (gclid, fbclid, ttclid, …) — campaign
265
+ * attribution only lands after client hydration, and never for visits the
266
+ * client SDK doesn't get to finish (bounce before hydrate). Pass it on
267
+ * landing pages that receive ad traffic:
268
+ *
269
+ * ```tsx
270
+ * export default async function Page({ searchParams }: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {
271
+ * return <AdaptiveRoot ... searchParams={await searchParams}>...</AdaptiveRoot>;
272
+ * }
273
+ * ```
274
+ */
275
+ searchParams?: Record<string, string | string[] | undefined> | URLSearchParams | string;
260
276
  /** Override: when set no network fetch is made. Useful for tests. */
261
277
  initialAssignments?: ServerAssignments;
262
278
  /**
@@ -1,4 +1,4 @@
1
- var pe=Object.defineProperty,le=Object.defineProperties;var ue=Object.getOwnPropertyDescriptors;var x=Object.getOwnPropertySymbols;var q=Object.prototype.hasOwnProperty,G=Object.prototype.propertyIsEnumerable;var W=(e,t,n)=>t in e?pe(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,y=(e,t)=>{for(var n in t||(t={}))q.call(t,n)&&W(e,n,t[n]);if(x)for(var n of x(t))G.call(t,n)&&W(e,n,t[n]);return e},S=(e,t)=>le(e,ue(t));var z=(e,t)=>{var n={};for(var s in e)q.call(e,s)&&t.indexOf(s)<0&&(n[s]=e[s]);if(e!=null&&x)for(var s of x(e))t.indexOf(s)<0&&G.call(e,s)&&(n[s]=e[s]);return n};import{deriveSessionSegment as Oe,matchedAgentToken as xe}from"@sentientui/core";import{cookies as Pe,headers as Le}from"next/headers";import{renderPrePaintScript as me}from"@sentientui/core";import{confidenceBand as fe}from"@sentientui/policy";import{jsx as ye}from"react/jsx-runtime";function Y(e){return JSON.stringify(e).replace(/</g,"\\u003c")}function Ae(e){return e.persona?'(function(){try{var d=document.documentElement;if(d.hasAttribute("data-sentient-persona"))return;d.setAttribute("data-sentient-persona",'+Y(e.persona.persona)+');d.setAttribute("data-sentient-confidence",'+Y(fe(e.persona.confidence))+");}catch(e){}})();":me(e.apiKey)}function Q(e){return ye("script",{"data-sentient-persona-script":"",nonce:e.nonce,dangerouslySetInnerHTML:{__html:Ae(e)}})}import{preloadAssignments as he,readSessionCookie as ve}from"@sentientui/core/server";import{preloadDecisions as Je}from"@sentientui/core/server";function Z(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function ee(e,t){var r,i,a;let n=(a=(i=ve(t.cookies,t.apiKey))!=null?i:(r=t.createSessionId)==null?void 0:r.call(t))!=null?a:Z();return{assignments:await he(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,origin:t.origin,userAgent:t.userAgent,referer:t.referer,doNotTrack:t.doNotTrack,timeoutMs:t.timeoutMs,persona:t.persona}),sessionId:n}}async function te(e){var a,c,p,I,k,w,o,l,u,h;let{preloadDecisions:t,readSessionCookie:n}=await import("@sentientui/core/server"),s=(p=(c=n(e.cookies,e.apiKey))!=null?c:(a=e.createSessionId)==null?void 0:a.call(e))!=null?p:Z();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let d={layoutOrder:(I=e.sections)!=null?I:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:s};try{let m=await import("@sentientui/core/local");if(!m.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."),d;let f=m.createLocalEngine({sessionId:s}).decide({sections:e.sections,components:(k=e.components)!=null?k:[],slots:(w=e.slots)!=null?w:[]});return{layoutOrder:(l=(o=f.layoutOrder)!=null?o:e.sections)!=null?l:[],assignments:f.assignments,slots:f.slots,persona:f.persona,confidence:f.confidence,sessionId:s}}catch(m){return d}}let i=await t({sections:e.sections,components:(u=e.components)!=null?u:[],slots:(h=e.slots)!=null?h:[]},s,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,doNotTrack:e.doNotTrack,timeoutMs:e.timeoutMs,persona:e.persona});return S(y({},i),{sessionId:s})}import{AdaptiveRootClient as Fe}from"./adaptive-root-client.js";var Se=["page","blocks","layoutOrder"],ne=new Map;function ke(e,t){ne.set(e,t)}function be(e){return ne.get(e)}function N(e){var r,i;let t=(i=(r=e.content)!=null?r:be(e.page))!=null?i:{},n={};for(let[a,c]of Object.entries(t))Se.includes(a)||(n[a]=c);let s=S(y({},n),{page:e.page,blocks:e.blocks});return e.layoutOrder&&(s.layoutOrder=e.layoutOrder),s}function se(e){return JSON.stringify(y({"@context":"https://schema.org","@type":"WebPage"},e)).replace(/</g,"\\u003c")}function re(e){let t=[];e.title&&t.push(`# ${e.title}`,""),e.summary&&t.push(String(e.summary),"");for(let[n,s]of Object.entries(e))["page","title","summary","blocks","layoutOrder"].includes(n)||t.push(`## ${n}`,"","```json",JSON.stringify(s,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(`
1
+ var me=Object.defineProperty,fe=Object.defineProperties;var Ae=Object.getOwnPropertyDescriptors;var x=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,Y=Object.prototype.propertyIsEnumerable;var G=(e,t,n)=>t in e?me(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,A=(e,t)=>{for(var n in t||(t={}))z.call(t,n)&&G(e,n,t[n]);if(x)for(var n of x(t))Y.call(t,n)&&G(e,n,t[n]);return e},k=(e,t)=>fe(e,Ae(t));var Q=(e,t)=>{var n={};for(var s in e)z.call(e,s)&&t.indexOf(s)<0&&(n[s]=e[s]);if(e!=null&&x)for(var s of x(e))t.indexOf(s)<0&&Y.call(e,s)&&(n[s]=e[s]);return n};import{deriveSessionSegment as Le,extractTrackedParams as Fe,matchedAgentToken as Ne}from"@sentientui/core";import{cookies as Ee,headers as De}from"next/headers";import{renderPrePaintScript as ye}from"@sentientui/core";import{confidenceBand as he}from"@sentientui/policy";import{jsx as ke}from"react/jsx-runtime";function Z(e){return JSON.stringify(e).replace(/</g,"\\u003c")}function Se(e){return e.persona?'(function(){try{var d=document.documentElement;if(d.hasAttribute("data-sentient-persona"))return;d.setAttribute("data-sentient-persona",'+Z(e.persona.persona)+');d.setAttribute("data-sentient-confidence",'+Z(he(e.persona.confidence))+");}catch(e){}})();":ye(e.apiKey)}function ee(e){return ke("script",{"data-sentient-persona-script":"",nonce:e.nonce,dangerouslySetInnerHTML:{__html:Se(e)}})}import{preloadAssignments as ve,readSessionCookie as Re}from"@sentientui/core/server";import{preloadDecisions as Xe}from"@sentientui/core/server";function te(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function ne(e,t){var r,o,i;let n=(i=(o=Re(t.cookies,t.apiKey))!=null?o:(r=t.createSessionId)==null?void 0:r.call(t))!=null?i:te();return{assignments:await ve(e,n,{apiKey:t.apiKey,baseUrl:t.baseUrl,origin:t.origin,userAgent:t.userAgent,referer:t.referer,utmParams:t.utmParams,clickIds:t.clickIds,doNotTrack:t.doNotTrack,timeoutMs:t.timeoutMs,persona:t.persona}),sessionId:n}}async function se(e){var i,g,y,u,I,v,P,a,l,m;let{preloadDecisions:t,readSessionCookie:n}=await import("@sentientui/core/server"),s=(y=(g=n(e.cookies,e.apiKey))!=null?g:(i=e.createSessionId)==null?void 0:i.call(e))!=null?y:te();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let h={layoutOrder:(u=e.sections)!=null?u:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:s};try{let c=await import("@sentientui/core/local");if(!c.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."),h;let p=c.createLocalEngine({sessionId:s}).decide({sections:e.sections,components:(I=e.components)!=null?I:[],slots:(v=e.slots)!=null?v:[]});return{layoutOrder:(a=(P=p.layoutOrder)!=null?P:e.sections)!=null?a:[],assignments:p.assignments,slots:p.slots,persona:p.persona,confidence:p.confidence,sessionId:s}}catch(c){return h}}let o=await t({sections:e.sections,components:(l=e.components)!=null?l:[],slots:(m=e.slots)!=null?m:[]},s,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,utmParams:e.utmParams,clickIds:e.clickIds,doNotTrack:e.doNotTrack,timeoutMs:e.timeoutMs,persona:e.persona});return k(A({},o),{sessionId:s})}import{AdaptiveRootClient as Ke}from"./adaptive-root-client.js";var be=["page","blocks","layoutOrder"],re=new Map;function Ie(e,t){re.set(e,t)}function Pe(e){return re.get(e)}function N(e){var r,o;let t=(o=(r=e.content)!=null?r:Pe(e.page))!=null?o:{},n={};for(let[i,g]of Object.entries(t))be.includes(i)||(n[i]=g);let s=k(A({},n),{page:e.page,blocks:e.blocks});return e.layoutOrder&&(s.layoutOrder=e.layoutOrder),s}function oe(e){return JSON.stringify(A({"@context":"https://schema.org","@type":"WebPage"},e)).replace(/</g,"\\u003c")}function ie(e){let t=[];e.title&&t.push(`# ${e.title}`,""),e.summary&&t.push(String(e.summary),"");for(let[n,s]of Object.entries(e))["page","title","summary","blocks","layoutOrder"].includes(n)||t.push(`## ${n}`,"","```json",JSON.stringify(s,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
- `}function oe(e,t={}){var s,r;let n=(s=t.fetchImpl)!=null?s:fetch;try{n(`${e.baseUrl}/crawler-events`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.apiKey}`},body:JSON.stringify({path:e.path,botName:e.botName,userAgent:(r=e.userAgent)!=null?r:null,source:"ssr"})}).catch(()=>{})}catch(i){}}import{matchedAgentToken as Re}from"@sentientui/core";function Ie(e,t){return e.pathname.endsWith(".md")||t.toLowerCase().includes("text/markdown")}function we(e){return async t=>{var c;let n=new URL(t.url),s=(c=t.headers.get("accept"))!=null?c:"",r=t.headers.get("user-agent"),i=n.pathname.replace(/\.(md|json)$/,"");if(e.onRead)try{Promise.resolve(e.onRead({path:i,userAgent:r,botName:Re(r!=null?r:"")})).catch(()=>{})}catch(p){}let a=await e.getFeed(t);return Ie(n,s)?new Response(re(a),{headers:{"content-type":"text/markdown; charset=utf-8"}}):new Response(JSON.stringify(a),{headers:{"content-type":"application/json; charset=utf-8"}})}}import{matchedAgentToken as at,uaTokenMatch as ct,agentIntent as dt,classifiedAgents as gt}from"@sentientui/core";import{Fragment as ie,jsx as E,jsxs as ae}from"react/jsx-runtime";var Ne="https://api.sentient-ui.com/v1";function Ee(e){return Object.entries(e).map(([t,n])=>{var s;return{id:t,variant:typeof n=="string"?n:(s=n==null?void 0:n.variantId)!=null?s:""}})}async function nt(e){var T,M,J,j,$,V,X,H;let B=e,{components:t=[],sections:n,slots:s,appOrigin:r,initialAssignments:i,ssrSessionId:a,timeoutMs:c,agentFeed:p,captureAgents:I,nonce:k,children:w}=B,o=z(B,["components","sections","slots","appOrigin","initialAssignments","ssrSessionId","timeoutMs","agentFeed","captureAgents","nonce","children"]),l=await Le(),u=l.get("host");!r&&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 h=r!=null?r:process.env.NODE_ENV==="production"?`https://${u!=null?u:"localhost"}`:"http://localhost:3001",d=(T=l.get("user-agent"))!=null?T:void 0,m=(M=l.get("referer"))!=null?M:void 0,f=l.get("dnt")==="1"||l.get("sec-gpc")==="1",ce=Oe({userAgent:d,referer:m,appOrigin:h}),P=await Pe(),A=o.consentFrom,L=($=o.consent)!=null?$:A!=null&&A.cookie&&!A.check?((J=P.get(A.cookie))==null?void 0:J.value)===((j=A.value)!=null?j:"accepted"):void 0,de=f||L===!1||A!=null&&L!==!0,F=o.apiBaseUrl?o.apiBaseUrl.replace(/\/$/,""):Ne,D=(X=(V=p==null?void 0:p.path)!=null?V:l.get("x-pathname"))!=null?X:"/",K=xe(d!=null?d:"");I!==!1&&K&&oe({baseUrl:F,apiKey:o.apiKey,path:D,botName:K,userAgent:d});let v,b=null,U,R=null,O;if(i)v=i,O=a;else if(de)v={};else if(n&&n.length>0||s&&s.length>0){let g=await te({sections:n!=null?n:[],components:t,slots:s,cookies:P,apiKey:o.apiKey,baseUrl:F,origin:h,userAgent:d,referer:m,timeoutMs:c,persona:o.persona});v=g.assignments,b=g.layoutOrder,U=g.slots,R=g.persona!==void 0?{persona:g.persona,confidence:(H=g.confidence)!=null?H:0}:null,O=g.sessionId}else{let g=await ee(t,{cookies:P,apiKey:o.apiKey,baseUrl:F,origin:h,userAgent:d,referer:m,timeoutMs:c,persona:o.persona});v=g.assignments,O=g.sessionId}let _=E(Q,{apiKey:o.apiKey,persona:R,nonce:k}),C=E(Fe,S(y({},o),{consent:L,initialAssignments:v,initialLayoutOrder:b,declaredSections:n,initialSlots:U,initialPersona:R!=null?R:void 0,sessionSegment:ce,ssrSessionId:O,children:w}));if(!p)return ae(ie,{children:[_,C]});let ge=N({page:D,blocks:Ee(v),layoutOrder:b!=null?b:void 0,content:p.content});return ae(ie,{children:[_,E("script",{type:"application/ld+json",nonce:k,dangerouslySetInnerHTML:{__html:se(ge)}}),C]})}export{nt as AdaptiveRoot,dt as agentIntent,N as buildAgentFeedFor,gt as classifiedAgents,we as createAgentFeed,ke as defineAgentContent,at as matchedAgentToken,ct as uaTokenMatch};
3
+ `}function ae(e,t={}){var s,r;let n=(s=t.fetchImpl)!=null?s:fetch;try{n(`${e.baseUrl}/crawler-events`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.apiKey}`},body:JSON.stringify({path:e.path,botName:e.botName,userAgent:(r=e.userAgent)!=null?r:null,source:"ssr"})}).catch(()=>{})}catch(o){}}import{matchedAgentToken as we}from"@sentientui/core";function xe(e,t){return e.pathname.endsWith(".md")||t.toLowerCase().includes("text/markdown")}function Oe(e){return async t=>{var g;let n=new URL(t.url),s=(g=t.headers.get("accept"))!=null?g:"",r=t.headers.get("user-agent"),o=n.pathname.replace(/\.(md|json)$/,"");if(e.onRead)try{Promise.resolve(e.onRead({path:o,userAgent:r,botName:we(r!=null?r:"")})).catch(()=>{})}catch(y){}let i=await e.getFeed(t);return xe(n,s)?new Response(ie(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 lt,uaTokenMatch as pt,agentIntent as ut,classifiedAgents as mt}from"@sentientui/core";import{Fragment as ce,jsx as E,jsxs as de}from"react/jsx-runtime";var Ue="https://api.sentient-ui.com/v1";function _e(e){return Object.entries(e).map(([t,n])=>{var s;return{id:t,variant:typeof n=="string"?n:(s=n==null?void 0:n.variantId)!=null?s:""}})}async function it(e){var J,j,$,V,X,H,W,q;let M=e,{components:t=[],sections:n,slots:s,appOrigin:r,searchParams:o,initialAssignments:i,ssrSessionId:g,timeoutMs:y,agentFeed:u,captureAgents:I,nonce:v,children:P}=M,a=Q(M,["components","sections","slots","appOrigin","searchParams","initialAssignments","ssrSessionId","timeoutMs","agentFeed","captureAgents","nonce","children"]),l=await De(),m=l.get("host");!r&&process.env.NODE_ENV==="production"&&!m&&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 h=r!=null?r:process.env.NODE_ENV==="production"?`https://${m!=null?m:"localhost"}`:"http://localhost:3001",c=(J=l.get("user-agent"))!=null?J:void 0,p=(j=l.get("referer"))!=null?j:void 0,{utmParams:D,clickIds:K}=Fe(o!=null?o:{}),ge=l.get("dnt")==="1"||l.get("sec-gpc")==="1",le=Le({userAgent:c,referer:p,appOrigin:h}),O=await Ee(),f=a.consentFrom,L=(X=a.consent)!=null?X:f!=null&&f.cookie&&!f.check?(($=O.get(f.cookie))==null?void 0:$.value)===((V=f.value)!=null?V:"accepted"):void 0,pe=ge||L===!1||f!=null&&L!==!0,F=a.apiBaseUrl?a.apiBaseUrl.replace(/\/$/,""):Ue,U=(W=(H=u==null?void 0:u.path)!=null?H:l.get("x-pathname"))!=null?W:"/",_=Ne(c!=null?c:"");I!==!1&&_&&ae({baseUrl:F,apiKey:a.apiKey,path:U,botName:_,userAgent:c});let S,R=null,C,b=null,w;if(i)S=i,w=g;else if(pe)S={};else if(n&&n.length>0||s&&s.length>0){let d=await se({sections:n!=null?n:[],components:t,slots:s,cookies:O,apiKey:a.apiKey,baseUrl:F,origin:h,userAgent:c,referer:p,utmParams:D,clickIds:K,timeoutMs:y,persona:a.persona});S=d.assignments,R=d.layoutOrder,C=d.slots,b=d.persona!==void 0?{persona:d.persona,confidence:(q=d.confidence)!=null?q:0}:null,w=d.sessionId}else{let d=await ne(t,{cookies:O,apiKey:a.apiKey,baseUrl:F,origin:h,userAgent:c,referer:p,utmParams:D,clickIds:K,timeoutMs:y,persona:a.persona});S=d.assignments,w=d.sessionId}let T=E(ee,{apiKey:a.apiKey,persona:b,nonce:v}),B=E(Ke,k(A({},a),{consent:L,initialAssignments:S,initialLayoutOrder:R,declaredSections:n,initialSlots:C,initialPersona:b!=null?b:void 0,sessionSegment:le,ssrSessionId:w,children:P}));if(!u)return de(ce,{children:[T,B]});let ue=N({page:U,blocks:_e(S),layoutOrder:R!=null?R:void 0,content:u.content});return de(ce,{children:[T,E("script",{type:"application/ld+json",nonce:v,dangerouslySetInnerHTML:{__html:oe(ue)}}),B]})}export{it as AdaptiveRoot,ut as agentIntent,N as buildAgentFeedFor,mt as classifiedAgents,Oe as createAgentFeed,Ie as defineAgentContent,lt as matchedAgentToken,pt as uaTokenMatch};
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/log-agent-fetch.ts","../../src/next/agent-feed-route.ts"],"sourcesContent":["import { deriveSessionSegment, matchedAgentToken } from '@sentientui/core';\nimport type { SlotDeclInput, SlotResult } from '@sentientui/core';\nimport { cookies, headers } from 'next/headers';\n// `type JSX` from react, not the global namespace removed in @types/react@19\n// (peers allow react >=18) — see adaptive-text.tsx.\nimport type { JSX, 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';\nimport { logAgentFetch } from './log-agent-fetch.js';\n\nexport { createAgentFeed } from './agent-feed-route.js';\nexport type { AgentFeedRouteConfig, AgentFeedReadEntry } from './agent-feed-route.js';\nexport { defineAgentContent, buildAgentFeed as buildAgentFeedFor } from '../agent-feed.js';\n// Re-exported from core on the SERVER entry (this module is server-only — it\n// imports next/headers). Lets server components do agent detection with just the\n// `@sentientui/react` package, no direct core dependency. Do NOT add this to the\n// package's client index: re-exporting a plain function through a 'use client'\n// module turns it into a client reference that throws when called during SSR.\nexport { matchedAgentToken, uaTokenMatch, agentIntent, classifiedAgents } from '@sentientui/core';\nexport type { AgentIntent } from '@sentientui/core';\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 // Every provider prop AdaptiveRoot itself resolves and passes AFTER the\n // {...providerProps} spread must be omitted here: a caller-supplied value\n // would typecheck but be silently clobbered by the spread order\n // (initialLayoutOrder, declaredSections and sessionSegment were missing\n // from this list and suffered exactly that).\n | 'initialAssignments'\n | 'onAssignment'\n | 'initialSlots'\n | 'initialPersona'\n | 'initialLayoutOrder'\n | 'declaredSections'\n | 'sessionSegment'\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 /**\n * When true (default), a known AI-agent fetch (matched by user-agent —\n * GPTBot, ChatGPT-User, Claude-User, PerplexityBot, …) is logged server-side\n * to your agent analytics. Machine telemetry only (no cookie, no session);\n * fire-and-forget, never affects render. Set false to opt out.\n */\n captureAgents?: boolean;\n /**\n * CSP nonce for the inline persona (and optional agent JSON-LD) scripts.\n * Pass through from Next.js middleware / `headers()` when using a strict CSP.\n */\n nonce?: string;\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 captureAgents,\n nonce,\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 // Honor a tracking opt-out at SSR: `DNT: 1` or the legally-enforceable\n // `Sec-GPC: 1`. When set we skip the session upsert + assign/decide so no\n // session row is minted for the visitor (audit P4) — matching the client SDK,\n // which already no-ops for these signals.\n const doNotTrack = headerStore.get('dnt') === '1' || headerStore.get('sec-gpc') === '1';\n // `consent: false` must gate the SERVER too, not just the client. Without\n // this the SSR decide/assign still ran and still minted a session row for a\n // visitor who had not consented — contradicting the documented contract\n // (\"no SDK is initialised, no cookies are written, no events are sent\") and\n // forcing sites to hide AdaptiveRoot behind a conditional render, which is\n // what made consent-after-load cost a full server round trip.\n const sessionSegment = deriveSessionSegment({ userAgent, referer, appOrigin: resolvedOrigin });\n const cookieStore = await cookies();\n\n // This is a Server Component and already has the request cookies, so resolve\n // a cookie-based `consentFrom` here rather than making the app read the same\n // cookie again just to pass `consent` — naming it twice only invites drift.\n // An already-consented visitor therefore gets SSR variant assignment (zero\n // layout shift) with no extra code.\n //\n // A `check()` source runs in the browser and cannot be evaluated here, so it\n // stays gated until the client resolves it. An explicit `consent` prop always\n // wins — it is the escape hatch for apps that track consent elsewhere.\n //\n // Consent gates the SERVER too, not just the client: without it the SSR\n // decide/assign still ran and still minted a session row for a visitor who\n // had not consented, contradicting the documented contract (\"no SDK is\n // initialised, no cookies are written, no events are sent\").\n const cf = providerProps.consentFrom;\n const consent =\n providerProps.consent ??\n (cf?.cookie && !cf.check\n ? cookieStore.get(cf.cookie)?.value === (cf.value ?? 'accepted')\n : undefined);\n const skipSsr = doNotTrack || consent === false || (cf != null && consent !== true);\n\n // SSR preload MUST hit the same API host the client will use, otherwise the\n // SSR-minted session lives on the wrong host and the client's first /assign\n // misses it and re-mints — silently breaking SSR→client continuity for any\n // non-default / self-hosted deployment. The client derives its base from\n // apiBaseUrl too (see provider.tsx), so thread the same value here.\n const baseUrl = providerProps.apiBaseUrl\n ? providerProps.apiBaseUrl.replace(/\\/$/, '')\n : DEFAULT_API_BASE_URL;\n\n // Server-side agent-fetch capture (spec: nextjs-agent-fetch-capture). JS-less\n // assistants (GPTBot / ChatGPT-User / Claude-User / PerplexityBot / …) never\n // run client JS, but they trigger SSR — so AdaptiveRoot sees their UA here.\n // Fire-and-forget; never blocks or breaks render. `agentPath` is reused by the\n // agentFeed JSON-LD below.\n const agentPath = agentFeed?.path ?? headerStore.get('x-pathname') ?? '/';\n const agentBot = matchedAgentToken(userAgent ?? '');\n if (captureAgents !== false && agentBot) {\n logAgentFetch({ baseUrl, apiKey: providerProps.apiKey, path: agentPath, botName: agentBot, userAgent });\n }\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 (skipSsr) {\n // Nothing server-side: no decide, no assign, no session. Components fall\n // back to `ssrFallback`, and the client starts only if the visitor later\n // consents — via the `consent` prop or grantConsent(), neither of which\n // needs a page reload.\n initialAssignments = {};\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,\n origin: resolvedOrigin,\n userAgent,\n referer,\n // doNotTrack is deliberately not passed: it is necessarily false on this\n // branch — a DNT/GPC or consent-gated request already took the skipSsr\n // arm above and never reaches this loader.\n timeoutMs,\n persona: providerProps.persona,\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,\n origin: resolvedOrigin,\n userAgent,\n referer,\n // doNotTrack is deliberately not passed: it is necessarily false on this\n // branch — a DNT/GPC or consent-gated request already took the skipSsr\n // arm above and never reaches this loader.\n timeoutMs,\n persona: providerProps.persona,\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} nonce={nonce} />\n );\n\n const client = (\n <AdaptiveRootClient\n {...providerProps}\n // Forward the server-resolved value so a consented visitor's client does\n // not start gated and re-resolve the same cookie on mount.\n consent={consent}\n initialAssignments={initialAssignments}\n initialLayoutOrder={initialLayoutOrder}\n // Declared regardless of what came back, so devtools can preview layout on\n // a page whose decision was gated or timed out.\n declaredSections={sections}\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 feed = buildAgentFeed({\n page: agentPath,\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 nonce={nonce}\n dangerouslySetInnerHTML={{ __html: renderAgentJsonLdBody(feed) }}\n />\n {client}\n </>\n );\n}\n","// `type JSX` from react, not the global namespace removed in @types/react@19\n// (peers allow react >=18) — see adaptive-text.tsx.\nimport type { JSX } from 'react';\nimport { 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 * CSP nonce for the inline pre-paint script. Pass the same nonce your\n * `Content-Security-Policy` `script-src` allows (e.g. from Next.js middleware).\n * Required for strict CSP deployments that block `'unsafe-inline'`.\n */\n nonce?: 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 nonce={props.nonce}\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 /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */\n doNotTrack?: boolean;\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 * Declared persona — the role your app already knows for this visitor (e.g.\n * from your auth context: 'admin', 'evaluator'). Must be a key in the\n * project's persona vocabulary; unrecognized values are ignored server-side.\n * Never a user id or email.\n */\n persona?: string;\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 // apiKey is not optional here: the client writes the per-project suffixed\n // cookie, so an un-keyed read missed every returning visitor and minted a\n // fresh orphan session per SSR request (see readSessionCookie in core).\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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 // Keyed read — the client's cookie name is suffixed per project (see\n // loadAdaptiveAssignments above). Works for keyless too: with no pk_ key the\n // client writes the bare legacy name, which the un-suffixed read falls back to.\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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","// Fire-and-forget server-side log of a known AI-agent fetch to crawler_requests\n// (via POST /v1/crawler-events). Machine telemetry — no cookie, no session.\n// MUST NOT throw or be awaited into the render path.\nexport type AgentFetchLog = {\n baseUrl: string; // API base ending in /v1\n apiKey: string; // public pk_ key\n path: string;\n botName: string;\n userAgent?: string;\n};\n\nexport function logAgentFetch(entry: AgentFetchLog, deps: { fetchImpl?: typeof fetch } = {}): void {\n const doFetch = deps.fetchImpl ?? fetch;\n try {\n void doFetch(`${entry.baseUrl}/crawler-events`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${entry.apiKey}` },\n body: JSON.stringify({\n path: entry.path,\n botName: entry.botName,\n userAgent: entry.userAgent ?? null,\n source: 'ssr',\n }),\n }).catch(() => {});\n } catch {\n /* never break render */\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"],"mappings":"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","names":["deriveSessionSegment","matchedAgentToken","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","logAgentFetch","entry","deps","_a","_b","doFetch","e","matchedAgentToken","wantsMarkdown","url","accept","createAgentFeed","config","request","_a","userAgent","path","matchedAgentToken","e","feed","renderAgentMarkdown","matchedAgentToken","uaTokenMatch","agentIntent","classifiedAgents","Fragment","jsx","jsxs","DEFAULT_API_BASE_URL","assignmentsToBlocks","assignments","id","v","_a","AdaptiveRoot","props","_b","_c","_d","_e","_f","_g","_h","_i","components","sections","slots","appOrigin","initialAssignmentsOverride","ssrSessionIdProp","timeoutMs","agentFeed","captureAgents","nonce","children","providerProps","__objRest","headerStore","headers","host","resolvedOrigin","userAgent","referer","doNotTrack","sessionSegment","deriveSessionSegment","cookieStore","cookies","cf","consent","skipSsr","baseUrl","agentPath","agentBot","matchedAgentToken","logAgentFetch","initialAssignments","initialLayoutOrder","initialSlots","initialPersona","ssrSessionId","decision","loadAdaptiveDecision","result","loadAdaptiveAssignments","personaScript","SentientPersonaScript","client","AdaptiveRootClient","__spreadProps","__spreadValues","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/log-agent-fetch.ts","../../src/next/agent-feed-route.ts"],"sourcesContent":["import { deriveSessionSegment, extractTrackedParams, matchedAgentToken } from '@sentientui/core';\nimport type { SlotDeclInput, SlotResult } from '@sentientui/core';\nimport { cookies, headers } from 'next/headers';\n// `type JSX` from react, not the global namespace removed in @types/react@19\n// (peers allow react >=18) — see adaptive-text.tsx.\nimport type { JSX, 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';\nimport { logAgentFetch } from './log-agent-fetch.js';\n\nexport { createAgentFeed } from './agent-feed-route.js';\nexport type { AgentFeedRouteConfig, AgentFeedReadEntry } from './agent-feed-route.js';\nexport { defineAgentContent, buildAgentFeed as buildAgentFeedFor } from '../agent-feed.js';\n// Re-exported from core on the SERVER entry (this module is server-only — it\n// imports next/headers). Lets server components do agent detection with just the\n// `@sentientui/react` package, no direct core dependency. Do NOT add this to the\n// package's client index: re-exporting a plain function through a 'use client'\n// module turns it into a client reference that throws when called during SSR.\nexport { matchedAgentToken, uaTokenMatch, agentIntent, classifiedAgents } from '@sentientui/core';\nexport type { AgentIntent } from '@sentientui/core';\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 // Every provider prop AdaptiveRoot itself resolves and passes AFTER the\n // {...providerProps} spread must be omitted here: a caller-supplied value\n // would typecheck but be silently clobbered by the spread order\n // (initialLayoutOrder, declaredSections and sessionSegment were missing\n // from this list and suffered exactly that).\n | 'initialAssignments'\n | 'onAssignment'\n | 'initialSlots'\n | 'initialPersona'\n | 'initialLayoutOrder'\n | 'declaredSections'\n | 'sessionSegment'\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 /**\n * The page's `searchParams` prop (or an equivalent query string /\n * URLSearchParams). Server Components cannot read the request URL from\n * `headers()`, so without this the SSR-minted session carries no `utm_*`\n * params and no ad click IDs (gclid, fbclid, ttclid, …) — campaign\n * attribution only lands after client hydration, and never for visits the\n * client SDK doesn't get to finish (bounce before hydrate). Pass it on\n * landing pages that receive ad traffic:\n *\n * ```tsx\n * export default async function Page({ searchParams }: { searchParams: Promise<Record<string, string | string[] | undefined>> }) {\n * return <AdaptiveRoot ... searchParams={await searchParams}>...</AdaptiveRoot>;\n * }\n * ```\n */\n searchParams?: Record<string, string | string[] | undefined> | URLSearchParams | 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 /**\n * When true (default), a known AI-agent fetch (matched by user-agent —\n * GPTBot, ChatGPT-User, Claude-User, PerplexityBot, …) is logged server-side\n * to your agent analytics. Machine telemetry only (no cookie, no session);\n * fire-and-forget, never affects render. Set false to opt out.\n */\n captureAgents?: boolean;\n /**\n * CSP nonce for the inline persona (and optional agent JSON-LD) scripts.\n * Pass through from Next.js middleware / `headers()` when using a strict CSP.\n */\n nonce?: string;\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 searchParams,\n initialAssignments: initialAssignmentsOverride,\n ssrSessionId: ssrSessionIdProp,\n timeoutMs,\n agentFeed,\n captureAgents,\n nonce,\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 // Landing-URL attribution (utm_* + ad click IDs). Only available when the\n // page passes its searchParams down — headers() never carries the request's\n // own query string, and the Referer is the PREVIOUS page, not this one.\n const { utmParams, clickIds } = extractTrackedParams(searchParams ?? {});\n // Honor a tracking opt-out at SSR: `DNT: 1` or the legally-enforceable\n // `Sec-GPC: 1`. When set we skip the session upsert + assign/decide so no\n // session row is minted for the visitor (audit P4) — matching the client SDK,\n // which already no-ops for these signals.\n const doNotTrack = headerStore.get('dnt') === '1' || headerStore.get('sec-gpc') === '1';\n // `consent: false` must gate the SERVER too, not just the client. Without\n // this the SSR decide/assign still ran and still minted a session row for a\n // visitor who had not consented — contradicting the documented contract\n // (\"no SDK is initialised, no cookies are written, no events are sent\") and\n // forcing sites to hide AdaptiveRoot behind a conditional render, which is\n // what made consent-after-load cost a full server round trip.\n const sessionSegment = deriveSessionSegment({ userAgent, referer, appOrigin: resolvedOrigin });\n const cookieStore = await cookies();\n\n // This is a Server Component and already has the request cookies, so resolve\n // a cookie-based `consentFrom` here rather than making the app read the same\n // cookie again just to pass `consent` — naming it twice only invites drift.\n // An already-consented visitor therefore gets SSR variant assignment (zero\n // layout shift) with no extra code.\n //\n // A `check()` source runs in the browser and cannot be evaluated here, so it\n // stays gated until the client resolves it. An explicit `consent` prop always\n // wins — it is the escape hatch for apps that track consent elsewhere.\n //\n // Consent gates the SERVER too, not just the client: without it the SSR\n // decide/assign still ran and still minted a session row for a visitor who\n // had not consented, contradicting the documented contract (\"no SDK is\n // initialised, no cookies are written, no events are sent\").\n const cf = providerProps.consentFrom;\n const consent =\n providerProps.consent ??\n (cf?.cookie && !cf.check\n ? cookieStore.get(cf.cookie)?.value === (cf.value ?? 'accepted')\n : undefined);\n const skipSsr = doNotTrack || consent === false || (cf != null && consent !== true);\n\n // SSR preload MUST hit the same API host the client will use, otherwise the\n // SSR-minted session lives on the wrong host and the client's first /assign\n // misses it and re-mints — silently breaking SSR→client continuity for any\n // non-default / self-hosted deployment. The client derives its base from\n // apiBaseUrl too (see provider.tsx), so thread the same value here.\n const baseUrl = providerProps.apiBaseUrl\n ? providerProps.apiBaseUrl.replace(/\\/$/, '')\n : DEFAULT_API_BASE_URL;\n\n // Server-side agent-fetch capture (spec: nextjs-agent-fetch-capture). JS-less\n // assistants (GPTBot / ChatGPT-User / Claude-User / PerplexityBot / …) never\n // run client JS, but they trigger SSR — so AdaptiveRoot sees their UA here.\n // Fire-and-forget; never blocks or breaks render. `agentPath` is reused by the\n // agentFeed JSON-LD below.\n const agentPath = agentFeed?.path ?? headerStore.get('x-pathname') ?? '/';\n const agentBot = matchedAgentToken(userAgent ?? '');\n if (captureAgents !== false && agentBot) {\n logAgentFetch({ baseUrl, apiKey: providerProps.apiKey, path: agentPath, botName: agentBot, userAgent });\n }\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 (skipSsr) {\n // Nothing server-side: no decide, no assign, no session. Components fall\n // back to `ssrFallback`, and the client starts only if the visitor later\n // consents — via the `consent` prop or grantConsent(), neither of which\n // needs a page reload.\n initialAssignments = {};\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,\n origin: resolvedOrigin,\n userAgent,\n referer,\n utmParams,\n clickIds,\n // doNotTrack is deliberately not passed: it is necessarily false on this\n // branch — a DNT/GPC or consent-gated request already took the skipSsr\n // arm above and never reaches this loader.\n timeoutMs,\n persona: providerProps.persona,\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,\n origin: resolvedOrigin,\n userAgent,\n referer,\n utmParams,\n clickIds,\n // doNotTrack is deliberately not passed: it is necessarily false on this\n // branch — a DNT/GPC or consent-gated request already took the skipSsr\n // arm above and never reaches this loader.\n timeoutMs,\n persona: providerProps.persona,\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} nonce={nonce} />\n );\n\n const client = (\n <AdaptiveRootClient\n {...providerProps}\n // Forward the server-resolved value so a consented visitor's client does\n // not start gated and re-resolve the same cookie on mount.\n consent={consent}\n initialAssignments={initialAssignments}\n initialLayoutOrder={initialLayoutOrder}\n // Declared regardless of what came back, so devtools can preview layout on\n // a page whose decision was gated or timed out.\n declaredSections={sections}\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 feed = buildAgentFeed({\n page: agentPath,\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 nonce={nonce}\n dangerouslySetInnerHTML={{ __html: renderAgentJsonLdBody(feed) }}\n />\n {client}\n </>\n );\n}\n","// `type JSX` from react, not the global namespace removed in @types/react@19\n// (peers allow react >=18) — see adaptive-text.tsx.\nimport type { JSX } from 'react';\nimport { 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 * CSP nonce for the inline pre-paint script. Pass the same nonce your\n * `Content-Security-Policy` `script-src` allows (e.g. from Next.js middleware).\n * Required for strict CSP deployments that block `'unsafe-inline'`.\n */\n nonce?: 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 nonce={props.nonce}\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 /**\n * `utm_*` params from the landing URL. The Referer header never carries the\n * page's OWN query string, so without this the SSR-minted session has no\n * campaign attribution until the client SDK hydrates and re-upserts.\n * Derive with `extractTrackedParams(searchParams)` from `@sentientui/core/server`.\n */\n utmParams?: Record<string, string>;\n /** Ad-platform click IDs (gclid, fbclid, ttclid, …) from the landing URL — same derivation as `utmParams`. */\n clickIds?: Record<string, string>;\n /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */\n doNotTrack?: boolean;\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 * Declared persona — the role your app already knows for this visitor (e.g.\n * from your auth context: 'admin', 'evaluator'). Must be a key in the\n * project's persona vocabulary; unrecognized values are ignored server-side.\n * Never a user id or email.\n */\n persona?: string;\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 // apiKey is not optional here: the client writes the per-project suffixed\n // cookie, so an un-keyed read missed every returning visitor and minted a\n // fresh orphan session per SSR request (see readSessionCookie in core).\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 utmParams: options.utmParams,\n clickIds: options.clickIds,\n doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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 // Keyed read — the client's cookie name is suffixed per project (see\n // loadAdaptiveAssignments above). Works for keyless too: with no pk_ key the\n // client writes the bare legacy name, which the un-suffixed read falls back to.\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 utmParams: options.utmParams,\n clickIds: options.clickIds,\n doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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","// Fire-and-forget server-side log of a known AI-agent fetch to crawler_requests\n// (via POST /v1/crawler-events). Machine telemetry — no cookie, no session.\n// MUST NOT throw or be awaited into the render path.\nexport type AgentFetchLog = {\n baseUrl: string; // API base ending in /v1\n apiKey: string; // public pk_ key\n path: string;\n botName: string;\n userAgent?: string;\n};\n\nexport function logAgentFetch(entry: AgentFetchLog, deps: { fetchImpl?: typeof fetch } = {}): void {\n const doFetch = deps.fetchImpl ?? fetch;\n try {\n void doFetch(`${entry.baseUrl}/crawler-events`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${entry.apiKey}` },\n body: JSON.stringify({\n path: entry.path,\n botName: entry.botName,\n userAgent: entry.userAgent ?? null,\n source: 'ssr',\n }),\n }).catch(() => {});\n } catch {\n /* never break render */\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"],"mappings":"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","names":["deriveSessionSegment","extractTrackedParams","matchedAgentToken","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","logAgentFetch","entry","deps","_a","_b","doFetch","e","matchedAgentToken","wantsMarkdown","url","accept","createAgentFeed","config","request","_a","userAgent","path","matchedAgentToken","e","feed","renderAgentMarkdown","matchedAgentToken","uaTokenMatch","agentIntent","classifiedAgents","Fragment","jsx","jsxs","DEFAULT_API_BASE_URL","assignmentsToBlocks","assignments","id","v","_a","AdaptiveRoot","props","_b","_c","_d","_e","_f","_g","_h","_i","components","sections","slots","appOrigin","searchParams","initialAssignmentsOverride","ssrSessionIdProp","timeoutMs","agentFeed","captureAgents","nonce","children","providerProps","__objRest","headerStore","headers","host","resolvedOrigin","userAgent","referer","utmParams","clickIds","extractTrackedParams","doNotTrack","sessionSegment","deriveSessionSegment","cookieStore","cookies","cf","consent","skipSsr","baseUrl","agentPath","agentBot","matchedAgentToken","logAgentFetch","initialAssignments","initialLayoutOrder","initialSlots","initialPersona","ssrSessionId","decision","loadAdaptiveDecision","result","loadAdaptiveAssignments","personaScript","SentientPersonaScript","client","AdaptiveRootClient","__spreadProps","__spreadValues","feed","buildAgentFeed","renderAgentJsonLdBody"]}
package/dist/server.d.cts CHANGED
@@ -25,6 +25,15 @@ type LoadAdaptiveAssignmentsOptions = {
25
25
  userAgent?: string;
26
26
  /** From Next.js `headers().get('referer')`. */
27
27
  referer?: string;
28
+ /**
29
+ * `utm_*` params from the landing URL. The Referer header never carries the
30
+ * page's OWN query string, so without this the SSR-minted session has no
31
+ * campaign attribution until the client SDK hydrates and re-upserts.
32
+ * Derive with `extractTrackedParams(searchParams)` from `@sentientui/core/server`.
33
+ */
34
+ utmParams?: Record<string, string>;
35
+ /** Ad-platform click IDs (gclid, fbclid, ttclid, …) from the landing URL — same derivation as `utmParams`. */
36
+ clickIds?: Record<string, string>;
28
37
  /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */
29
38
  doNotTrack?: boolean;
30
39
  /** 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). */
package/dist/server.d.ts CHANGED
@@ -25,6 +25,15 @@ type LoadAdaptiveAssignmentsOptions = {
25
25
  userAgent?: string;
26
26
  /** From Next.js `headers().get('referer')`. */
27
27
  referer?: string;
28
+ /**
29
+ * `utm_*` params from the landing URL. The Referer header never carries the
30
+ * page's OWN query string, so without this the SSR-minted session has no
31
+ * campaign attribution until the client SDK hydrates and re-upserts.
32
+ * Derive with `extractTrackedParams(searchParams)` from `@sentientui/core/server`.
33
+ */
34
+ utmParams?: Record<string, string>;
35
+ /** Ad-platform click IDs (gclid, fbclid, ttclid, …) from the landing URL — same derivation as `utmParams`. */
36
+ clickIds?: Record<string, string>;
28
37
  /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */
29
38
  doNotTrack?: boolean;
30
39
  /** 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). */
package/dist/server.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var K=Object.create;var c=Object.defineProperty,U=Object.defineProperties,_=Object.getOwnPropertyDescriptor,T=Object.getOwnPropertyDescriptors,w=Object.getOwnPropertyNames,k=Object.getOwnPropertySymbols,C=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty,M=Object.prototype.propertyIsEnumerable;var S=(e,s,t)=>s in e?c(e,s,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[s]=t,N=(e,s)=>{for(var t in s||(s={}))D.call(s,t)&&S(e,t,s[t]);if(k)for(var t of k(s))M.call(s,t)&&S(e,t,s[t]);return e},E=(e,s)=>U(e,T(s));var P=(e,s)=>{for(var t in s)c(e,t,{get:s[t],enumerable:!0})},O=(e,s,t,r)=>{if(s&&typeof s=="object"||typeof s=="function")for(let n of w(s))!D.call(e,n)&&n!==t&&c(e,n,{get:()=>s[n],enumerable:!(r=_(s,n))||r.enumerable});return e};var b=(e,s,t)=>(t=e!=null?K(C(e)):{},O(s||!e||!e.__esModule?c(t,"default",{value:e,enumerable:!0}):t,e)),h=e=>O(c({},"__esModule",{value:!0}),e);var G={};P(G,{loadAdaptiveAssignments:()=>V,loadAdaptiveDecision:()=>B,preloadAssignments:()=>i.preloadAssignments,preloadDecisions:()=>x.preloadDecisions,readSessionCookie:()=>i.readSessionCookie});module.exports=h(G);var i=require("@sentientui/core/server"),x=require("@sentientui/core/server");function R(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function V(e,s){var n,d,o;let t=(o=(d=(0,i.readSessionCookie)(s.cookies,s.apiKey))!=null?d:(n=s.createSessionId)==null?void 0:n.call(s))!=null?o:R();return{assignments:await(0,i.preloadAssignments)(e,t,{apiKey:s.apiKey,baseUrl:s.baseUrl,origin:s.origin,userAgent:s.userAgent,referer:s.referer,doNotTrack:s.doNotTrack,timeoutMs:s.timeoutMs,persona:s.persona}),sessionId:t}}async function B(e){var o,l,u,m,p,A,y,f,v,I;let{preloadDecisions:s,readSessionCookie:t}=await import("@sentientui/core/server"),r=(u=(l=t(e.cookies,e.apiKey))!=null?l:(o=e.createSessionId)==null?void 0:o.call(e))!=null?u:R();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let L={layoutOrder:(m=e.sections)!=null?m:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:r};try{let g=await import("@sentientui/core/local");if(!g.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."),L;let a=g.createLocalEngine({sessionId:r}).decide({sections:e.sections,components:(p=e.components)!=null?p:[],slots:(A=e.slots)!=null?A:[]});return{layoutOrder:(f=(y=a.layoutOrder)!=null?y:e.sections)!=null?f:[],assignments:a.assignments,slots:a.slots,persona:a.persona,confidence:a.confidence,sessionId:r}}catch(g){return L}}let d=await s({sections:e.sections,components:(v=e.components)!=null?v:[],slots:(I=e.slots)!=null?I:[]},r,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,doNotTrack:e.doNotTrack,timeoutMs:e.timeoutMs,persona:e.persona});return E(N({},d),{sessionId:r})}0&&(module.exports={loadAdaptiveAssignments,loadAdaptiveDecision,preloadAssignments,preloadDecisions,readSessionCookie});
1
+ "use strict";var K=Object.create;var c=Object.defineProperty,P=Object.defineProperties,U=Object.getOwnPropertyDescriptor,_=Object.getOwnPropertyDescriptors,T=Object.getOwnPropertyNames,L=Object.getOwnPropertySymbols,w=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty,C=Object.prototype.propertyIsEnumerable;var S=(e,s,r)=>s in e?c(e,s,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[s]=r,N=(e,s)=>{for(var r in s||(s={}))D.call(s,r)&&S(e,r,s[r]);if(L)for(var r of L(s))C.call(s,r)&&S(e,r,s[r]);return e},R=(e,s)=>P(e,_(s));var M=(e,s)=>{for(var r in s)c(e,r,{get:s[r],enumerable:!0})},E=(e,s,r,t)=>{if(s&&typeof s=="object"||typeof s=="function")for(let n of T(s))!D.call(e,n)&&n!==r&&c(e,n,{get:()=>s[n],enumerable:!(t=U(s,n))||t.enumerable});return e};var O=(e,s,r)=>(r=e!=null?K(w(e)):{},E(s||!e||!e.__esModule?c(r,"default",{value:e,enumerable:!0}):r,e)),h=e=>E(c({},"__esModule",{value:!0}),e);var G={};M(G,{loadAdaptiveAssignments:()=>V,loadAdaptiveDecision:()=>B,preloadAssignments:()=>i.preloadAssignments,preloadDecisions:()=>x.preloadDecisions,readSessionCookie:()=>i.readSessionCookie});module.exports=h(G);var i=require("@sentientui/core/server"),x=require("@sentientui/core/server");function b(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function V(e,s){var n,d,a;let r=(a=(d=(0,i.readSessionCookie)(s.cookies,s.apiKey))!=null?d:(n=s.createSessionId)==null?void 0:n.call(s))!=null?a:b();return{assignments:await(0,i.preloadAssignments)(e,r,{apiKey:s.apiKey,baseUrl:s.baseUrl,origin:s.origin,userAgent:s.userAgent,referer:s.referer,utmParams:s.utmParams,clickIds:s.clickIds,doNotTrack:s.doNotTrack,timeoutMs:s.timeoutMs,persona:s.persona}),sessionId:r}}async function B(e){var a,l,m,u,A,p,y,f,I,v;let{preloadDecisions:s,readSessionCookie:r}=await import("@sentientui/core/server"),t=(m=(l=r(e.cookies,e.apiKey))!=null?l:(a=e.createSessionId)==null?void 0:a.call(e))!=null?m:b();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let k={layoutOrder:(u=e.sections)!=null?u:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:t};try{let g=await import("@sentientui/core/local");if(!g.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."),k;let o=g.createLocalEngine({sessionId:t}).decide({sections:e.sections,components:(A=e.components)!=null?A:[],slots:(p=e.slots)!=null?p:[]});return{layoutOrder:(f=(y=o.layoutOrder)!=null?y:e.sections)!=null?f:[],assignments:o.assignments,slots:o.slots,persona:o.persona,confidence:o.confidence,sessionId:t}}catch(g){return k}}let d=await s({sections:e.sections,components:(I=e.components)!=null?I:[],slots:(v=e.slots)!=null?v:[]},t,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,utmParams:e.utmParams,clickIds:e.clickIds,doNotTrack:e.doNotTrack,timeoutMs:e.timeoutMs,persona:e.persona});return R(N({},d),{sessionId:t})}0&&(module.exports={loadAdaptiveAssignments,loadAdaptiveDecision,preloadAssignments,preloadDecisions,readSessionCookie});
2
2
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\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 /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */\n doNotTrack?: boolean;\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 * Declared persona — the role your app already knows for this visitor (e.g.\n * from your auth context: 'admin', 'evaluator'). Must be a key in the\n * project's persona vocabulary; unrecognized values are ignored server-side.\n * Never a user id or email.\n */\n persona?: string;\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 // apiKey is not optional here: the client writes the per-project suffixed\n // cookie, so an un-keyed read missed every returning visitor and minted a\n // fresh orphan session per SSR request (see readSessionCookie in core).\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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 // Keyed read — the client's cookie name is suffixed per project (see\n // loadAdaptiveAssignments above). Works for keyless too: with no pk_ key the\n // client writes the bare legacy name, which the un-suffixed read falls back to.\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\n },\n );\n\n return { ...result, sessionId };\n}\n"],"mappings":"i5BAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,6BAAAE,EAAA,yBAAAC,EAAA,+IAAAC,EAAAJ,GAGA,IAAAK,EAKO,mCA4EPA,EAAiC,mCAtCjC,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,CA7D1C,IAAAC,EAAAC,EAAAC,EAiEE,IAAMC,GACJD,GAAAD,KAAA,qBAAkBF,EAAQ,QAASA,EAAQ,MAAM,IAAjD,KAAAE,GACAD,EAAAD,EAAQ,kBAAR,YAAAC,EAAA,KAAAD,KADA,KAAAG,EAEAN,EAAiB,EAanB,MAAO,CAAE,YAXW,QAAM,sBAAmBE,EAAYK,EAAW,CAClE,OAAQJ,EAAQ,OAChB,QAASA,EAAQ,QACjB,OAAQA,EAAQ,OAChB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,QACjB,WAAYA,EAAQ,WACpB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,OACnB,CAAC,EAEqB,UAAAI,CAAU,CAClC,CAmCA,eAAsBC,EACpBL,EACqC,CAvHvC,IAAAC,EAAAC,EAAAC,EAAAG,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAwHE,GAAM,CAAE,iBAAAC,EAAkB,kBAAAC,CAAkB,EAAI,KAAM,QAAO,yBAAyB,EAKhFV,GACJD,GAAAD,EAAAY,EAAkBd,EAAQ,QAASA,EAAQ,MAAM,IAAjD,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,IAAMe,EAAuC,CAC3C,aAAaT,EAAAN,EAAQ,WAAR,KAAAM,EAAoB,CAAC,EAClC,YAAa,CAAC,EACd,MAAO,CAAC,EACR,QAAS,UACT,WAAY,EACZ,UAAAF,CACF,EACA,GAAI,CACF,IAAMY,EAAO,KAAM,QAAO,wBAAwB,EAgBlD,GAAI,CAACA,EAAI,uBAEP,eAAQ,MACN,mJACF,EACOD,EAET,IAAME,EAAUD,EAAI,kBAAkB,CAAE,UAAAZ,CAAU,CAAC,EAAE,OAAO,CAC1D,SAAUJ,EAAQ,SAClB,YAAYO,EAAAP,EAAQ,aAAR,KAAAO,EAAsB,CAAC,EACnC,OAAOC,EAAAR,EAAQ,QAAR,KAAAQ,EAAiB,CAAC,CAC3B,CAAC,EACD,MAAO,CACL,aAAaE,GAAAD,EAAAQ,EAAQ,cAAR,KAAAR,EAAuBT,EAAQ,WAA/B,KAAAU,EAA2C,CAAC,EACzD,YAAaO,EAAQ,YACrB,MAAOA,EAAQ,MACf,QAASA,EAAQ,QACjB,WAAYA,EAAQ,WACpB,UAAAb,CACF,CACF,OAAQc,EAAA,CACN,OAAOH,CACT,CACF,CAEA,IAAMI,EAAS,MAAMN,EACnB,CACE,SAAUb,EAAQ,SAClB,YAAYW,EAAAX,EAAQ,aAAR,KAAAW,EAAsB,CAAC,EACnC,OAAOC,EAAAZ,EAAQ,QAAR,KAAAY,EAAiB,CAAC,CAC3B,EACAR,EACA,CACE,OAAQJ,EAAQ,OAChB,QAASA,EAAQ,QACjB,OAAQA,EAAQ,OAChB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,QACjB,WAAYA,EAAQ,WACpB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,OACnB,CACF,EAEA,OAAOoB,EAAAC,EAAA,GAAKF,GAAL,CAAa,UAAAf,CAAU,EAChC","names":["server_exports","__export","loadAdaptiveAssignments","loadAdaptiveDecision","__toCommonJS","import_server","defaultSessionId","loadAdaptiveAssignments","components","options","_a","_b","_c","sessionId","loadAdaptiveDecision","_d","_e","_f","_g","_h","_i","_j","preloadDecisions","readSessionCookie","fallback","mod","outcome","e","result","__spreadProps","__spreadValues"]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\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 /**\n * `utm_*` params from the landing URL. The Referer header never carries the\n * page's OWN query string, so without this the SSR-minted session has no\n * campaign attribution until the client SDK hydrates and re-upserts.\n * Derive with `extractTrackedParams(searchParams)` from `@sentientui/core/server`.\n */\n utmParams?: Record<string, string>;\n /** Ad-platform click IDs (gclid, fbclid, ttclid, …) from the landing URL — same derivation as `utmParams`. */\n clickIds?: Record<string, string>;\n /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */\n doNotTrack?: boolean;\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 * Declared persona — the role your app already knows for this visitor (e.g.\n * from your auth context: 'admin', 'evaluator'). Must be a key in the\n * project's persona vocabulary; unrecognized values are ignored server-side.\n * Never a user id or email.\n */\n persona?: string;\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 // apiKey is not optional here: the client writes the per-project suffixed\n // cookie, so an un-keyed read missed every returning visitor and minted a\n // fresh orphan session per SSR request (see readSessionCookie in core).\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 utmParams: options.utmParams,\n clickIds: options.clickIds,\n doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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 // Keyed read — the client's cookie name is suffixed per project (see\n // loadAdaptiveAssignments above). Works for keyless too: with no pk_ key the\n // client writes the bare legacy name, which the un-suffixed read falls back to.\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 utmParams: options.utmParams,\n clickIds: options.clickIds,\n doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\n },\n );\n\n return { ...result, sessionId };\n}\n"],"mappings":"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","names":["server_exports","__export","loadAdaptiveAssignments","loadAdaptiveDecision","__toCommonJS","import_server","defaultSessionId","loadAdaptiveAssignments","components","options","_a","_b","_c","sessionId","loadAdaptiveDecision","_d","_e","_f","_g","_h","_i","_j","preloadDecisions","readSessionCookie","fallback","mod","outcome","e","result","__spreadProps","__spreadValues"]}
package/dist/server.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var N=Object.defineProperty,E=Object.defineProperties;var O=Object.getOwnPropertyDescriptors;var I=Object.getOwnPropertySymbols;var b=Object.prototype.hasOwnProperty,R=Object.prototype.propertyIsEnumerable;var L=(e,s,t)=>s in e?N(e,s,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[s]=t,k=(e,s)=>{for(var t in s||(s={}))b.call(s,t)&&L(e,t,s[t]);if(I)for(var t of I(s))R.call(s,t)&&L(e,t,s[t]);return e},S=(e,s)=>E(e,O(s));import{preloadAssignments as x,readSessionCookie as K}from"@sentientui/core/server";import{preloadDecisions as P}from"@sentientui/core/server";function D(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function T(e,s){var a,o,n;let t=(n=(o=K(s.cookies,s.apiKey))!=null?o:(a=s.createSessionId)==null?void 0:a.call(s))!=null?n:D();return{assignments:await x(e,t,{apiKey:s.apiKey,baseUrl:s.baseUrl,origin:s.origin,userAgent:s.userAgent,referer:s.referer,doNotTrack:s.doNotTrack,timeoutMs:s.timeoutMs,persona:s.persona}),sessionId:t}}async function w(e){var n,d,g,l,u,m,p,A,y,f;let{preloadDecisions:s,readSessionCookie:t}=await import("@sentientui/core/server"),r=(g=(d=t(e.cookies,e.apiKey))!=null?d:(n=e.createSessionId)==null?void 0:n.call(e))!=null?g:D();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let v={layoutOrder:(l=e.sections)!=null?l:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:r};try{let c=await import("@sentientui/core/local");if(!c.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."),v;let i=c.createLocalEngine({sessionId:r}).decide({sections:e.sections,components:(u=e.components)!=null?u:[],slots:(m=e.slots)!=null?m:[]});return{layoutOrder:(A=(p=i.layoutOrder)!=null?p:e.sections)!=null?A:[],assignments:i.assignments,slots:i.slots,persona:i.persona,confidence:i.confidence,sessionId:r}}catch(c){return v}}let o=await s({sections:e.sections,components:(y=e.components)!=null?y:[],slots:(f=e.slots)!=null?f:[]},r,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,doNotTrack:e.doNotTrack,timeoutMs:e.timeoutMs,persona:e.persona});return S(k({},o),{sessionId:r})}export{T as loadAdaptiveAssignments,w as loadAdaptiveDecision,x as preloadAssignments,P as preloadDecisions,K as readSessionCookie};
1
+ var N=Object.defineProperty,R=Object.defineProperties;var E=Object.getOwnPropertyDescriptors;var v=Object.getOwnPropertySymbols;var O=Object.prototype.hasOwnProperty,b=Object.prototype.propertyIsEnumerable;var k=(e,s,r)=>s in e?N(e,s,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[s]=r,L=(e,s)=>{for(var r in s||(s={}))O.call(s,r)&&k(e,r,s[r]);if(v)for(var r of v(s))b.call(s,r)&&k(e,r,s[r]);return e},S=(e,s)=>R(e,E(s));import{preloadAssignments as x,readSessionCookie as K}from"@sentientui/core/server";import{preloadDecisions as M}from"@sentientui/core/server";function D(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`snt-${Date.now()}-${Math.random().toString(36).slice(2,11)}`}async function _(e,s){var o,a,n;let r=(n=(a=K(s.cookies,s.apiKey))!=null?a:(o=s.createSessionId)==null?void 0:o.call(s))!=null?n:D();return{assignments:await x(e,r,{apiKey:s.apiKey,baseUrl:s.baseUrl,origin:s.origin,userAgent:s.userAgent,referer:s.referer,utmParams:s.utmParams,clickIds:s.clickIds,doNotTrack:s.doNotTrack,timeoutMs:s.timeoutMs,persona:s.persona}),sessionId:r}}async function T(e){var n,d,g,l,m,u,A,p,y,f;let{preloadDecisions:s,readSessionCookie:r}=await import("@sentientui/core/server"),t=(g=(d=r(e.cookies,e.apiKey))!=null?d:(n=e.createSessionId)==null?void 0:n.call(e))!=null?g:D();if(!(typeof e.apiKey=="string"&&e.apiKey.startsWith("pk_"))){let I={layoutOrder:(l=e.sections)!=null?l:[],assignments:{},slots:{},persona:"unknown",confidence:0,sessionId:t};try{let c=await import("@sentientui/core/local");if(!c.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."),I;let i=c.createLocalEngine({sessionId:t}).decide({sections:e.sections,components:(m=e.components)!=null?m:[],slots:(u=e.slots)!=null?u:[]});return{layoutOrder:(p=(A=i.layoutOrder)!=null?A:e.sections)!=null?p:[],assignments:i.assignments,slots:i.slots,persona:i.persona,confidence:i.confidence,sessionId:t}}catch(c){return I}}let a=await s({sections:e.sections,components:(y=e.components)!=null?y:[],slots:(f=e.slots)!=null?f:[]},t,{apiKey:e.apiKey,baseUrl:e.baseUrl,origin:e.origin,userAgent:e.userAgent,referer:e.referer,utmParams:e.utmParams,clickIds:e.clickIds,doNotTrack:e.doNotTrack,timeoutMs:e.timeoutMs,persona:e.persona});return S(L({},a),{sessionId:t})}export{_ as loadAdaptiveAssignments,T as loadAdaptiveDecision,x as preloadAssignments,M as preloadDecisions,K as readSessionCookie};
2
2
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\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 /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */\n doNotTrack?: boolean;\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 * Declared persona — the role your app already knows for this visitor (e.g.\n * from your auth context: 'admin', 'evaluator'). Must be a key in the\n * project's persona vocabulary; unrecognized values are ignored server-side.\n * Never a user id or email.\n */\n persona?: string;\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 // apiKey is not optional here: the client writes the per-project suffixed\n // cookie, so an un-keyed read missed every returning visitor and minted a\n // fresh orphan session per SSR request (see readSessionCookie in core).\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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 // Keyed read — the client's cookie name is suffixed per project (see\n // loadAdaptiveAssignments above). Works for keyless too: with no pk_ key the\n // client writes the bare legacy name, which the un-suffixed read falls back to.\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\n },\n );\n\n return { ...result, sessionId };\n}\n"],"mappings":"6aAGA,OACE,sBAAAA,EACA,qBAAAC,MAGK,0BA4EP,OAAS,oBAAAC,MAAwB,0BAtCjC,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,CA7D1C,IAAAC,EAAAC,EAAAC,EAiEE,IAAMC,GACJD,GAAAD,EAAAG,EAAkBL,EAAQ,QAASA,EAAQ,MAAM,IAAjD,KAAAE,GACAD,EAAAD,EAAQ,kBAAR,YAAAC,EAAA,KAAAD,KADA,KAAAG,EAEAN,EAAiB,EAanB,MAAO,CAAE,YAXW,MAAMS,EAAmBP,EAAYK,EAAW,CAClE,OAAQJ,EAAQ,OAChB,QAASA,EAAQ,QACjB,OAAQA,EAAQ,OAChB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,QACjB,WAAYA,EAAQ,WACpB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,OACnB,CAAC,EAEqB,UAAAI,CAAU,CAClC,CAmCA,eAAsBG,EACpBP,EACqC,CAvHvC,IAAAC,EAAAC,EAAAC,EAAAK,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAwHE,GAAM,CAAE,iBAAAC,EAAkB,kBAAAV,CAAkB,EAAI,KAAM,QAAO,yBAAyB,EAKhFD,GACJD,GAAAD,EAAAG,EAAkBL,EAAQ,QAASA,EAAQ,MAAM,IAAjD,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,WAAYA,EAAQ,WACpB,UAAWA,EAAQ,UACnB,QAASA,EAAQ,OACnB,CACF,EAEA,OAAOqB,EAAAC,EAAA,GAAKF,GAAL,CAAa,UAAAhB,CAAU,EAChC","names":["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"]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\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 /**\n * `utm_*` params from the landing URL. The Referer header never carries the\n * page's OWN query string, so without this the SSR-minted session has no\n * campaign attribution until the client SDK hydrates and re-upserts.\n * Derive with `extractTrackedParams(searchParams)` from `@sentientui/core/server`.\n */\n utmParams?: Record<string, string>;\n /** Ad-platform click IDs (gclid, fbclid, ttclid, …) from the landing URL — same derivation as `utmParams`. */\n clickIds?: Record<string, string>;\n /** Set true when the request carries `DNT: 1` or `Sec-GPC: 1` — skips the SSR session upsert + assignment so no session is minted for an opted-out visitor (audit P4). `AdaptiveRoot` sets this automatically from the request headers. */\n doNotTrack?: boolean;\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 * Declared persona — the role your app already knows for this visitor (e.g.\n * from your auth context: 'admin', 'evaluator'). Must be a key in the\n * project's persona vocabulary; unrecognized values are ignored server-side.\n * Never a user id or email.\n */\n persona?: string;\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 // apiKey is not optional here: the client writes the per-project suffixed\n // cookie, so an un-keyed read missed every returning visitor and minted a\n // fresh orphan session per SSR request (see readSessionCookie in core).\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 utmParams: options.utmParams,\n clickIds: options.clickIds,\n doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\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 // Keyed read — the client's cookie name is suffixed per project (see\n // loadAdaptiveAssignments above). Works for keyless too: with no pk_ key the\n // client writes the bare legacy name, which the un-suffixed read falls back to.\n const sessionId =\n readSessionCookie(options.cookies, options.apiKey) ??\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 utmParams: options.utmParams,\n clickIds: options.clickIds,\n doNotTrack: options.doNotTrack,\n timeoutMs: options.timeoutMs,\n persona: options.persona,\n },\n );\n\n return { ...result, sessionId };\n}\n"],"mappings":"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","names":["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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentientui/react",
3
- "version": "0.25.1",
3
+ "version": "0.26.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
@@ -74,7 +74,7 @@
74
74
  "llms.txt"
75
75
  ],
76
76
  "dependencies": {
77
- "@sentientui/core": "0.23.0",
77
+ "@sentientui/core": "0.24.0",
78
78
  "@sentientui/policy": "0.8.0"
79
79
  },
80
80
  "peerDependencies": {