@sentientui/react 0.12.1 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -45
- package/dist/devtools.d.cts +2 -1
- package/dist/devtools.d.ts +2 -1
- package/dist/devtools.js +1 -1
- package/dist/devtools.js.map +1 -1
- package/dist/devtools.mjs +1 -1
- package/dist/devtools.mjs.map +1 -1
- package/dist/index.d.cts +142 -2
- package/dist/index.d.ts +142 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/next/adaptive-root.d.ts +36 -2
- package/dist/next/adaptive-root.js +2 -2
- package/dist/next/adaptive-root.js.map +1 -1
- package/dist/server.d.cts +17 -5
- package/dist/server.d.ts +17 -5
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +1 -1
- package/dist/server.mjs.map +1 -1
- package/dist/testing/node.d.cts +5 -0
- package/dist/testing/node.d.ts +5 -0
- package/dist/testing/node.js +1 -1
- package/dist/testing/node.js.map +1 -1
- package/dist/testing/node.mjs +1 -1
- package/dist/testing/node.mjs.map +1 -1
- package/dist/testing.d.cts +15 -5
- package/dist/testing.d.ts +15 -5
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/testing.mjs.map +1 -1
- package/llms.txt +45 -0
- package/package.json +6 -3
package/dist/devtools.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/devtools/index.tsx","../src/devtools-registry.ts","../src/devtools-overrides.ts","../src/preview-mode.ts"],"sourcesContent":["'use client';\nimport { useEffect, useReducer, useState } from 'react';\nimport { getRegistered, subscribeRegistry } from '../devtools-registry.js';\nimport { setVariantOverride, clearVariantOverride, getOverrides } from '../devtools-overrides.js';\nimport { setPreviewMode, getPreviewMode } from '../preview-mode.js';\n\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\nconst IS_PROD = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production';\n\nconst SEED_PERSONAS = ['browsers', 'buyers', 'researchers', 'deal-seekers'];\n\n/** Simulate a persona via /v1/explain (read-only) and apply the result as overrides. */\nasync function forcePersona(apiKey: string, persona: string): Promise<void> {\n const sections = getRegistered().map((c) => ({ id: c.id }));\n const components = getRegistered().map((c) => ({ id: c.id, variantIds: c.variantIds }));\n const res = await fetch('/v1/explain', {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },\n body: JSON.stringify({ persona, sections, components }),\n });\n if (!res.ok) return;\n const data = (await res.json()) as { assignments: Record<string, string> };\n for (const [id, variantId] of Object.entries(data.assignments)) setVariantOverride(id, variantId);\n setPreviewMode(true);\n}\n\nexport function AdaptiveDevtools({ apiKey }: { apiKey?: string } = {}): JSX.Element | null {\n const [open, setOpen] = useState(false);\n const [, force] = useReducer((n: number) => n + 1, 0);\n useEffect(() => subscribeRegistry(force), []);\n\n // Never render in production, even if imported by mistake. (Hooks run first\n // so the rules of hooks hold regardless of this compile-time constant.)\n if (IS_PROD) return null;\n\n const components = getRegistered();\n const overrides = getOverrides();\n\n function choose(id: string, variantId: string): void {\n setVariantOverride(id, variantId);\n setPreviewMode(true); // suppress events while previewing\n force();\n }\n function reset(id: string): void {\n clearVariantOverride(id);\n if (Object.keys(getOverrides()).length === 0) setPreviewMode(false);\n force();\n }\n\n return (\n <div style={{ position: 'fixed', bottom: 16, right: 16, zIndex: 2147483647, fontFamily: 'system-ui' }}>\n {open && (\n <div style={{ width: 300, maxHeight: 420, overflowY: 'auto', background: '#111', color: '#eee',\n borderRadius: 8, padding: 12, marginBottom: 8, boxShadow: '0 8px 30px rgba(0,0,0,.4)', fontSize: 12 }}>\n <div style={{ opacity: .7, marginBottom: 8 }}>\n {components.length} component{components.length === 1 ? '' : 's'} · {getPreviewMode() ? 'preview — writing nothing' : 'live'}\n </div>\n {apiKey && (\n <div style={{ borderBottom: '1px solid #333', paddingBottom: 8, marginBottom: 8 }}>\n <div style={{ opacity: .7, marginBottom: 4 }}>Preview persona</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {SEED_PERSONAS.map((p) => (\n <button key={p} onClick={() => void forcePersona(apiKey, p).then(force)}\n style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #444', background: '#222', color: '#eee', cursor: 'pointer' }}>\n {p}\n </button>\n ))}\n </div>\n </div>\n )}\n {components.length === 0 && <div style={{ opacity: .6 }}>No components on this page yet.</div>}\n {components.map((c) => (\n <div key={c.id} style={{ borderTop: '1px solid #333', padding: '8px 0' }}>\n <div style={{ fontWeight: 600 }}>{c.id}{c.goal ? ` · goal: ${c.goal}` : ''}</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>\n {c.variantIds.map((v) => (\n <button key={v} onClick={() => choose(c.id, v)}\n style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #444',\n background: overrides[c.id] === v ? '#3b82f6' : '#222', color: '#eee', cursor: 'pointer' }}>\n {v}\n </button>\n ))}\n {overrides[c.id] && (\n <button onClick={() => reset(c.id)}\n style={{ padding: '2px 8px', borderRadius: 4, border: '1px solid #444', background: '#222', color: '#aaa', cursor: 'pointer' }}>\n reset\n </button>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n <button aria-label=\"Sentient DevTools\" onClick={() => setOpen((o) => !o)}\n style={{ width: 40, height: 40, borderRadius: 20, border: 'none', background: '#3b82f6', color: '#fff',\n cursor: 'pointer', boxShadow: '0 4px 14px rgba(0,0,0,.3)' }}>◧</button>\n </div>\n );\n}\n","export type RegisteredComponent = { id: string; variantIds: string[]; goal?: string };\n\nconst registry = new Map<string, RegisteredComponent>();\nconst listeners = new Set<() => void>();\n\nfunction emit(): void {\n for (const fn of listeners) fn();\n}\n\n/** Register (or re-register) a component. Returns an unregister function. */\nexport function registerComponent(c: RegisteredComponent): () => void {\n registry.set(c.id, c);\n emit();\n return () => {\n registry.delete(c.id);\n emit();\n };\n}\n\nexport function getRegistered(): RegisteredComponent[] {\n return [...registry.values()];\n}\n\nexport function subscribeRegistry(fn: () => void): () => void {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n","function store(): Record<string, string> {\n const w = window as unknown as { __sentient_overrides?: Record<string, string> };\n if (!w.__sentient_overrides) w.__sentient_overrides = {};\n return w.__sentient_overrides;\n}\n\n/** Force `componentId` to render `variantId` — read by `useAssignment`. */\nexport function setVariantOverride(componentId: string, variantId: string): void {\n store()[componentId] = variantId;\n}\n\nexport function clearVariantOverride(componentId: string): void {\n delete store()[componentId];\n}\n\nexport function getOverrides(): Record<string, string> {\n return { ...store() };\n}\n","import type { SentientClient } from '@sentientui/core';\n\nlet previewOn = false;\nconst listeners = new Set<() => void>();\n\nexport function setPreviewMode(on: boolean): void {\n if (previewOn === on) return;\n previewOn = on;\n for (const fn of listeners) fn();\n}\n\nexport function getPreviewMode(): boolean {\n return previewOn;\n}\n\nexport function subscribePreview(fn: () => void): () => void {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/**\n * Wraps a client so it writes nothing: reads pass through, all emitters no-op.\n * Used while previewing variants/personas so no `variant_assigned`, goal, or\n * session events are sent.\n */\nexport function createPreviewClient(inner: SentientClient): SentientClient {\n return {\n track: () => undefined,\n goal: () => undefined,\n componentGoal: () => undefined,\n identify: () => undefined,\n fetchWeights: () => Promise.resolve([]),\n getAssignment: (componentId, segment) => inner.getAssignment(componentId, segment),\n assign: (componentId, variantIds, agentData, agentDataByVariant) =>\n inner.assign(componentId, variantIds, agentData, agentDataByVariant),\n getGraph: () => inner.getGraph(),\n destroy: () => inner.destroy(),\n };\n}\n"],"mappings":"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","names":["useEffect","useReducer","useState","registry","listeners","getRegistered","registry","subscribeRegistry","fn","listeners","store","w","setVariantOverride","componentId","variantId","clearVariantOverride","getOverrides","__spreadValues","previewOn","listeners","setPreviewMode","on","fn","getPreviewMode","jsx","jsxs","_a","IS_PROD","SEED_PERSONAS","forcePersona","apiKey","persona","sections","getRegistered","c","components","res","data","id","variantId","setVariantOverride","setPreviewMode","AdaptiveDevtools","open","setOpen","useState","force","useReducer","n","useEffect","subscribeRegistry","overrides","getOverrides","choose","reset","clearVariantOverride","getPreviewMode","p","v","o"]}
|
|
1
|
+
{"version":3,"sources":["../src/devtools/index.tsx","../src/devtools-registry.ts","../src/devtools-overrides.ts","../src/devtools-slot-overrides.ts","../src/preview-mode.ts","../src/override-events.ts","../src/devtools-config.ts"],"sourcesContent":["'use client';\nimport { useEffect, useReducer, useState, type CSSProperties } from 'react';\nimport { PERSONAS, PERSONA_DISPLAY, confidenceBand } from '@sentientui/policy';\nimport { SNAPSHOT_STORAGE_KEY_PREFIX } from '@sentientui/core';\nimport {\n getRegistered,\n getRegisteredSlots,\n getRegisteredSections,\n subscribeRegistry,\n type RegisteredSlot,\n} from '../devtools-registry.js';\nimport { setVariantOverride, clearVariantOverride, getOverrides } from '../devtools-overrides.js';\nimport { setSlotOverride, clearSlotOverride, getSlotOverrides } from '../devtools-slot-overrides.js';\nimport { setPreviewMode, getPreviewMode } from '../preview-mode.js';\nimport { notifyOverridesChanged } from '../override-events.js';\nimport { readDevtoolsConfig, type DevtoolsConfig } from '../devtools-config.js';\n\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\nconst IS_PROD = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production';\nconst DEFAULT_API_BASE_URL = 'https://api.sentient-ui.com/v1';\n\nexport const LOCAL_MODE_DEVTOOLS_BANNER =\n 'Local mode — decisions are simulated; add a key to learn from real traffic';\n\ntype OutcomeToApply = {\n assignments?: Record<string, string>;\n layoutOrder?: string[] | null;\n slots?: Record<string, string | Record<string, string>>;\n personaAttributes?: { persona: string; confidence: 'low' | 'medium' | 'high' };\n};\n\ntype OverrideWindow = Window & {\n __sentient_layout_override?: string[];\n __sentient_slot_overrides?: Record<string, string | Record<string, string>>;\n};\n\n/** Apply a simulated outcome across every surface: variants, layout, slots/tokens, persona attrs. */\nfunction applyOutcome(result: OutcomeToApply): void {\n for (const [id, variantId] of Object.entries(result.assignments ?? {})) {\n setVariantOverride(id, variantId);\n }\n const w = window as unknown as OverrideWindow;\n if (result.layoutOrder && result.layoutOrder.length > 0) {\n w.__sentient_layout_override = result.layoutOrder;\n }\n if (result.slots) {\n w.__sentient_slot_overrides = { ...(w.__sentient_slot_overrides ?? {}), ...result.slots };\n }\n if (result.personaAttributes) {\n document.documentElement.dataset.sentientPersona = result.personaAttributes.persona;\n document.documentElement.dataset.sentientConfidence = result.personaAttributes.confidence;\n }\n setPreviewMode(true); // suppress events while previewing\n notifyOverridesChanged(); // re-render layout/slot consumers\n}\n\nfunction readSessionId(): string {\n try {\n const match = document.cookie.match(/(?:^|; )_snt_uid=([^;]*)/);\n if (match) return decodeURIComponent(match[1]);\n } catch {\n /* ignore */\n }\n return 'devtools-preview';\n}\n\nfunction slotDecls(): Array<{ id: string; arms?: string[]; dims?: RegisteredSlot['dims'] }> {\n return getRegisteredSlots().map((s) => ({\n id: s.id,\n ...(s.arms ? { arms: s.arms } : {}),\n ...(s.dims ? { dims: s.dims } : {}),\n }));\n}\n\n/** Keyed mode: simulate via /v1/explain (read-only, event-free). */\nasync function forcePersonaKeyed(apiKey: string, apiBaseUrl: string, persona: string): Promise<void> {\n const res = await fetch(`${apiBaseUrl}/explain`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },\n body: JSON.stringify({\n persona,\n sections: getRegisteredSections().map((id) => ({ id })),\n components: getRegistered().map((c) => ({ id: c.id, variantIds: c.variantIds })),\n slots: slotDecls(),\n }),\n });\n if (!res.ok) return;\n const data = (await res.json()) as OutcomeToApply;\n applyOutcome({\n ...data,\n personaAttributes: data.personaAttributes ?? { persona, confidence: 'high' },\n });\n}\n\n/** Local mode: simulate via the deterministic local engine — zero network. */\nasync function forcePersonaLocal(persona: string): Promise<void> {\n const mod = await import('@sentientui/core/local');\n if (!mod.LOCAL_ENGINE_AVAILABLE) return;\n const outcome = mod\n .createLocalEngine({ sessionId: readSessionId(), forcedPersona: persona })\n .decide({\n sections: getRegisteredSections(),\n components: getRegistered().map((c) => ({ id: c.id, variantIds: c.variantIds })),\n slots: slotDecls(),\n });\n applyOutcome({\n assignments: outcome.assignments,\n layoutOrder: outcome.layoutOrder,\n slots: outcome.slots,\n personaAttributes: {\n persona: outcome.persona,\n confidence: confidenceBand(outcome.confidence),\n },\n });\n}\n\n/** Reset: clear the decision snapshot + every override, then reload to re-decide. */\nfunction resetAll(): void {\n for (const id of Object.keys(getOverrides())) clearVariantOverride(id);\n const w = window as unknown as OverrideWindow;\n delete w.__sentient_layout_override;\n delete w.__sentient_slot_overrides;\n delete document.documentElement.dataset.sentientPersona;\n delete document.documentElement.dataset.sentientConfidence;\n try {\n const stale: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key && key.startsWith(SNAPSHOT_STORAGE_KEY_PREFIX)) stale.push(key);\n }\n for (const key of stale) localStorage.removeItem(key);\n } catch {\n /* ignore */\n }\n setPreviewMode(false);\n notifyOverridesChanged();\n try {\n window.location.reload();\n } catch {\n /* jsdom */\n }\n}\n\nconst btn = (active: boolean): CSSProperties => ({\n padding: '2px 8px',\n borderRadius: 4,\n border: '1px solid #444',\n background: active ? '#3b82f6' : '#222',\n color: '#eee',\n cursor: 'pointer',\n});\n\n/** Sentient \"S.\" wordmark, monoline — white strokes for the black launcher button. */\nfunction SentientMark({ size = 26 }: { size?: number } = {}): JSX.Element {\n return (\n <svg width={size} height={size} viewBox=\"0 0 32 32\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M21 9H14C11.2 9 9.8 10.8 9.8 13C9.8 15.4 11.6 16.6 14.5 16.6H18.5C20.5 16.6 20.7 18.2 20.4 19.6\"\n stroke=\"#fff\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path d=\"M10 22H17\" stroke=\"#fff\" strokeWidth=\"2.2\" strokeLinecap=\"round\" />\n <circle cx=\"20.6\" cy=\"22\" r=\"2.1\" fill=\"#fff\" />\n </svg>\n );\n}\n\nexport function AdaptiveDevtools({ apiKey }: { apiKey?: string } = {}): JSX.Element | null {\n const [open, setOpen] = useState(false);\n const [activePersona, setActivePersona] = useState<string | null>(null);\n const [mounted, setMounted] = useState(false);\n const [, force] = useReducer((n: number) => n + 1, 0);\n useEffect(() => subscribeRegistry(force), []);\n // Client-mount gate: render nothing during SSR / the first paint so the widget\n // never reads `window` on the server. Lets consumers drop `<AdaptiveDevtools/>`\n // straight into a tree without a `dynamic(..., { ssr: false })` wrapper.\n useEffect(() => setMounted(true), []);\n\n // Never render in production, even if imported by mistake. (Hooks run first\n // so the rules of hooks hold regardless of these early returns.)\n if (IS_PROD) return null;\n if (!mounted) return null;\n\n const config: DevtoolsConfig = readDevtoolsConfig() ?? {\n apiKey: apiKey ?? '',\n apiBaseUrl: DEFAULT_API_BASE_URL,\n isLocal: false,\n };\n const useLocalEngine = config.isLocal || !config.apiKey;\n const components = getRegistered();\n const slots = getRegisteredSlots();\n const overrides = getOverrides();\n const slotOverrides = getSlotOverrides();\n\n // Preview mode stays on while ANY override (variant or slot) is active.\n function maybeExitPreview(): void {\n if (Object.keys(getOverrides()).length === 0 && Object.keys(getSlotOverrides()).length === 0) {\n setPreviewMode(false);\n }\n }\n\n function choose(id: string, variantId: string): void {\n setVariantOverride(id, variantId);\n setPreviewMode(true);\n notifyOverridesChanged();\n force();\n }\n function resetVariant(id: string): void {\n clearVariantOverride(id);\n maybeExitPreview();\n notifyOverridesChanged();\n force();\n }\n function chooseSlotArm(id: string, arm: string): void {\n setSlotOverride(id, arm);\n setPreviewMode(true);\n notifyOverridesChanged();\n force();\n }\n function chooseSlotDim(id: string, dim: string, value: string, dims: RegisteredSlot['dims']): void {\n const current = getSlotOverrides()[id];\n // Merge onto the existing forced object, or seed from each dim's baseline\n // (first value) so unset dims stay at baseline instead of vanishing.\n const next: Record<string, string> =\n current && typeof current === 'object'\n ? { ...current }\n : Object.fromEntries(Object.entries(dims ?? {}).map(([d, values]) => [d, values[0]!]));\n next[dim] = value;\n setSlotOverride(id, next);\n setPreviewMode(true);\n notifyOverridesChanged();\n force();\n }\n function resetSlot(id: string): void {\n clearSlotOverride(id);\n maybeExitPreview();\n notifyOverridesChanged();\n force();\n }\n function choosePersona(persona: string): void {\n setActivePersona(persona);\n const apply = useLocalEngine\n ? forcePersonaLocal(persona)\n : forcePersonaKeyed(config.apiKey, config.apiBaseUrl, persona);\n void apply.then(force);\n }\n\n return (\n <div style={{ position: 'fixed', bottom: 16, right: 16, zIndex: 2147483647, fontFamily: 'system-ui' }}>\n {/* Panel stays mounted and animates in/out from the button's corner, so the\n launcher below never shifts. transform-origin is the button (bottom-right). */}\n <div\n aria-hidden={!open}\n style={{\n position: 'absolute',\n bottom: 52,\n right: 0,\n transformOrigin: 'bottom right',\n transition: 'opacity .18s ease, transform .2s cubic-bezier(.16,1,.3,1)',\n opacity: open ? 1 : 0,\n transform: open ? 'translateY(0) scale(1)' : 'translateY(6px) scale(.96)',\n pointerEvents: open ? 'auto' : 'none',\n }}\n >\n <div style={{ width: 300, maxHeight: 460, overflowY: 'auto', background: '#111', color: '#eee',\n borderRadius: 8, padding: 12, boxShadow: '0 8px 30px rgba(0,0,0,.4)', fontSize: 12 }}>\n {config.isLocal && (\n <div style={{ background: '#1e293b', border: '1px solid #334155', borderRadius: 4,\n padding: '6px 8px', marginBottom: 8 }}>\n {LOCAL_MODE_DEVTOOLS_BANNER}\n </div>\n )}\n <div style={{ opacity: .7, marginBottom: 8 }}>\n {components.length} component{components.length === 1 ? '' : 's'} · {getPreviewMode() ? 'preview — writing nothing' : 'live'}\n </div>\n <div style={{ borderBottom: '1px solid #333', paddingBottom: 8, marginBottom: 8 }}>\n <div style={{ opacity: .7, marginBottom: 4 }}>Preview persona</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {PERSONAS.map((p) => (\n <button key={p} onClick={() => choosePersona(p)} style={btn(activePersona === p)}>\n {PERSONA_DISPLAY[p]}\n </button>\n ))}\n {(activePersona !== null || Object.keys(overrides).length > 0 || Object.keys(slotOverrides).length > 0) && (\n <button onClick={resetAll} style={{ ...btn(false), color: '#aaa' }}>\n Reset\n </button>\n )}\n </div>\n </div>\n {components.length === 0 && slots.length === 0 && (\n <div style={{ opacity: .6 }}>No components or slots on this page yet.</div>\n )}\n {components.map((c) => (\n <div key={c.id} style={{ borderTop: '1px solid #333', padding: '8px 0' }}>\n <div style={{ fontWeight: 600 }}>{c.id}{c.goal ? ` · goal: ${c.goal}` : ''}</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>\n {c.variantIds.map((v) => (\n <button key={v} onClick={() => choose(c.id, v)} style={btn(overrides[c.id] === v)}>\n {v}\n </button>\n ))}\n {overrides[c.id] && (\n <button onClick={() => resetVariant(c.id)} style={{ ...btn(false), color: '#aaa' }}>\n reset\n </button>\n )}\n </div>\n </div>\n ))}\n {slots.length > 0 && (\n <div style={{ borderTop: '1px solid #333', paddingTop: 8, marginTop: 4 }}>\n <div style={{ opacity: .7, marginBottom: 4 }}>Slots</div>\n {slots.map((s) => {\n const ov = slotOverrides[s.id];\n return (\n <div key={s.id} style={{ padding: '6px 0' }}>\n <div style={{ fontWeight: 600 }}>{s.id}</div>\n {s.arms && (\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>\n {s.arms.map((arm) => (\n <button key={arm} onClick={() => chooseSlotArm(s.id, arm)} style={btn(ov === arm)}>\n {arm}\n </button>\n ))}\n </div>\n )}\n {s.dims && Object.entries(s.dims).map(([dim, values]) => (\n <div key={dim} style={{ marginTop: 4 }}>\n <div style={{ opacity: .6, fontSize: 11 }}>{dim}</div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>\n {values.map((v) => (\n <button\n key={v}\n onClick={() => chooseSlotDim(s.id, dim, v, s.dims)}\n style={btn(!!ov && typeof ov === 'object' && ov[dim] === v)}\n >\n {v}\n </button>\n ))}\n </div>\n </div>\n ))}\n {ov !== undefined && (\n <button onClick={() => resetSlot(s.id)} style={{ ...btn(false), color: '#aaa', marginTop: 4 }}>\n reset\n </button>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n <button\n aria-label=\"Sentient DevTools\"\n aria-expanded={open}\n onClick={() => setOpen((o) => !o)}\n style={{ width: 44, height: 44, borderRadius: 12, border: '1px solid #2a2a2a', background: '#000',\n display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 0,\n cursor: 'pointer', boxShadow: '0 6px 18px rgba(0,0,0,.4)' }}\n >\n <SentientMark />\n </button>\n </div>\n );\n}\n","export type RegisteredComponent = { id: string; variantIds: string[]; goal?: string };\nexport type RegisteredSlot = {\n id: string;\n arms?: string[];\n dims?: Record<string, readonly string[]>;\n};\n\ntype RegistryState = {\n components: Map<string, RegisteredComponent>;\n slots: Map<string, RegisteredSlot>;\n sections: string[];\n listeners: Set<() => void>;\n};\n\n// Shared through a window global: the main entry and the /devtools entry are\n// separate bundles, each with its own copy of this module — module-local\n// state would give the devtools an always-empty registry in published apps.\nconst ssrFallback: RegistryState = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n};\n\nfunction state(): RegistryState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_registry?: RegistryState };\n if (!w.__sentient_registry) {\n w.__sentient_registry = {\n components: new Map(),\n slots: new Map(),\n sections: [],\n listeners: new Set(),\n };\n }\n return w.__sentient_registry;\n}\n\nfunction emit(): void {\n for (const fn of state().listeners) fn();\n}\n\n/** Register (or re-register) a component. Returns an unregister function. */\nexport function registerComponent(c: RegisteredComponent): () => void {\n state().components.set(c.id, c);\n emit();\n return () => {\n state().components.delete(c.id);\n emit();\n };\n}\n\n/** Register (or re-register) a slot declaration. Returns an unregister function. */\nexport function registerSlot(s: RegisteredSlot): () => void {\n state().slots.set(s.id, s);\n emit();\n return () => {\n state().slots.delete(s.id);\n emit();\n };\n}\n\n/** Register the page's declared section ids (from AdaptiveRoot/provider). */\nexport function registerSections(sections: string[]): void {\n state().sections = [...sections];\n emit();\n}\n\nexport function getRegistered(): RegisteredComponent[] {\n return [...state().components.values()];\n}\n\nexport function getRegisteredSlots(): RegisteredSlot[] {\n return [...state().slots.values()];\n}\n\nexport function getRegisteredSections(): string[] {\n return [...state().sections];\n}\n\nexport function subscribeRegistry(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n","function store(): Record<string, string> {\n const w = window as unknown as { __sentient_overrides?: Record<string, string> };\n if (!w.__sentient_overrides) w.__sentient_overrides = {};\n return w.__sentient_overrides;\n}\n\n/** Force `componentId` to render `variantId` — read by `useAssignment`. */\nexport function setVariantOverride(componentId: string, variantId: string): void {\n store()[componentId] = variantId;\n}\n\nexport function clearVariantOverride(componentId: string): void {\n delete store()[componentId];\n}\n\nexport function getOverrides(): Record<string, string> {\n return { ...store() };\n}\n","import type { SlotResult } from '@sentientui/core';\n\n/**\n * Slot-override store — the channel `useSlotResult` reads (`useAdaptiveTokens` /\n * `AdaptiveGroup`). Separate from `__sentient_overrides` (variant components):\n * a slot result is a token object (`{ tone: 'urgent' }`) or an arm string\n * (`'social_first'`), never a bare variant id. Window-backed so the /devtools\n * bundle and the main bundle share one store.\n */\nfunction store(): Record<string, SlotResult> {\n const w = window as unknown as { __sentient_slot_overrides?: Record<string, SlotResult> };\n if (!w.__sentient_slot_overrides) w.__sentient_slot_overrides = {};\n return w.__sentient_slot_overrides;\n}\n\n/** Force `slotId` to resolve to `result` — read by `useSlotResult`. */\nexport function setSlotOverride(slotId: string, result: SlotResult): void {\n store()[slotId] = result;\n}\n\nexport function clearSlotOverride(slotId: string): void {\n delete store()[slotId];\n}\n\nexport function getSlotOverrides(): Record<string, SlotResult> {\n return { ...store() };\n}\n","import type { SentientClient } from '@sentientui/core';\n\ntype PreviewState = { on: boolean; listeners: Set<() => void> };\nconst ssrFallback: PreviewState = { on: false, listeners: new Set() };\n\n// Window-backed: the /devtools entry (a separate bundle) toggles preview mode\n// and the provider (main bundle) must observe it.\nfunction state(): PreviewState {\n if (typeof window === 'undefined') return ssrFallback;\n const w = window as unknown as { __sentient_preview?: PreviewState };\n if (!w.__sentient_preview) w.__sentient_preview = { on: false, listeners: new Set() };\n return w.__sentient_preview;\n}\n\nexport function setPreviewMode(on: boolean): void {\n const s = state();\n if (s.on === on) return;\n s.on = on;\n for (const fn of s.listeners) fn();\n}\n\nexport function getPreviewMode(): boolean {\n return state().on;\n}\n\nexport function subscribePreview(fn: () => void): () => void {\n const listeners = state().listeners;\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n}\n\n/**\n * Wraps a client so it writes nothing: reads pass through, all emitters no-op.\n * Used while previewing variants/personas so no `variant_assigned`, goal, or\n * session events are sent.\n */\nexport function createPreviewClient(inner: SentientClient): SentientClient {\n return {\n isLocal: inner.isLocal,\n track: () => undefined,\n goal: () => undefined,\n componentGoal: () => undefined,\n identify: () => undefined,\n fetchWeights: () => Promise.resolve([]),\n getAssignment: (componentId, segment) => inner.getAssignment(componentId, segment),\n assign: (componentId, variantIds, agentData, agentDataByVariant) =>\n inner.assign(componentId, variantIds, agentData, agentDataByVariant),\n // Reads pass through; decide is a write (slot decisions persist server-side)\n // so preview mode never issues it.\n decide: () => Promise.resolve(null),\n getSlotResult: (slotId) => inner.getSlotResult(slotId),\n getPersona: () => inner.getPersona(),\n getGraph: () => inner.getGraph(),\n destroy: () => inner.destroy(),\n };\n}\n","/**\n * Cross-bundle re-render bus for devtools overrides. The main entry and the\n * /devtools entry are separate bundles, so state and notifications go through\n * window (a version counter + a DOM event) — never module-local state.\n */\nconst EVENT = 'sentient:overrides-changed';\n\ntype VersionWindow = Window & { __sentient_overrides_version?: number };\n\nexport function getOverridesVersion(): number {\n if (typeof window === 'undefined') return 0;\n return (window as VersionWindow).__sentient_overrides_version ?? 0;\n}\n\nexport function notifyOverridesChanged(): void {\n if (typeof window === 'undefined') return;\n const w = window as VersionWindow;\n w.__sentient_overrides_version = (w.__sentient_overrides_version ?? 0) + 1;\n window.dispatchEvent(new Event(EVENT));\n}\n\nexport function subscribeOverridesChanged(fn: () => void): () => void {\n if (typeof window === 'undefined') return () => undefined;\n window.addEventListener(EVENT, fn);\n return () => window.removeEventListener(EVENT, fn);\n}\n","/** Provider → devtools config handoff. Window-backed: the /devtools entry is a\n * separate bundle and cannot share the provider's React context instance. */\nexport type DevtoolsConfig = {\n apiKey: string;\n apiBaseUrl: string;\n isLocal: boolean;\n};\n\ntype ConfigWindow = Window & { __sentient_devtools_config?: DevtoolsConfig };\n\nexport function publishDevtoolsConfig(config: DevtoolsConfig): void {\n if (typeof window === 'undefined') return;\n (window as ConfigWindow).__sentient_devtools_config = config;\n}\n\nexport function readDevtoolsConfig(): DevtoolsConfig | null {\n if (typeof window === 'undefined') return null;\n return (window as ConfigWindow).__sentient_devtools_config ?? null;\n}\n"],"mappings":"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","names":["useEffect","useReducer","useState","PERSONAS","PERSONA_DISPLAY","confidenceBand","SNAPSHOT_STORAGE_KEY_PREFIX","ssrFallback","state","w","getRegistered","state","getRegisteredSlots","getRegisteredSections","subscribeRegistry","fn","listeners","store","w","setVariantOverride","componentId","variantId","clearVariantOverride","getOverrides","__spreadValues","store","w","setSlotOverride","slotId","result","clearSlotOverride","getSlotOverrides","__spreadValues","ssrFallback","state","w","setPreviewMode","on","s","fn","getPreviewMode","EVENT","notifyOverridesChanged","_a","w","EVENT","readDevtoolsConfig","_a","jsx","jsxs","_a","IS_PROD","DEFAULT_API_BASE_URL","LOCAL_MODE_DEVTOOLS_BANNER","applyOutcome","result","_b","id","variantId","setVariantOverride","w","__spreadValues","setPreviewMode","notifyOverridesChanged","readSessionId","match","slotDecls","getRegisteredSlots","s","forcePersonaKeyed","apiKey","apiBaseUrl","persona","res","getRegisteredSections","getRegistered","c","data","__spreadProps","forcePersonaLocal","mod","outcome","confidenceBand","resetAll","getOverrides","clearVariantOverride","stale","i","key","SNAPSHOT_STORAGE_KEY_PREFIX","e","btn","active","SentientMark","size","AdaptiveDevtools","open","setOpen","useState","activePersona","setActivePersona","mounted","setMounted","force","useReducer","useEffect","subscribeRegistry","config","readDevtoolsConfig","useLocalEngine","components","slots","overrides","slotOverrides","getSlotOverrides","maybeExitPreview","choose","resetVariant","chooseSlotArm","arm","setSlotOverride","chooseSlotDim","dim","value","dims","current","next","d","values","resetSlot","clearSlotOverride","choosePersona","getPreviewMode","PERSONAS","p","PERSONA_DISPLAY","v","ov","o"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { SentientConfig, SentientClient, MicroSignalType, ComponentGoalOptions } from '@sentientui/core';
|
|
3
|
+
import { SentientConfig, SlotResult, SentientClient, MicroSignalType, ComponentGoalOptions } from '@sentientui/core';
|
|
4
4
|
export { deriveSessionSegment as detectSegment } from '@sentientui/core';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -60,6 +60,27 @@ type AdaptiveProviderProps = {
|
|
|
60
60
|
* `useLayoutOrder()` returns this on first render so there is no layout shift.
|
|
61
61
|
*/
|
|
62
62
|
initialLayoutOrder?: string[] | null;
|
|
63
|
+
/**
|
|
64
|
+
* SSR-preloaded slot results from `loadAdaptiveDecision()` (the `slots`
|
|
65
|
+
* field of its result). Guarantees `useAdaptiveTokens`/`AdaptiveGroup`
|
|
66
|
+
* render the decided arm in server HTML — zero flicker, hydration-safe.
|
|
67
|
+
*/
|
|
68
|
+
initialSlots?: Record<string, SlotResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Persona decided during SSR (`persona` + `confidence` fields of
|
|
71
|
+
* `loadAdaptiveDecision()`'s result). Adopted by the core client;
|
|
72
|
+
* rendered into html attributes only by `SentientPersonaScript`.
|
|
73
|
+
*/
|
|
74
|
+
initialPersona?: {
|
|
75
|
+
persona: string;
|
|
76
|
+
confidence: number;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Base URL of the Sentient API (no trailing slash). Read by the devtools
|
|
80
|
+
* panel for /v1/explain and by future client helpers. Defaults to the
|
|
81
|
+
* hosted API.
|
|
82
|
+
*/
|
|
83
|
+
apiBaseUrl?: string;
|
|
63
84
|
/**
|
|
64
85
|
* Session ID generated during SSR (the `sessionId` field returned by
|
|
65
86
|
* `loadAdaptiveAssignments` / `loadAdaptiveDecision`). When provided and no
|
|
@@ -74,6 +95,13 @@ type AdaptiveProviderProps = {
|
|
|
74
95
|
* sessions without client-side geo lookup.
|
|
75
96
|
*/
|
|
76
97
|
country?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Keyless local mode. 'auto' (default) simulates decisions on-device in
|
|
100
|
+
* development builds when no valid API key is configured; `true` forces the
|
|
101
|
+
* local engine; `false` restores the silent keyless no-op.
|
|
102
|
+
* @see SentientConfig.localMode
|
|
103
|
+
*/
|
|
104
|
+
localMode?: 'auto' | boolean;
|
|
77
105
|
/**
|
|
78
106
|
* Enable DOM graph scanning + page-structure sync. When `true`, the provider
|
|
79
107
|
* dynamically loads `@sentientui/core/graph` and uses its graph-capable
|
|
@@ -99,8 +127,12 @@ declare function useInitialAssignments(): Record<string, string>;
|
|
|
99
127
|
/**
|
|
100
128
|
* Returns the persona-specific section order from SSR, or null when no
|
|
101
129
|
* sections were declared on AdaptiveRoot or reliability is below threshold.
|
|
130
|
+
* Devtools/testing can force it via `window.__sentient_layout_override`;
|
|
131
|
+
* consumers re-render when the devtools notifies an override change.
|
|
102
132
|
*/
|
|
103
133
|
declare function useLayoutOrder(): string[] | null;
|
|
134
|
+
/** Internal: configured API base URL (devtools fetches /v1/explain against this, never a relative URL). */
|
|
135
|
+
declare function useAdaptiveApiBaseUrl(): string;
|
|
104
136
|
|
|
105
137
|
type ScrollDepthGoal = {
|
|
106
138
|
type: 'scroll_depth';
|
|
@@ -127,6 +159,7 @@ type WeightedCompositeGoal = {
|
|
|
127
159
|
steps: WeightedStep[];
|
|
128
160
|
};
|
|
129
161
|
type GoalConfig = ScrollDepthGoal | ClickGoal | FormSubmitGoal | CompositeGoal | WeightedCompositeGoal;
|
|
162
|
+
|
|
130
163
|
/** Maps a detected micro-signal to a named session goal (`client.goal`). */
|
|
131
164
|
type MicroSignalGoalConfig = string | {
|
|
132
165
|
name: string;
|
|
@@ -186,6 +219,12 @@ type AssignmentState = {
|
|
|
186
219
|
/**
|
|
187
220
|
* Returns a sticky variant assignment for a component.
|
|
188
221
|
*
|
|
222
|
+
* @deprecated Since 0.13.0 — use {@link useAdaptive} instead. `useAssignment`
|
|
223
|
+
* only SELECTS a variant; it wires no exposure tracking, no goal listeners,
|
|
224
|
+
* and no micro-signals, so components using it directly accumulate no
|
|
225
|
+
* learning signal. It keeps working (it is `useAdaptive`'s internal
|
|
226
|
+
* selection engine) but will move to internal-only in 1.0.0.
|
|
227
|
+
*
|
|
189
228
|
* First render reads the local SDK cache; if empty, falls back to a
|
|
190
229
|
* deterministic default and asynchronously calls `/v1/assign`. The server
|
|
191
230
|
* picks the actual variant via Thompson Sampling and the result replaces the fallback
|
|
@@ -211,6 +250,107 @@ type FireGoal = (goalType: string, opts?: ComponentGoalOptions) => void;
|
|
|
211
250
|
*/
|
|
212
251
|
declare function useAdaptiveGoal(componentId: string): FireGoal;
|
|
213
252
|
|
|
253
|
+
type SentientPersonaScriptProps = {
|
|
254
|
+
/** Publishable API key — selects the localStorage snapshot in the fallback path. */
|
|
255
|
+
apiKey: string;
|
|
256
|
+
/**
|
|
257
|
+
* SSR-decided persona (from `loadAdaptiveDecision`). When present the
|
|
258
|
+
* script embeds the literal values; when absent it reads the local
|
|
259
|
+
* decision snapshot (SPA / return-visit path).
|
|
260
|
+
*/
|
|
261
|
+
persona?: {
|
|
262
|
+
persona: string;
|
|
263
|
+
confidence: number;
|
|
264
|
+
} | null;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Single writer of the Rung-1a `<html>` attributes
|
|
268
|
+
* (`data-sentient-persona`, `data-sentient-confidence`), executed pre-paint.
|
|
269
|
+
*
|
|
270
|
+
* `AdaptiveRoot` renders this automatically as its first child. For Pages
|
|
271
|
+
* Router / Remix, render it yourself in `_document` / the root layout.
|
|
272
|
+
*
|
|
273
|
+
* IMPORTANT (install docs): add `suppressHydrationWarning` to your `<html>`
|
|
274
|
+
* element — this script mutates documentElement before React hydrates it
|
|
275
|
+
* (the same pattern next-themes uses). The client SDK adopts the attributes
|
|
276
|
+
* as truth and never rewrites them mid-session.
|
|
277
|
+
*/
|
|
278
|
+
declare function SentientPersonaScript(props: SentientPersonaScriptProps): JSX.Element;
|
|
279
|
+
|
|
280
|
+
type UseAdaptiveTokensOptions = {
|
|
281
|
+
goal?: string | GoalConfig;
|
|
282
|
+
};
|
|
283
|
+
type UseAdaptiveTokensResult = {
|
|
284
|
+
tokens: Record<string, string>;
|
|
285
|
+
/** Spread on the slot's element: `data-<dim>` per dim + `data-sentient-slot`. */
|
|
286
|
+
props: Record<string, string>;
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Rung 1b — adaptive design tokens. Declares a bounded token space; the
|
|
290
|
+
* optimizer picks per persona; values apply as element-scoped data
|
|
291
|
+
* attributes so they serialize through SSR markup (zero flicker,
|
|
292
|
+
* hydration-safe). First value of each dim = baseline.
|
|
293
|
+
*
|
|
294
|
+
* ```tsx
|
|
295
|
+
* const t = useAdaptiveTokens('hero', { tone: ['calm', 'urgent'] });
|
|
296
|
+
* return <section {...t.props} className="hero">…</section>;
|
|
297
|
+
* // CSS: .hero[data-tone="urgent"] .cta { … }
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
declare function useAdaptiveTokens(id: string, dims: Record<string, readonly string[]>, opts?: UseAdaptiveTokensOptions): UseAdaptiveTokensResult;
|
|
301
|
+
|
|
302
|
+
type UseAdaptiveBind = {
|
|
303
|
+
ref: (el: HTMLElement | null) => void;
|
|
304
|
+
'data-sentient-id': string;
|
|
305
|
+
'data-sentient-variant': string;
|
|
306
|
+
};
|
|
307
|
+
type UseAdaptiveResult<T> = {
|
|
308
|
+
variant: string;
|
|
309
|
+
value: T;
|
|
310
|
+
/** Spread on the rendered element — wires exposure, goal listeners, and micro-signals. */
|
|
311
|
+
bind: UseAdaptiveBind;
|
|
312
|
+
fireGoal: (goalType?: string, opts?: ComponentGoalOptions) => void;
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* Rung 2 — headless, measurement-complete variant swap. Supersedes
|
|
316
|
+
* `useAssignment` (which selects a variant but wires no measurement).
|
|
317
|
+
*
|
|
318
|
+
* `goal` is REQUIRED: without one the optimizer accumulates exposures with
|
|
319
|
+
* zero rewards and cannot learn. `bind` MUST be attached to the rendered
|
|
320
|
+
* element — dev mode warns loudly when a slot renders unbound.
|
|
321
|
+
*
|
|
322
|
+
* ```tsx
|
|
323
|
+
* const { value, bind } = useAdaptive('buy-box', {
|
|
324
|
+
* variants: { calm: <CalmBuyBox/>, urgent: <UrgentBuyBox/> }, // first key = baseline
|
|
325
|
+
* goal: 'buy_click',
|
|
326
|
+
* });
|
|
327
|
+
* return <div {...bind}>{value}</div>;
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
declare function useAdaptive<T>(id: string, config: {
|
|
331
|
+
variants: Record<string, T>;
|
|
332
|
+
goal: string | GoalConfig;
|
|
333
|
+
}): UseAdaptiveResult<T>;
|
|
334
|
+
|
|
335
|
+
type AdaptiveGroupProps = {
|
|
336
|
+
id: string;
|
|
337
|
+
/** Arrangement id → ordered child keys. FIRST key = baseline default. */
|
|
338
|
+
arrangements: Record<string, string[]>;
|
|
339
|
+
/** Explicit baseline arrangement id (defaults to the first declared). */
|
|
340
|
+
baseline?: string;
|
|
341
|
+
/** Optional slot-scoped goal — credited via componentGoal(group id). */
|
|
342
|
+
goal?: string | GoalConfig;
|
|
343
|
+
/** Keyed children — every key referenced by an arrangement must exist. */
|
|
344
|
+
children: ReactNode;
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* Rung 3 — bounded mini-layout. Reorders KEYED children into the decided
|
|
348
|
+
* arrangement (enumerated-arms slot: arms = Object.keys(arrangements)).
|
|
349
|
+
* Declared orders only — never free permutation, never show/hide.
|
|
350
|
+
* Fail-safe: unknown arrangement or key mismatch renders declaration order.
|
|
351
|
+
*/
|
|
352
|
+
declare function AdaptiveGroup(props: AdaptiveGroupProps): JSX.Element;
|
|
353
|
+
|
|
214
354
|
/** Per-component weights store with isolated subscriptions. */
|
|
215
355
|
type VariantWeight = {
|
|
216
356
|
variantId: string;
|
|
@@ -297,4 +437,4 @@ declare function renderAgentJsonLdBody(feed: AgentFeed): string;
|
|
|
297
437
|
/** Render the feed as Markdown for agents that negotiate `text/markdown`. */
|
|
298
438
|
declare function renderAgentMarkdown(feed: AgentFeed): string;
|
|
299
439
|
|
|
300
|
-
export { Adaptive, type AdaptiveProps, AdaptiveProvider, type AdaptiveProviderProps, AdaptiveText, type AdaptiveTextProps, type AgentBlock, type AgentFeed, type AssignmentState, type ClickGoal, type ComponentWeights, type CompositeGoal, type FireGoal, type FormSubmitGoal, type GoalConfig, type MicroSignalGoalConfig, type MicroSignalGoals, type ScrollDepthGoal, type SsrFallback, type VariantWeight, type WeightedCompositeGoal, type WeightedStep, buildAgentFeed, defineAgentContent, getAgentContent, getWeights, renderAgentJsonLd, renderAgentJsonLdBody, renderAgentMarkdown, subscribe as subscribeWeights, update as updateWeights, useAdaptiveGoal, useAssignment, useInitialAssignments, useLayoutOrder, useSentient };
|
|
440
|
+
export { Adaptive, AdaptiveGroup, type AdaptiveGroupProps, type AdaptiveProps, AdaptiveProvider, type AdaptiveProviderProps, AdaptiveText, type AdaptiveTextProps, type AgentBlock, type AgentFeed, type AssignmentState, type ClickGoal, type ComponentWeights, type CompositeGoal, type FireGoal, type FormSubmitGoal, type GoalConfig, type MicroSignalGoalConfig, type MicroSignalGoals, type ScrollDepthGoal, SentientPersonaScript, type SentientPersonaScriptProps, type SsrFallback, type UseAdaptiveBind, type UseAdaptiveResult, type UseAdaptiveTokensOptions, type UseAdaptiveTokensResult, type VariantWeight, type WeightedCompositeGoal, type WeightedStep, buildAgentFeed, defineAgentContent, getAgentContent, getWeights, renderAgentJsonLd, renderAgentJsonLdBody, renderAgentMarkdown, subscribe as subscribeWeights, update as updateWeights, useAdaptive, useAdaptiveApiBaseUrl, useAdaptiveGoal, useAdaptiveTokens, useAssignment, useInitialAssignments, useLayoutOrder, useSentient };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { SentientConfig, SentientClient, MicroSignalType, ComponentGoalOptions } from '@sentientui/core';
|
|
3
|
+
import { SentientConfig, SlotResult, SentientClient, MicroSignalType, ComponentGoalOptions } from '@sentientui/core';
|
|
4
4
|
export { deriveSessionSegment as detectSegment } from '@sentientui/core';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -60,6 +60,27 @@ type AdaptiveProviderProps = {
|
|
|
60
60
|
* `useLayoutOrder()` returns this on first render so there is no layout shift.
|
|
61
61
|
*/
|
|
62
62
|
initialLayoutOrder?: string[] | null;
|
|
63
|
+
/**
|
|
64
|
+
* SSR-preloaded slot results from `loadAdaptiveDecision()` (the `slots`
|
|
65
|
+
* field of its result). Guarantees `useAdaptiveTokens`/`AdaptiveGroup`
|
|
66
|
+
* render the decided arm in server HTML — zero flicker, hydration-safe.
|
|
67
|
+
*/
|
|
68
|
+
initialSlots?: Record<string, SlotResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Persona decided during SSR (`persona` + `confidence` fields of
|
|
71
|
+
* `loadAdaptiveDecision()`'s result). Adopted by the core client;
|
|
72
|
+
* rendered into html attributes only by `SentientPersonaScript`.
|
|
73
|
+
*/
|
|
74
|
+
initialPersona?: {
|
|
75
|
+
persona: string;
|
|
76
|
+
confidence: number;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Base URL of the Sentient API (no trailing slash). Read by the devtools
|
|
80
|
+
* panel for /v1/explain and by future client helpers. Defaults to the
|
|
81
|
+
* hosted API.
|
|
82
|
+
*/
|
|
83
|
+
apiBaseUrl?: string;
|
|
63
84
|
/**
|
|
64
85
|
* Session ID generated during SSR (the `sessionId` field returned by
|
|
65
86
|
* `loadAdaptiveAssignments` / `loadAdaptiveDecision`). When provided and no
|
|
@@ -74,6 +95,13 @@ type AdaptiveProviderProps = {
|
|
|
74
95
|
* sessions without client-side geo lookup.
|
|
75
96
|
*/
|
|
76
97
|
country?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Keyless local mode. 'auto' (default) simulates decisions on-device in
|
|
100
|
+
* development builds when no valid API key is configured; `true` forces the
|
|
101
|
+
* local engine; `false` restores the silent keyless no-op.
|
|
102
|
+
* @see SentientConfig.localMode
|
|
103
|
+
*/
|
|
104
|
+
localMode?: 'auto' | boolean;
|
|
77
105
|
/**
|
|
78
106
|
* Enable DOM graph scanning + page-structure sync. When `true`, the provider
|
|
79
107
|
* dynamically loads `@sentientui/core/graph` and uses its graph-capable
|
|
@@ -99,8 +127,12 @@ declare function useInitialAssignments(): Record<string, string>;
|
|
|
99
127
|
/**
|
|
100
128
|
* Returns the persona-specific section order from SSR, or null when no
|
|
101
129
|
* sections were declared on AdaptiveRoot or reliability is below threshold.
|
|
130
|
+
* Devtools/testing can force it via `window.__sentient_layout_override`;
|
|
131
|
+
* consumers re-render when the devtools notifies an override change.
|
|
102
132
|
*/
|
|
103
133
|
declare function useLayoutOrder(): string[] | null;
|
|
134
|
+
/** Internal: configured API base URL (devtools fetches /v1/explain against this, never a relative URL). */
|
|
135
|
+
declare function useAdaptiveApiBaseUrl(): string;
|
|
104
136
|
|
|
105
137
|
type ScrollDepthGoal = {
|
|
106
138
|
type: 'scroll_depth';
|
|
@@ -127,6 +159,7 @@ type WeightedCompositeGoal = {
|
|
|
127
159
|
steps: WeightedStep[];
|
|
128
160
|
};
|
|
129
161
|
type GoalConfig = ScrollDepthGoal | ClickGoal | FormSubmitGoal | CompositeGoal | WeightedCompositeGoal;
|
|
162
|
+
|
|
130
163
|
/** Maps a detected micro-signal to a named session goal (`client.goal`). */
|
|
131
164
|
type MicroSignalGoalConfig = string | {
|
|
132
165
|
name: string;
|
|
@@ -186,6 +219,12 @@ type AssignmentState = {
|
|
|
186
219
|
/**
|
|
187
220
|
* Returns a sticky variant assignment for a component.
|
|
188
221
|
*
|
|
222
|
+
* @deprecated Since 0.13.0 — use {@link useAdaptive} instead. `useAssignment`
|
|
223
|
+
* only SELECTS a variant; it wires no exposure tracking, no goal listeners,
|
|
224
|
+
* and no micro-signals, so components using it directly accumulate no
|
|
225
|
+
* learning signal. It keeps working (it is `useAdaptive`'s internal
|
|
226
|
+
* selection engine) but will move to internal-only in 1.0.0.
|
|
227
|
+
*
|
|
189
228
|
* First render reads the local SDK cache; if empty, falls back to a
|
|
190
229
|
* deterministic default and asynchronously calls `/v1/assign`. The server
|
|
191
230
|
* picks the actual variant via Thompson Sampling and the result replaces the fallback
|
|
@@ -211,6 +250,107 @@ type FireGoal = (goalType: string, opts?: ComponentGoalOptions) => void;
|
|
|
211
250
|
*/
|
|
212
251
|
declare function useAdaptiveGoal(componentId: string): FireGoal;
|
|
213
252
|
|
|
253
|
+
type SentientPersonaScriptProps = {
|
|
254
|
+
/** Publishable API key — selects the localStorage snapshot in the fallback path. */
|
|
255
|
+
apiKey: string;
|
|
256
|
+
/**
|
|
257
|
+
* SSR-decided persona (from `loadAdaptiveDecision`). When present the
|
|
258
|
+
* script embeds the literal values; when absent it reads the local
|
|
259
|
+
* decision snapshot (SPA / return-visit path).
|
|
260
|
+
*/
|
|
261
|
+
persona?: {
|
|
262
|
+
persona: string;
|
|
263
|
+
confidence: number;
|
|
264
|
+
} | null;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Single writer of the Rung-1a `<html>` attributes
|
|
268
|
+
* (`data-sentient-persona`, `data-sentient-confidence`), executed pre-paint.
|
|
269
|
+
*
|
|
270
|
+
* `AdaptiveRoot` renders this automatically as its first child. For Pages
|
|
271
|
+
* Router / Remix, render it yourself in `_document` / the root layout.
|
|
272
|
+
*
|
|
273
|
+
* IMPORTANT (install docs): add `suppressHydrationWarning` to your `<html>`
|
|
274
|
+
* element — this script mutates documentElement before React hydrates it
|
|
275
|
+
* (the same pattern next-themes uses). The client SDK adopts the attributes
|
|
276
|
+
* as truth and never rewrites them mid-session.
|
|
277
|
+
*/
|
|
278
|
+
declare function SentientPersonaScript(props: SentientPersonaScriptProps): JSX.Element;
|
|
279
|
+
|
|
280
|
+
type UseAdaptiveTokensOptions = {
|
|
281
|
+
goal?: string | GoalConfig;
|
|
282
|
+
};
|
|
283
|
+
type UseAdaptiveTokensResult = {
|
|
284
|
+
tokens: Record<string, string>;
|
|
285
|
+
/** Spread on the slot's element: `data-<dim>` per dim + `data-sentient-slot`. */
|
|
286
|
+
props: Record<string, string>;
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Rung 1b — adaptive design tokens. Declares a bounded token space; the
|
|
290
|
+
* optimizer picks per persona; values apply as element-scoped data
|
|
291
|
+
* attributes so they serialize through SSR markup (zero flicker,
|
|
292
|
+
* hydration-safe). First value of each dim = baseline.
|
|
293
|
+
*
|
|
294
|
+
* ```tsx
|
|
295
|
+
* const t = useAdaptiveTokens('hero', { tone: ['calm', 'urgent'] });
|
|
296
|
+
* return <section {...t.props} className="hero">…</section>;
|
|
297
|
+
* // CSS: .hero[data-tone="urgent"] .cta { … }
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
declare function useAdaptiveTokens(id: string, dims: Record<string, readonly string[]>, opts?: UseAdaptiveTokensOptions): UseAdaptiveTokensResult;
|
|
301
|
+
|
|
302
|
+
type UseAdaptiveBind = {
|
|
303
|
+
ref: (el: HTMLElement | null) => void;
|
|
304
|
+
'data-sentient-id': string;
|
|
305
|
+
'data-sentient-variant': string;
|
|
306
|
+
};
|
|
307
|
+
type UseAdaptiveResult<T> = {
|
|
308
|
+
variant: string;
|
|
309
|
+
value: T;
|
|
310
|
+
/** Spread on the rendered element — wires exposure, goal listeners, and micro-signals. */
|
|
311
|
+
bind: UseAdaptiveBind;
|
|
312
|
+
fireGoal: (goalType?: string, opts?: ComponentGoalOptions) => void;
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* Rung 2 — headless, measurement-complete variant swap. Supersedes
|
|
316
|
+
* `useAssignment` (which selects a variant but wires no measurement).
|
|
317
|
+
*
|
|
318
|
+
* `goal` is REQUIRED: without one the optimizer accumulates exposures with
|
|
319
|
+
* zero rewards and cannot learn. `bind` MUST be attached to the rendered
|
|
320
|
+
* element — dev mode warns loudly when a slot renders unbound.
|
|
321
|
+
*
|
|
322
|
+
* ```tsx
|
|
323
|
+
* const { value, bind } = useAdaptive('buy-box', {
|
|
324
|
+
* variants: { calm: <CalmBuyBox/>, urgent: <UrgentBuyBox/> }, // first key = baseline
|
|
325
|
+
* goal: 'buy_click',
|
|
326
|
+
* });
|
|
327
|
+
* return <div {...bind}>{value}</div>;
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
declare function useAdaptive<T>(id: string, config: {
|
|
331
|
+
variants: Record<string, T>;
|
|
332
|
+
goal: string | GoalConfig;
|
|
333
|
+
}): UseAdaptiveResult<T>;
|
|
334
|
+
|
|
335
|
+
type AdaptiveGroupProps = {
|
|
336
|
+
id: string;
|
|
337
|
+
/** Arrangement id → ordered child keys. FIRST key = baseline default. */
|
|
338
|
+
arrangements: Record<string, string[]>;
|
|
339
|
+
/** Explicit baseline arrangement id (defaults to the first declared). */
|
|
340
|
+
baseline?: string;
|
|
341
|
+
/** Optional slot-scoped goal — credited via componentGoal(group id). */
|
|
342
|
+
goal?: string | GoalConfig;
|
|
343
|
+
/** Keyed children — every key referenced by an arrangement must exist. */
|
|
344
|
+
children: ReactNode;
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* Rung 3 — bounded mini-layout. Reorders KEYED children into the decided
|
|
348
|
+
* arrangement (enumerated-arms slot: arms = Object.keys(arrangements)).
|
|
349
|
+
* Declared orders only — never free permutation, never show/hide.
|
|
350
|
+
* Fail-safe: unknown arrangement or key mismatch renders declaration order.
|
|
351
|
+
*/
|
|
352
|
+
declare function AdaptiveGroup(props: AdaptiveGroupProps): JSX.Element;
|
|
353
|
+
|
|
214
354
|
/** Per-component weights store with isolated subscriptions. */
|
|
215
355
|
type VariantWeight = {
|
|
216
356
|
variantId: string;
|
|
@@ -297,4 +437,4 @@ declare function renderAgentJsonLdBody(feed: AgentFeed): string;
|
|
|
297
437
|
/** Render the feed as Markdown for agents that negotiate `text/markdown`. */
|
|
298
438
|
declare function renderAgentMarkdown(feed: AgentFeed): string;
|
|
299
439
|
|
|
300
|
-
export { Adaptive, type AdaptiveProps, AdaptiveProvider, type AdaptiveProviderProps, AdaptiveText, type AdaptiveTextProps, type AgentBlock, type AgentFeed, type AssignmentState, type ClickGoal, type ComponentWeights, type CompositeGoal, type FireGoal, type FormSubmitGoal, type GoalConfig, type MicroSignalGoalConfig, type MicroSignalGoals, type ScrollDepthGoal, type SsrFallback, type VariantWeight, type WeightedCompositeGoal, type WeightedStep, buildAgentFeed, defineAgentContent, getAgentContent, getWeights, renderAgentJsonLd, renderAgentJsonLdBody, renderAgentMarkdown, subscribe as subscribeWeights, update as updateWeights, useAdaptiveGoal, useAssignment, useInitialAssignments, useLayoutOrder, useSentient };
|
|
440
|
+
export { Adaptive, AdaptiveGroup, type AdaptiveGroupProps, type AdaptiveProps, AdaptiveProvider, type AdaptiveProviderProps, AdaptiveText, type AdaptiveTextProps, type AgentBlock, type AgentFeed, type AssignmentState, type ClickGoal, type ComponentWeights, type CompositeGoal, type FireGoal, type FormSubmitGoal, type GoalConfig, type MicroSignalGoalConfig, type MicroSignalGoals, type ScrollDepthGoal, SentientPersonaScript, type SentientPersonaScriptProps, type SsrFallback, type UseAdaptiveBind, type UseAdaptiveResult, type UseAdaptiveTokensOptions, type UseAdaptiveTokensResult, type VariantWeight, type WeightedCompositeGoal, type WeightedStep, buildAgentFeed, defineAgentContent, getAgentContent, getWeights, renderAgentJsonLd, renderAgentJsonLdBody, renderAgentMarkdown, subscribe as subscribeWeights, update as updateWeights, useAdaptive, useAdaptiveApiBaseUrl, useAdaptiveGoal, useAdaptiveTokens, useAssignment, useInitialAssignments, useLayoutOrder, useSentient };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
"use strict";var Pe=Object.create;var K=Object.defineProperty,Me=Object.defineProperties,Te=Object.getOwnPropertyDescriptor,We=Object.getOwnPropertyDescriptors,De=Object.getOwnPropertyNames,re=Object.getOwnPropertySymbols,Ne=Object.getPrototypeOf,se=Object.prototype.hasOwnProperty,je=Object.prototype.propertyIsEnumerable;var oe=(e,t,n)=>t in e?K(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,M=(e,t)=>{for(var n in t||(t={}))se.call(t,n)&&oe(e,n,t[n]);if(re)for(var n of re(t))je.call(t,n)&&oe(e,n,t[n]);return e},$=(e,t)=>Me(e,We(t));var Ke=(e,t)=>{for(var n in t)K(e,n,{get:t[n],enumerable:!0})},ae=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of De(t))!se.call(e,i)&&i!==n&&K(e,i,{get:()=>t[i],enumerable:!(o=Te(t,i))||o.enumerable});return e};var Ve=(e,t,n)=>(n=e!=null?Pe(Ne(e)):{},ae(t||!e||!e.__esModule?K(n,"default",{value:e,enumerable:!0}):n,e)),$e=e=>ae(K({},"__esModule",{value:!0}),e);var et={};Ke(et,{Adaptive:()=>we,AdaptiveProvider:()=>ge,AdaptiveText:()=>xe,buildAgentFeed:()=>Ge,defineAgentContent:()=>Le,detectSegment:()=>te.deriveSessionSegment,getAgentContent:()=>ne,getWeights:()=>X,renderAgentJsonLd:()=>Oe,renderAgentJsonLdBody:()=>ie,renderAgentMarkdown:()=>_e,subscribeWeights:()=>B,updateWeights:()=>H,useAdaptiveGoal:()=>Ee,useAssignment:()=>Y,useInitialAssignments:()=>U,useLayoutOrder:()=>pe,useSentient:()=>G});module.exports=$e(et);var p=require("react"),N=require("@sentientui/core");var le=new Map,J=new Map;function B(e,t){let n=J.get(e);return n||(n=new Set,J.set(e,n)),n.add(t),()=>{n.delete(t),n.size===0&&J.delete(e)}}function H(e,t){le.set(e,t);let n=J.get(e);if(n)for(let o of n)try{o(t)}catch(i){}}function X(e){var t;return(t=le.get(e))!=null?t:null}var Je=!1,ce=new Set;function ee(){return Je}function ue(e){return ce.add(e),()=>{ce.delete(e)}}function de(e){return{track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},fetchWeights:()=>Promise.resolve([]),getAssignment:(t,n)=>e.getAssignment(t,n),assign:(t,n,o,i)=>e.assign(t,n,o,i),getGraph:()=>e.getGraph(),destroy:()=>e.destroy()}}var me=require("react/jsx-runtime");function Be(){var e,t;if(typeof window=="undefined")return"desktop:direct";try{let n=(0,N.detectDeviceClass)((e=navigator.userAgent)!=null?e:""),o=(0,N.detectTrafficSource)((t=document.referrer)!=null?t:"",window.location.origin);return`${n}:${o}`}catch(n){return"desktop:direct"}}var T=(0,p.createContext)({client:null,apiKey:"",initialAssignments:{},sessionSegment:"desktop:direct",ssrFallback:"first",onAssignment:void 0,initialLayoutOrder:null});function ge(e){var C;let[t,n]=(0,p.useState)(null),[o]=(0,p.useState)(()=>{var d;return(d=e.sessionSegment)!=null?d:Be()}),[i,A]=(0,p.useState)(ee());(0,p.useEffect)(()=>ue(()=>A(ee())),[]),(0,p.useEffect)(()=>{if(e.consent===!1&&!e.preConsentBehavior){n(a=>(a==null||a.destroy(),null));return}let d={apiKey:e.apiKey,context:e.context,debug:e.debug,initialAssignments:e.initialAssignments,sessionSegment:o,consent:e.consent,preConsentBehavior:e.preConsentBehavior,respectDoNotTrack:e.respectDoNotTrack,ssrSessionId:e.ssrSessionId,country:e.country},s=!1,b=null;return e.enableGraph?import("@sentientui/core/graph").then(({init:a})=>{s||(b=a($(M({},d),{graph:!0})),n(b))}):(b=(0,N.init)(d),n(b)),()=>{s=!0,b==null||b.destroy()}},[e.consent]),(0,p.useEffect)(()=>{if(!t)return;let d=!1,s=async()=>{if(d)return;let a;try{a=await t.fetchWeights()}catch(g){return}if(!d)for(let g of a){let h={componentId:g.componentId,updatedAt:g.updatedAt,variants:g.variants.map(I=>{var u;return{variantId:I.variantId,pulls:I.pulls,avgReward:(u=I.avgReward)!=null?u:0}})};H(g.componentId,h)}};s();let b=setInterval(()=>{s()},6e4);return()=>{d=!0,clearInterval(b)}},[t]);let l=(C=e.ssrFallback)!=null?C:"first",m=(0,p.useMemo)(()=>t&&i?de(t):t,[t,i]),O=(0,p.useMemo)(()=>{var d,s;return{client:m,apiKey:e.apiKey,initialAssignments:(d=e.initialAssignments)!=null?d:{},sessionSegment:o,ssrFallback:l,onAssignment:e.onAssignment,initialLayoutOrder:(s=e.initialLayoutOrder)!=null?s:null}},[m,e.apiKey,e.initialAssignments,o,l,e.onAssignment,e.initialLayoutOrder]);return(0,me.jsx)(T.Provider,{value:O,children:e.children})}function G(){return(0,p.useContext)(T).client}function z(){return(0,p.useContext)(T).apiKey}function U(){return(0,p.useContext)(T).initialAssignments}function q(){return(0,p.useContext)(T).sessionSegment}function fe(){return(0,p.useContext)(T).ssrFallback}function Q(){return(0,p.useContext)(T).onAssignment}function pe(){let e=(0,p.useContext)(T).initialLayoutOrder;if(typeof window!="undefined"){let t=window.__sentient_layout_override;if(t)return t}return e}var v=require("react"),be=require("@sentientui/core");var _=require("react");function He(e){var n;if(typeof window=="undefined")return null;let t=(n=window.__sentient_overrides)==null?void 0:n[e];if(t)return t;try{let o=new URLSearchParams(window.location.search);for(let i of o.getAll("sentient_variant")){let A=i.indexOf(":");if(A!==-1&&i.slice(0,A)===e)return i.slice(A+1)}}catch(o){}return null}function ve(e,t){var o;let n=null;for(let i of e.variants)t.includes(i.variantId)&&(!n||i.avgReward>n.avgReward)&&(n={variantId:i.variantId,avgReward:i.avgReward});return(o=n==null?void 0:n.variantId)!=null?o:null}function Y(e,t,n,o){let i=U(),A=fe(),l=G(),m=q(),O=Q(),C=(0,_.useRef)(null),d=He(e),s=d&&t.includes(d)?d:null,b=(0,_.useRef)(null);s&&b.current!==s&&(b.current=s,console.info(`[sentient] override active: ${e} -> ${s}`));let a=(()=>{var r,c;if(s)return{variantId:s,content:null,isLoading:!1};if(!l){let f=i[e];return f&&t.includes(f)?{variantId:f,content:null,isLoading:!1}:A==="first"&&t.length>0?{variantId:t[0],content:null,isLoading:!1}:{variantId:null,content:null,isLoading:!0}}let u=l.getAssignment(e,m);if(u&&(t.includes(u.variantId)||u.content))return{variantId:u.variantId,content:(r=u.content)!=null?r:null,isLoading:!1};let S=X(e);if(S){let f=ve(S,t);if(f)return{variantId:f,content:null,isLoading:!1}}return{variantId:(c=t[0])!=null?c:null,content:null,isLoading:!1}})(),[g,h]=(0,_.useState)(a),I=u=>{O&&C.current!==u&&(C.current=u,O(e,u))};return(0,_.useEffect)(()=>{var S;if(s||!l)return;let u=l.getAssignment(e,m);if(u&&(t.includes(u.variantId)||u.content)){h({variantId:u.variantId,content:(S=u.content)!=null?S:null,isLoading:!1}),I(u.variantId);return}h(r=>{var c;return r.variantId?r:{variantId:(c=t[0])!=null?c:null,content:null,isLoading:!1}})},[s,l,e,m]),(0,_.useEffect)(()=>{if(s||!l)return;let u=l.getAssignment(e,m);if(u&&t.includes(u.variantId))return;let S=!1;return l.assign(e,t,n,o).then(r=>{var c;S||r&&(!t.includes(r.variantId)&&!r.content||(h({variantId:r.variantId,content:(c=r.content)!=null?c:null,isLoading:!1}),I(r.variantId)))}),()=>{S=!0}},[s,l,e,m]),(0,_.useEffect)(()=>{if(!s&&l)return B(e,u=>{var c;let S=l.getAssignment(e,m);if(S&&(t.includes(S.variantId)||S.content)){h({variantId:S.variantId,content:(c=S.content)!=null?c:null,isLoading:!1});return}let r=ve(u,t);r&&h({variantId:r,content:null,isLoading:!1})})},[s,l,e,m]),s?{variantId:s,content:null,isLoading:!1}:g}var ye=new Map,Xe=new Set;function he(){for(let e of Xe)e()}function Ae(e){return ye.set(e.id,e),he(),()=>{ye.delete(e.id),he()}}var ke=require("react/jsx-runtime");function ze(e){return typeof e=="string"?{type:"click"}:e}var Ue=3e4;function qe(e,t){try{let n=`_snt_pv_${e}_${t}`;return sessionStorage.getItem(n)?!1:(sessionStorage.setItem(n,"1"),!0)}catch(n){return!0}}function Qe(e){if(!(e instanceof Element))return!1;let t=e.tagName.toLowerCase();return t==="a"||t==="button"?!0:e.getAttribute("role")==="button"}function Se(e,t,n){if(n){try{let i=e;for(;i&&i!==t;){if(i.matches(n))return!0;i=i.parentElement}}catch(i){}return!1}let o=e;for(;o&&o!==t;){if(Qe(o))return!0;o=o.parentElement}return!1}function Ye(e){var u,S;let t=G(),n=z(),o=(0,v.useMemo)(()=>Object.keys(e.variants),[e.variants]),{variantId:i,content:A}=Y(e.id,o,e.agentData,e.agentDataByVariant),l=(0,v.useRef)(null),[m,O]=(0,v.useState)(!1);(0,v.useEffect)(()=>{O(!0)},[]);let C=(0,v.useRef)(!1),d=(0,v.useRef)(new Set),s=(0,v.useRef)(null),b=typeof e.goal=="string"?e.goal:JSON.stringify(e.goal),a=(0,v.useMemo)(()=>ze(e.goal),[b]),g=typeof e.goal=="string"?e.goal:a.type;if((0,v.useEffect)(()=>Ae({id:e.id,variantIds:o,goal:g}),[e.id,o,g]),(0,v.useEffect)(()=>{var f,R;if(!t||!i||!n||s.current===i)return;let r=(R=(f=l.current)==null?void 0:f.innerHTML)!=null?R:"";if(!r)return;s.current=i;let c=r!==""&&qe(e.id,i);t.track({projectId:n,componentId:e.id,variantId:i,eventType:"variant_assigned",payload:c?{previewHtml:r.slice(0,Ue)}:{}})},[t,i,n,e.id,m,A]),(0,v.useEffect)(()=>{C.current=!1,d.current=new Set},[i,a]),(0,v.useEffect)(()=>{if(!t||!i)return;let r=l.current;if(!r)return;let c=null,f=0,R=()=>{f=Date.now(),c=setTimeout(()=>{t.track({projectId:n,componentId:e.id,variantId:i,eventType:"cursor_signal",payload:{hoverDuration:Date.now()-f}}),c=null},800)},w=()=>{c!==null&&(clearTimeout(c),c=null)};return r.addEventListener("mouseenter",R),r.addEventListener("mouseleave",w),()=>{r.removeEventListener("mouseenter",R),r.removeEventListener("mouseleave",w),c!==null&&clearTimeout(c)}},[t,i,n,e.id]),(0,v.useEffect)(()=>{if(!t||!i)return;let r=l.current;if(!r)return;let c=Date.now();return(0,be.attachMicroSignalDetectors)((f,R={})=>{var y,x,L;t.track({projectId:n,componentId:e.id,variantId:i,eventType:"micro_signal",payload:M({signalType:f},R)});let w=(y=e.microSignalGoals)==null?void 0:y[f];if(!w||d.current.has(f))return;d.current.add(f);let D=typeof w=="string"?w:w.name,k=typeof w=="string"?1:(x=w.weight)!=null?x:1,E=typeof w=="string"?0:(L=w.stepIndex)!=null?L:0;t.goal(D,M({signalType:f},R),k,E)},r,c)},[t,i,n,e.id,e.microSignalGoals]),(0,v.useEffect)(()=>{if(!t||!i)return;let r=l.current;if(!r)return;if(a.type==="weighted_composite"){let k=new Set,E=[];return a.steps.forEach(({goal:y,name:x,weight:L},j)=>{let Z=()=>{k.has(j)||(k.add(j),t.track({projectId:n,componentId:e.id,variantId:i,eventType:"goal_achieved",goalType:x,payload:{reward:L}}),t.goal(x,{},L,j))};if(y.type==="click"){let F=P=>{let V=P.target;V instanceof Element&&Se(V,r,y.selector)&&Z()};r.addEventListener("click",F),E.push(()=>r.removeEventListener("click",F));return}if(y.type==="form_submit"){let F=P=>{P.target instanceof HTMLFormElement&&r.contains(P.target)&&Z()};r.addEventListener("submit",F),E.push(()=>r.removeEventListener("submit",F));return}if(y.type==="scroll_depth"){let F=Math.max(0,Math.min(1,y.threshold)),P=new IntersectionObserver(V=>{for(let Fe of V)if(Fe.intersectionRatio>=F){Z(),P.disconnect();break}},{threshold:[F]});P.observe(r),E.push(()=>P.disconnect())}}),()=>{for(let y of E)y()}}let c=()=>{C.current||(C.current=!0,t.track({projectId:n,componentId:e.id,variantId:i,eventType:"goal_achieved",goalType:g,payload:{reward:1}}),t.goal(g,{componentId:e.id,variantId:i},1,0))},f=a.type==="composite"?a.all:[a],R=new Set(f.map((k,E)=>E)),w=k=>{R.delete(k),R.size===0&&c()},D=[];return f.forEach((k,E)=>{if(k.type==="click"){let y=x=>{let L=x.target;L instanceof Element&&Se(L,r,k.selector)&&(a.type==="composite"?w(E):c())};r.addEventListener("click",y),D.push(()=>r.removeEventListener("click",y));return}if(k.type==="form_submit"){let y=x=>{x.target instanceof HTMLFormElement&&r.contains(x.target)&&(a.type==="composite"?w(E):c())};r.addEventListener("submit",y),D.push(()=>r.removeEventListener("submit",y));return}if(k.type==="scroll_depth"){let y=Math.max(0,Math.min(1,k.threshold)),x=new IntersectionObserver(L=>{for(let j of L)if(j.intersectionRatio>=y){a.type==="composite"?w(E):c(),x.disconnect();break}},{threshold:[y]});x.observe(r),D.push(()=>x.disconnect());return}}),()=>{for(let k of D)k()}},[t,i,n,e.id,a,g]),e.clientOnly&&(!m||!t)||!i)return null;let h=(u=e.variants[i])!=null?u:null,I=h===null?A:null;return((S=process==null?void 0:process.env)==null?void 0:S.NODE_ENV)!=="production"&&h===null&&I===null&&console.warn(`[sentient] <Adaptive id="${e.id}"> was assigned variant "${i}" but no matching key exists in props.variants. If this is a dashboard-managed text variant, use <AdaptiveText id="${e.id}"> instead.`),(0,ke.jsx)("div",{ref:l,"data-sentient-id":e.id,"data-sentient-variant":i,children:h!=null?h:I})}var we=(0,v.memo)(Ye,(e,t)=>{if(e.id!==t.id||JSON.stringify(e.goal)!==JSON.stringify(t.goal)||e.microSignalGoals!==t.microSignalGoals)return!1;if(e.variants===t.variants)return!0;let n=Object.keys(e.variants),o=Object.keys(t.variants);return n.length!==o.length?!1:n.every(i=>i in t.variants)});var W=require("react");var Ce=require("react/jsx-runtime");function xe({id:e,default:t,component:n="span",className:o}){let i=G(),A=z(),l=Q(),m=q(),O=(0,W.useRef)(null),[C,d]=(0,W.useState)(()=>{var a,g;return(g=(a=i==null?void 0:i.getAssignment(e,m))==null?void 0:a.content)!=null?g:null}),[s,b]=(0,W.useState)(()=>{var a,g;return(g=(a=i==null?void 0:i.getAssignment(e,m))==null?void 0:a.variantId)!=null?g:null});return(0,W.useEffect)(()=>{var g;if(!i||((g=i.getAssignment(e,m))==null?void 0:g.content)!==void 0)return;let a=!1;return i.assign(e).then(h=>{var I;if(!a){if(!h){((I=process==null?void 0:process.env)==null?void 0:I.NODE_ENV)!=="production"&&console.warn(`[sentient] <AdaptiveText id="${e}"> assignment failed \u2014 showing default text.`);return}b(h.variantId),h.content&&d(h.content)}}),()=>{a=!0}},[i,e,m]),(0,W.useEffect)(()=>{!i||!s||!A||O.current!==s&&(O.current=s,i.track({projectId:A,componentId:e,variantId:s,eventType:"variant_assigned",payload:{}}),l==null||l(e,s))},[i,s,A,e,l]),(0,Ce.jsx)(n,{className:o,children:C!=null?C:t})}var Ie=require("react");function Ee(e){let t=G();return(0,Ie.useCallback)((n,o)=>{t==null||t.componentGoal(e,n,o)},[t,e])}var te=require("@sentientui/core");var Ze=["page","blocks","layoutOrder"],Re=new Map;function Le(e,t){Re.set(e,t)}function ne(e){return Re.get(e)}function Ge(e){var i,A;let t=(A=(i=e.content)!=null?i:ne(e.page))!=null?A:{},n={};for(let[l,m]of Object.entries(t))Ze.includes(l)||(n[l]=m);let o=$(M({},n),{page:e.page,blocks:e.blocks});return e.layoutOrder&&(o.layoutOrder=e.layoutOrder),o}function Oe(e){return`<script type="application/ld+json">${ie(e)}</script>`}function ie(e){return JSON.stringify(M({"@context":"https://schema.org","@type":"WebPage"},e)).replace(/</g,"\\u003c")}function _e(e){let t=[];e.title&&t.push(`# ${e.title}`,""),e.summary&&t.push(String(e.summary),"");for(let[n,o]of Object.entries(e))["page","title","summary","blocks","layoutOrder"].includes(n)||t.push(`## ${n}`,"","```json",JSON.stringify(o,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
|
+
"use strict";var at=Object.create;var V=Object.defineProperty,lt=Object.defineProperties,ct=Object.getOwnPropertyDescriptor,ut=Object.getOwnPropertyDescriptors,dt=Object.getOwnPropertyNames,pe=Object.getOwnPropertySymbols,gt=Object.getPrototypeOf,ve=Object.prototype.hasOwnProperty,ft=Object.prototype.propertyIsEnumerable;var me=(e,t,n)=>t in e?V(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,G=(e,t)=>{for(var n in t||(t={}))ve.call(t,n)&&me(e,n,t[n]);if(pe)for(var n of pe(t))ft.call(t,n)&&me(e,n,t[n]);return e},H=(e,t)=>lt(e,ut(t));var pt=(e,t)=>{for(var n in t)V(e,n,{get:t[n],enumerable:!0})},ye=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of dt(t))!ve.call(e,i)&&i!==n&&V(e,i,{get:()=>t[i],enumerable:!(o=ct(t,i))||o.enumerable});return e};var mt=(e,t,n)=>(n=e!=null?at(gt(e)):{},ye(t||!e||!e.__esModule?V(n,"default",{value:e,enumerable:!0}):n,e)),vt=e=>ye(V({},"__esModule",{value:!0}),e);var Et={};pt(Et,{Adaptive:()=>De,AdaptiveGroup:()=>Qe,AdaptiveProvider:()=>Ce,AdaptiveText:()=>We,SentientPersonaScript:()=>Ue,buildAgentFeed:()=>tt,defineAgentContent:()=>et,detectSegment:()=>le.deriveSessionSegment,getAgentContent:()=>ce,getWeights:()=>Q,renderAgentJsonLd:()=>nt,renderAgentJsonLdBody:()=>ue,renderAgentMarkdown:()=>it,subscribeWeights:()=>X,updateWeights:()=>q,useAdaptive:()=>qe,useAdaptiveApiBaseUrl:()=>Le,useAdaptiveGoal:()=>je,useAdaptiveTokens:()=>Je,useAssignment:()=>N,useInitialAssignments:()=>te,useLayoutOrder:()=>Ge,useSentient:()=>_});module.exports=vt(Et);var w=require("react"),K=require("@sentientui/core");var Se=new Map,z=new Map;function X(e,t){let n=z.get(e);return n||(n=new Set,z.set(e,n)),n.add(t),()=>{n.delete(t),n.size===0&&z.delete(e)}}function q(e,t){Se.set(e,t);let n=z.get(e);if(n)for(let o of n)try{o(t)}catch(i){}}function Q(e){var t;return(t=Se.get(e))!=null?t:null}var yt={on:!1,listeners:new Set};function he(){if(typeof window=="undefined")return yt;let e=window;return e.__sentient_preview||(e.__sentient_preview={on:!1,listeners:new Set}),e.__sentient_preview}function se(){return he().on}function we(e){let t=he().listeners;return t.add(e),()=>{t.delete(e)}}function be(e){return{isLocal:e.isLocal,track:()=>{},goal:()=>{},componentGoal:()=>{},identify:()=>{},fetchWeights:()=>Promise.resolve([]),getAssignment:(t,n)=>e.getAssignment(t,n),assign:(t,n,o,i)=>e.assign(t,n,o,i),decide:()=>Promise.resolve(null),getSlotResult:t=>e.getSlotResult(t),getPersona:()=>e.getPersona(),getGraph:()=>e.getGraph(),destroy:()=>e.destroy()}}var Ae="sentient:overrides-changed";function Y(){var e;return typeof window=="undefined"?0:(e=window.__sentient_overrides_version)!=null?e:0}function B(e){return typeof window=="undefined"?()=>{}:(window.addEventListener(Ae,e),()=>window.removeEventListener(Ae,e))}function xe(e){typeof window!="undefined"&&(window.__sentient_devtools_config=e)}var St={components:new Map,slots:new Map,sections:[],listeners:new Set};function j(){if(typeof window=="undefined")return St;let e=window;return e.__sentient_registry||(e.__sentient_registry={components:new Map,slots:new Map,sections:[],listeners:new Set}),e.__sentient_registry}function J(){for(let e of j().listeners)e()}function Z(e){return j().components.set(e.id,e),J(),()=>{j().components.delete(e.id),J()}}function ee(e){return j().slots.set(e.id,e),J(),()=>{j().slots.delete(e.id),J()}}function ke(e){j().sections=[...e],J()}var Oe=require("react/jsx-runtime");function ht(){var e,t;if(typeof window=="undefined")return"desktop:direct";try{let n=(0,K.detectDeviceClass)((e=navigator.userAgent)!=null?e:""),o=(0,K.detectTrafficSource)((t=document.referrer)!=null?t:"",window.location.origin);return`${n}:${o}`}catch(n){return"desktop:direct"}}var _e="https://api.sentient-ui.com/v1",O=(0,w.createContext)({client:null,apiKey:"",initialAssignments:{},sessionSegment:"desktop:direct",ssrFallback:"first",onAssignment:void 0,initialLayoutOrder:null,initialSlots:{},initialPersona:null,apiBaseUrl:_e});function Ce(e){var y,c;let[t,n]=(0,w.useState)(null),[o]=(0,w.useState)(()=>{var u;return(u=e.sessionSegment)!=null?u:ht()}),[i,m]=(0,w.useState)(se());(0,w.useEffect)(()=>we(()=>m(se())),[]),(0,w.useEffect)(()=>{if(e.consent===!1&&!e.preConsentBehavior){n(l=>(l==null||l.destroy(),null));return}let u={apiKey:e.apiKey,context:e.context,debug:e.debug,initialAssignments:e.initialAssignments,sessionSegment:o,consent:e.consent,preConsentBehavior:e.preConsentBehavior,respectDoNotTrack:e.respectDoNotTrack,ssrSessionId:e.ssrSessionId,country:e.country,localMode:e.localMode,initialSlots:e.initialSlots,initialPersona:e.initialPersona,ingestUrl:e.apiBaseUrl?`${e.apiBaseUrl.replace(/\/$/,"")}/events`:void 0},f=!1,s=null;return e.enableGraph?import("@sentientui/core/graph").then(({init:l})=>{f||(s=l(H(G({},u),{graph:!0})),n(s))}):(s=(0,K.init)(u),n(s)),()=>{f=!0,s==null||s.destroy()}},[e.consent]),(0,w.useEffect)(()=>{if(!t)return;let u=!1,f=async()=>{if(u)return;let l;try{l=await t.fetchWeights()}catch(b){return}if(!u)for(let b of l){let h={componentId:b.componentId,updatedAt:b.updatedAt,variants:b.variants.map(S=>{var v;return{variantId:S.variantId,pulls:S.pulls,avgReward:(v=S.avgReward)!=null?v:0}})};q(b.componentId,h)}};f();let s=setInterval(()=>{f()},6e4);return()=>{u=!0,clearInterval(s)}},[t]);let r=(y=e.ssrFallback)!=null?y:"first",a=(c=e.apiBaseUrl)!=null?c:_e;(0,w.useEffect)(()=>{var u;typeof process!="undefined"&&((u=process.env)==null?void 0:u.NODE_ENV)==="production"||xe({apiKey:e.apiKey,apiBaseUrl:a,isLocal:(t==null?void 0:t.isLocal)===!0})},[t,e.apiKey,a]),(0,w.useEffect)(()=>{e.initialLayoutOrder&&e.initialLayoutOrder.length>0&&ke(e.initialLayoutOrder)},[e.initialLayoutOrder]);let g=(0,w.useMemo)(()=>t&&i?be(t):t,[t,i]),d=(0,w.useMemo)(()=>{var u,f,s,l;return{client:g,apiKey:e.apiKey,initialAssignments:(u=e.initialAssignments)!=null?u:{},sessionSegment:o,ssrFallback:r,onAssignment:e.onAssignment,initialLayoutOrder:(f=e.initialLayoutOrder)!=null?f:null,initialSlots:(s=e.initialSlots)!=null?s:{},initialPersona:(l=e.initialPersona)!=null?l:null,apiBaseUrl:a}},[g,e.apiKey,e.initialAssignments,o,r,e.onAssignment,e.initialLayoutOrder,e.initialSlots,e.initialPersona,a]);return(0,Oe.jsx)(O.Provider,{value:d,children:e.children})}function _(){return(0,w.useContext)(O).client}function I(){return(0,w.useContext)(O).apiKey}function te(){return(0,w.useContext)(O).initialAssignments}function ne(){return(0,w.useContext)(O).sessionSegment}function Re(){return(0,w.useContext)(O).ssrFallback}function ie(){return(0,w.useContext)(O).onAssignment}function Ge(){let e=(0,w.useContext)(O).initialLayoutOrder,t=(0,w.useSyncExternalStore)(B,()=>{var n;return typeof window=="undefined"?null:(n=window.__sentient_layout_override)!=null?n:null},()=>null);return t!=null?t:e}function Ee(){return(0,w.useContext)(O).initialSlots}function Le(){return(0,w.useContext)(O).apiBaseUrl}var x=require("react"),Te=require("@sentientui/core");var L=require("react");function wt(e){var n;if(typeof window=="undefined")return null;let t=(n=window.__sentient_overrides)==null?void 0:n[e];if(t)return t;try{let o=new URLSearchParams(window.location.search);for(let i of o.getAll("sentient_variant")){let m=i.indexOf(":");if(m!==-1&&i.slice(0,m)===e)return i.slice(m+1)}}catch(o){}return null}function Ie(e,t){var o;let n=null;for(let i of e.variants)t.includes(i.variantId)&&(!n||i.avgReward>n.avgReward)&&(n={variantId:i.variantId,avgReward:i.avgReward});return(o=n==null?void 0:n.variantId)!=null?o:null}function N(e,t,n,o){let i=te(),m=Re(),r=_(),a=ne(),g=ie(),d=(0,L.useRef)(null);(0,L.useSyncExternalStore)(B,Y,()=>0);let y=wt(e),c=y&&t.includes(y)?y:null,u=(0,L.useRef)(null);c&&u.current!==c&&(u.current=c,console.info(`[sentient] override active: ${e} -> ${c}`));let f=(()=>{var v,p;if(c)return{variantId:c,content:null,isLoading:!1};if(!r){let A=i[e];return A&&t.includes(A)?{variantId:A,content:null,isLoading:!1}:m==="first"&&t.length>0?{variantId:t[0],content:null,isLoading:!1}:{variantId:null,content:null,isLoading:!0}}let h=r.getAssignment(e,a);if(h&&(t.includes(h.variantId)||h.content))return{variantId:h.variantId,content:(v=h.content)!=null?v:null,isLoading:!1};let S=Q(e);if(S){let A=Ie(S,t);if(A)return{variantId:A,content:null,isLoading:!1}}return{variantId:(p=t[0])!=null?p:null,content:null,isLoading:!1}})(),[s,l]=(0,L.useState)(f),b=h=>{g&&d.current!==h&&(d.current=h,g(e,h))};return(0,L.useEffect)(()=>{var S;if(c||!r)return;let h=r.getAssignment(e,a);if(h&&(t.includes(h.variantId)||h.content)){l({variantId:h.variantId,content:(S=h.content)!=null?S:null,isLoading:!1}),b(h.variantId);return}l(v=>{var p;return v.variantId?v:{variantId:(p=t[0])!=null?p:null,content:null,isLoading:!1}})},[c,r,e,a]),(0,L.useEffect)(()=>{if(c||!r)return;let h=r.getAssignment(e,a);if(h&&t.includes(h.variantId))return;let S=!1;return r.assign(e,t,n,o).then(v=>{var p;S||v&&(!t.includes(v.variantId)&&!v.content||(l({variantId:v.variantId,content:(p=v.content)!=null?p:null,isLoading:!1}),b(v.variantId)))}),()=>{S=!0}},[c,r,e,a]),(0,L.useEffect)(()=>{if(!c&&r)return X(e,h=>{var p;let S=r.getAssignment(e,a);if(S&&(t.includes(S.variantId)||S.content)){l({variantId:S.variantId,content:(p=S.content)!=null?p:null,isLoading:!1});return}let v=Ie(h,t);v&&l({variantId:v,content:null,isLoading:!1})})},[c,r,e,a]),c?{variantId:c,content:null,isLoading:!1}:s}function E(){var e;return typeof process=="undefined"||((e=process.env)==null?void 0:e.NODE_ENV)!=="production"}function T(e){return typeof e=="string"?{type:"click"}:e}function $(e){return typeof e=="string"?e:e.type}var bt=3e4;function At(e,t){try{let n=`_snt_pv_${e}_${t}`;return sessionStorage.getItem(n)?!1:(sessionStorage.setItem(n,"1"),!0)}catch(n){return!0}}function xt(e){if(!(e instanceof Element))return!1;let t=e.tagName.toLowerCase();return t==="a"||t==="button"?!0:e.getAttribute("role")==="button"}function Pe(e,t,n){if(n){try{let i=e;for(;i&&i!==t;){if(i.matches(n))return!0;i=i.parentElement}}catch(i){}return!1}let o=e;for(;o&&o!==t;){if(xt(o))return!0;o=o.parentElement}return!1}function D(e,t,n){if(t.type==="weighted_composite"){let a=new Set,g=[];return t.steps.forEach(({goal:d,name:y,weight:c},u)=>{let f=()=>{a.has(u)||(a.add(u),n.fireStep(y,c,u))};if(d.type==="click"){let s=l=>{let b=l.target;b instanceof Element&&Pe(b,e,d.selector)&&f()};e.addEventListener("click",s),g.push(()=>e.removeEventListener("click",s));return}if(d.type==="form_submit"){let s=l=>{l.target instanceof HTMLFormElement&&e.contains(l.target)&&f()};e.addEventListener("submit",s),g.push(()=>e.removeEventListener("submit",s));return}if(d.type==="scroll_depth"){let s=Math.max(0,Math.min(1,d.threshold)),l=new IntersectionObserver(b=>{for(let h of b)if(h.intersectionRatio>=s){f(),l.disconnect();break}},{threshold:[s]});l.observe(e),g.push(()=>l.disconnect())}}),()=>{for(let d of g)d()}}let o=t.type==="composite"?t.all:[t],i=new Set(o.map((a,g)=>g)),m=a=>{i.delete(a),i.size===0&&n.fireGoal()},r=[];return o.forEach((a,g)=>{if(a.type==="click"){let d=y=>{let c=y.target;c instanceof Element&&Pe(c,e,a.selector)&&(t.type==="composite"?m(g):n.fireGoal())};e.addEventListener("click",d),r.push(()=>e.removeEventListener("click",d));return}if(a.type==="form_submit"){let d=y=>{y.target instanceof HTMLFormElement&&e.contains(y.target)&&(t.type==="composite"?m(g):n.fireGoal())};e.addEventListener("submit",d),r.push(()=>e.removeEventListener("submit",d));return}if(a.type==="scroll_depth"){let d=Math.max(0,Math.min(1,a.threshold)),y=new IntersectionObserver(c=>{for(let u of c)if(u.intersectionRatio>=d){t.type==="composite"?m(g):n.fireGoal(),y.disconnect();break}},{threshold:[d]});y.observe(e),r.push(()=>y.disconnect());return}}),()=>{for(let a of r)a()}}function M(e,t,n,o,i){var a;let m=(a=i==null?void 0:i.innerHTML)!=null?a:"",r=m!==""&&At(n,o);e.track({projectId:t,componentId:n,variantId:o,eventType:"variant_assigned",payload:r?{previewHtml:m.slice(0,bt)}:{}})}var Me=require("react/jsx-runtime");function kt(e){var h;let t=_(),n=I(),o=(0,x.useMemo)(()=>Object.keys(e.variants),[e.variants]),{variantId:i,content:m}=N(e.id,o,e.agentData,e.agentDataByVariant),r=(0,x.useRef)(null),[a,g]=(0,x.useState)(!1);(0,x.useEffect)(()=>{g(!0)},[]);let d=(0,x.useRef)(!1),y=(0,x.useRef)(new Set),c=(0,x.useRef)(null),u=typeof e.goal=="string"?e.goal:JSON.stringify(e.goal),f=(0,x.useMemo)(()=>T(e.goal),[u]),s=typeof e.goal=="string"?e.goal:f.type;if((0,x.useEffect)(()=>Z({id:e.id,variantIds:o,goal:s}),[e.id,o,s]),(0,x.useEffect)(()=>{var v,p;!t||!i||!n||c.current===i||!((p=(v=r.current)==null?void 0:v.innerHTML)!=null&&p)||(c.current=i,M(t,n,e.id,i,r.current))},[t,i,n,e.id,a,m]),(0,x.useEffect)(()=>{d.current=!1,y.current=new Set},[i,f]),(0,x.useEffect)(()=>{if(!t||!i)return;let S=r.current;if(!S)return;let v=null,p=0,A=()=>{p=Date.now(),v=setTimeout(()=>{t.track({projectId:n,componentId:e.id,variantId:i,eventType:"cursor_signal",payload:{hoverDuration:Date.now()-p}}),v=null},800)},C=()=>{v!==null&&(clearTimeout(v),v=null)};return S.addEventListener("mouseenter",A),S.addEventListener("mouseleave",C),()=>{S.removeEventListener("mouseenter",A),S.removeEventListener("mouseleave",C),v!==null&&clearTimeout(v)}},[t,i,n,e.id]),(0,x.useEffect)(()=>{if(!t||!i)return;let S=r.current;if(!S)return;let v=Date.now();return(0,Te.attachMicroSignalDetectors)((p,A={})=>{var de,ge,fe;t.track({projectId:n,componentId:e.id,variantId:i,eventType:"micro_signal",payload:G({signalType:p},A)});let C=(de=e.microSignalGoals)==null?void 0:de[p];if(!C||y.current.has(p))return;y.current.add(p);let rt=typeof C=="string"?C:C.name,ot=typeof C=="string"?1:(ge=C.weight)!=null?ge:1,st=typeof C=="string"?0:(fe=C.stepIndex)!=null?fe:0;t.goal(rt,G({signalType:p},A),ot,st)},S,v)},[t,i,n,e.id,e.microSignalGoals]),(0,x.useEffect)(()=>{if(!t||!i)return;let S=r.current;if(S)return D(S,f,{fireGoal:()=>{d.current||(d.current=!0,t.track({projectId:n,componentId:e.id,variantId:i,eventType:"goal_achieved",goalType:s,payload:{reward:1}}),t.goal(s,{componentId:e.id,variantId:i},1,0))},fireStep:(v,p,A)=>{t.track({projectId:n,componentId:e.id,variantId:i,eventType:"goal_achieved",goalType:v,payload:{reward:p}}),t.goal(v,{},p,A)}})},[t,i,n,e.id,f,s]),e.clientOnly&&(!a||!t)||!i)return null;let l=(h=e.variants[i])!=null?h:null,b=l===null?m:null;return E()&&l===null&&b===null&&console.warn(`[sentient] <Adaptive id="${e.id}"> was assigned variant "${i}" but no matching key exists in props.variants. If this is a dashboard-managed text variant, use <AdaptiveText id="${e.id}"> instead.`),(0,Me.jsx)("div",{ref:r,"data-sentient-id":e.id,"data-sentient-variant":i,children:l!=null?l:b})}var De=(0,x.memo)(kt,(e,t)=>{if(e.id!==t.id||JSON.stringify(e.goal)!==JSON.stringify(t.goal)||e.microSignalGoals!==t.microSignalGoals)return!1;if(e.variants===t.variants)return!0;let n=Object.keys(e.variants),o=Object.keys(t.variants);return n.length!==o.length?!1:n.every(i=>i in t.variants)});var W=require("react");var Fe=require("react/jsx-runtime");function We({id:e,default:t,component:n="span",className:o}){let i=_(),m=I(),r=ie(),a=ne(),g=(0,W.useRef)(null),[d,y]=(0,W.useState)(()=>{var f,s;return(s=(f=i==null?void 0:i.getAssignment(e,a))==null?void 0:f.content)!=null?s:null}),[c,u]=(0,W.useState)(()=>{var f,s;return(s=(f=i==null?void 0:i.getAssignment(e,a))==null?void 0:f.variantId)!=null?s:null});return(0,W.useEffect)(()=>{var s;if(!i||((s=i.getAssignment(e,a))==null?void 0:s.content)!==void 0)return;let f=!1;return i.assign(e).then(l=>{if(!f){if(!l){E()&&console.warn(`[sentient] <AdaptiveText id="${e}"> assignment failed \u2014 showing default text.`);return}u(l.variantId),l.content&&y(l.content)}}),()=>{f=!0}},[i,e,a]),(0,W.useEffect)(()=>{!i||!c||!m||g.current!==c&&(g.current=c,i.track({projectId:m,componentId:e,variantId:c,eventType:"variant_assigned",payload:{}}),r==null||r(e,c))},[i,c,m,e,r]),(0,Fe.jsx)(n,{className:o,children:d!=null?d:t})}var Be=require("react");function je(e){let t=_();return(0,Be.useCallback)((n,o)=>{t==null||t.componentGoal(e,n,o)},[t,e])}var Ne=require("@sentientui/core"),$e=require("@sentientui/policy"),Ve=require("react/jsx-runtime");function Ke(e){return JSON.stringify(e).replace(/</g,"\\u003c")}function _t(e){return e.persona?'(function(){try{var d=document.documentElement;if(d.hasAttribute("data-sentient-persona"))return;d.setAttribute("data-sentient-persona",'+Ke(e.persona.persona)+');d.setAttribute("data-sentient-confidence",'+Ke((0,$e.confidenceBand)(e.persona.confidence))+");}catch(e){}})();":(0,Ne.renderPrePaintScript)(e.apiKey)}function Ue(e){return(0,Ve.jsx)("script",{"data-sentient-persona-script":"",dangerouslySetInnerHTML:{__html:_t(e)}})}var P=require("react"),He=require("@sentientui/policy");var U=require("react"),F=require("@sentientui/core"),Ct=require("@sentientui/policy");function re(e,t){var y;(0,U.useSyncExternalStore)(B,Y,()=>0);let n=_(),o=Ee(),[,i]=(0,U.useReducer)(c=>c+1,0),m=typeof window!="undefined"?(y=window.__sentient_slot_overrides)==null?void 0:y[e]:void 0,r=m===void 0?o[e]:void 0,a=m===void 0&&r===void 0&&n?n.getSlotResult(e):null,g=(n==null?void 0:n.isLocal)===!0&&m===void 0&&r===void 0&&a===null;if((0,U.useEffect)(()=>{if(!g||!n)return;let c=!1;return n.decide({slots:[t]}).then(u=>{!c&&u&&i()}),()=>{c=!0}},[n,e,g]),m!==void 0)return{result:m,arm:(0,F.armOfResult)(m),source:"override"};if(r!==void 0)return{result:r,arm:(0,F.armOfResult)(r),source:"preloaded"};if(a!==null)return{result:a,arm:(0,F.armOfResult)(a),source:"client"};let d=(0,F.baselineResultFor)(t);return{result:d,arm:(0,F.armOfResult)(d),source:"baseline"}}var ae=new Set;function Rt(e){return typeof CSS!="undefined"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/"/g,'\\"')}function Je(e,t,n){let o=_(),i=I(),m=(0,P.useMemo)(()=>({id:e,dims:t}),[e]),{result:r,arm:a}=re(e,m),g=(0,P.useMemo)(()=>typeof r=="string"?{}:r,[a]);if(E()&&!ae.has(e)){let u=(0,He.validateSlotDecl)({id:e,dims:Object.fromEntries(Object.entries(t).map(([s,l])=>[s,[...l]]))}),f=Object.values(t).reduce((s,l)=>s*l.length,1);u.ok?f>4&&(ae.add(e),console.warn(`[sentient] useAdaptiveTokens("${e}") declares ${f} combinations \u2014 more than the recommended 4. Each extra combination needs more traffic to learn; consider fewer dims/values.`)):(ae.add(e),console.warn(`[sentient] useAdaptiveTokens("${e}"): invalid declaration \u2014 ${u.reason}. Serving baseline.`))}let d=(n==null?void 0:n.goal)===void 0?null:typeof n.goal=="string"?n.goal:JSON.stringify(n.goal);(0,P.useEffect)(()=>ee({id:e,dims:t}),[e]);let y=(0,P.useRef)(null);(0,P.useEffect)(()=>{!o||y.current===a||(y.current=a,M(o,i,e,a,null))},[o,i,e,a]),(0,P.useEffect)(()=>{if(!o||!(n!=null&&n.goal))return;let u=document.querySelector(`[data-sentient-slot="${Rt(e)}"]`);if(!u){E()&&console.warn(`[sentient] useAdaptiveTokens("${e}"): a goal is declared but no element carries the returned props \u2014 spread {...props} on the slot's element.`);return}let f=$(n.goal),s=!1;return D(u,T(n.goal),{fireGoal:()=>{s||(s=!0,o.componentGoal(e,f))},fireStep:(l,b)=>{o.componentGoal(e,l,{reward:b})}})},[o,e,d,a]);let c=(0,P.useMemo)(()=>{let u={"data-sentient-slot":e};for(let[f,s]of Object.entries(g))u[`data-${f}`]=s;return u},[e,g]);return{tokens:g,props:c}}var k=require("react"),Xe=require("@sentientui/core");var ze=new Set;function qe(e,t){var v;if(E()&&!t.goal)throw new Error(`[sentient] useAdaptive("${e}"): a goal is required \u2014 without one the optimizer accumulates exposures with no rewards and cannot learn. Pass e.g. goal: 'buy_click'.`);let n=_(),o=I(),i=(0,k.useMemo)(()=>Object.keys(t.variants),[e]),{variantId:m}=N(e,i),r=(v=m!=null?m:i[0])!=null?v:"",a=t.variants[r],[g,d]=(0,k.useState)(null),y=(0,k.useRef)(null),c=(0,k.useCallback)(p=>{y.current=p,d(p)},[]),u=typeof t.goal=="string"?t.goal:JSON.stringify(t.goal),f=(0,k.useMemo)(()=>T(t.goal),[u]),s=$(t.goal);(0,k.useEffect)(()=>Z({id:e,variantIds:i,goal:s}),[e,i,s]);let l=(0,k.useRef)(null);(0,k.useEffect)(()=>{!n||!r||!g||l.current!==r&&(l.current=r,M(n,o,e,r,g))},[n,o,e,r,g]);let b=(0,k.useRef)(!1);(0,k.useEffect)(()=>{b.current=!1},[r,u]),(0,k.useEffect)(()=>{if(!(!n||!r||!g))return D(g,f,{fireGoal:()=>{b.current||(b.current=!0,n.track({projectId:o,componentId:e,variantId:r,eventType:"goal_achieved",goalType:s,payload:{reward:1}}),n.goal(s,{componentId:e,variantId:r},1,0))},fireStep:(p,A,C)=>{n.track({projectId:o,componentId:e,variantId:r,eventType:"goal_achieved",goalType:p,payload:{reward:A}}),n.goal(p,{},A,C)}})},[n,g,r,o,e,f,s]),(0,k.useEffect)(()=>{if(!n||!r||!g)return;let p=Date.now();return(0,Xe.attachMicroSignalDetectors)((A,C={})=>{n.track({projectId:o,componentId:e,variantId:r,eventType:"micro_signal",payload:G({signalType:A},C)})},g,p)},[n,g,r,o,e]),(0,k.useEffect)(()=>{if(!E()||!n)return;let p=setTimeout(()=>{!y.current&&!ze.has(e)&&(ze.add(e),console.warn(`[sentient] useAdaptive("${e}"): bind was never attached \u2014 spread {...bind} on the rendered element, otherwise exposure and goal tracking cannot work and the optimizer learns nothing.`))},0);return()=>clearTimeout(p)},[n,e]);let h=(0,k.useCallback)((p,A)=>{n==null||n.componentGoal(e,p!=null?p:s,A)},[n,e,s]),S=(0,k.useMemo)(()=>({ref:c,"data-sentient-id":e,"data-sentient-variant":r}),[c,e,r]);return{variant:r,value:a,bind:S,fireGoal:h}}var R=require("react");var Ye=require("react/jsx-runtime"),oe=new Set;function Qe(e){var s;let t=_(),n=I(),o=(0,R.useRef)(null),i=(0,R.useMemo)(()=>Object.keys(e.arrangements),[e.id]),m=(0,R.useMemo)(()=>G({id:e.id,arms:i},e.baseline!==void 0?{baseline:e.baseline}:{}),[e.id,i,e.baseline]),{arm:r}=re(e.id,m);E()&&e.baseline!==void 0&&e.baseline!==i[0]&&!oe.has(e.id+":baseline")&&(oe.add(e.id+":baseline"),console.warn(`[sentient] <AdaptiveGroup id="${e.id}">: baseline "${e.baseline}" is not the first-declared arrangement ("${i[0]}"). The first arrangement should usually be the page's real incumbent (the holdout sees it).`));let a=R.Children.toArray(e.children).filter(R.isValidElement),g=new Map;for(let l of a)g.set(String((s=l.key)!=null?s:"").replace(/^\.\$/,""),l);let d=e.arrangements[r],y=d!==void 0&&d.length===a.length&&d.every(l=>g.has(l));E()&&d!==void 0&&!y&&!oe.has(e.id+":keys")&&(oe.add(e.id+":keys"),console.warn(`[sentient] <AdaptiveGroup id="${e.id}">: arrangement "${r}" [${d.join(", ")}] does not match the children's keys \u2014 rendering declaration order (fail-safe).`));let c=y?d.map(l=>g.get(l)):a;(0,R.useEffect)(()=>ee({id:e.id,arms:Object.keys(e.arrangements)}),[e.id]);let u=(0,R.useRef)(null);(0,R.useEffect)(()=>{!t||u.current===r||(u.current=r,M(t,n,e.id,r,o.current))},[t,n,e.id,r]);let f=e.goal===void 0?null:typeof e.goal=="string"?e.goal:JSON.stringify(e.goal);return(0,R.useEffect)(()=>{if(!t||e.goal===void 0)return;let l=o.current;if(!l)return;let b=$(e.goal),h=!1;return D(l,T(e.goal),{fireGoal:()=>{h||(h=!0,t.componentGoal(e.id,b))},fireStep:(S,v)=>{t.componentGoal(e.id,S,{reward:v})}})},[t,e.id,f,r]),(0,Ye.jsx)("div",{ref:o,"data-sentient-id":e.id,"data-sentient-variant":r,children:c})}var le=require("@sentientui/core");var Gt=["page","blocks","layoutOrder"],Ze=new Map;function et(e,t){Ze.set(e,t)}function ce(e){return Ze.get(e)}function tt(e){var i,m;let t=(m=(i=e.content)!=null?i:ce(e.page))!=null?m:{},n={};for(let[r,a]of Object.entries(t))Gt.includes(r)||(n[r]=a);let o=H(G({},n),{page:e.page,blocks:e.blocks});return e.layoutOrder&&(o.layoutOrder=e.layoutOrder),o}function nt(e){return`<script type="application/ld+json">${ue(e)}</script>`}function ue(e){return JSON.stringify(G({"@context":"https://schema.org","@type":"WebPage"},e)).replace(/</g,"\\u003c")}function it(e){let t=[];e.title&&t.push(`# ${e.title}`,""),e.summary&&t.push(String(e.summary),"");for(let[n,o]of Object.entries(e))["page","title","summary","blocks","layoutOrder"].includes(n)||t.push(`## ${n}`,"","```json",JSON.stringify(o,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(`
|
|
3
3
|
`).trimEnd()+`
|
|
4
|
-
`}0&&(module.exports={Adaptive,AdaptiveProvider,AdaptiveText,buildAgentFeed,defineAgentContent,detectSegment,getAgentContent,getWeights,renderAgentJsonLd,renderAgentJsonLdBody,renderAgentMarkdown,subscribeWeights,updateWeights,useAdaptiveGoal,useAssignment,useInitialAssignments,useLayoutOrder,useSentient});
|
|
4
|
+
`}0&&(module.exports={Adaptive,AdaptiveGroup,AdaptiveProvider,AdaptiveText,SentientPersonaScript,buildAgentFeed,defineAgentContent,detectSegment,getAgentContent,getWeights,renderAgentJsonLd,renderAgentJsonLdBody,renderAgentMarkdown,subscribeWeights,updateWeights,useAdaptive,useAdaptiveApiBaseUrl,useAdaptiveGoal,useAdaptiveTokens,useAssignment,useInitialAssignments,useLayoutOrder,useSentient});
|
|
5
5
|
//# sourceMappingURL=index.js.map
|