@kywi-software/js 0.6.7 → 0.7.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/context.ts", "../src/entity.ts", "../src/feed.ts", "../src/render-feed.ts", "../src/module-system.ts", "../src/form-hooks.ts", "../src/experiments/index.ts", "../../core/src/audiences/types.ts", "../../core/src/audiences/evaluator/glob.ts", "../../core/src/audiences/evaluator/instant-match.ts", "../../core/src/audiences/evaluator/score.ts", "../../core/src/audiences/evaluator/condition-registry.ts", "../../core/src/audiences/evaluator/resolver.ts", "../src/audience/behavioral-collector.ts", "../src/audience/selfid-collector.ts", "../src/audience/evaluate.ts", "../src/audience/dom-patcher.ts", "../src/cookies.ts", "../src/audience/transparency.ts", "../src/audience/preview.ts", "../src/audience/data-layer.ts", "../src/audience/adapter-runner.ts", "../src/audience/selfid-submit.ts", "../src/audience/selfid-widget.ts", "../src/personalization/badge.ts", "../src/audience/index.ts", "../src/index.ts"],
4
- "sourcesContent": ["// packages/kywi-js/src/context.ts\nimport type { KywiContext } from './types.js'\n\nexport function readContext(): KywiContext {\n const meta = (name: string): string => {\n if (typeof document === 'undefined') return ''\n const el = document.querySelector(`meta[name=\"kywi:${name}\"]`)\n return el?.getAttribute('content') ?? ''\n }\n return {\n siteId: meta('site-id') || document?.documentElement?.getAttribute('data-kywi-site') || '',\n locale: document?.documentElement?.lang || 'en',\n themePath: meta('theme-path') || '',\n basePath: meta('base-path') || '/',\n csrfToken: meta('csrf-token') || '',\n isEditMode: document?.body?.classList?.contains('kywi-edit-mode') ?? false,\n }\n}\n", "// packages/kywi-js/src/entity.ts\nimport type { KywiEntityObject } from './types.js'\n\nfunction createEntity(type: string, basePath: string, csrfToken: string, data: Record<string, unknown>): KywiEntityObject {\n const fields = { ...data }\n const dirty = new Map<string, unknown>()\n const errors: string[] = []\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (csrfToken) headers['X-CSRF-Token'] = csrfToken\n\n const entity: KywiEntityObject = {\n get(field: string) { return fields[field] },\n set(field: string, value: unknown) { fields[field] = value; dirty.set(field, value); return entity },\n async save() {\n const id = fields['id'] as string | undefined\n const url = id ? `${basePath}/content/${type}/${id}` : `${basePath}/content/${type}`\n const res = await fetch(url, { method: id ? 'PUT' : 'POST', headers, body: JSON.stringify(Object.fromEntries(dirty)) })\n const json = await res.json() as { data?: Record<string, unknown>; error?: { message: string } }\n if (!res.ok || json.error) { errors.push(json.error?.message ?? 'Save failed'); throw entity }\n if (json.data) Object.assign(fields, json.data)\n dirty.clear()\n return entity\n },\n async delete() {\n const id = fields['id'] as string\n await fetch(`${basePath}/content/${type}/${id}`, { method: 'DELETE', headers })\n },\n getErrors() { return [...errors] },\n async loadBy(field: string, value: string) {\n const url = field === 'id' ? `${basePath}/content/${type}/${value}` : `${basePath}/content/${type}?${field}=${encodeURIComponent(value)}`\n const res = await fetch(url, { headers })\n const json = await res.json() as { data?: Record<string, unknown>; error?: { message: string } }\n if (!res.ok || json.error) { errors.push(json.error?.message ?? 'Load failed'); throw entity }\n if (json.data) Object.assign(fields, json.data)\n return entity\n },\n }\n return entity\n}\n\nexport function createEntityFactory(basePath: string, csrfToken: string) {\n return (type: string): KywiEntityObject => createEntity(type, basePath, csrfToken, {})\n}\n", "// packages/kywi-js/src/feed.ts\nimport type { KywiEntityObject, KywiFeedResult } from './types.js'\n\ninterface Filter { field: string; operator: string; value?: unknown; conjunction: 'and' | 'or' }\n\nexport type AggregateFunction = 'count' | 'sum' | 'min' | 'max' | 'avg'\nexport type AggregateResult = Record<string, unknown>\n\nclass PropBuilder {\n constructor(private builder: FeedBuilder, private field: string, private conj: 'and' | 'or') {}\n private add(op: string, value?: unknown) { this.builder._filters.push({ field: this.field, operator: op, value, conjunction: this.conj }); return this.builder }\n isEQ(v: unknown) { return this.add('eq', v) }\n isNEQ(v: unknown) { return this.add('neq', v) }\n isLT(v: unknown) { return this.add('lt', v) }\n isLTE(v: unknown) { return this.add('lte', v) }\n isGT(v: unknown) { return this.add('gt', v) }\n isGTE(v: unknown) { return this.add('gte', v) }\n beginsWith(v: unknown) { return this.add('beginsWith', v) }\n endsWith(v: unknown) { return this.add('endsWith', v) }\n contains(v: unknown) { return this.add('contains', v) }\n isNull() { return this.add('isNull') }\n isNotNull() { return this.add('isNotNull') }\n}\n\nclass FeedBuilder {\n _filters: Filter[] = []\n private _sort: { field: string; direction: 'asc' | 'desc' } | null = null\n private _limit: number | null = null\n private _page: number | null = null\n constructor(private contentType: string, private basePath: string, private csrfToken: string) {}\n\n where(): this { return this }\n prop(field: string) { return new PropBuilder(this, field, 'and') }\n andProp(field: string) { return new PropBuilder(this, field, 'and') }\n orProp(field: string) { return new PropBuilder(this, field, 'or') }\n sort(field: string, direction: 'asc' | 'desc' = 'asc'): this { this._sort = { field, direction }; return this }\n maxItems(n: number): this { this._limit = n; return this }\n page(n: number): this { this._page = n; return this }\n\n private buildBody(): Record<string, unknown> {\n const filterArray = this._filters.map(f => ({\n field: f.field,\n operator: f.operator,\n value: f.value,\n conjunction: f.conjunction,\n }))\n const body: Record<string, unknown> = { contentType: this.contentType }\n if (filterArray.length > 0) body['filters'] = filterArray\n if (this._sort) body['sort'] = this._sort\n if (this._limit !== null) body['limit'] = this._limit\n if (this._page !== null) body['page'] = this._page\n return body\n }\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (this.csrfToken) headers['X-CSRF-Token'] = this.csrfToken\n return headers\n }\n\n async aggregate(fn: AggregateFunction, field?: string): Promise<AggregateResult> {\n const body = this.buildBody()\n const agg: Record<string, string> = { function: fn }\n if (field) agg['field'] = field\n body['aggregate'] = agg\n\n const res = await fetch(`${this.basePath}/feeds/aggregate`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n const json = await res.json() as { data?: AggregateResult }\n return json.data ?? {}\n }\n\n async getQuery(): Promise<KywiFeedResult> {\n const body = this.buildBody()\n const res = await fetch(`${this.basePath}/feeds/query`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n // Two response envelopes are supported:\n // 1. The live @kywi-software/core server (POST /feeds/query -> jsonOk(executeFeedQuery))\n // returns { data: { items, total, page, pageSize, totalPages } }.\n // 2. A flatter { data: [ ...items ], meta: { total, page, totalPages } } shape.\n // Normalise both so the decoupled client works against the real API.\n const json = await res.json() as {\n data?: Array<Record<string, unknown>> | { items?: Array<Record<string, unknown>>; total?: number; page?: number; pageSize?: number; totalPages?: number }\n meta?: { total?: number; page?: number; totalPages?: number }\n }\n\n const payload = json.data\n const rawItems: Array<Record<string, unknown>> = Array.isArray(payload)\n ? payload\n : (payload?.items ?? [])\n const total = Array.isArray(payload) ? (json.meta?.total ?? rawItems.length) : (payload?.total ?? rawItems.length)\n const page = Array.isArray(payload) ? (json.meta?.page ?? 1) : (payload?.page ?? 1)\n const pages = Array.isArray(payload) ? (json.meta?.totalPages ?? 0) : (payload?.totalPages ?? 0)\n\n const items: KywiEntityObject[] = rawItems.map(d => ({\n get(field: string) { return d[field] },\n set() { throw new Error('Feed results are read-only') },\n save() { return Promise.reject(new Error('Feed results are read-only')) },\n delete() { return Promise.reject(new Error('Feed results are read-only')) },\n getErrors() { return [] },\n loadBy() { return Promise.reject(new Error('Use Kywi.getEntity() to load by field')) },\n }))\n\n return { items, total, page, pages }\n }\n}\n\nexport function createFeedFactory(basePath: string, csrfToken: string) {\n return (type: string) => new FeedBuilder(type, basePath, csrfToken)\n}\n", "// packages/kywi-js/src/render-feed.ts\nimport type { KywiEntityObject, KywiFeedResult } from './types.js'\n\ninterface RenderFeedOptions {\n feed: { getQuery(): Promise<KywiFeedResult> }\n container: HTMLElement\n template: (item: KywiEntityObject) => string | Node\n loadingText?: string; emptyText?: string\n wrapperTag?: string; wrapperClass?: string\n unsafeHtml?: boolean\n onRender?: (container: HTMLElement) => void\n}\n\nexport async function renderFeed(options: RenderFeedOptions): Promise<void> {\n const { feed, container, template, loadingText = '', emptyText = '', wrapperTag = 'div', wrapperClass, unsafeHtml = false, onRender } = options\n if (loadingText) container.textContent = loadingText\n const result = await feed.getQuery()\n container.textContent = ''\n if (result.items.length === 0) { if (emptyText) container.textContent = emptyText; return }\n const wrapper = document.createElement(wrapperTag)\n if (wrapperClass) wrapper.className = wrapperClass\n for (const item of result.items) {\n const rendered = template(item)\n if (rendered instanceof Node) {\n wrapper.appendChild(rendered)\n } else if (unsafeHtml) {\n const span = document.createElement('span')\n // intentional: caller explicitly opts in via unsafeHtml\n span['innerHTML'] = rendered\n wrapper.appendChild(span)\n } else {\n const span = document.createElement('span')\n span.textContent = rendered // SAFE: always textContent for string templates\n wrapper.appendChild(span)\n }\n }\n container.appendChild(wrapper)\n if (onRender) onRender(container)\n}\n", "// packages/kywi-js/src/module-system.ts\nimport { Kywi } from './index.js'\nimport type { KywiModuleContext } from './types.js'\n\nfunction readParams(el: HTMLElement): Record<string, string> {\n const params: Record<string, string> = {}\n for (const attr of Array.from(el.attributes)) {\n if (attr.name.startsWith('data-kywi-param-')) {\n params[attr.name.slice(16)] = attr.value\n }\n }\n return params\n}\n\nexport function initModules(): void {\n const elements = document.querySelectorAll('[data-kywi-module]')\n for (const el of Array.from(elements)) {\n const htmlEl = el as HTMLElement\n const moduleName = htmlEl.getAttribute('data-kywi-module')\n if (!moduleName) continue\n const def = Kywi.Module[moduleName]\n if (!def || !def.renderClient) continue\n const context: KywiModuleContext = { targetEl: htmlEl, ...readParams(htmlEl) }\n def.renderClient.call({ context, ...def })\n }\n}\n", "// packages/kywi-js/src/form-hooks.ts\nimport { Kywi } from './index.js'\n\nexport function initFormHooks(): void {\n const forms = document.querySelectorAll('[data-kywi-form]')\n for (const formEl of Array.from(forms)) {\n const htmlForm = formEl as HTMLFormElement\n const hooks = Kywi.DisplayObject.Form._hooks\n if (hooks['onAfterRender']) hooks['onAfterRender'].call({ context: { targetEl: htmlForm } })\n htmlForm.addEventListener('submit', (e) => {\n if (hooks['onSubmit']) {\n const result = hooks['onSubmit'].call({ context: { targetEl: htmlForm } })\n if (result === false) e.preventDefault()\n }\n })\n }\n}\n\nexport async function submitKywiForm(form: HTMLFormElement, endpoint: string): Promise<void> {\n const formData = new FormData(form)\n const data: Record<string, string> = {}\n formData.forEach((value, key) => { data[key] = value as string })\n\n const res = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n const json = await res.json() as { success: boolean; errors?: Record<string, string>; data?: Record<string, unknown> }\n const hooks = Kywi.DisplayObject.Form._hooks\n\n if (!json.success && json.errors) {\n if (typeof hooks['onAfterErrorRender'] === 'function') {\n hooks['onAfterErrorRender']({ errors: json.errors, targetEl: form })\n }\n } else if (json.success && json.data) {\n if (typeof hooks['onAfterResponseRender'] === 'function') {\n hooks['onAfterResponseRender']({ response: json.data, targetEl: form })\n }\n }\n}\n", "// packages/kywi-js/src/experiments/index.ts\n//\n// Client-side A/B experiment beacons. Reads the server-rendered kywi:* meta\n// tags, confirms the exposure, and reports conversion signals (pageview,\n// form-submit, custom) back to the runtime endpoints. Fire-and-forget: every\n// call is best-effort and never throws into the host page.\n\nimport { readContext } from '../context.js'\nimport type { KywiContext } from '../types.js'\n\nexport interface ConversionSignal {\n type: 'pageview' | 'form_submit' | 'custom'\n url?: string\n formId?: string\n eventName?: string\n}\n\nexport interface ExperimentBootConfig {\n context?: KywiContext\n apiBase?: string\n visitorId?: string\n currentPath?: string\n /** Auto-emit a pageview conversion signal on boot (default true). */\n autoPageview?: boolean\n}\n\nexport interface ExperimentRuntime {\n /** Emit a custom conversion event, e.g. kywi.track('signup'). */\n track(eventName: string): void\n /** Emit a raw conversion signal. */\n trackConversion(signal: ConversionSignal): void\n}\n\nfunction apiBaseFrom(ctx: KywiContext): string {\n return ctx.basePath && ctx.basePath !== '/' ? `${ctx.basePath}/api/v1` : '/api/v1'\n}\n\nfunction metaContent(name: string): string | null {\n if (typeof document === 'undefined') return null\n return document.querySelector(`meta[name=\"kywi:${name}\"]`)?.getAttribute('content') ?? null\n}\n\n// A single document-level submit listener is installed once and routes to the\n// most recent boot's handler \u2014 booting twice must not double-count conversions.\nlet submitListenerInstalled = false\nlet currentFormConversion: ((formId: string) => void) | null = null\n\nfunction installFormListener(): void {\n if (submitListenerInstalled || typeof document === 'undefined') return\n submitListenerInstalled = true\n document.addEventListener(\n 'submit',\n (e) => {\n const form = e.target as HTMLElement | null\n if (!form || form.tagName !== 'FORM') return\n const formId = form.getAttribute('data-kywi-form-id') ?? form.getAttribute('id')\n if (formId && currentFormConversion) currentFormConversion(formId)\n },\n true,\n )\n}\n\nfunction beacon(url: string, body: unknown, csrfToken?: string): void {\n try {\n void fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {}) },\n body: JSON.stringify(body),\n keepalive: true,\n }).catch(() => {})\n } catch {\n /* never throw into the host page */\n }\n}\n\n/**\n * Boot the experiment beacons. Safe to call once per page load; when no\n * experiment meta is present it only wires the conversion listeners.\n */\nexport function bootExperiments(config: ExperimentBootConfig = {}): ExperimentRuntime {\n const ctx = config.context ?? readContext()\n const apiBase = config.apiBase ?? apiBaseFrom(ctx)\n const csrf = ctx.csrfToken || undefined\n const experimentId = metaContent('experiment-id')\n const visitorId = config.visitorId ?? metaContent('visitor-id') ?? undefined\n const currentPath = config.currentPath ?? (typeof location !== 'undefined' ? location.pathname : '/')\n\n function trackConversion(signal: ConversionSignal): void {\n beacon(`${apiBase}/kywi/experiments/conversion`, { visitorId, event: signal }, csrf)\n }\n function track(eventName: string): void {\n trackConversion({ type: 'custom', eventName })\n }\n\n // 1) Exposure \u2014 confirm the server-rendered variant was seen. The variant is\n // recomputed server-side, so we only send the experiment + visitor ids.\n if (experimentId) {\n beacon(`${apiBase}/kywi/experiments/exposure`, { experimentId, visitorId }, csrf)\n }\n\n // 2) Pageview conversion signal \u2014 lets pageview-goal experiments convert when\n // an enrolled visitor lands on the goal path.\n if (config.autoPageview !== false) {\n trackConversion({ type: 'pageview', url: currentPath })\n }\n\n // 3) Form-submit conversion \u2014 capture submits of any tagged form. The listener\n // is installed once; this boot becomes its active handler.\n currentFormConversion = (formId: string) => trackConversion({ type: 'form_submit', formId })\n installFormListener()\n\n const runtime: ExperimentRuntime = { track, trackConversion }\n\n // Expose on the data layer so analytics / manual conversions can reach it.\n const g = ((globalThis as unknown as { kywi?: Record<string, unknown> }).kywi ?? {})\n g['track'] = track\n g['trackConversion'] = trackConversion\n ;(globalThis as unknown as { kywi?: Record<string, unknown> }).kywi = g\n\n return runtime\n}\n", "// \u2500\u2500 Visitor Signals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface VisitorSignals {\n utm: {\n source: string | null\n medium: string | null\n campaign: string | null\n term: string | null\n content: string | null\n }\n referrer: {\n raw: string | null\n domain: string | null\n sourceType: 'organic' | 'paid' | 'social' | 'email' | 'direct' | 'other'\n }\n session: {\n pageViewCount: number\n totalPageViews: number\n sessionDuration: number\n entryPage: string\n pagesVisited: string[]\n }\n behavioral: {\n categoryScores: Record<string, number>\n totalScore: number\n }\n selfId: Record<string, string>\n identity: {\n visitorId: string\n isKnown: boolean\n maLeadId: string | null\n }\n adapters: Record<string, unknown>\n meta: {\n isOptedOut: boolean\n isPreview: boolean\n previewAudienceId: string | null\n resolvedAt: 'server' | 'client'\n }\n}\n\n// \u2500\u2500 Evaluation Result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface VisitorContext {\n request: Request\n partialSignals?: Partial<VisitorSignals>\n}\n\nexport interface AudienceResult {\n winningAudienceId: string | null\n allMatchedIds: string[]\n signals: VisitorSignals\n isOptedOut: boolean\n}\n\n// \u2500\u2500 Audience & Rule Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type AudienceStatus = 'active' | 'draft' | 'archived'\n\nexport interface Audience {\n id: string\n siteId: string\n name: string\n description: string | null\n priority: number\n status: AudienceStatus\n conditionGroups: ConditionGroup[]\n scoreThreshold: number | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface ConditionGroup {\n id: string\n audienceId: string\n sortOrder: number\n conditions: Condition[]\n}\n\nexport type Condition = InstantMatchCondition | ScoreContributionCondition\n\nexport interface InstantMatchCondition {\n type: 'instant'\n id: string\n groupId: string\n signal: InstantSignalRef\n operator: InstantOperator\n value: string | string[]\n}\n\nexport type InstantSignalRef =\n | 'utm.source' | 'utm.medium' | 'utm.campaign' | 'utm.term' | 'utm.content'\n | 'referrer.domain' | 'referrer.sourceType'\n | `selfId.${string}`\n | `adapter.${string}`\n | 'identity.isKnown'\n | 'session.entryPage'\n | 'session.pagesVisited'\n\nexport type InstantOperator =\n | 'equals' | 'not_equals' | 'contains' | 'starts_with' | 'matches_glob'\n | 'is_one_of' | 'is_true' | 'is_false'\n | 'gte' | 'lte'\n\nexport interface ScoreContributionCondition {\n type: 'score'\n id: string\n groupId: string\n trigger: ScoreTrigger\n points: number\n threshold?: number\n category?: string\n pattern?: string\n /**\n * For `trigger: 'signalMatch'` \u2014 award `points` when an arbitrary instant\n * signal matches (e.g. `utm.campaign contains 'enterprise' \u2192 +30`). Reuses the\n * instant-match operator set so any signal (UTM / referrer / self-ID / adapter)\n * can contribute to a score, not just the five behavioral triggers.\n */\n signal?: InstantSignalRef\n operator?: InstantOperator\n value?: string | string[]\n}\n\nexport type ScoreTrigger =\n | 'pageViewCount'\n | 'totalPageViews'\n | 'urlMatch'\n | 'categoryViewed'\n | 'timeOnSite'\n | 'signalMatch'\n\n// \u2500\u2500 Self-ID Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface SelfIdField {\n id: string\n siteId: string\n label: string\n picklist: Array<{ value: string; label: string }>\n required: boolean\n sortOrder: number\n}\n\nexport interface SelfIdWidgetConfig {\n id: string\n siteId: string\n displayMode: 'hello_bar_top' | 'hello_bar_bottom' | 'modal' | 'inline' | 'drawer' | 'slide-in'\n trigger: SelfIdTrigger\n headline: string\n subheadline: string | null\n fieldIds: string[]\n submitLabel: string\n skipLabel: string | null\n frequency: 'once_visitor' | 'once_session' | 'always'\n}\n\nexport type SelfIdTrigger =\n | { type: 'immediate' }\n | { type: 'scroll'; depth: number }\n | { type: 'delay'; seconds: number }\n | { type: 'manual' }\n\n// \u2500\u2500 Preview Token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PreviewTokenPayload {\n jti: string\n audienceId: string\n expiresAt: number\n}\n\n// \u2500\u2500 Default Signals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function createEmptySignals(): VisitorSignals {\n return {\n utm: { source: null, medium: null, campaign: null, term: null, content: null },\n referrer: { raw: null, domain: null, sourceType: 'direct' },\n session: { pageViewCount: 0, totalPageViews: 0, sessionDuration: 0, entryPage: '/', pagesVisited: [] },\n behavioral: { categoryScores: {}, totalScore: 0 },\n selfId: {},\n identity: { visitorId: '', isKnown: false, maLeadId: null },\n adapters: {},\n meta: { isOptedOut: false, isPreview: false, previewAudienceId: null, resolvedAt: 'server' },\n }\n}\n", "export function matchGlob(pattern: string, value: string): boolean {\n const parts = pattern.split('*')\n if (parts.length === 1) return pattern === value\n let pos = 0\n const first = parts[0]!\n if (first !== '') {\n if (!value.startsWith(first)) return false\n pos = first.length\n }\n for (let i = 1; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (part === '') continue\n const idx = value.indexOf(part, pos)\n if (idx < 0) return false\n pos = idx + part.length\n }\n const last = parts[parts.length - 1]!\n if (last !== '') {\n if (!value.endsWith(last)) return false\n if (value.length - last.length < pos) return false\n }\n return true\n}\n", "import type { VisitorSignals, InstantMatchCondition, InstantSignalRef } from '../types.js'\nimport { matchGlob } from './glob.js'\n\nexport function resolveSignalValue(signals: VisitorSignals, ref: InstantSignalRef): string | null {\n if (ref === 'utm.source') return signals.utm.source\n if (ref === 'utm.medium') return signals.utm.medium\n if (ref === 'utm.campaign') return signals.utm.campaign\n if (ref === 'utm.term') return signals.utm.term\n if (ref === 'utm.content') return signals.utm.content\n if (ref === 'referrer.domain') return signals.referrer.domain\n if (ref === 'referrer.sourceType') return signals.referrer.sourceType\n if (ref === 'identity.isKnown') return signals.identity.isKnown ? 'true' : 'false'\n if (ref === 'session.entryPage') return signals.session.entryPage\n if (ref === 'session.pagesVisited') return signals.session.pagesVisited.join(',')\n if (ref.startsWith('selfId.')) {\n const key = ref.slice(7)\n return signals.selfId[key] ?? null\n }\n if (ref.startsWith('adapter.')) {\n const key = ref.slice(8)\n const val = signals.adapters[key]\n return val !== undefined && val !== null ? String(val) : null\n }\n return null\n}\n\nexport function evaluateInstantCondition(condition: InstantMatchCondition, signals: VisitorSignals): boolean {\n const actual = resolveSignalValue(signals, condition.signal)\n const expected = condition.value\n switch (condition.operator) {\n case 'equals': return actual === expected\n case 'not_equals': return actual !== expected\n case 'contains': return actual !== null && typeof expected === 'string' && actual.includes(expected)\n case 'starts_with': return actual !== null && typeof expected === 'string' && actual.startsWith(expected)\n case 'matches_glob': return actual !== null && typeof expected === 'string' && matchGlob(expected, actual)\n case 'is_one_of': return actual !== null && Array.isArray(condition.value) && condition.value.includes(actual)\n case 'is_true': return actual === 'true'\n case 'is_false': return actual === 'false'\n case 'gte': return actual !== null && typeof expected === 'string' && Number(actual) >= Number(expected)\n case 'lte': return actual !== null && typeof expected === 'string' && Number(actual) <= Number(expected)\n default: return false\n }\n}\n", "import type { VisitorSignals, ScoreContributionCondition } from '../types.js'\nimport { matchGlob } from './glob.js'\nimport { evaluateInstantCondition } from './instant-match.js'\n\nfunction evaluateOneScore(cond: ScoreContributionCondition, signals: VisitorSignals): number {\n const threshold = cond.threshold ?? 0\n switch (cond.trigger) {\n case 'pageViewCount': return signals.session.pageViewCount >= threshold ? cond.points : 0\n case 'totalPageViews': return signals.session.totalPageViews >= threshold ? cond.points : 0\n case 'timeOnSite': return signals.session.sessionDuration >= threshold ? cond.points : 0\n case 'categoryViewed': {\n const cat = cond.category ?? ''\n const score = signals.behavioral.categoryScores[cat]\n return score !== undefined && score >= threshold ? cond.points : 0\n }\n case 'urlMatch': {\n const pattern = cond.pattern ?? '*'\n const matched = signals.session.pagesVisited.some(url => matchGlob(pattern, url))\n return matched ? cond.points : 0\n }\n case 'signalMatch': {\n // Award points when an arbitrary instant signal matches. Reuses the\n // instant-match evaluator so every operator/signal is supported.\n if (!cond.signal || !cond.operator) return 0\n const matched = evaluateInstantCondition(\n {\n type: 'instant',\n id: cond.id,\n groupId: cond.groupId,\n signal: cond.signal,\n operator: cond.operator,\n value: cond.value ?? '',\n },\n signals,\n )\n return matched ? cond.points : 0\n }\n default: return 0\n }\n}\n\nexport function evaluateScoreConditions(conditions: ScoreContributionCondition[], signals: VisitorSignals): number {\n let total = 0\n for (const cond of conditions) { total += evaluateOneScore(cond, signals) }\n return total\n}\n", "import type { Condition, VisitorSignals } from '../types.js'\n\n// \u2500\u2500\u2500 Custom Condition Type Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Allows third-party code (plugins, adapters, custom app code) to register\n// additional condition type evaluators without forking the core evaluator.\n//\n// Usage:\n// import { registerConditionType } from '@kywi-software/core'\n//\n// registerConditionType('my_custom_type', (condition, signals) => {\n// // Return true if the condition matches the current visitor signals\n// return signals.adapters['my_adapter'] === condition.value\n// })\n\ntype ConditionEvaluator = (condition: Condition, signals: VisitorSignals) => boolean\n\nconst registry = new Map<string, ConditionEvaluator>()\n\n/**\n * Register a custom condition type evaluator.\n *\n * @param name - The condition `type` string this evaluator handles.\n * @param evaluate - Pure function that returns `true` when the condition matches.\n *\n * Calling this with an already-registered name overwrites the previous evaluator.\n */\nexport function registerConditionType(name: string, evaluate: ConditionEvaluator): void {\n registry.set(name, evaluate)\n}\n\n/**\n * Remove a previously registered condition type evaluator.\n * No-op if the name was never registered.\n */\nexport function unregisterConditionType(name: string): void {\n registry.delete(name)\n}\n\n/**\n * Evaluate a condition using a registered custom evaluator.\n * Returns `false` if no evaluator is registered for the condition's type.\n */\nexport function evaluateCustomCondition(condition: Condition, signals: VisitorSignals): boolean {\n const evaluator = registry.get(condition.type)\n if (!evaluator) return false\n return evaluator(condition, signals)\n}\n\n/**\n * Returns true if a custom evaluator is registered for the given condition type name.\n */\nexport function hasConditionType(name: string): boolean {\n return registry.has(name)\n}\n\n/**\n * Returns the names of all registered custom condition types.\n */\nexport function listConditionTypes(): string[] {\n return [...registry.keys()]\n}\n", "import type { Audience, VisitorSignals, ConditionGroup, InstantMatchCondition, ScoreContributionCondition } from '../types.js'\nimport { evaluateInstantCondition } from './instant-match.js'\nimport { evaluateScoreConditions } from './score.js'\nimport { hasConditionType, evaluateCustomCondition } from './condition-registry.js'\n\nexport interface ConditionTrace {\n conditionId: string\n type: 'instant' | 'score'\n passed: boolean\n scoreContributed?: number\n}\n\nexport interface EvaluationTrace {\n audienceId: string\n matched: boolean\n groupTraces: Array<{ groupId: string; matched: boolean; conditionTraces: ConditionTrace[] }>\n totalScore?: number\n}\n\nexport interface ResolveResult {\n winningAudienceId: string | null\n allMatchedIds: string[]\n traces: EvaluationTrace[]\n}\n\n// Evaluate one group: AND all instant + custom conditions, accumulate score conditions\nfunction evaluateGroup(group: ConditionGroup, signals: VisitorSignals) {\n const conditionTraces: ConditionTrace[] = []\n const instants: InstantMatchCondition[] = []\n const scores: ScoreContributionCondition[] = []\n const customs: typeof group.conditions = []\n\n for (const c of group.conditions) {\n // The Condition union only models 'instant'/'score', but the registry\n // dispatches custom condition kinds by their `type` string at runtime.\n // Capture it as a string so the custom branch stays reachable.\n const conditionType: string = c.type\n if (c.type === 'instant') instants.push(c)\n else if (c.type === 'score') scores.push(c)\n else if (hasConditionType(conditionType)) customs.push(c)\n // Unknown types with no registered evaluator are silently skipped\n }\n\n let allInstantsPassed = true\n\n for (const ic of instants) {\n const passed = evaluateInstantCondition(ic, signals)\n conditionTraces.push({ conditionId: ic.id, type: 'instant', passed })\n if (!passed) allInstantsPassed = false\n }\n\n // Custom conditions are ANDed with instant conditions\n for (const cc of customs) {\n const passed = evaluateCustomCondition(cc, signals)\n conditionTraces.push({ conditionId: cc.id, type: cc.type as 'instant', passed })\n if (!passed) allInstantsPassed = false\n }\n\n const totalScore = evaluateScoreConditions(scores, signals)\n for (const sc of scores) {\n const contributed = evaluateScoreConditions([sc], signals)\n conditionTraces.push({ conditionId: sc.id, type: 'score', passed: contributed > 0, scoreContributed: contributed })\n }\n\n return { matched: allInstantsPassed, conditionTraces, totalScore }\n}\n\nexport function resolveAudiences(audiences: Audience[], signals: VisitorSignals): ResolveResult {\n const allMatchedIds: string[] = []\n const traces: EvaluationTrace[] = []\n\n for (const audience of audiences) {\n const groupTraces: EvaluationTrace['groupTraces'] = []\n let audienceMatched = false\n let accumulatedScore = 0\n\n for (const group of audience.conditionGroups) {\n const { matched, conditionTraces, totalScore } = evaluateGroup(group, signals)\n accumulatedScore += totalScore\n groupTraces.push({ groupId: group.id, matched, conditionTraces })\n if (matched) audienceMatched = true\n }\n\n if (audience.scoreThreshold !== null) {\n const scoreThresholdMet = accumulatedScore >= audience.scoreThreshold\n const hasInstantConditions = audience.conditionGroups.some(g => g.conditions.some(c => c.type === 'instant'))\n if (hasInstantConditions) {\n audienceMatched = audienceMatched && scoreThresholdMet\n } else {\n audienceMatched = scoreThresholdMet\n }\n }\n\n traces.push({\n audienceId: audience.id,\n matched: audienceMatched,\n groupTraces,\n ...(accumulatedScore > 0 ? { totalScore: accumulatedScore } : {}),\n })\n if (audienceMatched) allMatchedIds.push(audience.id)\n }\n\n return { winningAudienceId: allMatchedIds[0] ?? null, allMatchedIds, traces }\n}\n", "// packages/kywi-js/src/audience/behavioral-collector.ts\nconst SESSION_KEY = 'kywi_session'\nconst TOTAL_VIEWS_KEY = 'kywi_total_views'\nconst CATEGORY_SCORES_KEY = 'kywi_category_scores'\nconst SESSION_START_KEY = 'kywi_session_start'\n\ninterface SessionData { pageViewCount: number; entryPage: string; pagesVisited: string[] }\n\nexport interface BehavioralResult {\n session: { pageViewCount: number; totalPageViews: number; sessionDuration: number; entryPage: string; pagesVisited: string[] }\n behavioral: { categoryScores: Record<string, number>; totalScore: number }\n}\n\nfunction getSession(): SessionData {\n const raw = sessionStorage.getItem(SESSION_KEY)\n if (raw) { try { return JSON.parse(raw) as SessionData } catch { /* fall through */ } }\n return { pageViewCount: 0, entryPage: '', pagesVisited: [] }\n}\n\nfunction getSessionStart(): number {\n const raw = sessionStorage.getItem(SESSION_START_KEY)\n if (raw) return Number(raw)\n const now = Date.now()\n sessionStorage.setItem(SESSION_START_KEY, String(now))\n return now\n}\n\nfunction getCategoryScores(): Record<string, number> {\n const raw = localStorage.getItem(CATEGORY_SCORES_KEY)\n if (raw) { try { return JSON.parse(raw) as Record<string, number> } catch { /* fall through */ } }\n return {}\n}\n\nexport function collectBehavioral(currentPath: string, category?: string): BehavioralResult {\n const session = getSession()\n session.pageViewCount += 1\n if (!session.entryPage) session.entryPage = currentPath\n session.pagesVisited.push(currentPath)\n sessionStorage.setItem(SESSION_KEY, JSON.stringify(session))\n\n const totalViews = (Number(localStorage.getItem(TOTAL_VIEWS_KEY)) || 0) + 1\n localStorage.setItem(TOTAL_VIEWS_KEY, String(totalViews))\n\n const sessionStart = getSessionStart()\n const categoryScores = getCategoryScores()\n if (category) {\n categoryScores[category] = (categoryScores[category] ?? 0) + 1\n localStorage.setItem(CATEGORY_SCORES_KEY, JSON.stringify(categoryScores))\n }\n\n return {\n session: { pageViewCount: session.pageViewCount, totalPageViews: totalViews, sessionDuration: Math.floor((Date.now() - sessionStart) / 1000), entryPage: session.entryPage, pagesVisited: session.pagesVisited },\n behavioral: { categoryScores, totalScore: 0 },\n }\n}\n", "// packages/kywi-js/src/audience/selfid-collector.ts\nconst SELFID_KEY = 'kywi_selfid'\n\nexport function collectSelfId(): Record<string, string> {\n const raw = localStorage.getItem(SELFID_KEY)\n if (!raw) return {}\n try { return JSON.parse(raw) as Record<string, string> } catch { return {} }\n}\n\nexport function storeSelfId(responses: Record<string, string>): void {\n localStorage.setItem(SELFID_KEY, JSON.stringify(responses))\n}\n", "// packages/kywi-js/src/audience/evaluate.ts\nimport type { Audience, VisitorSignals, AudienceResult } from '@kywi-software/core/audiences/types'\nimport { createEmptySignals } from '@kywi-software/core/audiences/types'\nimport { resolveAudiences } from '@kywi-software/core/evaluator'\nimport { collectBehavioral } from './behavioral-collector.js'\nimport { collectSelfId } from './selfid-collector.js'\n\nfunction merge(base: VisitorSignals, partial: Partial<VisitorSignals>): VisitorSignals {\n return {\n utm: partial.utm ?? base.utm, referrer: partial.referrer ?? base.referrer,\n session: partial.session ?? base.session, behavioral: partial.behavioral ?? base.behavioral,\n selfId: { ...base.selfId, ...partial.selfId }, identity: partial.identity ?? base.identity,\n adapters: { ...base.adapters, ...partial.adapters }, meta: { ...base.meta, ...partial.meta },\n }\n}\n\nexport function evaluateClientSide(\n audiences: Audience[], serverSignals: Partial<VisitorSignals>, currentPath: string, pageCategory?: string,\n): AudienceResult {\n let signals = merge(createEmptySignals(), serverSignals)\n const client = collectBehavioral(currentPath, pageCategory)\n const selfId = collectSelfId()\n signals = merge(signals, { session: client.session, behavioral: client.behavioral, selfId, meta: { ...signals.meta, resolvedAt: 'client' } })\n const { winningAudienceId, allMatchedIds } = resolveAudiences(audiences, signals)\n const isOptedOut = signals.meta.isOptedOut\n return { winningAudienceId: isOptedOut ? null : winningAudienceId, allMatchedIds, signals, isOptedOut }\n}\n", "// packages/kywi-js/src/audience/dom-patcher.ts\nexport function patchVariantContainers(winningAudienceId: string | null): void {\n const containers = document.querySelectorAll('.kywi-variant-container')\n for (const container of Array.from(containers)) {\n const el = container as HTMLElement\n const arms = Array.from(el.querySelectorAll('[data-kywi-variant]'))\n\n // Only module-level containers (VariantContainerModule in\n // packages/core/src/layout/modules-extended.tsx) render every arm into the\n // DOM for this client-side swap \u2014 each tagged `[data-kywi-variant]`, with at\n // least a \"default\" arm present even while loading. Section-level containers\n // (SectionRenderer's VariantContainerRenderer in packages/core/src/layout/\n // renderer.tsx, and components/personalization/VariantContainer.tsx) share\n // the `.kywi-variant-container` selector but are fully server-resolved: they\n // render only the winning arm's markup directly, so they never have any\n // `[data-kywi-variant]` children. That \"has arms to toggle\" structure is the\n // most robust discriminator available (unlike a class or `data-mode`\n // attribute, it can't drift out of sync with what this function actually\n // needs to do) \u2014 skip anything without arms so we never overwrite a\n // server-resolved container's `data-variant` with a client-side audience id\n // that disagrees with the content already rendered (kywi-cms#99).\n if (arms.length === 0) continue\n\n el.classList.remove('kywi-variant-loading')\n el.removeAttribute('aria-busy')\n const skeleton = el.querySelector('.kywi-variant-skeleton')\n if (skeleton) skeleton.remove()\n const target = winningAudienceId ?? 'default'\n el.setAttribute('data-variant', target)\n for (const child of arms) {\n const h = child as HTMLElement\n h.style.display = h.getAttribute('data-kywi-variant') === target ? '' : 'none'\n }\n }\n}\n", "// packages/kywi-js/src/cookies.ts\nexport const COOKIE_NAMES = {\n SIGNALS: 'kywi_signals', VISITOR: 'kywi_visitor', UTM: 'kywi_utm',\n AUDIENCE: 'kywi_audience', OPTOUT: 'kywi_optout', KNOWN: 'kywi_known',\n PREVIEW_INIT: 'kywi_preview_init',\n} as const\n\nexport function readCookies(): Map<string, string> {\n const map = new Map<string, string>()\n if (typeof document === 'undefined') return map\n for (const pair of document.cookie.split(';')) {\n const trimmed = pair.trim()\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx < 0) continue\n map.set(trimmed.slice(0, eqIdx), decodeURIComponent(trimmed.slice(eqIdx + 1)))\n }\n return map\n}\n\nexport function setCookie(name: string, value: string, maxAge?: number): void {\n let str = `${name}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`\n if (maxAge !== undefined && maxAge >= 0) str += `; Max-Age=${maxAge}`\n document.cookie = str\n}\n\nexport function deleteCookie(name: string): void {\n document.cookie = `${name}=; Path=/; Max-Age=0`\n}\n", "// packages/kywi-js/src/audience/transparency.ts\n//\n// The transparency surface: the single global control through which a visitor\n// sees THAT the page is personalized, WHICH audience it was personalized for,\n// and can switch audience, reset to automatic resolution, or turn\n// personalization off entirely (issue #105).\n//\n// Three states:\n// 1. nothing \u2014 not personalizing and no match available\n// 2. collapsed pill \u2014 small, unobtrusive, click/Enter expands\n// 3. expanded panel \u2014 audience name, switcher, reset, opt-out/opt-in\n//\n// Collapsing is NOT dismissal: there is no permanent suppression any more (a\n// promise of transparency the visitor can silence forever is not one). The\n// collapsed/expanded choice is remembered in localStorage; the legacy\n// `kywi_transparency_dismissed` flag is migrated to \"collapsed\".\n//\n// All styling lives in `@kywi-software/core`'s site/styles.css (token-driven,\n// overridable) \u2014 this module ships no stylesheet of its own.\n\nimport { COOKIE_NAMES, readCookies, setCookie, deleteCookie } from '../cookies.js'\n\nconst COLLAPSED_KEY = 'kywi_transparency_collapsed'\n/** Pre-#105 permanent-dismissal flag; read once and migrated to \"collapsed\". */\nconst LEGACY_DISMISSED_KEY = 'kywi_transparency_dismissed'\n\nconst ROOT_ID = 'kywi-transparency'\nconst PANEL_ID = 'kywi-transparency-panel'\nconst TITLE_ID = 'kywi-transparency-title'\nconst SWITCHER_LABEL_ID = 'kywi-transparency-switcher-label'\n\nconst DEFAULT_API_BASE = '/api/v1'\n\n/** An audience the visitor can be shown as, or switch to. */\nexport interface TransparencyAudience {\n id: string\n name: string\n}\n\nexport interface TransparencyState {\n /** The page is currently rendering an audience's variant content. */\n isPersonalized: boolean\n isOptedOut: boolean\n /** At least one audience matched \u2014 i.e. personalization is available here. */\n hasMatchAvailable: boolean\n /** The audience the page was personalized for (resolves the displayed name). */\n audienceId?: string | null\n /** Active audiences, by name \u2014 powers the name lookup and the switcher. */\n audiences?: TransparencyAudience[]\n /** Mounted CMS API base (e.g. `/api/v1`); the switcher posts to `{apiBase}/kywi/audience`. */\n apiBase?: string\n csrfToken?: string | null\n /**\n * `personalization.transparencyNotice.enabled`. When false the surface never\n * appears on its own; `openTransparencyPanel()` (e.g. a personalizationBadge\n * click) can still open it deliberately.\n */\n enabled?: boolean\n}\n\n// The last state boot handed us, so a programmatic open() can re-render the\n// panel with real data instead of an empty shell.\nlet lastState: TransparencyState | null = null\n// Set by openTransparencyPanel(): render even when the automatic gate says no.\nlet forcedOpen = false\n\n/* \u2500\u2500 storage (never let a blocked/full localStorage break the page) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nfunction readStorage(key: string): string | null {\n try { return localStorage.getItem(key) } catch { return null }\n}\nfunction writeStorage(key: string, value: string): void {\n try { localStorage.setItem(key, value) } catch { /* private mode / quota */ }\n}\nfunction removeStorage(key: string): void {\n try { localStorage.removeItem(key) } catch { /* private mode / quota */ }\n}\n\n/** True when the surface should render as the pill. Defaults to collapsed. */\nexport function isCollapsed(): boolean {\n if (readStorage(LEGACY_DISMISSED_KEY) === '1') {\n // Migration: a visitor who permanently dismissed the old bar gets the pill,\n // not silence. Rewriting the flag makes the migration a one-time cost.\n removeStorage(LEGACY_DISMISSED_KEY)\n writeStorage(COLLAPSED_KEY, '1')\n return true\n }\n return readStorage(COLLAPSED_KEY) !== '0'\n}\n\nfunction setCollapsed(collapsed: boolean): void {\n writeStorage(COLLAPSED_KEY, collapsed ? '1' : '0')\n}\n\n/* \u2500\u2500 visitor preferences \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport function optOut(): void {\n setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600)\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n}\n\nexport function optIn(): void {\n deleteCookie(COOKIE_NAMES.OPTOUT)\n}\n\n/** Clears the manual audience pin so resolution goes back to signals. */\nexport function resetToAutomatic(): void {\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n}\n\nfunction hasPin(): boolean {\n return readCookies().has(COOKIE_NAMES.AUDIENCE)\n}\n\n/**\n * Pins the visitor to `audienceId` via the public runtime route \u2014 the same\n * endpoint and payload the boot path already uses to persist a client-resolved\n * audience. The server re-validates the id against the active audiences.\n */\nexport async function pinAudience(\n audienceId: string,\n opts: { apiBase?: string | undefined; csrfToken?: string | null | undefined } = {},\n): Promise<void> {\n const apiBase = opts.apiBase ?? DEFAULT_API_BASE\n try {\n await fetch(`${apiBase}/kywi/audience`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(opts.csrfToken ? { 'X-CSRF-Token': opts.csrfToken } : {}) },\n body: JSON.stringify({ audienceId }),\n })\n } catch { /* offline / blocked \u2014 the reload below simply keeps the old state */ }\n}\n\nfunction reload(): void {\n try { window.location.reload() } catch { /* non-navigating test environments */ }\n}\n\n/* \u2500\u2500 rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nfunction removeSurface(): void {\n document.getElementById(ROOT_ID)?.remove()\n // Pre-#105 markup, in case a stale bar is still on the page.\n document.querySelector('.kywi-transparency-bar')?.remove()\n}\n\nfunction button(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.type = 'button'\n btn.className = className\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nfunction shouldRenderAutomatically(state: TransparencyState): boolean {\n if (state.enabled === false) return false\n return (state.isPersonalized && !state.isOptedOut) || (state.isOptedOut && state.hasMatchAvailable)\n}\n\nfunction audienceName(state: TransparencyState): string | null {\n if (!state.audienceId) return null\n return state.audiences?.find((a) => a.id === state.audienceId)?.name ?? null\n}\n\n/**\n * Renders (or removes) the transparency surface for `state`. Safe to call on\n * every boot; it replaces whatever is currently mounted.\n */\nexport function renderTransparencyPanel(state: TransparencyState): void {\n lastState = state\n if (typeof document === 'undefined') return\n removeSurface()\n if (!forcedOpen && !shouldRenderAutomatically(state)) return\n\n const active = state.isPersonalized && !state.isOptedOut\n const collapsed = forcedOpen ? false : isCollapsed()\n\n const root = document.createElement('div')\n root.id = ROOT_ID\n root.className = `kywi-transparency ${active ? 'kywi-transparency-active' : 'kywi-transparency-opted-out'}`\n root.dataset.state = collapsed ? 'collapsed' : 'expanded'\n\n /* pill */\n const pill = document.createElement('button')\n pill.type = 'button'\n pill.className = 'kywi-transparency-pill'\n pill.setAttribute('aria-expanded', String(!collapsed))\n pill.setAttribute('aria-controls', PANEL_ID)\n const pillIcon = document.createElement('span')\n pillIcon.className = 'kywi-transparency-pill-icon'\n pillIcon.setAttribute('aria-hidden', 'true')\n pillIcon.textContent = '\u2726'\n const pillLabel = document.createElement('span')\n pillLabel.className = 'kywi-transparency-pill-label'\n pillLabel.textContent = active ? 'Personalized' : 'Personalization off'\n pill.append(pillIcon, pillLabel)\n pill.addEventListener('click', () => expandPanel())\n pill.hidden = !collapsed\n root.appendChild(pill)\n\n /* panel */\n const panel = document.createElement('section')\n panel.id = PANEL_ID\n panel.className = 'kywi-transparency-panel'\n panel.setAttribute('role', 'dialog')\n panel.setAttribute('aria-labelledby', TITLE_ID)\n panel.hidden = collapsed\n\n const header = document.createElement('div')\n header.className = 'kywi-transparency-header'\n const title = document.createElement('h2')\n title.id = TITLE_ID\n title.className = 'kywi-transparency-title'\n const name = audienceName(state)\n title.textContent = !active\n ? 'Personalization is off'\n : name\n ? 'This page is personalized for:'\n : 'This page is personalized'\n header.appendChild(title)\n const collapseBtn = button('kywi-transparency-collapse', '\u2715', () => collapsePanel())\n collapseBtn.setAttribute('aria-label', 'Collapse')\n header.appendChild(collapseBtn)\n panel.appendChild(header)\n\n if (active) {\n const audience = document.createElement('p')\n audience.className = 'kywi-transparency-audience'\n if (name) {\n const strong = document.createElement('strong')\n strong.textContent = name\n audience.appendChild(strong)\n } else {\n audience.textContent = 'Based on your browsing context.'\n }\n panel.appendChild(audience)\n }\n\n const note = document.createElement('p')\n note.className = 'kywi-transparency-note'\n note.textContent = active\n ? 'Parts of this page are chosen to match this audience. You can switch, reset, or turn personalization off.'\n : 'Personalization is turned off, so you are seeing the default version of this page.'\n panel.appendChild(note)\n\n /* audience switcher \u2014 pointless while opted out (opt-out beats a pin) */\n const options = state.audiences ?? []\n if (active && options.length > 0) {\n const switcher = document.createElement('div')\n switcher.className = 'kywi-transparency-switcher'\n const switcherLabel = document.createElement('span')\n switcherLabel.id = SWITCHER_LABEL_ID\n switcherLabel.className = 'kywi-transparency-switcher-label'\n switcherLabel.textContent = 'See this page as'\n switcher.appendChild(switcherLabel)\n\n const group = document.createElement('div')\n group.className = 'kywi-transparency-options'\n group.setAttribute('role', 'group')\n group.setAttribute('aria-labelledby', SWITCHER_LABEL_ID)\n for (const option of options) {\n const isCurrent = option.id === state.audienceId\n const optionBtn = button('kywi-transparency-option', option.name, () => {\n if (isCurrent) return\n void pinAudience(option.id, { apiBase: state.apiBase, csrfToken: state.csrfToken }).then(reload)\n })\n optionBtn.dataset.kywiAudienceId = option.id\n optionBtn.setAttribute('aria-pressed', String(isCurrent))\n group.appendChild(optionBtn)\n }\n switcher.appendChild(group)\n panel.appendChild(switcher)\n }\n\n /* actions */\n const actions = document.createElement('div')\n actions.className = 'kywi-transparency-actions'\n if (state.isOptedOut) {\n actions.appendChild(button('kywi-transparency-opt-in', 'Enable personalization', () => { optIn(); reload() }))\n } else {\n if (hasPin()) {\n actions.appendChild(button('kywi-transparency-reset', 'Reset to automatic', () => { resetToAutomatic(); reload() }))\n }\n actions.appendChild(button('kywi-transparency-opt-out', 'Turn off personalization', () => { optOut(); reload() }))\n }\n panel.appendChild(actions)\n\n panel.addEventListener('keydown', (e) => {\n if ((e as KeyboardEvent).key === 'Escape') collapsePanel()\n })\n\n root.appendChild(panel)\n document.body.appendChild(root)\n}\n\nfunction currentSurface(): { root: HTMLElement; pill: HTMLElement; panel: HTMLElement } | null {\n const root = document.getElementById(ROOT_ID)\n if (!root) return null\n const pill = root.querySelector<HTMLElement>('.kywi-transparency-pill')\n const panel = root.querySelector<HTMLElement>('.kywi-transparency-panel')\n if (!pill || !panel) return null\n return { root, pill, panel }\n}\n\nfunction setExpanded(expanded: boolean): void {\n const surface = currentSurface()\n if (!surface) return\n surface.root.dataset.state = expanded ? 'expanded' : 'collapsed'\n surface.pill.hidden = expanded\n surface.pill.setAttribute('aria-expanded', String(expanded))\n surface.panel.hidden = !expanded\n const focusTarget = expanded\n ? surface.panel.querySelector<HTMLElement>('.kywi-transparency-collapse')\n : surface.pill\n focusTarget?.focus()\n}\n\n/** Expands the panel and remembers the choice. */\nexport function expandPanel(): void {\n setCollapsed(false)\n setExpanded(true)\n}\n\n/** Collapses back to the pill and remembers the choice \u2014 never full suppression. */\nexport function collapsePanel(): void {\n forcedOpen = false\n setCollapsed(true)\n setExpanded(false)\n}\n\n/**\n * Opens the transparency panel from anywhere \u2014 the programmatic entry point the\n * personalizationBadge module's status pill calls (#107), so opt-out and\n * audience switching live in exactly one surface. Renders the panel even when\n * the automatic gate (or `transparencyNotice.enabled: false`) would hide it,\n * because opening it is an explicit visitor action.\n */\nexport function openTransparencyPanel(): void {\n if (typeof document === 'undefined') return\n forcedOpen = true\n const state: TransparencyState = lastState ?? {\n isPersonalized: false,\n isOptedOut: readCookies().has(COOKIE_NAMES.OPTOUT),\n hasMatchAvailable: false,\n }\n renderTransparencyPanel(state)\n currentSurface()?.panel.querySelector<HTMLElement>('.kywi-transparency-collapse')?.focus()\n}\n\n/** Test seam: forget the cached boot state and any forced-open flag. */\nexport function resetTransparencyState(): void {\n lastState = null\n forcedOpen = false\n}\n", "// packages/kywi-js/src/audience/preview.ts\nimport { COOKIE_NAMES, readCookies, deleteCookie } from '../cookies.js'\n\nconst PREVIEW_KEY = 'kywi_preview_audience'\n\nexport function getPreviewAudienceId(): string | null { return sessionStorage.getItem(PREVIEW_KEY) }\nexport function setPreviewAudienceId(id: string): void { sessionStorage.setItem(PREVIEW_KEY, id) }\nexport function clearPreview(): void { sessionStorage.removeItem(PREVIEW_KEY) }\n\nexport function checkPreviewInit(): void {\n const cookies = readCookies()\n const initId = cookies.get(COOKIE_NAMES.PREVIEW_INIT)\n if (initId) { setPreviewAudienceId(initId); deleteCookie(COOKIE_NAMES.PREVIEW_INIT) }\n}\n\nexport function renderPreviewBanner(audienceName: string): void {\n document.querySelector('.kywi-preview-banner')?.remove()\n const banner = document.createElement('div')\n banner.className = 'kywi-preview-banner'\n banner.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-preview-text'\n text.textContent = 'Previewing as: '\n const strong = document.createElement('strong')\n strong.textContent = audienceName\n text.appendChild(strong)\n banner.appendChild(text)\n const exitBtn = document.createElement('button')\n exitBtn.className = 'kywi-preview-exit'\n exitBtn.type = 'button'\n exitBtn.textContent = 'Exit Preview'\n exitBtn.addEventListener('click', () => { clearPreview(); window.location.reload() })\n banner.appendChild(exitBtn)\n document.body.appendChild(banner)\n}\n", "// packages/kywi-js/src/audience/data-layer.ts\nimport type { KywiVisitor } from '../types.js'\n\nexport function populateDataLayer(visitor: KywiVisitor): void {\n const g = ((window as any).kywi ?? {}) as { visitor?: KywiVisitor }\n g.visitor = visitor\n ;(window as any).kywi = g\n}\n\nexport function fireKywiReady(): void { window.dispatchEvent(new CustomEvent('kywiReady')) }\n\nexport interface ServerMeta { audienceId: string | null; experimentId: string | null; variantId: string | null; visitorId: string }\n\nexport function readServerMeta(): ServerMeta {\n const m = (n: string) => document.querySelector(`meta[name=\"kywi:${n}\"]`)?.getAttribute('content') ?? null\n return { audienceId: m('audience-id'), experimentId: m('experiment-id'), variantId: m('variant-id'), visitorId: m('visitor-id') ?? '' }\n}\n", "// packages/kywi-js/src/audience/adapter-runner.ts\nimport type { VisitorSignals } from '@kywi-software/core/audiences/types'\n\ninterface PullAdapter {\n id: string\n side: 'client' | 'server-proxy'\n fields: string[]\n collect: (signals: Partial<VisitorSignals>) => Promise<Record<string, unknown>>\n}\n\nconst CACHE_PREFIX = 'kywi_adapter_'\n\nfunction getCached(adapterId: string): Record<string, unknown> | null {\n const raw = sessionStorage.getItem(CACHE_PREFIX + adapterId)\n if (!raw) return null\n try { return JSON.parse(raw) as Record<string, unknown> } catch { return null }\n}\n\nfunction setCache(adapterId: string, data: Record<string, unknown>): void {\n sessionStorage.setItem(CACHE_PREFIX + adapterId, JSON.stringify(data))\n}\n\nexport async function runClientAdapters(\n adapters: PullAdapter[], currentSignals: Partial<VisitorSignals>,\n apiBase = '/api/v1',\n): Promise<Record<string, unknown>> {\n const merged: Record<string, unknown> = {}\n\n const tasks = adapters.map(async (adapter) => {\n const cached = getCached(adapter.id)\n if (cached) return cached\n\n let result: Record<string, unknown>\n if (adapter.side === 'server-proxy') {\n // The proxy lives in the CMS runtime namespace (`{apiBase}/kywi/adapters/:id`),\n // alongside the audience-assignment and identity routes \u2014 not a bare\n // `/api/kywi/...` path, which would miss a handler mounted at `/api/v1`.\n const res = await fetch(`${apiBase}/kywi/adapters/${adapter.id}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ signals: currentSignals }),\n })\n const json = await res.json() as { data?: Record<string, unknown> }\n result = json.data ?? {}\n } else {\n result = await adapter.collect(currentSignals)\n }\n\n setCache(adapter.id, result)\n return result\n })\n\n const results = await Promise.all(tasks)\n for (const r of results) Object.assign(merged, r)\n return merged\n}\n", "// packages/kywi-js/src/audience/selfid-submit.ts\nimport { storeSelfId } from './selfid-collector.js'\nimport { evaluateClientSide } from './evaluate.js'\nimport { patchVariantContainers } from './dom-patcher.js'\nimport { populateDataLayer, fireKywiReady, readServerMeta } from './data-layer.js'\nimport { readCookies, COOKIE_NAMES } from '../cookies.js'\nimport type { Audience, VisitorSignals } from '@kywi-software/core/audiences/types'\n\nexport function handleSelfIdSubmit(\n responses: Record<string, string>,\n audiences?: Audience[],\n currentPath?: string,\n): void {\n // 1. Store responses (replaces previous)\n storeSelfId(responses)\n\n // 2. Re-evaluate if audiences provided\n if (audiences && currentPath) {\n const cookies = readCookies()\n const serverMeta = readServerMeta()\n const serverSignals: Partial<VisitorSignals> = {\n identity: { visitorId: serverMeta.visitorId || cookies.get(COOKIE_NAMES.VISITOR) || '', isKnown: cookies.has(COOKIE_NAMES.KNOWN), maLeadId: null },\n meta: { isOptedOut: cookies.has(COOKIE_NAMES.OPTOUT), isPreview: false, previewAudienceId: null, resolvedAt: 'server' },\n }\n const result = evaluateClientSide(audiences, serverSignals, currentPath)\n patchVariantContainers(result.winningAudienceId)\n populateDataLayer({\n visitorId: result.signals.identity.visitorId,\n audienceId: result.winningAudienceId,\n experimentId: serverMeta.experimentId,\n variantId: serverMeta.variantId,\n isPreview: false,\n isOptedOut: result.isOptedOut,\n })\n }\n}\n", "// packages/kywi-js/src/audience/selfid-widget.ts\nimport { storeSelfId } from './selfid-collector.js'\nimport { handleSelfIdSubmit } from './selfid-submit.js'\nimport type { Audience } from '@kywi-software/core/audiences/types'\n\nconst SHOWN_KEY = 'kywi_selfid_shown'\nconst MS_PER_DAY = 86_400_000\n\n/**\n * Display modes that render their own explicit dismiss control (#97, #106).\n * Every overlay mode is dismissible \u2014 an overlay a visitor cannot close is a\n * trap. Only `inline` is excluded: it is part of the host's page content and\n * has no viewport-covering surface to escape from.\n */\nconst DISMISSIBLE_MODES = new Set(['modal', 'slide-in', 'hello_bar_top', 'hello_bar_bottom', 'drawer'])\n\n/** Modes that float over the page and therefore close themselves on submit. */\nconst OVERLAY_MODES = DISMISSIBLE_MODES\n\n/**\n * Host mount contract for `inline` mode (#106): when the page contains an\n * element matching this selector, the widget renders INTO it instead of into\n * the runtime's own `#kywi-selfid-container` (which is appended to the end of\n * `<body>`, i.e. after the footer). Hosts opt in by putting\n * `<div data-kywi-selfid-mount></div>` wherever the card belongs.\n */\nexport const SELFID_MOUNT_SELECTOR = '[data-kywi-selfid-mount]'\n\n/** Body class + custom property published while a top hello bar is on screen. */\nexport const HELLO_BAR_TOP_CLASS = 'kywi-selfid-hello-bar-top-open'\nconst HELLO_BAR_HEIGHT_PROPERTY = '--kywi-selfid-hello-bar-height'\n\nconst MODAL_LABEL_ID = 'kywi-selfid-headline'\n\n/**\n * The host slot for `inline` mode, when one exists. Returns null for every\n * other display mode \u2014 modal/drawer/hello-bar/slide-in position themselves\n * against the viewport, so a content slot would be meaningless for them.\n */\nexport function resolveSelfIdMount(displayMode?: SelfIdWidgetConfig['displayMode']): HTMLElement | null {\n if (typeof document === 'undefined') return null\n if (displayMode && displayMode !== 'inline') return null\n return document.querySelector<HTMLElement>(SELFID_MOUNT_SELECTOR)\n}\n\n/** A picklist option: the value submitted, and the label shown to the visitor. */\nexport interface SelfIdFieldOption {\n value: string\n label: string\n}\n\nexport interface SelfIdFieldConfig {\n id: string\n label: string\n type: 'text' | 'select' | 'email'\n /**\n * Either `{value, label}` pairs (current server shape \u2014 see\n * resolveSelfIdWidget in the create-kywi-app scaffold) or bare strings (older\n * config shape, kept for backward compatibility). A bare string is treated as\n * both its own value and its own label.\n */\n options?: Array<string | SelfIdFieldOption>\n required?: boolean\n}\n\n/** Normalize a picklist option to `{value, label}`, treating a bare string as both. */\nfunction normalizeOption(opt: string | SelfIdFieldOption): SelfIdFieldOption {\n return typeof opt === 'string' ? { value: opt, label: opt } : opt\n}\n\n/** When the widget is shown, once frequency allows. Defaults to immediate. */\nexport type SelfIdWidgetTrigger =\n | { type: 'immediate' }\n | { type: 'scroll'; depth: number }\n | { type: 'delay'; seconds: number }\n | { type: 'manual' }\n\nexport interface SelfIdWidgetConfig {\n fields: SelfIdFieldConfig[]\n headline?: string\n subheadline?: string\n submitLabel?: string\n skipLabel?: string\n displayMode?: 'modal' | 'inline' | 'slide-in' | 'hello_bar_top' | 'hello_bar_bottom' | 'drawer'\n frequency?: 'once' | 'session' | 'daily' | 'always'\n trigger?: SelfIdWidgetTrigger\n /**\n * The full audience rule definitions to re-evaluate client-side after a\n * submission. These flow straight into `handleSelfIdSubmit` \u2192\n * `evaluateClientSide` \u2192 `resolveAudiences`, which iterates each audience's\n * `conditionGroups`, so full `Audience` objects are required (not id strings).\n */\n audiences?: Audience[]\n currentPath?: string\n}\n\nexport interface SelfIdWidget {\n shouldShow(): boolean\n markShown(): void\n render(container: HTMLElement): void\n handleSubmit(responses: Record<string, string>): void\n}\n\nconst FOCUSABLE_SELECTOR =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction focusableElements(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter((el) => !el.hidden)\n}\n\n/** Keeps Tab inside `root`, wrapping at both ends. */\nfunction trapTab(root: HTMLElement, e: KeyboardEvent): void {\n const focusable = focusableElements(root)\n if (focusable.length === 0) {\n e.preventDefault()\n root.focus()\n return\n }\n const first = focusable[0]!\n const last = focusable[focusable.length - 1]!\n const active = document.activeElement as HTMLElement | null\n const inside = active !== null && root.contains(active) && active !== root\n if (e.shiftKey) {\n if (!inside || active === first) { e.preventDefault(); last.focus() }\n } else if (!inside || active === last) {\n e.preventDefault()\n first.focus()\n }\n}\n\nexport function createSelfIdWidget(config: SelfIdWidgetConfig): SelfIdWidget {\n const frequency = config.frequency ?? 'once'\n const displayMode = config.displayMode ?? 'inline'\n const isModal = displayMode === 'modal'\n\n /** Undo callbacks for everything render() attached outside the container. */\n let cleanups: Array<() => void> = []\n\n function shouldShow(): boolean {\n if (frequency === 'always') return true\n if (frequency === 'session') return false\n\n const raw = localStorage.getItem(SHOWN_KEY)\n if (!raw) return true\n\n if (frequency === 'once') return false\n\n // 'daily' \u2014 true if more than 24h since last shown\n const ts = Number(raw)\n return !isNaN(ts) && Date.now() - ts > MS_PER_DAY\n }\n\n function markShown(): void {\n localStorage.setItem(SHOWN_KEY, String(Date.now()))\n }\n\n function handleSubmit(responses: Record<string, string>): void {\n storeSelfId(responses)\n // Attempt the immediate variant swap, but never let a personalization/resolver\n // error skip markShown() \u2014 otherwise a `frequency: 'once'` widget re-shows on\n // every subsequent page load forever (issue #80). The `finally` keeps the\n // frequency gate honored even if `handleSelfIdSubmit` throws.\n try {\n handleSelfIdSubmit(responses, config.audiences ?? [], config.currentPath ?? '/')\n } finally {\n markShown()\n }\n }\n\n /** Removes the widget and everything it attached to the document. */\n function teardown(container: HTMLElement): void {\n for (const undo of cleanups) undo()\n cleanups = []\n container.replaceChildren()\n container.className = ''\n container.removeAttribute('role')\n container.removeAttribute('aria-modal')\n container.removeAttribute('aria-label')\n container.removeAttribute('aria-labelledby')\n container.removeAttribute('tabindex')\n container.hidden = true\n }\n\n /**\n * Visitor closed the widget without answering. Dismissing honors the\n * frequency gate exactly like skipping does, so a `once` widget does not\n * reappear on the next page.\n */\n function dismiss(container: HTMLElement): void {\n markShown()\n teardown(container)\n }\n\n function render(container: HTMLElement): void {\n for (const undo of cleanups) undo()\n cleanups = []\n container.replaceChildren()\n container.hidden = false\n // Style hook uses kebab-case (kywi-selfid-hello-bar-top) even though the\n // config value is snake_case (hello_bar_top), matching the existing\n // kywi-selfid-slide-in convention.\n const displayModeClass = displayMode.replace(/_/g, '-')\n container.className = `kywi-selfid-widget kywi-selfid-${displayModeClass}`\n\n if (isModal) {\n // A real backdrop ELEMENT (the old ::before pseudo could not be clicked):\n // clicking it dismisses without submitting.\n const backdrop = document.createElement('div')\n backdrop.className = 'kywi-selfid-backdrop'\n backdrop.addEventListener('click', () => dismiss(container))\n ;(container.parentElement ?? document.body).appendChild(backdrop)\n cleanups.push(() => backdrop.remove())\n\n const previousOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n cleanups.push(() => { document.body.style.overflow = previousOverflow })\n\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') { e.preventDefault(); dismiss(container); return }\n if (e.key === 'Tab') trapTab(container, e)\n }\n document.addEventListener('keydown', onKeydown, true)\n cleanups.push(() => document.removeEventListener('keydown', onKeydown, true))\n\n container.setAttribute('role', 'dialog')\n container.setAttribute('aria-modal', 'true')\n if (config.headline) {\n container.setAttribute('aria-labelledby', MODAL_LABEL_ID)\n } else {\n container.setAttribute('aria-label', 'Personalize your experience')\n }\n container.tabIndex = -1\n }\n\n if (displayMode === 'hello_bar_top') {\n // Offset hook (#106): hosts push their own content down with\n // `body.kywi-selfid-hello-bar-top-open` and/or the measured height in\n // `--kywi-selfid-hello-bar-height` \u2014 no hardcoded header height anywhere.\n document.body.classList.add(HELLO_BAR_TOP_CLASS)\n const syncHeight = () => {\n document.documentElement.style.setProperty(HELLO_BAR_HEIGHT_PROPERTY, `${container.offsetHeight}px`)\n }\n window.addEventListener('resize', syncHeight)\n cleanups.push(() => {\n document.body.classList.remove(HELLO_BAR_TOP_CLASS)\n document.documentElement.style.removeProperty(HELLO_BAR_HEIGHT_PROPERTY)\n window.removeEventListener('resize', syncHeight)\n })\n // Measured once the card's children exist (i.e. after render() returns).\n queueMicrotask(syncHeight)\n }\n\n if (DISMISSIBLE_MODES.has(displayMode)) {\n const dismissBtn = document.createElement('button')\n dismissBtn.type = 'button'\n dismissBtn.className = 'kywi-selfid-dismiss'\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n dismissBtn.textContent = '\u00D7'\n dismissBtn.addEventListener('click', () => dismiss(container))\n container.appendChild(dismissBtn)\n }\n\n if (config.headline) {\n const h = document.createElement('h3')\n h.className = 'kywi-selfid-headline'\n h.textContent = config.headline\n if (isModal) h.id = MODAL_LABEL_ID\n container.appendChild(h)\n }\n\n if (config.subheadline) {\n const p = document.createElement('p')\n p.className = 'kywi-selfid-subheadline'\n p.textContent = config.subheadline\n container.appendChild(p)\n }\n\n const form = document.createElement('form')\n form.className = 'kywi-selfid-form'\n\n for (const field of config.fields) {\n const fieldWrap = document.createElement('div')\n fieldWrap.className = 'kywi-selfid-field'\n\n const label = document.createElement('label')\n label.htmlFor = `kywi-field-${field.id}`\n label.textContent = field.label\n fieldWrap.appendChild(label)\n\n let input: HTMLInputElement | HTMLSelectElement\n\n if (field.type === 'select') {\n const select = document.createElement('select')\n select.id = `kywi-field-${field.id}`\n select.name = field.id\n if (field.required) select.required = true\n if (field.options) {\n const placeholder = document.createElement('option')\n placeholder.value = ''\n placeholder.textContent = ''\n select.appendChild(placeholder)\n for (const opt of field.options) {\n const { value, label } = normalizeOption(opt)\n const option = document.createElement('option')\n option.value = value\n option.textContent = label\n select.appendChild(option)\n }\n }\n input = select\n } else {\n const inp = document.createElement('input')\n inp.id = `kywi-field-${field.id}`\n inp.name = field.id\n inp.type = field.type\n if (field.required) inp.required = true\n input = inp\n }\n\n fieldWrap.appendChild(input)\n form.appendChild(fieldWrap)\n }\n\n const actions = document.createElement('div')\n actions.className = 'kywi-selfid-actions'\n\n const submitBtn = document.createElement('button')\n submitBtn.type = 'submit'\n submitBtn.className = 'kywi-selfid-submit'\n submitBtn.textContent = config.submitLabel ?? 'Submit'\n actions.appendChild(submitBtn)\n\n if (config.skipLabel) {\n const skipBtn = document.createElement('button')\n skipBtn.type = 'button'\n skipBtn.className = 'kywi-selfid-skip'\n skipBtn.textContent = config.skipLabel\n skipBtn.addEventListener('click', () => dismiss(container))\n actions.appendChild(skipBtn)\n }\n\n form.appendChild(actions)\n\n form.addEventListener('submit', (e) => {\n e.preventDefault()\n const data = new FormData(form)\n const responses: Record<string, string> = {}\n data.forEach((value, key) => {\n responses[key] = String(value)\n })\n handleSubmit(responses)\n // An overlay must not stay on screen over the freshly personalized page \u2014\n // and for the modal, leaving it up would also leave the scroll lock on.\n if (OVERLAY_MODES.has(displayMode)) teardown(container)\n })\n\n container.appendChild(form)\n\n if (isModal) container.focus()\n }\n\n return { shouldShow, markShown, render, handleSubmit }\n}\n", "// packages/kywi-js/src/personalization/badge.ts\n//\n// The `personalizationBadge` layout module's runtime half (#107). It is a\n// PASSIVE status pill \u2014 \"Personalization active/off\", plus the audience name\n// when there is one \u2014 that opens the global transparency panel on click. It\n// deliberately embeds no opt-in/opt-out controls of its own: opting out and\n// switching audience live in exactly one surface (see audience/transparency.ts),\n// so a badge placed on a page can never disagree with the global panel.\n\nimport { COOKIE_NAMES, readCookies } from '../cookies.js'\nimport { openTransparencyPanel } from '../audience/transparency.js'\n\nexport interface PersonalizationBadgeInfo {\n /** The audience the page was personalized for, if any. */\n audienceName?: string | null\n}\n\nfunction isOptedOut(): boolean {\n return readCookies().has(COOKIE_NAMES.OPTOUT)\n}\n\nexport function renderPersonalizationBadge(info: PersonalizationBadgeInfo = {}): void {\n const containers = document.querySelectorAll('[data-kywi-personalization-badge]')\n if (containers.length === 0) return\n\n const optedOut = isOptedOut()\n\n for (const container of Array.from(containers)) {\n // Clear existing badge to avoid duplication\n container.querySelector('.kywi-personalization-badge')?.remove()\n\n const badge = document.createElement('div')\n badge.className = 'kywi-personalization-badge'\n\n const trigger = document.createElement('button')\n trigger.type = 'button'\n trigger.className = 'kywi-badge-open'\n trigger.setAttribute('aria-label', 'Personalization details')\n\n const status = document.createElement('span')\n status.className = 'kywi-badge-status'\n status.textContent = optedOut ? 'Personalization off' : 'Personalization active'\n trigger.appendChild(status)\n\n if (!optedOut && info.audienceName) {\n const audience = document.createElement('span')\n audience.className = 'kywi-badge-audience'\n audience.textContent = info.audienceName\n trigger.appendChild(audience)\n }\n\n trigger.addEventListener('click', () => openTransparencyPanel())\n badge.appendChild(trigger)\n container.appendChild(badge)\n }\n}\n", "// packages/kywi-js/src/audience/index.ts\nimport type { Audience, VisitorSignals } from '@kywi-software/core/audiences/types'\nimport { evaluateClientSide } from './evaluate.js'\nimport { patchVariantContainers } from './dom-patcher.js'\nimport { renderTransparencyPanel } from './transparency.js'\nimport { checkPreviewInit, getPreviewAudienceId, renderPreviewBanner } from './preview.js'\nimport { populateDataLayer, fireKywiReady, readServerMeta } from './data-layer.js'\nimport { readCookies, COOKIE_NAMES } from '../cookies.js'\nimport { runClientAdapters } from './adapter-runner.js'\nimport { Kywi } from '../index.js'\nimport { createSelfIdWidget, resolveSelfIdMount, type SelfIdWidgetConfig } from './selfid-widget.js'\nimport { renderPersonalizationBadge } from '../personalization/badge.js'\n\nexport interface AudienceBootConfig {\n audiences: Audience[]\n currentPath: string\n pageCategory?: string\n serverSignals?: Partial<VisitorSignals>\n adapters?: Array<{ id: string; side: 'client' | 'server-proxy'; fields: string[]; collect: (s: Partial<VisitorSignals>) => Promise<Record<string, unknown>> }>\n selfIdWidget?: SelfIdWidgetConfig\n /**\n * Base path of the mounted CMS API (e.g. `/api/v1`). Runtime calls\n * (server-proxy adapters, audience assignment) are made under `{apiBase}/kywi/*`.\n * Defaults to the same `{basePath}/api/v1` derivation the entity/feed factories\n * use, so it matches the reference app's mount out of the box.\n */\n apiBase?: string\n /**\n * `personalization.transparencyNotice.enabled`. When false, the global\n * transparency surface never appears on its own \u2014 the visitor can still open\n * it deliberately through a `personalizationBadge` module. Defaults to true;\n * the host page passes the resolved config value through.\n */\n transparencyNotice?: boolean\n}\n\n/** The mounted CMS API base \u2014 mirrors the derivation in Kywi.boot(). */\nfunction resolveApiBase(explicit?: string): string {\n if (explicit) return explicit\n const basePath = Kywi.context?.basePath\n if (!basePath || basePath === '/') return '/api/v1'\n return `${basePath}/api/v1`\n}\n\nexport async function bootAudienceEngine(config: AudienceBootConfig): Promise<void> {\n const { audiences, currentPath, pageCategory, serverSignals } = config\n const apiBase = resolveApiBase(config.apiBase)\n checkPreviewInit()\n const serverMeta = readServerMeta()\n const previewId = getPreviewAudienceId()\n\n // Audiences the visitor can be shown as \u2014 the switcher's option list and the\n // lookup that turns a resolved audience id into a name the visitor recognizes.\n const activeAudiences = audiences\n .filter((a) => a.status === 'active')\n .map((a) => ({ id: a.id, name: a.name }))\n const nameOf = (id: string | null): string | null =>\n id ? activeAudiences.find((a) => a.id === id)?.name ?? null : null\n\n if (previewId) {\n patchVariantContainers(previewId)\n // Show the audience's name, falling back to the raw id for an audience that\n // is not in this page's list (e.g. previewing a draft audience).\n renderPreviewBanner(nameOf(previewId) ?? previewId)\n renderPersonalizationBadge({ audienceName: nameOf(previewId) })\n populateDataLayer({ visitorId: serverMeta.visitorId, audienceId: previewId, experimentId: null, variantId: null, isPreview: true, isOptedOut: false })\n fireKywiReady()\n return\n }\n\n const cookies = readCookies()\n let merged: Partial<VisitorSignals> = {\n ...serverSignals,\n identity: { visitorId: serverMeta.visitorId || cookies.get(COOKIE_NAMES.VISITOR) || '', isKnown: cookies.has(COOKIE_NAMES.KNOWN), maLeadId: null },\n meta: { isOptedOut: cookies.has(COOKIE_NAMES.OPTOUT), isPreview: false, previewAudienceId: null, resolvedAt: 'server' },\n }\n\n // Run client-side adapters if configured\n if (config.adapters && config.adapters.length > 0) {\n const adapterResults = await runClientAdapters(config.adapters, merged, apiBase)\n merged.adapters = { ...merged.adapters, ...adapterResults }\n }\n\n const result = evaluateClientSide(audiences, merged, currentPath, pageCategory)\n\n // A manual pin (kywi_audience \u2014 written by the transparency panel's switcher,\n // or by this boot path persisting a client-resolved audience) beats signal\n // resolution, matching the server engine's precedence. Without this the client\n // would re-resolve from signals and immediately overwrite the visitor's own\n // choice on the very next page view.\n const pinnedId = cookies.get(COOKIE_NAMES.AUDIENCE) ?? null\n const isPinned = !result.isOptedOut && pinnedId !== null && activeAudiences.some((a) => a.id === pinnedId)\n const effectiveAudienceId = isPinned ? pinnedId : result.winningAudienceId\n\n patchVariantContainers(effectiveAudienceId)\n renderTransparencyPanel({\n isPersonalized: effectiveAudienceId !== null,\n isOptedOut: result.isOptedOut,\n hasMatchAvailable: result.allMatchedIds.length > 0,\n audienceId: effectiveAudienceId,\n audiences: activeAudiences,\n apiBase,\n csrfToken: Kywi.context?.csrfToken ?? null,\n enabled: config.transparencyNotice !== false,\n })\n // Render the status pill wherever a personalizationBadge module was placed.\n renderPersonalizationBadge({ audienceName: nameOf(effectiveAudienceId) })\n populateDataLayer({ visitorId: result.signals.identity.visitorId, audienceId: effectiveAudienceId, experimentId: serverMeta.experimentId, variantId: serverMeta.variantId, isPreview: false, isOptedOut: result.isOptedOut })\n fireKywiReady()\n\n if (!isPinned && result.winningAudienceId && result.winningAudienceId !== serverMeta.audienceId) {\n fetch(`${apiBase}/kywi/audience`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(Kywi.context?.csrfToken ? { 'X-CSRF-Token': Kywi.context.csrfToken } : {}) },\n body: JSON.stringify({ audienceId: result.winningAudienceId }),\n }).catch(() => {})\n }\n\n // Self-ID widget \u2014 mount when frequency allows, timed by its trigger.\n if (config.selfIdWidget) {\n const widget = createSelfIdWidget(config.selfIdWidget)\n if (widget.shouldShow()) {\n const doRender = () => {\n // Inline mode renders into the host's own slot when one is declared\n // ([data-kywi-selfid-mount]); otherwise it falls back to the runtime's\n // container at the end of <body>, like the overlay modes.\n const mount = resolveSelfIdMount(config.selfIdWidget!.displayMode)\n if (mount) { widget.render(mount); return }\n const existing = document.getElementById('kywi-selfid-container')\n const container = existing ?? document.createElement('div')\n if (!container.id) {\n container.id = 'kywi-selfid-container'\n document.body.appendChild(container)\n }\n widget.render(container)\n }\n scheduleSelfIdWidget(config.selfIdWidget.trigger, doRender)\n }\n }\n}\n\n/**\n * Show the self-ID widget per its trigger: immediately, after a delay, or once\n * the visitor scrolls past a depth fraction (0-1). `manual` never auto-shows \u2014\n * the host page decides. An absent trigger behaves as immediate.\n */\nfunction scheduleSelfIdWidget(trigger: SelfIdWidgetConfig['trigger'], render: () => void): void {\n if (!trigger || trigger.type === 'immediate') { render(); return }\n if (trigger.type === 'manual') return\n if (trigger.type === 'delay') {\n window.setTimeout(render, Math.max(0, trigger.seconds) * 1000)\n return\n }\n // scroll: fire once when scrolled past `depth` (fraction of scrollable height).\n const target = Math.min(Math.max(trigger.depth, 0), 1)\n let fired = false\n const onScroll = () => {\n if (fired) return\n const scrollable = document.documentElement.scrollHeight - window.innerHeight\n const progress = scrollable > 0 ? window.scrollY / scrollable : 1\n if (progress >= target) {\n fired = true\n window.removeEventListener('scroll', onScroll)\n render()\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n onScroll()\n}\n", "// packages/kywi-js/src/index.ts\nimport type { KywiContext, KywiModuleDefinition } from './types.js'\nimport { readContext } from './context.js'\nimport { createEntityFactory } from './entity.js'\nimport { createFeedFactory } from './feed.js'\nimport { renderFeed } from './render-feed.js'\nimport { initModules } from './module-system.js'\nimport { initFormHooks } from './form-hooks.js'\nimport { bootExperiments } from './experiments/index.js'\n\ntype PreInitCallback = (kywi: typeof Kywi) => void\nconst preInitCallbacks: PreInitCallback[] = []\nlet booted = false\n\nexport const Kywi = {\n version: '0.1.0',\n context: null as unknown as KywiContext,\n Module: {} as Record<string, KywiModuleDefinition>,\n preInit(fn: PreInitCallback): void {\n if (booted) { fn(Kywi) } else { preInitCallbacks.push(fn) }\n },\n UI: {\n extend(definition: KywiModuleDefinition): KywiModuleDefinition {\n return { ...definition }\n },\n },\n DisplayObject: {\n Form: {\n _hooks: {} as Record<string, (...args: unknown[]) => unknown>,\n extend(methods: Record<string, (...args: unknown[]) => unknown>): void {\n Object.assign(Kywi.DisplayObject.Form._hooks, methods)\n },\n },\n },\n getEntity: null as unknown as (type: string) => any,\n getFeed: null as unknown as (type: string) => any,\n renderFeed: null as unknown as (options: any) => void,\n boot(): void {\n if (booted) return\n Kywi.context = readContext()\n for (const fn of preInitCallbacks) { fn(Kywi) }\n const basePath = Kywi.context.basePath === '/' ? '/api/v1' : `${Kywi.context.basePath}/api/v1`\n Kywi.getEntity = createEntityFactory(basePath, Kywi.context.csrfToken)\n Kywi.getFeed = createFeedFactory(basePath, Kywi.context.csrfToken)\n Kywi.renderFeed = renderFeed\n initModules()\n initFormHooks()\n // A/B experiment beacons: confirm exposure of the server-rendered variant\n // and wire conversion signals (pageview / form-submit / kywi.track).\n bootExperiments({ context: Kywi.context })\n booted = true\n },\n}\n\nif (typeof globalThis !== 'undefined') { (globalThis as any).Kywi = Kywi }\nif (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => Kywi.boot())\n } else {\n Kywi.boot()\n }\n}\n\nexport { bootAudienceEngine } from './audience/index.js'\nexport {\n openTransparencyPanel,\n renderTransparencyPanel,\n type TransparencyState,\n type TransparencyAudience,\n} from './audience/transparency.js'\nexport { bootExperiments, type ExperimentRuntime, type ConversionSignal } from './experiments/index.js'\n"],
5
- "mappings": ";AAGO,SAAS,cAA2B;AACzC,QAAM,OAAO,CAAC,SAAyB;AACrC,QAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,UAAM,KAAK,SAAS,cAAc,mBAAmB,IAAI,IAAI;AAC7D,WAAO,IAAI,aAAa,SAAS,KAAK;AAAA,EACxC;AACA,SAAO;AAAA,IACL,QAAQ,KAAK,SAAS,KAAK,UAAU,iBAAiB,aAAa,gBAAgB,KAAK;AAAA,IACxF,QAAQ,UAAU,iBAAiB,QAAQ;AAAA,IAC3C,WAAW,KAAK,YAAY,KAAK;AAAA,IACjC,UAAU,KAAK,WAAW,KAAK;AAAA,IAC/B,WAAW,KAAK,YAAY,KAAK;AAAA,IACjC,YAAY,UAAU,MAAM,WAAW,SAAS,gBAAgB,KAAK;AAAA,EACvE;AACF;;;ACdA,SAAS,aAAa,MAAc,UAAkB,WAAmB,MAAiD;AACxH,QAAM,SAAS,EAAE,GAAG,KAAK;AACzB,QAAM,QAAQ,oBAAI,IAAqB;AACvC,QAAM,SAAmB,CAAC;AAC1B,QAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,MAAI,UAAW,SAAQ,cAAc,IAAI;AAEzC,QAAM,SAA2B;AAAA,IAC/B,IAAI,OAAe;AAAE,aAAO,OAAO,KAAK;AAAA,IAAE;AAAA,IAC1C,IAAI,OAAe,OAAgB;AAAE,aAAO,KAAK,IAAI;AAAO,YAAM,IAAI,OAAO,KAAK;AAAG,aAAO;AAAA,IAAO;AAAA,IACnG,MAAM,OAAO;AACX,YAAM,KAAK,OAAO,IAAI;AACtB,YAAM,MAAM,KAAK,GAAG,QAAQ,YAAY,IAAI,IAAI,EAAE,KAAK,GAAG,QAAQ,YAAY,IAAI;AAClF,YAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,KAAK,QAAQ,QAAQ,SAAS,MAAM,KAAK,UAAU,OAAO,YAAY,KAAK,CAAC,EAAE,CAAC;AACtH,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,CAAC,IAAI,MAAM,KAAK,OAAO;AAAE,eAAO,KAAK,KAAK,OAAO,WAAW,aAAa;AAAG,cAAM;AAAA,MAAO;AAC7F,UAAI,KAAK,KAAM,QAAO,OAAO,QAAQ,KAAK,IAAI;AAC9C,YAAM,MAAM;AACZ,aAAO;AAAA,IACT;AAAA,IACA,MAAM,SAAS;AACb,YAAM,KAAK,OAAO,IAAI;AACtB,YAAM,MAAM,GAAG,QAAQ,YAAY,IAAI,IAAI,EAAE,IAAI,EAAE,QAAQ,UAAU,QAAQ,CAAC;AAAA,IAChF;AAAA,IACA,YAAY;AAAE,aAAO,CAAC,GAAG,MAAM;AAAA,IAAE;AAAA,IACjC,MAAM,OAAO,OAAe,OAAe;AACzC,YAAM,MAAM,UAAU,OAAO,GAAG,QAAQ,YAAY,IAAI,IAAI,KAAK,KAAK,GAAG,QAAQ,YAAY,IAAI,IAAI,KAAK,IAAI,mBAAmB,KAAK,CAAC;AACvI,YAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,CAAC;AACxC,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,CAAC,IAAI,MAAM,KAAK,OAAO;AAAE,eAAO,KAAK,KAAK,OAAO,WAAW,aAAa;AAAG,cAAM;AAAA,MAAO;AAC7F,UAAI,KAAK,KAAM,QAAO,OAAO,QAAQ,KAAK,IAAI;AAC9C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,oBAAoB,UAAkB,WAAmB;AACvE,SAAO,CAAC,SAAmC,aAAa,MAAM,UAAU,WAAW,CAAC,CAAC;AACvF;;;AClCA,IAAM,cAAN,MAAkB;AAAA,EAChB,YAAoB,SAA8B,OAAuB,MAAoB;AAAzE;AAA8B;AAAuB;AAAA,EAAqB;AAAA,EACtF,IAAI,IAAY,OAAiB;AAAE,SAAK,QAAQ,SAAS,KAAK,EAAE,OAAO,KAAK,OAAO,UAAU,IAAI,OAAO,aAAa,KAAK,KAAK,CAAC;AAAG,WAAO,KAAK;AAAA,EAAQ;AAAA,EAC/J,KAAK,GAAY;AAAE,WAAO,KAAK,IAAI,MAAM,CAAC;AAAA,EAAE;AAAA,EAC5C,MAAM,GAAY;AAAE,WAAO,KAAK,IAAI,OAAO,CAAC;AAAA,EAAE;AAAA,EAC9C,KAAK,GAAY;AAAE,WAAO,KAAK,IAAI,MAAM,CAAC;AAAA,EAAE;AAAA,EAC5C,MAAM,GAAY;AAAE,WAAO,KAAK,IAAI,OAAO,CAAC;AAAA,EAAE;AAAA,EAC9C,KAAK,GAAY;AAAE,WAAO,KAAK,IAAI,MAAM,CAAC;AAAA,EAAE;AAAA,EAC5C,MAAM,GAAY;AAAE,WAAO,KAAK,IAAI,OAAO,CAAC;AAAA,EAAE;AAAA,EAC9C,WAAW,GAAY;AAAE,WAAO,KAAK,IAAI,cAAc,CAAC;AAAA,EAAE;AAAA,EAC1D,SAAS,GAAY;AAAE,WAAO,KAAK,IAAI,YAAY,CAAC;AAAA,EAAE;AAAA,EACtD,SAAS,GAAY;AAAE,WAAO,KAAK,IAAI,YAAY,CAAC;AAAA,EAAE;AAAA,EACtD,SAAS;AAAE,WAAO,KAAK,IAAI,QAAQ;AAAA,EAAE;AAAA,EACrC,YAAY;AAAE,WAAO,KAAK,IAAI,WAAW;AAAA,EAAE;AAC7C;AAEA,IAAM,cAAN,MAAkB;AAAA,EAKhB,YAAoB,aAA6B,UAA0B,WAAmB;AAA1E;AAA6B;AAA0B;AAAA,EAAoB;AAAA,EAJ/F,WAAqB,CAAC;AAAA,EACd,QAA6D;AAAA,EAC7D,SAAwB;AAAA,EACxB,QAAuB;AAAA,EAG/B,QAAc;AAAE,WAAO;AAAA,EAAK;AAAA,EAC5B,KAAK,OAAe;AAAE,WAAO,IAAI,YAAY,MAAM,OAAO,KAAK;AAAA,EAAE;AAAA,EACjE,QAAQ,OAAe;AAAE,WAAO,IAAI,YAAY,MAAM,OAAO,KAAK;AAAA,EAAE;AAAA,EACpE,OAAO,OAAe;AAAE,WAAO,IAAI,YAAY,MAAM,OAAO,IAAI;AAAA,EAAE;AAAA,EAClE,KAAK,OAAe,YAA4B,OAAa;AAAE,SAAK,QAAQ,EAAE,OAAO,UAAU;AAAG,WAAO;AAAA,EAAK;AAAA,EAC9G,SAAS,GAAiB;AAAE,SAAK,SAAS;AAAG,WAAO;AAAA,EAAK;AAAA,EACzD,KAAK,GAAiB;AAAE,SAAK,QAAQ;AAAG,WAAO;AAAA,EAAK;AAAA,EAE5C,YAAqC;AAC3C,UAAM,cAAc,KAAK,SAAS,IAAI,QAAM;AAAA,MAC1C,OAAO,EAAE;AAAA,MACT,UAAU,EAAE;AAAA,MACZ,OAAO,EAAE;AAAA,MACT,aAAa,EAAE;AAAA,IACjB,EAAE;AACF,UAAM,OAAgC,EAAE,aAAa,KAAK,YAAY;AACtE,QAAI,YAAY,SAAS,EAAG,MAAK,SAAS,IAAI;AAC9C,QAAI,KAAK,MAAO,MAAK,MAAM,IAAI,KAAK;AACpC,QAAI,KAAK,WAAW,KAAM,MAAK,OAAO,IAAI,KAAK;AAC/C,QAAI,KAAK,UAAU,KAAM,MAAK,MAAM,IAAI,KAAK;AAC7C,WAAO;AAAA,EACT;AAAA,EAEQ,eAAuC;AAC7C,UAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,QAAI,KAAK,UAAW,SAAQ,cAAc,IAAI,KAAK;AACnD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,IAAuB,OAA0C;AAC/E,UAAM,OAAO,KAAK,UAAU;AAC5B,UAAM,MAA8B,EAAE,UAAU,GAAG;AACnD,QAAI,MAAO,KAAI,OAAO,IAAI;AAC1B,SAAK,WAAW,IAAI;AAEpB,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,QAAQ,oBAAoB;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS,KAAK,aAAa;AAAA,MAC3B,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AACD,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,KAAK,QAAQ,CAAC;AAAA,EACvB;AAAA,EAEA,MAAM,WAAoC;AACxC,UAAM,OAAO,KAAK,UAAU;AAC5B,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,QAAQ,gBAAgB;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS,KAAK,aAAa;AAAA,MAC3B,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAMD,UAAM,OAAO,MAAM,IAAI,KAAK;AAK5B,UAAM,UAAU,KAAK;AACrB,UAAM,WAA2C,MAAM,QAAQ,OAAO,IAClE,UACC,SAAS,SAAS,CAAC;AACxB,UAAM,QAAQ,MAAM,QAAQ,OAAO,IAAK,KAAK,MAAM,SAAS,SAAS,SAAW,SAAS,SAAS,SAAS;AAC3G,UAAM,OAAO,MAAM,QAAQ,OAAO,IAAK,KAAK,MAAM,QAAQ,IAAM,SAAS,QAAQ;AACjF,UAAM,QAAQ,MAAM,QAAQ,OAAO,IAAK,KAAK,MAAM,cAAc,IAAM,SAAS,cAAc;AAE9F,UAAM,QAA4B,SAAS,IAAI,QAAM;AAAA,MACnD,IAAI,OAAe;AAAE,eAAO,EAAE,KAAK;AAAA,MAAE;AAAA,MACrC,MAAM;AAAE,cAAM,IAAI,MAAM,4BAA4B;AAAA,MAAE;AAAA,MACtD,OAAO;AAAE,eAAO,QAAQ,OAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,MAAE;AAAA,MACxE,SAAS;AAAE,eAAO,QAAQ,OAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,MAAE;AAAA,MAC1E,YAAY;AAAE,eAAO,CAAC;AAAA,MAAE;AAAA,MACxB,SAAS;AAAE,eAAO,QAAQ,OAAO,IAAI,MAAM,uCAAuC,CAAC;AAAA,MAAE;AAAA,IACvF,EAAE;AAEF,WAAO,EAAE,OAAO,OAAO,MAAM,MAAM;AAAA,EACrC;AACF;AAEO,SAAS,kBAAkB,UAAkB,WAAmB;AACrE,SAAO,CAAC,SAAiB,IAAI,YAAY,MAAM,UAAU,SAAS;AACpE;;;ACtGA,eAAsB,WAAW,SAA2C;AAC1E,QAAM,EAAE,MAAM,WAAW,UAAU,cAAc,IAAI,YAAY,IAAI,aAAa,OAAO,cAAc,aAAa,OAAO,SAAS,IAAI;AACxI,MAAI,YAAa,WAAU,cAAc;AACzC,QAAM,SAAS,MAAM,KAAK,SAAS;AACnC,YAAU,cAAc;AACxB,MAAI,OAAO,MAAM,WAAW,GAAG;AAAE,QAAI,UAAW,WAAU,cAAc;AAAW;AAAA,EAAO;AAC1F,QAAM,UAAU,SAAS,cAAc,UAAU;AACjD,MAAI,aAAc,SAAQ,YAAY;AACtC,aAAW,QAAQ,OAAO,OAAO;AAC/B,UAAM,WAAW,SAAS,IAAI;AAC9B,QAAI,oBAAoB,MAAM;AAC5B,cAAQ,YAAY,QAAQ;AAAA,IAC9B,WAAW,YAAY;AACrB,YAAM,OAAO,SAAS,cAAc,MAAM;AAE1C,WAAK,WAAW,IAAI;AACpB,cAAQ,YAAY,IAAI;AAAA,IAC1B,OAAO;AACL,YAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,WAAK,cAAc;AACnB,cAAQ,YAAY,IAAI;AAAA,IAC1B;AAAA,EACF;AACA,YAAU,YAAY,OAAO;AAC7B,MAAI,SAAU,UAAS,SAAS;AAClC;;;AClCA,SAAS,WAAW,IAAyC;AAC3D,QAAM,SAAiC,CAAC;AACxC,aAAW,QAAQ,MAAM,KAAK,GAAG,UAAU,GAAG;AAC5C,QAAI,KAAK,KAAK,WAAW,kBAAkB,GAAG;AAC5C,aAAO,KAAK,KAAK,MAAM,EAAE,CAAC,IAAI,KAAK;AAAA,IACrC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,cAAoB;AAClC,QAAM,WAAW,SAAS,iBAAiB,oBAAoB;AAC/D,aAAW,MAAM,MAAM,KAAK,QAAQ,GAAG;AACrC,UAAM,SAAS;AACf,UAAM,aAAa,OAAO,aAAa,kBAAkB;AACzD,QAAI,CAAC,WAAY;AACjB,UAAM,MAAM,KAAK,OAAO,UAAU;AAClC,QAAI,CAAC,OAAO,CAAC,IAAI,aAAc;AAC/B,UAAM,UAA6B,EAAE,UAAU,QAAQ,GAAG,WAAW,MAAM,EAAE;AAC7E,QAAI,aAAa,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;AAAA,EAC3C;AACF;;;ACtBO,SAAS,gBAAsB;AACpC,QAAM,QAAQ,SAAS,iBAAiB,kBAAkB;AAC1D,aAAW,UAAU,MAAM,KAAK,KAAK,GAAG;AACtC,UAAM,WAAW;AACjB,UAAM,QAAQ,KAAK,cAAc,KAAK;AACtC,QAAI,MAAM,eAAe,EAAG,OAAM,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,SAAS,EAAE,CAAC;AAC3F,aAAS,iBAAiB,UAAU,CAAC,MAAM;AACzC,UAAI,MAAM,UAAU,GAAG;AACrB,cAAM,SAAS,MAAM,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,SAAS,EAAE,CAAC;AACzE,YAAI,WAAW,MAAO,GAAE,eAAe;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACiBA,SAAS,YAAY,KAA0B;AAC7C,SAAO,IAAI,YAAY,IAAI,aAAa,MAAM,GAAG,IAAI,QAAQ,YAAY;AAC3E;AAEA,SAAS,YAAY,MAA6B;AAChD,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,SAAO,SAAS,cAAc,mBAAmB,IAAI,IAAI,GAAG,aAAa,SAAS,KAAK;AACzF;AAIA,IAAI,0BAA0B;AAC9B,IAAI,wBAA2D;AAE/D,SAAS,sBAA4B;AACnC,MAAI,2BAA2B,OAAO,aAAa,YAAa;AAChE,4BAA0B;AAC1B,WAAS;AAAA,IACP;AAAA,IACA,CAAC,MAAM;AACL,YAAM,OAAO,EAAE;AACf,UAAI,CAAC,QAAQ,KAAK,YAAY,OAAQ;AACtC,YAAM,SAAS,KAAK,aAAa,mBAAmB,KAAK,KAAK,aAAa,IAAI;AAC/E,UAAI,UAAU,sBAAuB,uBAAsB,MAAM;AAAA,IACnE;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,OAAO,KAAa,MAAe,WAA0B;AACpE,MAAI;AACF,SAAK,MAAM,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAI,YAAY,EAAE,gBAAgB,UAAU,IAAI,CAAC,EAAG;AAAA,MACnG,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,WAAW;AAAA,IACb,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB,QAAQ;AAAA,EAER;AACF;AAMO,SAAS,gBAAgB,SAA+B,CAAC,GAAsB;AACpF,QAAM,MAAM,OAAO,WAAW,YAAY;AAC1C,QAAM,UAAU,OAAO,WAAW,YAAY,GAAG;AACjD,QAAM,OAAO,IAAI,aAAa;AAC9B,QAAM,eAAe,YAAY,eAAe;AAChD,QAAM,YAAY,OAAO,aAAa,YAAY,YAAY,KAAK;AACnE,QAAM,cAAc,OAAO,gBAAgB,OAAO,aAAa,cAAc,SAAS,WAAW;AAEjG,WAAS,gBAAgB,QAAgC;AACvD,WAAO,GAAG,OAAO,gCAAgC,EAAE,WAAW,OAAO,OAAO,GAAG,IAAI;AAAA,EACrF;AACA,WAAS,MAAM,WAAyB;AACtC,oBAAgB,EAAE,MAAM,UAAU,UAAU,CAAC;AAAA,EAC/C;AAIA,MAAI,cAAc;AAChB,WAAO,GAAG,OAAO,8BAA8B,EAAE,cAAc,UAAU,GAAG,IAAI;AAAA,EAClF;AAIA,MAAI,OAAO,iBAAiB,OAAO;AACjC,oBAAgB,EAAE,MAAM,YAAY,KAAK,YAAY,CAAC;AAAA,EACxD;AAIA,0BAAwB,CAAC,WAAmB,gBAAgB,EAAE,MAAM,eAAe,OAAO,CAAC;AAC3F,sBAAoB;AAEpB,QAAM,UAA6B,EAAE,OAAO,gBAAgB;AAG5D,QAAM,IAAM,WAA6D,QAAQ,CAAC;AAClF,IAAE,OAAO,IAAI;AACb,IAAE,iBAAiB,IAAI;AACtB,EAAC,WAA6D,OAAO;AAEtE,SAAO;AACT;;;ACoDM,SAAU,qBAAkB;AAChC,SAAO;IACL,KAAK,EAAE,QAAQ,MAAM,QAAQ,MAAM,UAAU,MAAM,MAAM,MAAM,SAAS,KAAI;IAC5E,UAAU,EAAE,KAAK,MAAM,QAAQ,MAAM,YAAY,SAAQ;IACzD,SAAS,EAAE,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,WAAW,KAAK,cAAc,CAAA,EAAE;IACpG,YAAY,EAAE,gBAAgB,CAAA,GAAI,YAAY,EAAC;IAC/C,QAAQ,CAAA;IACR,UAAU,EAAE,WAAW,IAAI,SAAS,OAAO,UAAU,KAAI;IACzD,UAAU,CAAA;IACV,MAAM,EAAE,YAAY,OAAO,WAAW,OAAO,mBAAmB,MAAM,YAAY,SAAQ;;AAE9F;;;ACvLM,SAAU,UAAU,SAAiB,OAAa;AACtD,QAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,MAAI,MAAM,WAAW;AAAG,WAAO,YAAY;AAC3C,MAAI,MAAM;AACV,QAAM,QAAQ,MAAM,CAAC;AACrB,MAAI,UAAU,IAAI;AAChB,QAAI,CAAC,MAAM,WAAW,KAAK;AAAG,aAAO;AACrC,UAAM,MAAM;EACd;AACA,WAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,SAAS;AAAI;AACjB,UAAM,MAAM,MAAM,QAAQ,MAAM,GAAG;AACnC,QAAI,MAAM;AAAG,aAAO;AACpB,UAAM,MAAM,KAAK;EACnB;AACA,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,MAAI,SAAS,IAAI;AACf,QAAI,CAAC,MAAM,SAAS,IAAI;AAAG,aAAO;AAClC,QAAI,MAAM,SAAS,KAAK,SAAS;AAAK,aAAO;EAC/C;AACA,SAAO;AACT;;;ACnBM,SAAU,mBAAmB,SAAyB,KAAqB;AAC/E,MAAI,QAAQ;AAAc,WAAO,QAAQ,IAAI;AAC7C,MAAI,QAAQ;AAAc,WAAO,QAAQ,IAAI;AAC7C,MAAI,QAAQ;AAAgB,WAAO,QAAQ,IAAI;AAC/C,MAAI,QAAQ;AAAY,WAAO,QAAQ,IAAI;AAC3C,MAAI,QAAQ;AAAe,WAAO,QAAQ,IAAI;AAC9C,MAAI,QAAQ;AAAmB,WAAO,QAAQ,SAAS;AACvD,MAAI,QAAQ;AAAuB,WAAO,QAAQ,SAAS;AAC3D,MAAI,QAAQ;AAAoB,WAAO,QAAQ,SAAS,UAAU,SAAS;AAC3E,MAAI,QAAQ;AAAqB,WAAO,QAAQ,QAAQ;AACxD,MAAI,QAAQ;AAAwB,WAAO,QAAQ,QAAQ,aAAa,KAAK,GAAG;AAChF,MAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,UAAM,MAAM,IAAI,MAAM,CAAC;AACvB,WAAO,QAAQ,OAAO,GAAG,KAAK;EAChC;AACA,MAAI,IAAI,WAAW,UAAU,GAAG;AAC9B,UAAM,MAAM,IAAI,MAAM,CAAC;AACvB,UAAM,MAAM,QAAQ,SAAS,GAAG;AAChC,WAAO,QAAQ,UAAa,QAAQ,OAAO,OAAO,GAAG,IAAI;EAC3D;AACA,SAAO;AACT;AAEM,SAAU,yBAAyB,WAAkC,SAAuB;AAChG,QAAM,SAAS,mBAAmB,SAAS,UAAU,MAAM;AAC3D,QAAM,WAAW,UAAU;AAC3B,UAAQ,UAAU,UAAU;IAC1B,KAAK;AAAU,aAAO,WAAW;IACjC,KAAK;AAAc,aAAO,WAAW;IACrC,KAAK;AAAY,aAAO,WAAW,QAAQ,OAAO,aAAa,YAAY,OAAO,SAAS,QAAQ;IACnG,KAAK;AAAe,aAAO,WAAW,QAAQ,OAAO,aAAa,YAAY,OAAO,WAAW,QAAQ;IACxG,KAAK;AAAgB,aAAO,WAAW,QAAQ,OAAO,aAAa,YAAY,UAAU,UAAU,MAAM;IACzG,KAAK;AAAa,aAAO,WAAW,QAAQ,MAAM,QAAQ,UAAU,KAAK,KAAK,UAAU,MAAM,SAAS,MAAM;IAC7G,KAAK;AAAW,aAAO,WAAW;IAClC,KAAK;AAAY,aAAO,WAAW;IACnC,KAAK;AAAO,aAAO,WAAW,QAAQ,OAAO,aAAa,YAAY,OAAO,MAAM,KAAK,OAAO,QAAQ;IACvG,KAAK;AAAO,aAAO,WAAW,QAAQ,OAAO,aAAa,YAAY,OAAO,MAAM,KAAK,OAAO,QAAQ;IACvG;AAAS,aAAO;EAClB;AACF;;;ACtCA,SAAS,iBAAiB,MAAkC,SAAuB;AACjF,QAAM,YAAY,KAAK,aAAa;AACpC,UAAQ,KAAK,SAAS;IACpB,KAAK;AAAiB,aAAO,QAAQ,QAAQ,iBAAiB,YAAY,KAAK,SAAS;IACxF,KAAK;AAAkB,aAAO,QAAQ,QAAQ,kBAAkB,YAAY,KAAK,SAAS;IAC1F,KAAK;AAAc,aAAO,QAAQ,QAAQ,mBAAmB,YAAY,KAAK,SAAS;IACvF,KAAK,kBAAkB;AACrB,YAAM,MAAM,KAAK,YAAY;AAC7B,YAAM,QAAQ,QAAQ,WAAW,eAAe,GAAG;AACnD,aAAO,UAAU,UAAa,SAAS,YAAY,KAAK,SAAS;IACnE;IACA,KAAK,YAAY;AACf,YAAM,UAAU,KAAK,WAAW;AAChC,YAAM,UAAU,QAAQ,QAAQ,aAAa,KAAK,SAAO,UAAU,SAAS,GAAG,CAAC;AAChF,aAAO,UAAU,KAAK,SAAS;IACjC;IACA,KAAK,eAAe;AAGlB,UAAI,CAAC,KAAK,UAAU,CAAC,KAAK;AAAU,eAAO;AAC3C,YAAM,UAAU,yBACd;QACE,MAAM;QACN,IAAI,KAAK;QACT,SAAS,KAAK;QACd,QAAQ,KAAK;QACb,UAAU,KAAK;QACf,OAAO,KAAK,SAAS;SAEvB,OAAO;AAET,aAAO,UAAU,KAAK,SAAS;IACjC;IACA;AAAS,aAAO;EAClB;AACF;AAEM,SAAU,wBAAwB,YAA0C,SAAuB;AACvG,MAAI,QAAQ;AACZ,aAAW,QAAQ,YAAY;AAAE,aAAS,iBAAiB,MAAM,OAAO;EAAE;AAC1E,SAAO;AACT;;;AC5BA,IAAM,WAAW,oBAAI,IAAG;AA0BlB,SAAU,wBAAwB,WAAsB,SAAuB;AACnF,QAAM,YAAY,SAAS,IAAI,UAAU,IAAI;AAC7C,MAAI,CAAC;AAAW,WAAO;AACvB,SAAO,UAAU,WAAW,OAAO;AACrC;AAKM,SAAU,iBAAiB,MAAY;AAC3C,SAAO,SAAS,IAAI,IAAI;AAC1B;;;AC5BA,SAAS,cAAc,OAAuB,SAAuB;AACnE,QAAM,kBAAoC,CAAA;AAC1C,QAAM,WAAoC,CAAA;AAC1C,QAAM,SAAuC,CAAA;AAC7C,QAAM,UAAmC,CAAA;AAEzC,aAAW,KAAK,MAAM,YAAY;AAIhC,UAAM,gBAAwB,EAAE;AAChC,QAAI,EAAE,SAAS;AAAW,eAAS,KAAK,CAAC;aAChC,EAAE,SAAS;AAAS,aAAO,KAAK,CAAC;aACjC,iBAAiB,aAAa;AAAG,cAAQ,KAAK,CAAC;EAE1D;AAEA,MAAI,oBAAoB;AAExB,aAAW,MAAM,UAAU;AACzB,UAAM,SAAS,yBAAyB,IAAI,OAAO;AACnD,oBAAgB,KAAK,EAAE,aAAa,GAAG,IAAI,MAAM,WAAW,OAAM,CAAE;AACpE,QAAI,CAAC;AAAQ,0BAAoB;EACnC;AAGA,aAAW,MAAM,SAAS;AACxB,UAAM,SAAS,wBAAwB,IAAI,OAAO;AAClD,oBAAgB,KAAK,EAAE,aAAa,GAAG,IAAI,MAAM,GAAG,MAAmB,OAAM,CAAE;AAC/E,QAAI,CAAC;AAAQ,0BAAoB;EACnC;AAEA,QAAM,aAAa,wBAAwB,QAAQ,OAAO;AAC1D,aAAW,MAAM,QAAQ;AACvB,UAAM,cAAc,wBAAwB,CAAC,EAAE,GAAG,OAAO;AACzD,oBAAgB,KAAK,EAAE,aAAa,GAAG,IAAI,MAAM,SAAS,QAAQ,cAAc,GAAG,kBAAkB,YAAW,CAAE;EACpH;AAEA,SAAO,EAAE,SAAS,mBAAmB,iBAAiB,WAAU;AAClE;AAEM,SAAU,iBAAiB,WAAuB,SAAuB;AAC7E,QAAM,gBAA0B,CAAA;AAChC,QAAM,SAA4B,CAAA;AAElC,aAAW,YAAY,WAAW;AAChC,UAAM,cAA8C,CAAA;AACpD,QAAI,kBAAkB;AACtB,QAAI,mBAAmB;AAEvB,eAAW,SAAS,SAAS,iBAAiB;AAC5C,YAAM,EAAE,SAAS,iBAAiB,WAAU,IAAK,cAAc,OAAO,OAAO;AAC7E,0BAAoB;AACpB,kBAAY,KAAK,EAAE,SAAS,MAAM,IAAI,SAAS,gBAAe,CAAE;AAChE,UAAI;AAAS,0BAAkB;IACjC;AAEA,QAAI,SAAS,mBAAmB,MAAM;AACpC,YAAM,oBAAoB,oBAAoB,SAAS;AACvD,YAAM,uBAAuB,SAAS,gBAAgB,KAAK,OAAK,EAAE,WAAW,KAAK,OAAK,EAAE,SAAS,SAAS,CAAC;AAC5G,UAAI,sBAAsB;AACxB,0BAAkB,mBAAmB;MACvC,OAAO;AACL,0BAAkB;MACpB;IACF;AAEA,WAAO,KAAK;MACV,YAAY,SAAS;MACrB,SAAS;MACT;MACA,GAAI,mBAAmB,IAAI,EAAE,YAAY,iBAAgB,IAAK,CAAA;KAC/D;AACD,QAAI;AAAiB,oBAAc,KAAK,SAAS,EAAE;EACrD;AAEA,SAAO,EAAE,mBAAmB,cAAc,CAAC,KAAK,MAAM,eAAe,OAAM;AAC7E;;;ACtGA,IAAM,cAAc;AACpB,IAAM,kBAAkB;AACxB,IAAM,sBAAsB;AAC5B,IAAM,oBAAoB;AAS1B,SAAS,aAA0B;AACjC,QAAM,MAAM,eAAe,QAAQ,WAAW;AAC9C,MAAI,KAAK;AAAE,QAAI;AAAE,aAAO,KAAK,MAAM,GAAG;AAAA,IAAiB,QAAQ;AAAA,IAAqB;AAAA,EAAE;AACtF,SAAO,EAAE,eAAe,GAAG,WAAW,IAAI,cAAc,CAAC,EAAE;AAC7D;AAEA,SAAS,kBAA0B;AACjC,QAAM,MAAM,eAAe,QAAQ,iBAAiB;AACpD,MAAI,IAAK,QAAO,OAAO,GAAG;AAC1B,QAAM,MAAM,KAAK,IAAI;AACrB,iBAAe,QAAQ,mBAAmB,OAAO,GAAG,CAAC;AACrD,SAAO;AACT;AAEA,SAAS,oBAA4C;AACnD,QAAM,MAAM,aAAa,QAAQ,mBAAmB;AACpD,MAAI,KAAK;AAAE,QAAI;AAAE,aAAO,KAAK,MAAM,GAAG;AAAA,IAA4B,QAAQ;AAAA,IAAqB;AAAA,EAAE;AACjG,SAAO,CAAC;AACV;AAEO,SAAS,kBAAkB,aAAqB,UAAqC;AAC1F,QAAM,UAAU,WAAW;AAC3B,UAAQ,iBAAiB;AACzB,MAAI,CAAC,QAAQ,UAAW,SAAQ,YAAY;AAC5C,UAAQ,aAAa,KAAK,WAAW;AACrC,iBAAe,QAAQ,aAAa,KAAK,UAAU,OAAO,CAAC;AAE3D,QAAM,cAAc,OAAO,aAAa,QAAQ,eAAe,CAAC,KAAK,KAAK;AAC1E,eAAa,QAAQ,iBAAiB,OAAO,UAAU,CAAC;AAExD,QAAM,eAAe,gBAAgB;AACrC,QAAM,iBAAiB,kBAAkB;AACzC,MAAI,UAAU;AACZ,mBAAe,QAAQ,KAAK,eAAe,QAAQ,KAAK,KAAK;AAC7D,iBAAa,QAAQ,qBAAqB,KAAK,UAAU,cAAc,CAAC;AAAA,EAC1E;AAEA,SAAO;AAAA,IACL,SAAS,EAAE,eAAe,QAAQ,eAAe,gBAAgB,YAAY,iBAAiB,KAAK,OAAO,KAAK,IAAI,IAAI,gBAAgB,GAAI,GAAG,WAAW,QAAQ,WAAW,cAAc,QAAQ,aAAa;AAAA,IAC/M,YAAY,EAAE,gBAAgB,YAAY,EAAE;AAAA,EAC9C;AACF;;;ACrDA,IAAM,aAAa;AAEZ,SAAS,gBAAwC;AACtD,QAAM,MAAM,aAAa,QAAQ,UAAU;AAC3C,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,MAAI;AAAE,WAAO,KAAK,MAAM,GAAG;AAAA,EAA4B,QAAQ;AAAE,WAAO,CAAC;AAAA,EAAE;AAC7E;AAEO,SAAS,YAAY,WAAyC;AACnE,eAAa,QAAQ,YAAY,KAAK,UAAU,SAAS,CAAC;AAC5D;;;ACJA,SAAS,MAAM,MAAsB,SAAkD;AACrF,SAAO;AAAA,IACL,KAAK,QAAQ,OAAO,KAAK;AAAA,IAAK,UAAU,QAAQ,YAAY,KAAK;AAAA,IACjE,SAAS,QAAQ,WAAW,KAAK;AAAA,IAAS,YAAY,QAAQ,cAAc,KAAK;AAAA,IACjF,QAAQ,EAAE,GAAG,KAAK,QAAQ,GAAG,QAAQ,OAAO;AAAA,IAAG,UAAU,QAAQ,YAAY,KAAK;AAAA,IAClF,UAAU,EAAE,GAAG,KAAK,UAAU,GAAG,QAAQ,SAAS;AAAA,IAAG,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,QAAQ,KAAK;AAAA,EAC7F;AACF;AAEO,SAAS,mBACd,WAAuB,eAAwC,aAAqB,cACpE;AAChB,MAAI,UAAU,MAAM,mBAAmB,GAAG,aAAa;AACvD,QAAM,SAAS,kBAAkB,aAAa,YAAY;AAC1D,QAAM,SAAS,cAAc;AAC7B,YAAU,MAAM,SAAS,EAAE,SAAS,OAAO,SAAS,YAAY,OAAO,YAAY,QAAQ,MAAM,EAAE,GAAG,QAAQ,MAAM,YAAY,SAAS,EAAE,CAAC;AAC5I,QAAM,EAAE,mBAAmB,cAAc,IAAI,iBAAiB,WAAW,OAAO;AAChF,QAAMA,cAAa,QAAQ,KAAK;AAChC,SAAO,EAAE,mBAAmBA,cAAa,OAAO,mBAAmB,eAAe,SAAS,YAAAA,YAAW;AACxG;;;ACzBO,SAAS,uBAAuB,mBAAwC;AAC7E,QAAM,aAAa,SAAS,iBAAiB,yBAAyB;AACtE,aAAW,aAAa,MAAM,KAAK,UAAU,GAAG;AAC9C,UAAM,KAAK;AACX,UAAM,OAAO,MAAM,KAAK,GAAG,iBAAiB,qBAAqB,CAAC;AAgBlE,QAAI,KAAK,WAAW,EAAG;AAEvB,OAAG,UAAU,OAAO,sBAAsB;AAC1C,OAAG,gBAAgB,WAAW;AAC9B,UAAM,WAAW,GAAG,cAAc,wBAAwB;AAC1D,QAAI,SAAU,UAAS,OAAO;AAC9B,UAAM,SAAS,qBAAqB;AACpC,OAAG,aAAa,gBAAgB,MAAM;AACtC,eAAW,SAAS,MAAM;AACxB,YAAM,IAAI;AACV,QAAE,MAAM,UAAU,EAAE,aAAa,mBAAmB,MAAM,SAAS,KAAK;AAAA,IAC1E;AAAA,EACF;AACF;;;ACjCO,IAAM,eAAe;AAAA,EAC1B,SAAS;AAAA,EAAgB,SAAS;AAAA,EAAgB,KAAK;AAAA,EACvD,UAAU;AAAA,EAAiB,QAAQ;AAAA,EAAe,OAAO;AAAA,EACzD,cAAc;AAChB;AAEO,SAAS,cAAmC;AACjD,QAAM,MAAM,oBAAI,IAAoB;AACpC,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,aAAW,QAAQ,SAAS,OAAO,MAAM,GAAG,GAAG;AAC7C,UAAM,UAAU,KAAK,KAAK;AAC1B,UAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,QAAI,QAAQ,EAAG;AACf,QAAI,IAAI,QAAQ,MAAM,GAAG,KAAK,GAAG,mBAAmB,QAAQ,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC/E;AACA,SAAO;AACT;AAEO,SAAS,UAAU,MAAc,OAAe,QAAuB;AAC5E,MAAI,MAAM,GAAG,IAAI,IAAI,mBAAmB,KAAK,CAAC;AAC9C,MAAI,WAAW,UAAa,UAAU,EAAG,QAAO,aAAa,MAAM;AACnE,WAAS,SAAS;AACpB;AAEO,SAAS,aAAa,MAAoB;AAC/C,WAAS,SAAS,GAAG,IAAI;AAC3B;;;ACLA,IAAM,gBAAgB;AAEtB,IAAM,uBAAuB;AAE7B,IAAM,UAAU;AAChB,IAAM,WAAW;AACjB,IAAM,WAAW;AACjB,IAAM,oBAAoB;AAE1B,IAAM,mBAAmB;AA+BzB,IAAI,YAAsC;AAE1C,IAAI,aAAa;AAIjB,SAAS,YAAY,KAA4B;AAC/C,MAAI;AAAE,WAAO,aAAa,QAAQ,GAAG;AAAA,EAAE,QAAQ;AAAE,WAAO;AAAA,EAAK;AAC/D;AACA,SAAS,aAAa,KAAa,OAAqB;AACtD,MAAI;AAAE,iBAAa,QAAQ,KAAK,KAAK;AAAA,EAAE,QAAQ;AAAA,EAA6B;AAC9E;AACA,SAAS,cAAc,KAAmB;AACxC,MAAI;AAAE,iBAAa,WAAW,GAAG;AAAA,EAAE,QAAQ;AAAA,EAA6B;AAC1E;AAGO,SAAS,cAAuB;AACrC,MAAI,YAAY,oBAAoB,MAAM,KAAK;AAG7C,kBAAc,oBAAoB;AAClC,iBAAa,eAAe,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,SAAO,YAAY,aAAa,MAAM;AACxC;AAEA,SAAS,aAAa,WAA0B;AAC9C,eAAa,eAAe,YAAY,MAAM,GAAG;AACnD;AAIO,SAAS,SAAe;AAC7B,YAAU,aAAa,QAAQ,KAAK,MAAM,KAAK,IAAI;AACnD,eAAa,aAAa,QAAQ;AACpC;AAEO,SAAS,QAAc;AAC5B,eAAa,aAAa,MAAM;AAClC;AAGO,SAAS,mBAAyB;AACvC,eAAa,aAAa,QAAQ;AACpC;AAEA,SAAS,SAAkB;AACzB,SAAO,YAAY,EAAE,IAAI,aAAa,QAAQ;AAChD;AAOA,eAAsB,YACpB,YACA,OAAgF,CAAC,GAClE;AACf,QAAM,UAAU,KAAK,WAAW;AAChC,MAAI;AACF,UAAM,MAAM,GAAG,OAAO,kBAAkB;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAI,KAAK,YAAY,EAAE,gBAAgB,KAAK,UAAU,IAAI,CAAC,EAAG;AAAA,MAC7G,MAAM,KAAK,UAAU,EAAE,WAAW,CAAC;AAAA,IACrC,CAAC;AAAA,EACH,QAAQ;AAAA,EAAwE;AAClF;AAEA,SAAS,SAAe;AACtB,MAAI;AAAE,WAAO,SAAS,OAAO;AAAA,EAAE,QAAQ;AAAA,EAAyC;AAClF;AAIA,SAAS,gBAAsB;AAC7B,WAAS,eAAe,OAAO,GAAG,OAAO;AAEzC,WAAS,cAAc,wBAAwB,GAAG,OAAO;AAC3D;AAEA,SAAS,OAAO,WAAmB,MAAc,SAAwC;AACvF,QAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,MAAI,OAAO;AACX,MAAI,YAAY;AAChB,MAAI,cAAc;AAClB,MAAI,iBAAiB,SAAS,OAAO;AACrC,SAAO;AACT;AAEA,SAAS,0BAA0B,OAAmC;AACpE,MAAI,MAAM,YAAY,MAAO,QAAO;AACpC,SAAQ,MAAM,kBAAkB,CAAC,MAAM,cAAgB,MAAM,cAAc,MAAM;AACnF;AAEA,SAAS,aAAa,OAAyC;AAC7D,MAAI,CAAC,MAAM,WAAY,QAAO;AAC9B,SAAO,MAAM,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,UAAU,GAAG,QAAQ;AAC1E;AAMO,SAAS,wBAAwB,OAAgC;AACtE,cAAY;AACZ,MAAI,OAAO,aAAa,YAAa;AACrC,gBAAc;AACd,MAAI,CAAC,cAAc,CAAC,0BAA0B,KAAK,EAAG;AAEtD,QAAM,SAAS,MAAM,kBAAkB,CAAC,MAAM;AAC9C,QAAM,YAAY,aAAa,QAAQ,YAAY;AAEnD,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,KAAK;AACV,OAAK,YAAY,qBAAqB,SAAS,6BAA6B,6BAA6B;AACzG,OAAK,QAAQ,QAAQ,YAAY,cAAc;AAG/C,QAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,OAAK,OAAO;AACZ,OAAK,YAAY;AACjB,OAAK,aAAa,iBAAiB,OAAO,CAAC,SAAS,CAAC;AACrD,OAAK,aAAa,iBAAiB,QAAQ;AAC3C,QAAM,WAAW,SAAS,cAAc,MAAM;AAC9C,WAAS,YAAY;AACrB,WAAS,aAAa,eAAe,MAAM;AAC3C,WAAS,cAAc;AACvB,QAAM,YAAY,SAAS,cAAc,MAAM;AAC/C,YAAU,YAAY;AACtB,YAAU,cAAc,SAAS,iBAAiB;AAClD,OAAK,OAAO,UAAU,SAAS;AAC/B,OAAK,iBAAiB,SAAS,MAAM,YAAY,CAAC;AAClD,OAAK,SAAS,CAAC;AACf,OAAK,YAAY,IAAI;AAGrB,QAAM,QAAQ,SAAS,cAAc,SAAS;AAC9C,QAAM,KAAK;AACX,QAAM,YAAY;AAClB,QAAM,aAAa,QAAQ,QAAQ;AACnC,QAAM,aAAa,mBAAmB,QAAQ;AAC9C,QAAM,SAAS;AAEf,QAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,SAAO,YAAY;AACnB,QAAM,QAAQ,SAAS,cAAc,IAAI;AACzC,QAAM,KAAK;AACX,QAAM,YAAY;AAClB,QAAM,OAAO,aAAa,KAAK;AAC/B,QAAM,cAAc,CAAC,SACjB,2BACA,OACE,mCACA;AACN,SAAO,YAAY,KAAK;AACxB,QAAM,cAAc,OAAO,8BAA8B,UAAK,MAAM,cAAc,CAAC;AACnF,cAAY,aAAa,cAAc,UAAU;AACjD,SAAO,YAAY,WAAW;AAC9B,QAAM,YAAY,MAAM;AAExB,MAAI,QAAQ;AACV,UAAM,WAAW,SAAS,cAAc,GAAG;AAC3C,aAAS,YAAY;AACrB,QAAI,MAAM;AACR,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,cAAc;AACrB,eAAS,YAAY,MAAM;AAAA,IAC7B,OAAO;AACL,eAAS,cAAc;AAAA,IACzB;AACA,UAAM,YAAY,QAAQ;AAAA,EAC5B;AAEA,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,YAAY;AACjB,OAAK,cAAc,SACf,8GACA;AACJ,QAAM,YAAY,IAAI;AAGtB,QAAM,UAAU,MAAM,aAAa,CAAC;AACpC,MAAI,UAAU,QAAQ,SAAS,GAAG;AAChC,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,UAAM,gBAAgB,SAAS,cAAc,MAAM;AACnD,kBAAc,KAAK;AACnB,kBAAc,YAAY;AAC1B,kBAAc,cAAc;AAC5B,aAAS,YAAY,aAAa;AAElC,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,YAAY;AAClB,UAAM,aAAa,QAAQ,OAAO;AAClC,UAAM,aAAa,mBAAmB,iBAAiB;AACvD,eAAW,UAAU,SAAS;AAC5B,YAAM,YAAY,OAAO,OAAO,MAAM;AACtC,YAAM,YAAY,OAAO,4BAA4B,OAAO,MAAM,MAAM;AACtE,YAAI,UAAW;AACf,aAAK,YAAY,OAAO,IAAI,EAAE,SAAS,MAAM,SAAS,WAAW,MAAM,UAAU,CAAC,EAAE,KAAK,MAAM;AAAA,MACjG,CAAC;AACD,gBAAU,QAAQ,iBAAiB,OAAO;AAC1C,gBAAU,aAAa,gBAAgB,OAAO,SAAS,CAAC;AACxD,YAAM,YAAY,SAAS;AAAA,IAC7B;AACA,aAAS,YAAY,KAAK;AAC1B,UAAM,YAAY,QAAQ;AAAA,EAC5B;AAGA,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,UAAQ,YAAY;AACpB,MAAI,MAAM,YAAY;AACpB,YAAQ,YAAY,OAAO,4BAA4B,0BAA0B,MAAM;AAAE,YAAM;AAAG,aAAO;AAAA,IAAE,CAAC,CAAC;AAAA,EAC/G,OAAO;AACL,QAAI,OAAO,GAAG;AACZ,cAAQ,YAAY,OAAO,2BAA2B,sBAAsB,MAAM;AAAE,yBAAiB;AAAG,eAAO;AAAA,MAAE,CAAC,CAAC;AAAA,IACrH;AACA,YAAQ,YAAY,OAAO,6BAA6B,4BAA4B,MAAM;AAAE,aAAO;AAAG,aAAO;AAAA,IAAE,CAAC,CAAC;AAAA,EACnH;AACA,QAAM,YAAY,OAAO;AAEzB,QAAM,iBAAiB,WAAW,CAAC,MAAM;AACvC,QAAK,EAAoB,QAAQ,SAAU,eAAc;AAAA,EAC3D,CAAC;AAED,OAAK,YAAY,KAAK;AACtB,WAAS,KAAK,YAAY,IAAI;AAChC;AAEA,SAAS,iBAAsF;AAC7F,QAAM,OAAO,SAAS,eAAe,OAAO;AAC5C,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,OAAO,KAAK,cAA2B,yBAAyB;AACtE,QAAM,QAAQ,KAAK,cAA2B,0BAA0B;AACxE,MAAI,CAAC,QAAQ,CAAC,MAAO,QAAO;AAC5B,SAAO,EAAE,MAAM,MAAM,MAAM;AAC7B;AAEA,SAAS,YAAY,UAAyB;AAC5C,QAAM,UAAU,eAAe;AAC/B,MAAI,CAAC,QAAS;AACd,UAAQ,KAAK,QAAQ,QAAQ,WAAW,aAAa;AACrD,UAAQ,KAAK,SAAS;AACtB,UAAQ,KAAK,aAAa,iBAAiB,OAAO,QAAQ,CAAC;AAC3D,UAAQ,MAAM,SAAS,CAAC;AACxB,QAAM,cAAc,WAChB,QAAQ,MAAM,cAA2B,6BAA6B,IACtE,QAAQ;AACZ,eAAa,MAAM;AACrB;AAGO,SAAS,cAAoB;AAClC,eAAa,KAAK;AAClB,cAAY,IAAI;AAClB;AAGO,SAAS,gBAAsB;AACpC,eAAa;AACb,eAAa,IAAI;AACjB,cAAY,KAAK;AACnB;AASO,SAAS,wBAA8B;AAC5C,MAAI,OAAO,aAAa,YAAa;AACrC,eAAa;AACb,QAAM,QAA2B,aAAa;AAAA,IAC5C,gBAAgB;AAAA,IAChB,YAAY,YAAY,EAAE,IAAI,aAAa,MAAM;AAAA,IACjD,mBAAmB;AAAA,EACrB;AACA,0BAAwB,KAAK;AAC7B,iBAAe,GAAG,MAAM,cAA2B,6BAA6B,GAAG,MAAM;AAC3F;;;ACxVA,IAAM,cAAc;AAEb,SAAS,uBAAsC;AAAE,SAAO,eAAe,QAAQ,WAAW;AAAE;AAC5F,SAAS,qBAAqB,IAAkB;AAAE,iBAAe,QAAQ,aAAa,EAAE;AAAE;AAC1F,SAAS,eAAqB;AAAE,iBAAe,WAAW,WAAW;AAAE;AAEvE,SAAS,mBAAyB;AACvC,QAAM,UAAU,YAAY;AAC5B,QAAM,SAAS,QAAQ,IAAI,aAAa,YAAY;AACpD,MAAI,QAAQ;AAAE,yBAAqB,MAAM;AAAG,iBAAa,aAAa,YAAY;AAAA,EAAE;AACtF;AAEO,SAAS,oBAAoBC,eAA4B;AAC9D,WAAS,cAAc,sBAAsB,GAAG,OAAO;AACvD,QAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,SAAO,YAAY;AACnB,SAAO,aAAa,QAAQ,QAAQ;AACpC,QAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,OAAK,YAAY;AACjB,OAAK,cAAc;AACnB,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,cAAcA;AACrB,OAAK,YAAY,MAAM;AACvB,SAAO,YAAY,IAAI;AACvB,QAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,UAAQ,YAAY;AACpB,UAAQ,OAAO;AACf,UAAQ,cAAc;AACtB,UAAQ,iBAAiB,SAAS,MAAM;AAAE,iBAAa;AAAG,WAAO,SAAS,OAAO;AAAA,EAAE,CAAC;AACpF,SAAO,YAAY,OAAO;AAC1B,WAAS,KAAK,YAAY,MAAM;AAClC;;;AC/BO,SAAS,kBAAkB,SAA4B;AAC5D,QAAM,IAAM,OAAe,QAAQ,CAAC;AACpC,IAAE,UAAU;AACX,EAAC,OAAe,OAAO;AAC1B;AAEO,SAAS,gBAAsB;AAAE,SAAO,cAAc,IAAI,YAAY,WAAW,CAAC;AAAE;AAIpF,SAAS,iBAA6B;AAC3C,QAAM,IAAI,CAAC,MAAc,SAAS,cAAc,mBAAmB,CAAC,IAAI,GAAG,aAAa,SAAS,KAAK;AACtG,SAAO,EAAE,YAAY,EAAE,aAAa,GAAG,cAAc,EAAE,eAAe,GAAG,WAAW,EAAE,YAAY,GAAG,WAAW,EAAE,YAAY,KAAK,GAAG;AACxI;;;ACNA,IAAM,eAAe;AAErB,SAAS,UAAU,WAAmD;AACpE,QAAM,MAAM,eAAe,QAAQ,eAAe,SAAS;AAC3D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AAAE,WAAO,KAAK,MAAM,GAAG;AAAA,EAA6B,QAAQ;AAAE,WAAO;AAAA,EAAK;AAChF;AAEA,SAAS,SAAS,WAAmB,MAAqC;AACxE,iBAAe,QAAQ,eAAe,WAAW,KAAK,UAAU,IAAI,CAAC;AACvE;AAEA,eAAsB,kBACpB,UAAyB,gBACzB,UAAU,WACwB;AAClC,QAAM,SAAkC,CAAC;AAEzC,QAAM,QAAQ,SAAS,IAAI,OAAO,YAAY;AAC5C,UAAM,SAAS,UAAU,QAAQ,EAAE;AACnC,QAAI,OAAQ,QAAO;AAEnB,QAAI;AACJ,QAAI,QAAQ,SAAS,gBAAgB;AAInC,YAAM,MAAM,MAAM,MAAM,GAAG,OAAO,kBAAkB,QAAQ,EAAE,IAAI;AAAA,QAChE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,eAAe,CAAC;AAAA,MAClD,CAAC;AACD,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,eAAS,KAAK,QAAQ,CAAC;AAAA,IACzB,OAAO;AACL,eAAS,MAAM,QAAQ,QAAQ,cAAc;AAAA,IAC/C;AAEA,aAAS,QAAQ,IAAI,MAAM;AAC3B,WAAO;AAAA,EACT,CAAC;AAED,QAAM,UAAU,MAAM,QAAQ,IAAI,KAAK;AACvC,aAAW,KAAK,QAAS,QAAO,OAAO,QAAQ,CAAC;AAChD,SAAO;AACT;;;AC/CO,SAAS,mBACd,WACA,WACA,aACM;AAEN,cAAY,SAAS;AAGrB,MAAI,aAAa,aAAa;AAC5B,UAAM,UAAU,YAAY;AAC5B,UAAM,aAAa,eAAe;AAClC,UAAM,gBAAyC;AAAA,MAC7C,UAAU,EAAE,WAAW,WAAW,aAAa,QAAQ,IAAI,aAAa,OAAO,KAAK,IAAI,SAAS,QAAQ,IAAI,aAAa,KAAK,GAAG,UAAU,KAAK;AAAA,MACjJ,MAAM,EAAE,YAAY,QAAQ,IAAI,aAAa,MAAM,GAAG,WAAW,OAAO,mBAAmB,MAAM,YAAY,SAAS;AAAA,IACxH;AACA,UAAM,SAAS,mBAAmB,WAAW,eAAe,WAAW;AACvE,2BAAuB,OAAO,iBAAiB;AAC/C,sBAAkB;AAAA,MAChB,WAAW,OAAO,QAAQ,SAAS;AAAA,MACnC,YAAY,OAAO;AAAA,MACnB,cAAc,WAAW;AAAA,MACzB,WAAW,WAAW;AAAA,MACtB,WAAW;AAAA,MACX,YAAY,OAAO;AAAA,IACrB,CAAC;AAAA,EACH;AACF;;;AC9BA,IAAM,YAAY;AAClB,IAAM,aAAa;AAQnB,IAAM,oBAAoB,oBAAI,IAAI,CAAC,SAAS,YAAY,iBAAiB,oBAAoB,QAAQ,CAAC;AAGtG,IAAM,gBAAgB;AASf,IAAM,wBAAwB;AAG9B,IAAM,sBAAsB;AACnC,IAAM,4BAA4B;AAElC,IAAM,iBAAiB;AAOhB,SAAS,mBAAmB,aAAqE;AACtG,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,MAAI,eAAe,gBAAgB,SAAU,QAAO;AACpD,SAAO,SAAS,cAA2B,qBAAqB;AAClE;AAuBA,SAAS,gBAAgB,KAAoD;AAC3E,SAAO,OAAO,QAAQ,WAAW,EAAE,OAAO,KAAK,OAAO,IAAI,IAAI;AAChE;AAmCA,IAAM,qBACJ;AAEF,SAAS,kBAAkB,MAAkC;AAC3D,SAAO,MAAM,KAAK,KAAK,iBAA8B,kBAAkB,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,MAAM;AACrG;AAGA,SAAS,QAAQ,MAAmB,GAAwB;AAC1D,QAAM,YAAY,kBAAkB,IAAI;AACxC,MAAI,UAAU,WAAW,GAAG;AAC1B,MAAE,eAAe;AACjB,SAAK,MAAM;AACX;AAAA,EACF;AACA,QAAM,QAAQ,UAAU,CAAC;AACzB,QAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAC3C,QAAM,SAAS,SAAS;AACxB,QAAM,SAAS,WAAW,QAAQ,KAAK,SAAS,MAAM,KAAK,WAAW;AACtE,MAAI,EAAE,UAAU;AACd,QAAI,CAAC,UAAU,WAAW,OAAO;AAAE,QAAE,eAAe;AAAG,WAAK,MAAM;AAAA,IAAE;AAAA,EACtE,WAAW,CAAC,UAAU,WAAW,MAAM;AACrC,MAAE,eAAe;AACjB,UAAM,MAAM;AAAA,EACd;AACF;AAEO,SAAS,mBAAmB,QAA0C;AAC3E,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,cAAc,OAAO,eAAe;AAC1C,QAAM,UAAU,gBAAgB;AAGhC,MAAI,WAA8B,CAAC;AAEnC,WAAS,aAAsB;AAC7B,QAAI,cAAc,SAAU,QAAO;AACnC,QAAI,cAAc,UAAW,QAAO;AAEpC,UAAM,MAAM,aAAa,QAAQ,SAAS;AAC1C,QAAI,CAAC,IAAK,QAAO;AAEjB,QAAI,cAAc,OAAQ,QAAO;AAGjC,UAAM,KAAK,OAAO,GAAG;AACrB,WAAO,CAAC,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,KAAK;AAAA,EACzC;AAEA,WAAS,YAAkB;AACzB,iBAAa,QAAQ,WAAW,OAAO,KAAK,IAAI,CAAC,CAAC;AAAA,EACpD;AAEA,WAAS,aAAa,WAAyC;AAC7D,gBAAY,SAAS;AAKrB,QAAI;AACF,yBAAmB,WAAW,OAAO,aAAa,CAAC,GAAG,OAAO,eAAe,GAAG;AAAA,IACjF,UAAE;AACA,gBAAU;AAAA,IACZ;AAAA,EACF;AAGA,WAAS,SAAS,WAA8B;AAC9C,eAAW,QAAQ,SAAU,MAAK;AAClC,eAAW,CAAC;AACZ,cAAU,gBAAgB;AAC1B,cAAU,YAAY;AACtB,cAAU,gBAAgB,MAAM;AAChC,cAAU,gBAAgB,YAAY;AACtC,cAAU,gBAAgB,YAAY;AACtC,cAAU,gBAAgB,iBAAiB;AAC3C,cAAU,gBAAgB,UAAU;AACpC,cAAU,SAAS;AAAA,EACrB;AAOA,WAAS,QAAQ,WAA8B;AAC7C,cAAU;AACV,aAAS,SAAS;AAAA,EACpB;AAEA,WAAS,OAAO,WAA8B;AAC5C,eAAW,QAAQ,SAAU,MAAK;AAClC,eAAW,CAAC;AACZ,cAAU,gBAAgB;AAC1B,cAAU,SAAS;AAInB,UAAM,mBAAmB,YAAY,QAAQ,MAAM,GAAG;AACtD,cAAU,YAAY,kCAAkC,gBAAgB;AAExE,QAAI,SAAS;AAGX,YAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,eAAS,YAAY;AACrB,eAAS,iBAAiB,SAAS,MAAM,QAAQ,SAAS,CAAC;AAC1D,OAAC,UAAU,iBAAiB,SAAS,MAAM,YAAY,QAAQ;AAChE,eAAS,KAAK,MAAM,SAAS,OAAO,CAAC;AAErC,YAAM,mBAAmB,SAAS,KAAK,MAAM;AAC7C,eAAS,KAAK,MAAM,WAAW;AAC/B,eAAS,KAAK,MAAM;AAAE,iBAAS,KAAK,MAAM,WAAW;AAAA,MAAiB,CAAC;AAEvE,YAAM,YAAY,CAAC,MAAqB;AACtC,YAAI,EAAE,QAAQ,UAAU;AAAE,YAAE,eAAe;AAAG,kBAAQ,SAAS;AAAG;AAAA,QAAO;AACzE,YAAI,EAAE,QAAQ,MAAO,SAAQ,WAAW,CAAC;AAAA,MAC3C;AACA,eAAS,iBAAiB,WAAW,WAAW,IAAI;AACpD,eAAS,KAAK,MAAM,SAAS,oBAAoB,WAAW,WAAW,IAAI,CAAC;AAE5E,gBAAU,aAAa,QAAQ,QAAQ;AACvC,gBAAU,aAAa,cAAc,MAAM;AAC3C,UAAI,OAAO,UAAU;AACnB,kBAAU,aAAa,mBAAmB,cAAc;AAAA,MAC1D,OAAO;AACL,kBAAU,aAAa,cAAc,6BAA6B;AAAA,MACpE;AACA,gBAAU,WAAW;AAAA,IACvB;AAEA,QAAI,gBAAgB,iBAAiB;AAInC,eAAS,KAAK,UAAU,IAAI,mBAAmB;AAC/C,YAAM,aAAa,MAAM;AACvB,iBAAS,gBAAgB,MAAM,YAAY,2BAA2B,GAAG,UAAU,YAAY,IAAI;AAAA,MACrG;AACA,aAAO,iBAAiB,UAAU,UAAU;AAC5C,eAAS,KAAK,MAAM;AAClB,iBAAS,KAAK,UAAU,OAAO,mBAAmB;AAClD,iBAAS,gBAAgB,MAAM,eAAe,yBAAyB;AACvE,eAAO,oBAAoB,UAAU,UAAU;AAAA,MACjD,CAAC;AAED,qBAAe,UAAU;AAAA,IAC3B;AAEA,QAAI,kBAAkB,IAAI,WAAW,GAAG;AACtC,YAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,iBAAW,OAAO;AAClB,iBAAW,YAAY;AACvB,iBAAW,aAAa,cAAc,SAAS;AAC/C,iBAAW,cAAc;AACzB,iBAAW,iBAAiB,SAAS,MAAM,QAAQ,SAAS,CAAC;AAC7D,gBAAU,YAAY,UAAU;AAAA,IAClC;AAEA,QAAI,OAAO,UAAU;AACnB,YAAM,IAAI,SAAS,cAAc,IAAI;AACrC,QAAE,YAAY;AACd,QAAE,cAAc,OAAO;AACvB,UAAI,QAAS,GAAE,KAAK;AACpB,gBAAU,YAAY,CAAC;AAAA,IACzB;AAEA,QAAI,OAAO,aAAa;AACtB,YAAM,IAAI,SAAS,cAAc,GAAG;AACpC,QAAE,YAAY;AACd,QAAE,cAAc,OAAO;AACvB,gBAAU,YAAY,CAAC;AAAA,IACzB;AAEA,UAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,SAAK,YAAY;AAEjB,eAAW,SAAS,OAAO,QAAQ;AACjC,YAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,gBAAU,YAAY;AAEtB,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,UAAU,cAAc,MAAM,EAAE;AACtC,YAAM,cAAc,MAAM;AAC1B,gBAAU,YAAY,KAAK;AAE3B,UAAI;AAEJ,UAAI,MAAM,SAAS,UAAU;AAC3B,cAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,eAAO,KAAK,cAAc,MAAM,EAAE;AAClC,eAAO,OAAO,MAAM;AACpB,YAAI,MAAM,SAAU,QAAO,WAAW;AACtC,YAAI,MAAM,SAAS;AACjB,gBAAM,cAAc,SAAS,cAAc,QAAQ;AACnD,sBAAY,QAAQ;AACpB,sBAAY,cAAc;AAC1B,iBAAO,YAAY,WAAW;AAC9B,qBAAW,OAAO,MAAM,SAAS;AAC/B,kBAAM,EAAE,OAAO,OAAAC,OAAM,IAAI,gBAAgB,GAAG;AAC5C,kBAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,mBAAO,QAAQ;AACf,mBAAO,cAAcA;AACrB,mBAAO,YAAY,MAAM;AAAA,UAC3B;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,OAAO;AACL,cAAM,MAAM,SAAS,cAAc,OAAO;AAC1C,YAAI,KAAK,cAAc,MAAM,EAAE;AAC/B,YAAI,OAAO,MAAM;AACjB,YAAI,OAAO,MAAM;AACjB,YAAI,MAAM,SAAU,KAAI,WAAW;AACnC,gBAAQ;AAAA,MACV;AAEA,gBAAU,YAAY,KAAK;AAC3B,WAAK,YAAY,SAAS;AAAA,IAC5B;AAEA,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AAEpB,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,OAAO;AACjB,cAAU,YAAY;AACtB,cAAU,cAAc,OAAO,eAAe;AAC9C,YAAQ,YAAY,SAAS;AAE7B,QAAI,OAAO,WAAW;AACpB,YAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,cAAQ,OAAO;AACf,cAAQ,YAAY;AACpB,cAAQ,cAAc,OAAO;AAC7B,cAAQ,iBAAiB,SAAS,MAAM,QAAQ,SAAS,CAAC;AAC1D,cAAQ,YAAY,OAAO;AAAA,IAC7B;AAEA,SAAK,YAAY,OAAO;AAExB,SAAK,iBAAiB,UAAU,CAAC,MAAM;AACrC,QAAE,eAAe;AACjB,YAAM,OAAO,IAAI,SAAS,IAAI;AAC9B,YAAM,YAAoC,CAAC;AAC3C,WAAK,QAAQ,CAAC,OAAO,QAAQ;AAC3B,kBAAU,GAAG,IAAI,OAAO,KAAK;AAAA,MAC/B,CAAC;AACD,mBAAa,SAAS;AAGtB,UAAI,cAAc,IAAI,WAAW,EAAG,UAAS,SAAS;AAAA,IACxD,CAAC;AAED,cAAU,YAAY,IAAI;AAE1B,QAAI,QAAS,WAAU,MAAM;AAAA,EAC/B;AAEA,SAAO,EAAE,YAAY,WAAW,QAAQ,aAAa;AACvD;;;ACzVA,SAAS,aAAsB;AAC7B,SAAO,YAAY,EAAE,IAAI,aAAa,MAAM;AAC9C;AAEO,SAAS,2BAA2B,OAAiC,CAAC,GAAS;AACpF,QAAM,aAAa,SAAS,iBAAiB,mCAAmC;AAChF,MAAI,WAAW,WAAW,EAAG;AAE7B,QAAM,WAAW,WAAW;AAE5B,aAAW,aAAa,MAAM,KAAK,UAAU,GAAG;AAE9C,cAAU,cAAc,6BAA6B,GAAG,OAAO;AAE/D,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,YAAY;AAElB,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,OAAO;AACf,YAAQ,YAAY;AACpB,YAAQ,aAAa,cAAc,yBAAyB;AAE5D,UAAM,SAAS,SAAS,cAAc,MAAM;AAC5C,WAAO,YAAY;AACnB,WAAO,cAAc,WAAW,wBAAwB;AACxD,YAAQ,YAAY,MAAM;AAE1B,QAAI,CAAC,YAAY,KAAK,cAAc;AAClC,YAAM,WAAW,SAAS,cAAc,MAAM;AAC9C,eAAS,YAAY;AACrB,eAAS,cAAc,KAAK;AAC5B,cAAQ,YAAY,QAAQ;AAAA,IAC9B;AAEA,YAAQ,iBAAiB,SAAS,MAAM,sBAAsB,CAAC;AAC/D,UAAM,YAAY,OAAO;AACzB,cAAU,YAAY,KAAK;AAAA,EAC7B;AACF;;;AClBA,SAAS,eAAe,UAA2B;AACjD,MAAI,SAAU,QAAO;AACrB,QAAM,WAAW,KAAK,SAAS;AAC/B,MAAI,CAAC,YAAY,aAAa,IAAK,QAAO;AAC1C,SAAO,GAAG,QAAQ;AACpB;AAEA,eAAsB,mBAAmB,QAA2C;AAClF,QAAM,EAAE,WAAW,aAAa,cAAc,cAAc,IAAI;AAChE,QAAM,UAAU,eAAe,OAAO,OAAO;AAC7C,mBAAiB;AACjB,QAAM,aAAa,eAAe;AAClC,QAAM,YAAY,qBAAqB;AAIvC,QAAM,kBAAkB,UACrB,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EACnC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,EAAE;AAC1C,QAAM,SAAS,CAAC,OACd,KAAK,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,OAAO;AAEhE,MAAI,WAAW;AACb,2BAAuB,SAAS;AAGhC,wBAAoB,OAAO,SAAS,KAAK,SAAS;AAClD,+BAA2B,EAAE,cAAc,OAAO,SAAS,EAAE,CAAC;AAC9D,sBAAkB,EAAE,WAAW,WAAW,WAAW,YAAY,WAAW,cAAc,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY,MAAM,CAAC;AACrJ,kBAAc;AACd;AAAA,EACF;AAEA,QAAM,UAAU,YAAY;AAC5B,MAAI,SAAkC;AAAA,IACpC,GAAG;AAAA,IACH,UAAU,EAAE,WAAW,WAAW,aAAa,QAAQ,IAAI,aAAa,OAAO,KAAK,IAAI,SAAS,QAAQ,IAAI,aAAa,KAAK,GAAG,UAAU,KAAK;AAAA,IACjJ,MAAM,EAAE,YAAY,QAAQ,IAAI,aAAa,MAAM,GAAG,WAAW,OAAO,mBAAmB,MAAM,YAAY,SAAS;AAAA,EACxH;AAGA,MAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;AACjD,UAAM,iBAAiB,MAAM,kBAAkB,OAAO,UAAU,QAAQ,OAAO;AAC/E,WAAO,WAAW,EAAE,GAAG,OAAO,UAAU,GAAG,eAAe;AAAA,EAC5D;AAEA,QAAM,SAAS,mBAAmB,WAAW,QAAQ,aAAa,YAAY;AAO9E,QAAM,WAAW,QAAQ,IAAI,aAAa,QAAQ,KAAK;AACvD,QAAM,WAAW,CAAC,OAAO,cAAc,aAAa,QAAQ,gBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AACzG,QAAM,sBAAsB,WAAW,WAAW,OAAO;AAEzD,yBAAuB,mBAAmB;AAC1C,0BAAwB;AAAA,IACtB,gBAAgB,wBAAwB;AAAA,IACxC,YAAY,OAAO;AAAA,IACnB,mBAAmB,OAAO,cAAc,SAAS;AAAA,IACjD,YAAY;AAAA,IACZ,WAAW;AAAA,IACX;AAAA,IACA,WAAW,KAAK,SAAS,aAAa;AAAA,IACtC,SAAS,OAAO,uBAAuB;AAAA,EACzC,CAAC;AAED,6BAA2B,EAAE,cAAc,OAAO,mBAAmB,EAAE,CAAC;AACxE,oBAAkB,EAAE,WAAW,OAAO,QAAQ,SAAS,WAAW,YAAY,qBAAqB,cAAc,WAAW,cAAc,WAAW,WAAW,WAAW,WAAW,OAAO,YAAY,OAAO,WAAW,CAAC;AAC5N,gBAAc;AAEd,MAAI,CAAC,YAAY,OAAO,qBAAqB,OAAO,sBAAsB,WAAW,YAAY;AAC/F,UAAM,GAAG,OAAO,kBAAkB;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAI,KAAK,SAAS,YAAY,EAAE,gBAAgB,KAAK,QAAQ,UAAU,IAAI,CAAC,EAAG;AAAA,MAC9H,MAAM,KAAK,UAAU,EAAE,YAAY,OAAO,kBAAkB,CAAC;AAAA,IAC/D,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB;AAGA,MAAI,OAAO,cAAc;AACvB,UAAM,SAAS,mBAAmB,OAAO,YAAY;AACrD,QAAI,OAAO,WAAW,GAAG;AACvB,YAAM,WAAW,MAAM;AAIrB,cAAM,QAAQ,mBAAmB,OAAO,aAAc,WAAW;AACjE,YAAI,OAAO;AAAE,iBAAO,OAAO,KAAK;AAAG;AAAA,QAAO;AAC1C,cAAM,WAAW,SAAS,eAAe,uBAAuB;AAChE,cAAM,YAAY,YAAY,SAAS,cAAc,KAAK;AAC1D,YAAI,CAAC,UAAU,IAAI;AACjB,oBAAU,KAAK;AACf,mBAAS,KAAK,YAAY,SAAS;AAAA,QACrC;AACA,eAAO,OAAO,SAAS;AAAA,MACzB;AACA,2BAAqB,OAAO,aAAa,SAAS,QAAQ;AAAA,IAC5D;AAAA,EACF;AACF;AAOA,SAAS,qBAAqB,SAAwC,QAA0B;AAC9F,MAAI,CAAC,WAAW,QAAQ,SAAS,aAAa;AAAE,WAAO;AAAG;AAAA,EAAO;AACjE,MAAI,QAAQ,SAAS,SAAU;AAC/B,MAAI,QAAQ,SAAS,SAAS;AAC5B,WAAO,WAAW,QAAQ,KAAK,IAAI,GAAG,QAAQ,OAAO,IAAI,GAAI;AAC7D;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,IAAI,KAAK,IAAI,QAAQ,OAAO,CAAC,GAAG,CAAC;AACrD,MAAI,QAAQ;AACZ,QAAM,WAAW,MAAM;AACrB,QAAI,MAAO;AACX,UAAM,aAAa,SAAS,gBAAgB,eAAe,OAAO;AAClE,UAAM,WAAW,aAAa,IAAI,OAAO,UAAU,aAAa;AAChE,QAAI,YAAY,QAAQ;AACtB,cAAQ;AACR,aAAO,oBAAoB,UAAU,QAAQ;AAC7C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;AAC7D,WAAS;AACX;;;AC7JA,IAAM,mBAAsC,CAAC;AAC7C,IAAI,SAAS;AAEN,IAAM,OAAO;AAAA,EAClB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ,CAAC;AAAA,EACT,QAAQ,IAA2B;AACjC,QAAI,QAAQ;AAAE,SAAG,IAAI;AAAA,IAAE,OAAO;AAAE,uBAAiB,KAAK,EAAE;AAAA,IAAE;AAAA,EAC5D;AAAA,EACA,IAAI;AAAA,IACF,OAAO,YAAwD;AAC7D,aAAO,EAAE,GAAG,WAAW;AAAA,IACzB;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,MACJ,QAAQ,CAAC;AAAA,MACT,OAAO,SAAgE;AACrE,eAAO,OAAO,KAAK,cAAc,KAAK,QAAQ,OAAO;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,OAAa;AACX,QAAI,OAAQ;AACZ,SAAK,UAAU,YAAY;AAC3B,eAAW,MAAM,kBAAkB;AAAE,SAAG,IAAI;AAAA,IAAE;AAC9C,UAAM,WAAW,KAAK,QAAQ,aAAa,MAAM,YAAY,GAAG,KAAK,QAAQ,QAAQ;AACrF,SAAK,YAAY,oBAAoB,UAAU,KAAK,QAAQ,SAAS;AACrE,SAAK,UAAU,kBAAkB,UAAU,KAAK,QAAQ,SAAS;AACjE,SAAK,aAAa;AAClB,gBAAY;AACZ,kBAAc;AAGd,oBAAgB,EAAE,SAAS,KAAK,QAAQ,CAAC;AACzC,aAAS;AAAA,EACX;AACF;AAEA,IAAI,OAAO,eAAe,aAAa;AAAE,EAAC,WAAmB,OAAO;AAAK;AACzE,IAAI,OAAO,aAAa,aAAa;AACnC,MAAI,SAAS,eAAe,WAAW;AACrC,aAAS,iBAAiB,oBAAoB,MAAM,KAAK,KAAK,CAAC;AAAA,EACjE,OAAO;AACL,SAAK,KAAK;AAAA,EACZ;AACF;",
3
+ "sources": ["../src/context.ts", "../src/entity.ts", "../src/feed.ts", "../src/render-feed.ts", "../src/module-system.ts", "../src/form-hooks.ts", "../src/nav/menu.ts", "../src/experiments/index.ts", "../../core/src/audiences/types.ts", "../../core/src/audiences/evaluator/glob.ts", "../../core/src/audiences/evaluator/instant-match.ts", "../../core/src/audiences/evaluator/score.ts", "../../core/src/audiences/evaluator/condition-registry.ts", "../../core/src/audiences/evaluator/resolver.ts", "../src/audience/behavioral-collector.ts", "../src/audience/selfid-collector.ts", "../src/audience/evaluate.ts", "../src/audience/dom-patcher.ts", "../src/cookies.ts", "../src/audience/transparency.ts", "../src/audience/preview.ts", "../src/audience/data-layer.ts", "../src/audience/adapter-runner.ts", "../src/audience/selfid-submit.ts", "../src/audience/selfid-widget.ts", "../src/personalization/badge.ts", "../src/audience/index.ts", "../src/index.ts"],
4
+ "sourcesContent": ["// packages/kywi-js/src/context.ts\nimport type { KywiContext } from './types.js'\n\nexport function readContext(): KywiContext {\n const meta = (name: string): string => {\n if (typeof document === 'undefined') return ''\n const el = document.querySelector(`meta[name=\"kywi:${name}\"]`)\n return el?.getAttribute('content') ?? ''\n }\n return {\n siteId: meta('site-id') || document?.documentElement?.getAttribute('data-kywi-site') || '',\n locale: document?.documentElement?.lang || 'en',\n themePath: meta('theme-path') || '',\n basePath: meta('base-path') || '/',\n csrfToken: meta('csrf-token') || '',\n isEditMode: document?.body?.classList?.contains('kywi-edit-mode') ?? false,\n }\n}\n", "// packages/kywi-js/src/entity.ts\nimport type { KywiEntityObject } from './types.js'\n\nfunction createEntity(type: string, basePath: string, csrfToken: string, data: Record<string, unknown>): KywiEntityObject {\n const fields = { ...data }\n const dirty = new Map<string, unknown>()\n const errors: string[] = []\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (csrfToken) headers['X-CSRF-Token'] = csrfToken\n\n const entity: KywiEntityObject = {\n get(field: string) { return fields[field] },\n set(field: string, value: unknown) { fields[field] = value; dirty.set(field, value); return entity },\n async save() {\n const id = fields['id'] as string | undefined\n const url = id ? `${basePath}/content/${type}/${id}` : `${basePath}/content/${type}`\n const res = await fetch(url, { method: id ? 'PUT' : 'POST', headers, body: JSON.stringify(Object.fromEntries(dirty)) })\n const json = await res.json() as { data?: Record<string, unknown>; error?: { message: string } }\n if (!res.ok || json.error) { errors.push(json.error?.message ?? 'Save failed'); throw entity }\n if (json.data) Object.assign(fields, json.data)\n dirty.clear()\n return entity\n },\n async delete() {\n const id = fields['id'] as string\n await fetch(`${basePath}/content/${type}/${id}`, { method: 'DELETE', headers })\n },\n getErrors() { return [...errors] },\n async loadBy(field: string, value: string) {\n const url = field === 'id' ? `${basePath}/content/${type}/${value}` : `${basePath}/content/${type}?${field}=${encodeURIComponent(value)}`\n const res = await fetch(url, { headers })\n const json = await res.json() as { data?: Record<string, unknown>; error?: { message: string } }\n if (!res.ok || json.error) { errors.push(json.error?.message ?? 'Load failed'); throw entity }\n if (json.data) Object.assign(fields, json.data)\n return entity\n },\n }\n return entity\n}\n\nexport function createEntityFactory(basePath: string, csrfToken: string) {\n return (type: string): KywiEntityObject => createEntity(type, basePath, csrfToken, {})\n}\n", "// packages/kywi-js/src/feed.ts\nimport type { KywiEntityObject, KywiFeedResult } from './types.js'\n\ninterface Filter { field: string; operator: string; value?: unknown; conjunction: 'and' | 'or' }\n\nexport type AggregateFunction = 'count' | 'sum' | 'min' | 'max' | 'avg'\nexport type AggregateResult = Record<string, unknown>\n\nclass PropBuilder {\n constructor(private builder: FeedBuilder, private field: string, private conj: 'and' | 'or') {}\n private add(op: string, value?: unknown) { this.builder._filters.push({ field: this.field, operator: op, value, conjunction: this.conj }); return this.builder }\n isEQ(v: unknown) { return this.add('eq', v) }\n isNEQ(v: unknown) { return this.add('neq', v) }\n isLT(v: unknown) { return this.add('lt', v) }\n isLTE(v: unknown) { return this.add('lte', v) }\n isGT(v: unknown) { return this.add('gt', v) }\n isGTE(v: unknown) { return this.add('gte', v) }\n beginsWith(v: unknown) { return this.add('beginsWith', v) }\n endsWith(v: unknown) { return this.add('endsWith', v) }\n contains(v: unknown) { return this.add('contains', v) }\n isNull() { return this.add('isNull') }\n isNotNull() { return this.add('isNotNull') }\n}\n\nclass FeedBuilder {\n _filters: Filter[] = []\n private _sort: { field: string; direction: 'asc' | 'desc' } | null = null\n private _limit: number | null = null\n private _page: number | null = null\n constructor(private contentType: string, private basePath: string, private csrfToken: string) {}\n\n where(): this { return this }\n prop(field: string) { return new PropBuilder(this, field, 'and') }\n andProp(field: string) { return new PropBuilder(this, field, 'and') }\n orProp(field: string) { return new PropBuilder(this, field, 'or') }\n sort(field: string, direction: 'asc' | 'desc' = 'asc'): this { this._sort = { field, direction }; return this }\n maxItems(n: number): this { this._limit = n; return this }\n page(n: number): this { this._page = n; return this }\n\n private buildBody(): Record<string, unknown> {\n const filterArray = this._filters.map(f => ({\n field: f.field,\n operator: f.operator,\n value: f.value,\n conjunction: f.conjunction,\n }))\n const body: Record<string, unknown> = { contentType: this.contentType }\n if (filterArray.length > 0) body['filters'] = filterArray\n if (this._sort) body['sort'] = this._sort\n if (this._limit !== null) body['limit'] = this._limit\n if (this._page !== null) body['page'] = this._page\n return body\n }\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n if (this.csrfToken) headers['X-CSRF-Token'] = this.csrfToken\n return headers\n }\n\n async aggregate(fn: AggregateFunction, field?: string): Promise<AggregateResult> {\n const body = this.buildBody()\n const agg: Record<string, string> = { function: fn }\n if (field) agg['field'] = field\n body['aggregate'] = agg\n\n const res = await fetch(`${this.basePath}/feeds/aggregate`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n const json = await res.json() as { data?: AggregateResult }\n return json.data ?? {}\n }\n\n async getQuery(): Promise<KywiFeedResult> {\n const body = this.buildBody()\n const res = await fetch(`${this.basePath}/feeds/query`, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(body),\n })\n // Two response envelopes are supported:\n // 1. The live @kywi-software/core server (POST /feeds/query -> jsonOk(executeFeedQuery))\n // returns { data: { items, total, page, pageSize, totalPages } }.\n // 2. A flatter { data: [ ...items ], meta: { total, page, totalPages } } shape.\n // Normalise both so the decoupled client works against the real API.\n const json = await res.json() as {\n data?: Array<Record<string, unknown>> | { items?: Array<Record<string, unknown>>; total?: number; page?: number; pageSize?: number; totalPages?: number }\n meta?: { total?: number; page?: number; totalPages?: number }\n }\n\n const payload = json.data\n const rawItems: Array<Record<string, unknown>> = Array.isArray(payload)\n ? payload\n : (payload?.items ?? [])\n const total = Array.isArray(payload) ? (json.meta?.total ?? rawItems.length) : (payload?.total ?? rawItems.length)\n const page = Array.isArray(payload) ? (json.meta?.page ?? 1) : (payload?.page ?? 1)\n const pages = Array.isArray(payload) ? (json.meta?.totalPages ?? 0) : (payload?.totalPages ?? 0)\n\n const items: KywiEntityObject[] = rawItems.map(d => ({\n get(field: string) { return d[field] },\n set() { throw new Error('Feed results are read-only') },\n save() { return Promise.reject(new Error('Feed results are read-only')) },\n delete() { return Promise.reject(new Error('Feed results are read-only')) },\n getErrors() { return [] },\n loadBy() { return Promise.reject(new Error('Use Kywi.getEntity() to load by field')) },\n }))\n\n return { items, total, page, pages }\n }\n}\n\nexport function createFeedFactory(basePath: string, csrfToken: string) {\n return (type: string) => new FeedBuilder(type, basePath, csrfToken)\n}\n", "// packages/kywi-js/src/render-feed.ts\nimport type { KywiEntityObject, KywiFeedResult } from './types.js'\n\ninterface RenderFeedOptions {\n feed: { getQuery(): Promise<KywiFeedResult> }\n container: HTMLElement\n template: (item: KywiEntityObject) => string | Node\n loadingText?: string; emptyText?: string\n wrapperTag?: string; wrapperClass?: string\n unsafeHtml?: boolean\n onRender?: (container: HTMLElement) => void\n}\n\nexport async function renderFeed(options: RenderFeedOptions): Promise<void> {\n const { feed, container, template, loadingText = '', emptyText = '', wrapperTag = 'div', wrapperClass, unsafeHtml = false, onRender } = options\n if (loadingText) container.textContent = loadingText\n const result = await feed.getQuery()\n container.textContent = ''\n if (result.items.length === 0) { if (emptyText) container.textContent = emptyText; return }\n const wrapper = document.createElement(wrapperTag)\n if (wrapperClass) wrapper.className = wrapperClass\n for (const item of result.items) {\n const rendered = template(item)\n if (rendered instanceof Node) {\n wrapper.appendChild(rendered)\n } else if (unsafeHtml) {\n const span = document.createElement('span')\n // intentional: caller explicitly opts in via unsafeHtml\n span['innerHTML'] = rendered\n wrapper.appendChild(span)\n } else {\n const span = document.createElement('span')\n span.textContent = rendered // SAFE: always textContent for string templates\n wrapper.appendChild(span)\n }\n }\n container.appendChild(wrapper)\n if (onRender) onRender(container)\n}\n", "// packages/kywi-js/src/module-system.ts\nimport { Kywi } from './index.js'\nimport type { KywiModuleContext } from './types.js'\n\nfunction readParams(el: HTMLElement): Record<string, string> {\n const params: Record<string, string> = {}\n for (const attr of Array.from(el.attributes)) {\n if (attr.name.startsWith('data-kywi-param-')) {\n params[attr.name.slice(16)] = attr.value\n }\n }\n return params\n}\n\nexport function initModules(): void {\n const elements = document.querySelectorAll('[data-kywi-module]')\n for (const el of Array.from(elements)) {\n const htmlEl = el as HTMLElement\n const moduleName = htmlEl.getAttribute('data-kywi-module')\n if (!moduleName) continue\n const def = Kywi.Module[moduleName]\n if (!def || !def.renderClient) continue\n const context: KywiModuleContext = { targetEl: htmlEl, ...readParams(htmlEl) }\n def.renderClient.call({ context, ...def })\n }\n}\n", "// packages/kywi-js/src/form-hooks.ts\nimport { Kywi } from './index.js'\n\nexport function initFormHooks(): void {\n const forms = document.querySelectorAll('[data-kywi-form]')\n for (const formEl of Array.from(forms)) {\n const htmlForm = formEl as HTMLFormElement\n const hooks = Kywi.DisplayObject.Form._hooks\n if (hooks['onAfterRender']) hooks['onAfterRender'].call({ context: { targetEl: htmlForm } })\n htmlForm.addEventListener('submit', (e) => {\n if (hooks['onSubmit']) {\n const result = hooks['onSubmit'].call({ context: { targetEl: htmlForm } })\n if (result === false) e.preventDefault()\n }\n })\n }\n}\n\nexport async function submitKywiForm(form: HTMLFormElement, endpoint: string): Promise<void> {\n const formData = new FormData(form)\n const data: Record<string, string> = {}\n formData.forEach((value, key) => { data[key] = value as string })\n\n const res = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n })\n const json = await res.json() as { success: boolean; errors?: Record<string, string>; data?: Record<string, unknown> }\n const hooks = Kywi.DisplayObject.Form._hooks\n\n if (!json.success && json.errors) {\n if (typeof hooks['onAfterErrorRender'] === 'function') {\n hooks['onAfterErrorRender']({ errors: json.errors, targetEl: form })\n }\n } else if (json.success && json.data) {\n if (typeof hooks['onAfterResponseRender'] === 'function') {\n hooks['onAfterResponseRender']({ response: json.data, targetEl: form })\n }\n }\n}\n", "// packages/kywi-js/src/nav/menu.ts\n//\n// Progressive enhancement for the server-rendered nav modules (`navMenu` /\n// `navigation`, kywi-cms#111). The markup is already usable without this file:\n// every link is server-rendered, panels open on `:hover` / `:focus-within`, and\n// below the breakpoint the whole bar collapses behind a native `<details>`\n// hamburger. What this adds is the polish CSS cannot express \u2014 hover intent\n// (a close delay so the pointer can cross the gap), a real click target with\n// `aria-expanded` in sync, Escape-to-close with focus returned, arrow-key\n// movement inside an open panel, outside-click dismissal, and flipping a panel\n// that would run off the right edge of the viewport.\n//\n// Dependency-free and defensive: it enhances whatever `[data-kywi-nav]` roots\n// exist and no-ops when a nav has no disclosure items.\n\n/**\n * Desktop breakpoint, in pixels. The single source shared with core's\n * `site/styles.css`, whose one media query is `(max-width: 859.98px)` \u2014 the\n * last step below this value. Change both together.\n */\nexport const NAV_BREAKPOINT = 860\n\n/** Grace period before a hover-opened panel closes, in ms. */\nconst CLOSE_DELAY_MS = 120\n\nconst ITEM_CLASS = 'kywi-nav-item--has-children'\nconst OPEN_CLASS = 'kywi-nav-item--open'\nconst TOGGLE_CLASS = 'kywi-nav-toggle'\nconst PANEL_CLASS = 'kywi-nav-panel'\nconst FLIP_CLASS = 'kywi-nav-panel--flip'\nconst READY_ATTRIBUTE = 'data-kywi-nav-ready'\n\ninterface NavEntry {\n item: HTMLElement\n toggle: HTMLElement\n panel: HTMLElement\n}\n\nfunction directChild(parent: HTMLElement, className: string): HTMLElement | null {\n for (const child of Array.from(parent.children)) {\n if (child instanceof HTMLElement && child.classList.contains(className)) return child\n }\n return null\n}\n\nfunction isDesktop(): boolean {\n if (typeof window === 'undefined') return false\n if (typeof window.matchMedia !== 'function') return true\n return window.matchMedia(`(min-width: ${NAV_BREAKPOINT}px)`).matches\n}\n\nfunction panelLinks(panel: HTMLElement): HTMLElement[] {\n return Array.from(panel.querySelectorAll<HTMLElement>('a[href], button:not([disabled])'))\n}\n\n/** Enhance one `[data-kywi-nav]` root. Returns a teardown for tests/SPAs. */\nexport function enhanceNav(nav: HTMLElement): () => void {\n const cleanups: Array<() => void> = []\n const entries: NavEntry[] = []\n\n for (const item of Array.from(nav.querySelectorAll<HTMLElement>(`.${ITEM_CLASS}`))) {\n const toggle = directChild(item, TOGGLE_CLASS)\n const panel = directChild(item, PANEL_CLASS)\n if (toggle && panel) entries.push({ item, toggle, panel })\n }\n if (entries.length === 0) return () => {}\n\n let closeTimer: ReturnType<typeof setTimeout> | undefined\n const cancelClose = () => {\n if (closeTimer !== undefined) { clearTimeout(closeTimer); closeTimer = undefined }\n }\n\n function isOpen(entry: NavEntry): boolean {\n return entry.item.classList.contains(OPEN_CLASS)\n }\n\n function close(entry: NavEntry): void {\n entry.item.classList.remove(OPEN_CLASS)\n entry.toggle.setAttribute('aria-expanded', 'false')\n entry.panel.classList.remove(FLIP_CLASS)\n }\n\n function closeAll(except?: NavEntry): void {\n for (const entry of entries) {\n // A nested fly-out keeps its ancestors open.\n if (except && (entry === except || entry.item.contains(except.item))) continue\n close(entry)\n }\n }\n\n /** Flip a panel that would overflow the right edge (measured while open). */\n function applyEdgeFlip(entry: NavEntry): void {\n if (typeof entry.panel.getBoundingClientRect !== 'function') return\n entry.panel.classList.remove(FLIP_CLASS)\n const rect = entry.panel.getBoundingClientRect()\n const viewport = window.innerWidth || document.documentElement.clientWidth || 0\n if (viewport > 0 && rect.width > 0 && rect.right > viewport - 4) {\n entry.panel.classList.add(FLIP_CLASS)\n }\n }\n\n function open(entry: NavEntry): void {\n cancelClose()\n closeAll(entry)\n entry.item.classList.add(OPEN_CLASS)\n entry.toggle.setAttribute('aria-expanded', 'true')\n applyEdgeFlip(entry)\n }\n\n function on<E extends Event>(\n target: EventTarget,\n type: string,\n handler: (event: E) => void,\n options?: AddEventListenerOptions,\n ): void {\n target.addEventListener(type, handler as EventListener, options)\n cleanups.push(() => target.removeEventListener(type, handler as EventListener, options))\n }\n\n for (const entry of entries) {\n on(entry.toggle, 'click', (event: MouseEvent) => {\n event.preventDefault()\n if (isOpen(entry)) { close(entry) } else { open(entry) }\n })\n\n // Hover intent \u2014 pointer only, and only where panels actually float.\n on(entry.item, 'mouseenter', () => {\n if (!isDesktop()) return\n open(entry)\n })\n on(entry.item, 'mouseleave', () => {\n if (!isDesktop()) return\n cancelClose()\n closeTimer = setTimeout(() => { close(entry); closeTimer = undefined }, CLOSE_DELAY_MS)\n })\n }\n\n // Keyboard focus moving into a panel opens it; moving out of the item closes\n // it. Focus landing on the toggle itself is left alone so a click (which\n // focuses first) still reads as a toggle rather than an open-then-close.\n on(nav, 'focusin', (event: FocusEvent) => {\n const target = event.target as Node | null\n if (!target) return\n for (const entry of entries) {\n if (entry.panel.contains(target)) { open(entry); return }\n }\n for (const entry of entries) {\n if (!entry.item.contains(target)) close(entry)\n }\n })\n\n on(nav, 'keydown', (event: KeyboardEvent) => {\n const target = event.target as HTMLElement | null\n if (!target) return\n const entry = entries.find((e) => e.item.contains(target))\n if (!entry) return\n\n if (event.key === 'Escape') {\n const openEntry = entries.filter((e) => e.item.contains(target) && isOpen(e)).pop()\n if (!openEntry) return\n event.preventDefault()\n close(openEntry)\n openEntry.toggle.focus()\n return\n }\n\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return\n\n // On the trigger: ArrowDown opens and enters the panel, ArrowUp closes.\n if (target === entry.toggle) {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!isOpen(entry)) open(entry)\n panelLinks(entry.panel)[0]?.focus()\n } else if (isOpen(entry)) {\n event.preventDefault()\n close(entry)\n }\n return\n }\n\n // Inside a panel: move between its links.\n const owner = entries.find((e) => e.panel.contains(target))\n if (!owner) return\n const links = panelLinks(owner.panel)\n const index = links.indexOf(target)\n if (index === -1) return\n event.preventDefault()\n const next = event.key === 'ArrowDown'\n ? links[(index + 1) % links.length]\n : links[(index - 1 + links.length) % links.length]\n next?.focus()\n })\n\n on(document, 'click', (event: MouseEvent) => {\n const target = event.target as Node | null\n if (target && nav.contains(target)) return\n cancelClose()\n closeAll()\n })\n\n // Crossing the breakpoint changes what \"open\" means; start from closed.\n if (typeof window.matchMedia === 'function') {\n const query = window.matchMedia(`(min-width: ${NAV_BREAKPOINT}px)`)\n const onChange = () => { cancelClose(); closeAll() }\n if (typeof query.addEventListener === 'function') {\n query.addEventListener('change', onChange)\n cleanups.push(() => query.removeEventListener('change', onChange))\n }\n }\n\n nav.setAttribute(READY_ATTRIBUTE, '')\n\n return () => {\n cancelClose()\n for (const undo of cleanups) undo()\n cleanups.length = 0\n closeAll()\n nav.removeAttribute(READY_ATTRIBUTE)\n }\n}\n\n/**\n * Enhance every nav under `root` that has not been enhanced yet. Called from\n * `Kywi.boot()`; safe to call again after injecting markup client-side.\n */\nexport function initNavMenus(root: ParentNode = document): () => void {\n if (typeof document === 'undefined') return () => {}\n const teardowns: Array<() => void> = []\n for (const nav of Array.from(root.querySelectorAll<HTMLElement>('[data-kywi-nav]'))) {\n if (nav.hasAttribute(READY_ATTRIBUTE)) continue\n teardowns.push(enhanceNav(nav))\n }\n return () => { for (const undo of teardowns) undo() }\n}\n", "// packages/kywi-js/src/experiments/index.ts\n//\n// Client-side A/B experiment beacons. Reads the server-rendered kywi:* meta\n// tags, confirms the exposure, and reports conversion signals (pageview,\n// form-submit, custom) back to the runtime endpoints. Fire-and-forget: every\n// call is best-effort and never throws into the host page.\n\nimport { readContext } from '../context.js'\nimport type { KywiContext } from '../types.js'\n\nexport interface ConversionSignal {\n type: 'pageview' | 'form_submit' | 'custom'\n url?: string\n formId?: string\n eventName?: string\n}\n\nexport interface ExperimentBootConfig {\n context?: KywiContext\n apiBase?: string\n visitorId?: string\n currentPath?: string\n /** Auto-emit a pageview conversion signal on boot (default true). */\n autoPageview?: boolean\n}\n\nexport interface ExperimentRuntime {\n /** Emit a custom conversion event, e.g. kywi.track('signup'). */\n track(eventName: string): void\n /** Emit a raw conversion signal. */\n trackConversion(signal: ConversionSignal): void\n}\n\nfunction apiBaseFrom(ctx: KywiContext): string {\n return ctx.basePath && ctx.basePath !== '/' ? `${ctx.basePath}/api/v1` : '/api/v1'\n}\n\nfunction metaContent(name: string): string | null {\n if (typeof document === 'undefined') return null\n return document.querySelector(`meta[name=\"kywi:${name}\"]`)?.getAttribute('content') ?? null\n}\n\n// A single document-level submit listener is installed once and routes to the\n// most recent boot's handler \u2014 booting twice must not double-count conversions.\nlet submitListenerInstalled = false\nlet currentFormConversion: ((formId: string) => void) | null = null\n\nfunction installFormListener(): void {\n if (submitListenerInstalled || typeof document === 'undefined') return\n submitListenerInstalled = true\n document.addEventListener(\n 'submit',\n (e) => {\n const form = e.target as HTMLElement | null\n if (!form || form.tagName !== 'FORM') return\n const formId = form.getAttribute('data-kywi-form-id') ?? form.getAttribute('id')\n if (formId && currentFormConversion) currentFormConversion(formId)\n },\n true,\n )\n}\n\nfunction beacon(url: string, body: unknown, csrfToken?: string): void {\n try {\n void fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {}) },\n body: JSON.stringify(body),\n keepalive: true,\n }).catch(() => {})\n } catch {\n /* never throw into the host page */\n }\n}\n\n/**\n * Boot the experiment beacons. Safe to call once per page load; when no\n * experiment meta is present it only wires the conversion listeners.\n */\nexport function bootExperiments(config: ExperimentBootConfig = {}): ExperimentRuntime {\n const ctx = config.context ?? readContext()\n const apiBase = config.apiBase ?? apiBaseFrom(ctx)\n const csrf = ctx.csrfToken || undefined\n const experimentId = metaContent('experiment-id')\n const visitorId = config.visitorId ?? metaContent('visitor-id') ?? undefined\n const currentPath = config.currentPath ?? (typeof location !== 'undefined' ? location.pathname : '/')\n\n function trackConversion(signal: ConversionSignal): void {\n beacon(`${apiBase}/kywi/experiments/conversion`, { visitorId, event: signal }, csrf)\n }\n function track(eventName: string): void {\n trackConversion({ type: 'custom', eventName })\n }\n\n // 1) Exposure \u2014 confirm the server-rendered variant was seen. The variant is\n // recomputed server-side, so we only send the experiment + visitor ids.\n if (experimentId) {\n beacon(`${apiBase}/kywi/experiments/exposure`, { experimentId, visitorId }, csrf)\n }\n\n // 2) Pageview conversion signal \u2014 lets pageview-goal experiments convert when\n // an enrolled visitor lands on the goal path.\n if (config.autoPageview !== false) {\n trackConversion({ type: 'pageview', url: currentPath })\n }\n\n // 3) Form-submit conversion \u2014 capture submits of any tagged form. The listener\n // is installed once; this boot becomes its active handler.\n currentFormConversion = (formId: string) => trackConversion({ type: 'form_submit', formId })\n installFormListener()\n\n const runtime: ExperimentRuntime = { track, trackConversion }\n\n // Expose on the data layer so analytics / manual conversions can reach it.\n const g = ((globalThis as unknown as { kywi?: Record<string, unknown> }).kywi ?? {})\n g['track'] = track\n g['trackConversion'] = trackConversion\n ;(globalThis as unknown as { kywi?: Record<string, unknown> }).kywi = g\n\n return runtime\n}\n", "// \u2500\u2500 Visitor Signals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface VisitorSignals {\n utm: {\n source: string | null\n medium: string | null\n campaign: string | null\n term: string | null\n content: string | null\n }\n referrer: {\n raw: string | null\n domain: string | null\n sourceType: 'organic' | 'paid' | 'social' | 'email' | 'direct' | 'other'\n }\n session: {\n pageViewCount: number\n totalPageViews: number\n sessionDuration: number\n entryPage: string\n pagesVisited: string[]\n }\n behavioral: {\n categoryScores: Record<string, number>\n totalScore: number\n }\n selfId: Record<string, string>\n identity: {\n visitorId: string\n isKnown: boolean\n maLeadId: string | null\n }\n adapters: Record<string, unknown>\n meta: {\n isOptedOut: boolean\n isPreview: boolean\n previewAudienceId: string | null\n resolvedAt: 'server' | 'client'\n }\n}\n\n// \u2500\u2500 Evaluation Result \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface VisitorContext {\n request: Request\n partialSignals?: Partial<VisitorSignals>\n}\n\nexport interface AudienceResult {\n winningAudienceId: string | null\n allMatchedIds: string[]\n signals: VisitorSignals\n isOptedOut: boolean\n}\n\n// \u2500\u2500 Audience & Rule Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type AudienceStatus = 'active' | 'draft' | 'archived'\n\nexport interface Audience {\n id: string\n siteId: string\n name: string\n description: string | null\n priority: number\n status: AudienceStatus\n conditionGroups: ConditionGroup[]\n scoreThreshold: number | null\n createdAt: Date\n updatedAt: Date\n}\n\nexport interface ConditionGroup {\n id: string\n audienceId: string\n sortOrder: number\n conditions: Condition[]\n}\n\nexport type Condition = InstantMatchCondition | ScoreContributionCondition\n\nexport interface InstantMatchCondition {\n type: 'instant'\n id: string\n groupId: string\n signal: InstantSignalRef\n operator: InstantOperator\n value: string | string[]\n}\n\nexport type InstantSignalRef =\n | 'utm.source' | 'utm.medium' | 'utm.campaign' | 'utm.term' | 'utm.content'\n | 'referrer.domain' | 'referrer.sourceType'\n | `selfId.${string}`\n | `adapter.${string}`\n | 'identity.isKnown'\n | 'session.entryPage'\n | 'session.pagesVisited'\n\nexport type InstantOperator =\n | 'equals' | 'not_equals' | 'contains' | 'starts_with' | 'matches_glob'\n | 'is_one_of' | 'is_true' | 'is_false'\n | 'gte' | 'lte'\n\nexport interface ScoreContributionCondition {\n type: 'score'\n id: string\n groupId: string\n trigger: ScoreTrigger\n points: number\n threshold?: number\n category?: string\n pattern?: string\n /**\n * For `trigger: 'signalMatch'` \u2014 award `points` when an arbitrary instant\n * signal matches (e.g. `utm.campaign contains 'enterprise' \u2192 +30`). Reuses the\n * instant-match operator set so any signal (UTM / referrer / self-ID / adapter)\n * can contribute to a score, not just the five behavioral triggers.\n */\n signal?: InstantSignalRef\n operator?: InstantOperator\n value?: string | string[]\n}\n\nexport type ScoreTrigger =\n | 'pageViewCount'\n | 'totalPageViews'\n | 'urlMatch'\n | 'categoryViewed'\n | 'timeOnSite'\n | 'signalMatch'\n\n// \u2500\u2500 Self-ID Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface SelfIdField {\n id: string\n siteId: string\n label: string\n picklist: Array<{ value: string; label: string }>\n required: boolean\n sortOrder: number\n}\n\nexport interface SelfIdWidgetConfig {\n id: string\n siteId: string\n displayMode: 'hello_bar_top' | 'hello_bar_bottom' | 'modal' | 'inline' | 'drawer' | 'slide-in'\n trigger: SelfIdTrigger\n headline: string\n subheadline: string | null\n fieldIds: string[]\n submitLabel: string\n skipLabel: string | null\n frequency: 'once_visitor' | 'once_session' | 'always'\n}\n\nexport type SelfIdTrigger =\n | { type: 'immediate' }\n | { type: 'scroll'; depth: number }\n | { type: 'delay'; seconds: number }\n | { type: 'manual' }\n\n// \u2500\u2500 Preview Token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface PreviewTokenPayload {\n jti: string\n audienceId: string\n expiresAt: number\n}\n\n// \u2500\u2500 Default Signals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function createEmptySignals(): VisitorSignals {\n return {\n utm: { source: null, medium: null, campaign: null, term: null, content: null },\n referrer: { raw: null, domain: null, sourceType: 'direct' },\n session: { pageViewCount: 0, totalPageViews: 0, sessionDuration: 0, entryPage: '/', pagesVisited: [] },\n behavioral: { categoryScores: {}, totalScore: 0 },\n selfId: {},\n identity: { visitorId: '', isKnown: false, maLeadId: null },\n adapters: {},\n meta: { isOptedOut: false, isPreview: false, previewAudienceId: null, resolvedAt: 'server' },\n }\n}\n", "export function matchGlob(pattern: string, value: string): boolean {\n const parts = pattern.split('*')\n if (parts.length === 1) return pattern === value\n let pos = 0\n const first = parts[0]!\n if (first !== '') {\n if (!value.startsWith(first)) return false\n pos = first.length\n }\n for (let i = 1; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (part === '') continue\n const idx = value.indexOf(part, pos)\n if (idx < 0) return false\n pos = idx + part.length\n }\n const last = parts[parts.length - 1]!\n if (last !== '') {\n if (!value.endsWith(last)) return false\n if (value.length - last.length < pos) return false\n }\n return true\n}\n", "import type { VisitorSignals, InstantMatchCondition, InstantSignalRef } from '../types.js'\nimport { matchGlob } from './glob.js'\n\nexport function resolveSignalValue(signals: VisitorSignals, ref: InstantSignalRef): string | null {\n if (ref === 'utm.source') return signals.utm.source\n if (ref === 'utm.medium') return signals.utm.medium\n if (ref === 'utm.campaign') return signals.utm.campaign\n if (ref === 'utm.term') return signals.utm.term\n if (ref === 'utm.content') return signals.utm.content\n if (ref === 'referrer.domain') return signals.referrer.domain\n if (ref === 'referrer.sourceType') return signals.referrer.sourceType\n if (ref === 'identity.isKnown') return signals.identity.isKnown ? 'true' : 'false'\n if (ref === 'session.entryPage') return signals.session.entryPage\n if (ref === 'session.pagesVisited') return signals.session.pagesVisited.join(',')\n if (ref.startsWith('selfId.')) {\n const key = ref.slice(7)\n return signals.selfId[key] ?? null\n }\n if (ref.startsWith('adapter.')) {\n const key = ref.slice(8)\n const val = signals.adapters[key]\n return val !== undefined && val !== null ? String(val) : null\n }\n return null\n}\n\nexport function evaluateInstantCondition(condition: InstantMatchCondition, signals: VisitorSignals): boolean {\n const actual = resolveSignalValue(signals, condition.signal)\n const expected = condition.value\n switch (condition.operator) {\n case 'equals': return actual === expected\n case 'not_equals': return actual !== expected\n case 'contains': return actual !== null && typeof expected === 'string' && actual.includes(expected)\n case 'starts_with': return actual !== null && typeof expected === 'string' && actual.startsWith(expected)\n case 'matches_glob': return actual !== null && typeof expected === 'string' && matchGlob(expected, actual)\n case 'is_one_of': return actual !== null && Array.isArray(condition.value) && condition.value.includes(actual)\n case 'is_true': return actual === 'true'\n case 'is_false': return actual === 'false'\n case 'gte': return actual !== null && typeof expected === 'string' && Number(actual) >= Number(expected)\n case 'lte': return actual !== null && typeof expected === 'string' && Number(actual) <= Number(expected)\n default: return false\n }\n}\n", "import type { VisitorSignals, ScoreContributionCondition } from '../types.js'\nimport { matchGlob } from './glob.js'\nimport { evaluateInstantCondition } from './instant-match.js'\n\nfunction evaluateOneScore(cond: ScoreContributionCondition, signals: VisitorSignals): number {\n const threshold = cond.threshold ?? 0\n switch (cond.trigger) {\n case 'pageViewCount': return signals.session.pageViewCount >= threshold ? cond.points : 0\n case 'totalPageViews': return signals.session.totalPageViews >= threshold ? cond.points : 0\n case 'timeOnSite': return signals.session.sessionDuration >= threshold ? cond.points : 0\n case 'categoryViewed': {\n const cat = cond.category ?? ''\n const score = signals.behavioral.categoryScores[cat]\n return score !== undefined && score >= threshold ? cond.points : 0\n }\n case 'urlMatch': {\n const pattern = cond.pattern ?? '*'\n const matched = signals.session.pagesVisited.some(url => matchGlob(pattern, url))\n return matched ? cond.points : 0\n }\n case 'signalMatch': {\n // Award points when an arbitrary instant signal matches. Reuses the\n // instant-match evaluator so every operator/signal is supported.\n if (!cond.signal || !cond.operator) return 0\n const matched = evaluateInstantCondition(\n {\n type: 'instant',\n id: cond.id,\n groupId: cond.groupId,\n signal: cond.signal,\n operator: cond.operator,\n value: cond.value ?? '',\n },\n signals,\n )\n return matched ? cond.points : 0\n }\n default: return 0\n }\n}\n\nexport function evaluateScoreConditions(conditions: ScoreContributionCondition[], signals: VisitorSignals): number {\n let total = 0\n for (const cond of conditions) { total += evaluateOneScore(cond, signals) }\n return total\n}\n", "import type { Condition, VisitorSignals } from '../types.js'\n\n// \u2500\u2500\u2500 Custom Condition Type Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Allows third-party code (plugins, adapters, custom app code) to register\n// additional condition type evaluators without forking the core evaluator.\n//\n// Usage:\n// import { registerConditionType } from '@kywi-software/core'\n//\n// registerConditionType('my_custom_type', (condition, signals) => {\n// // Return true if the condition matches the current visitor signals\n// return signals.adapters['my_adapter'] === condition.value\n// })\n\ntype ConditionEvaluator = (condition: Condition, signals: VisitorSignals) => boolean\n\nconst registry = new Map<string, ConditionEvaluator>()\n\n/**\n * Register a custom condition type evaluator.\n *\n * @param name - The condition `type` string this evaluator handles.\n * @param evaluate - Pure function that returns `true` when the condition matches.\n *\n * Calling this with an already-registered name overwrites the previous evaluator.\n */\nexport function registerConditionType(name: string, evaluate: ConditionEvaluator): void {\n registry.set(name, evaluate)\n}\n\n/**\n * Remove a previously registered condition type evaluator.\n * No-op if the name was never registered.\n */\nexport function unregisterConditionType(name: string): void {\n registry.delete(name)\n}\n\n/**\n * Evaluate a condition using a registered custom evaluator.\n * Returns `false` if no evaluator is registered for the condition's type.\n */\nexport function evaluateCustomCondition(condition: Condition, signals: VisitorSignals): boolean {\n const evaluator = registry.get(condition.type)\n if (!evaluator) return false\n return evaluator(condition, signals)\n}\n\n/**\n * Returns true if a custom evaluator is registered for the given condition type name.\n */\nexport function hasConditionType(name: string): boolean {\n return registry.has(name)\n}\n\n/**\n * Returns the names of all registered custom condition types.\n */\nexport function listConditionTypes(): string[] {\n return [...registry.keys()]\n}\n", "import type { Audience, VisitorSignals, ConditionGroup, InstantMatchCondition, ScoreContributionCondition } from '../types.js'\nimport { evaluateInstantCondition } from './instant-match.js'\nimport { evaluateScoreConditions } from './score.js'\nimport { hasConditionType, evaluateCustomCondition } from './condition-registry.js'\n\nexport interface ConditionTrace {\n conditionId: string\n type: 'instant' | 'score'\n passed: boolean\n scoreContributed?: number\n}\n\nexport interface EvaluationTrace {\n audienceId: string\n matched: boolean\n groupTraces: Array<{ groupId: string; matched: boolean; conditionTraces: ConditionTrace[] }>\n totalScore?: number\n}\n\nexport interface ResolveResult {\n winningAudienceId: string | null\n allMatchedIds: string[]\n traces: EvaluationTrace[]\n}\n\n// Evaluate one group: AND all instant + custom conditions, accumulate score conditions\nfunction evaluateGroup(group: ConditionGroup, signals: VisitorSignals) {\n const conditionTraces: ConditionTrace[] = []\n const instants: InstantMatchCondition[] = []\n const scores: ScoreContributionCondition[] = []\n const customs: typeof group.conditions = []\n\n for (const c of group.conditions) {\n // The Condition union only models 'instant'/'score', but the registry\n // dispatches custom condition kinds by their `type` string at runtime.\n // Capture it as a string so the custom branch stays reachable.\n const conditionType: string = c.type\n if (c.type === 'instant') instants.push(c)\n else if (c.type === 'score') scores.push(c)\n else if (hasConditionType(conditionType)) customs.push(c)\n // Unknown types with no registered evaluator are silently skipped\n }\n\n let allInstantsPassed = true\n\n for (const ic of instants) {\n const passed = evaluateInstantCondition(ic, signals)\n conditionTraces.push({ conditionId: ic.id, type: 'instant', passed })\n if (!passed) allInstantsPassed = false\n }\n\n // Custom conditions are ANDed with instant conditions\n for (const cc of customs) {\n const passed = evaluateCustomCondition(cc, signals)\n conditionTraces.push({ conditionId: cc.id, type: cc.type as 'instant', passed })\n if (!passed) allInstantsPassed = false\n }\n\n const totalScore = evaluateScoreConditions(scores, signals)\n for (const sc of scores) {\n const contributed = evaluateScoreConditions([sc], signals)\n conditionTraces.push({ conditionId: sc.id, type: 'score', passed: contributed > 0, scoreContributed: contributed })\n }\n\n return { matched: allInstantsPassed, conditionTraces, totalScore }\n}\n\nexport function resolveAudiences(audiences: Audience[], signals: VisitorSignals): ResolveResult {\n const allMatchedIds: string[] = []\n const traces: EvaluationTrace[] = []\n\n for (const audience of audiences) {\n const groupTraces: EvaluationTrace['groupTraces'] = []\n let audienceMatched = false\n let accumulatedScore = 0\n\n for (const group of audience.conditionGroups) {\n const { matched, conditionTraces, totalScore } = evaluateGroup(group, signals)\n accumulatedScore += totalScore\n groupTraces.push({ groupId: group.id, matched, conditionTraces })\n if (matched) audienceMatched = true\n }\n\n if (audience.scoreThreshold !== null) {\n const scoreThresholdMet = accumulatedScore >= audience.scoreThreshold\n const hasInstantConditions = audience.conditionGroups.some(g => g.conditions.some(c => c.type === 'instant'))\n if (hasInstantConditions) {\n audienceMatched = audienceMatched && scoreThresholdMet\n } else {\n audienceMatched = scoreThresholdMet\n }\n }\n\n traces.push({\n audienceId: audience.id,\n matched: audienceMatched,\n groupTraces,\n ...(accumulatedScore > 0 ? { totalScore: accumulatedScore } : {}),\n })\n if (audienceMatched) allMatchedIds.push(audience.id)\n }\n\n return { winningAudienceId: allMatchedIds[0] ?? null, allMatchedIds, traces }\n}\n", "// packages/kywi-js/src/audience/behavioral-collector.ts\nconst SESSION_KEY = 'kywi_session'\nconst TOTAL_VIEWS_KEY = 'kywi_total_views'\nconst CATEGORY_SCORES_KEY = 'kywi_category_scores'\nconst SESSION_START_KEY = 'kywi_session_start'\n\ninterface SessionData { pageViewCount: number; entryPage: string; pagesVisited: string[] }\n\nexport interface BehavioralResult {\n session: { pageViewCount: number; totalPageViews: number; sessionDuration: number; entryPage: string; pagesVisited: string[] }\n behavioral: { categoryScores: Record<string, number>; totalScore: number }\n}\n\nfunction getSession(): SessionData {\n const raw = sessionStorage.getItem(SESSION_KEY)\n if (raw) { try { return JSON.parse(raw) as SessionData } catch { /* fall through */ } }\n return { pageViewCount: 0, entryPage: '', pagesVisited: [] }\n}\n\nfunction getSessionStart(): number {\n const raw = sessionStorage.getItem(SESSION_START_KEY)\n if (raw) return Number(raw)\n const now = Date.now()\n sessionStorage.setItem(SESSION_START_KEY, String(now))\n return now\n}\n\nfunction getCategoryScores(): Record<string, number> {\n const raw = localStorage.getItem(CATEGORY_SCORES_KEY)\n if (raw) { try { return JSON.parse(raw) as Record<string, number> } catch { /* fall through */ } }\n return {}\n}\n\nexport function collectBehavioral(currentPath: string, category?: string): BehavioralResult {\n const session = getSession()\n session.pageViewCount += 1\n if (!session.entryPage) session.entryPage = currentPath\n session.pagesVisited.push(currentPath)\n sessionStorage.setItem(SESSION_KEY, JSON.stringify(session))\n\n const totalViews = (Number(localStorage.getItem(TOTAL_VIEWS_KEY)) || 0) + 1\n localStorage.setItem(TOTAL_VIEWS_KEY, String(totalViews))\n\n const sessionStart = getSessionStart()\n const categoryScores = getCategoryScores()\n if (category) {\n categoryScores[category] = (categoryScores[category] ?? 0) + 1\n localStorage.setItem(CATEGORY_SCORES_KEY, JSON.stringify(categoryScores))\n }\n\n return {\n session: { pageViewCount: session.pageViewCount, totalPageViews: totalViews, sessionDuration: Math.floor((Date.now() - sessionStart) / 1000), entryPage: session.entryPage, pagesVisited: session.pagesVisited },\n behavioral: { categoryScores, totalScore: 0 },\n }\n}\n", "// packages/kywi-js/src/audience/selfid-collector.ts\nconst SELFID_KEY = 'kywi_selfid'\n\nexport function collectSelfId(): Record<string, string> {\n const raw = localStorage.getItem(SELFID_KEY)\n if (!raw) return {}\n try { return JSON.parse(raw) as Record<string, string> } catch { return {} }\n}\n\nexport function storeSelfId(responses: Record<string, string>): void {\n localStorage.setItem(SELFID_KEY, JSON.stringify(responses))\n}\n", "// packages/kywi-js/src/audience/evaluate.ts\nimport type { Audience, VisitorSignals, AudienceResult } from '@kywi-software/core/audiences/types'\nimport { createEmptySignals } from '@kywi-software/core/audiences/types'\nimport { resolveAudiences } from '@kywi-software/core/evaluator'\nimport { collectBehavioral } from './behavioral-collector.js'\nimport { collectSelfId } from './selfid-collector.js'\n\nfunction merge(base: VisitorSignals, partial: Partial<VisitorSignals>): VisitorSignals {\n return {\n utm: partial.utm ?? base.utm, referrer: partial.referrer ?? base.referrer,\n session: partial.session ?? base.session, behavioral: partial.behavioral ?? base.behavioral,\n selfId: { ...base.selfId, ...partial.selfId }, identity: partial.identity ?? base.identity,\n adapters: { ...base.adapters, ...partial.adapters }, meta: { ...base.meta, ...partial.meta },\n }\n}\n\nexport function evaluateClientSide(\n audiences: Audience[], serverSignals: Partial<VisitorSignals>, currentPath: string, pageCategory?: string,\n): AudienceResult {\n let signals = merge(createEmptySignals(), serverSignals)\n const client = collectBehavioral(currentPath, pageCategory)\n const selfId = collectSelfId()\n signals = merge(signals, { session: client.session, behavioral: client.behavioral, selfId, meta: { ...signals.meta, resolvedAt: 'client' } })\n const { winningAudienceId, allMatchedIds } = resolveAudiences(audiences, signals)\n const isOptedOut = signals.meta.isOptedOut\n return { winningAudienceId: isOptedOut ? null : winningAudienceId, allMatchedIds, signals, isOptedOut }\n}\n", "// packages/kywi-js/src/audience/dom-patcher.ts\nexport function patchVariantContainers(winningAudienceId: string | null): void {\n const containers = document.querySelectorAll('.kywi-variant-container')\n for (const container of Array.from(containers)) {\n const el = container as HTMLElement\n const arms = Array.from(el.querySelectorAll('[data-kywi-variant]'))\n\n // Only module-level containers (VariantContainerModule in\n // packages/core/src/layout/modules-extended.tsx) render every arm into the\n // DOM for this client-side swap \u2014 each tagged `[data-kywi-variant]`, with at\n // least a \"default\" arm present even while loading. Section-level containers\n // (SectionRenderer's VariantContainerRenderer in packages/core/src/layout/\n // renderer.tsx, and components/personalization/VariantContainer.tsx) share\n // the `.kywi-variant-container` selector but are fully server-resolved: they\n // render only the winning arm's markup directly, so they never have any\n // `[data-kywi-variant]` children. That \"has arms to toggle\" structure is the\n // most robust discriminator available (unlike a class or `data-mode`\n // attribute, it can't drift out of sync with what this function actually\n // needs to do) \u2014 skip anything without arms so we never overwrite a\n // server-resolved container's `data-variant` with a client-side audience id\n // that disagrees with the content already rendered (kywi-cms#99).\n if (arms.length === 0) continue\n\n el.classList.remove('kywi-variant-loading')\n el.removeAttribute('aria-busy')\n const skeleton = el.querySelector('.kywi-variant-skeleton')\n if (skeleton) skeleton.remove()\n const target = winningAudienceId ?? 'default'\n el.setAttribute('data-variant', target)\n for (const child of arms) {\n const h = child as HTMLElement\n h.style.display = h.getAttribute('data-kywi-variant') === target ? '' : 'none'\n }\n }\n}\n", "// packages/kywi-js/src/cookies.ts\nexport const COOKIE_NAMES = {\n SIGNALS: 'kywi_signals', VISITOR: 'kywi_visitor', UTM: 'kywi_utm',\n AUDIENCE: 'kywi_audience', OPTOUT: 'kywi_optout', KNOWN: 'kywi_known',\n PREVIEW_INIT: 'kywi_preview_init',\n} as const\n\nexport function readCookies(): Map<string, string> {\n const map = new Map<string, string>()\n if (typeof document === 'undefined') return map\n for (const pair of document.cookie.split(';')) {\n const trimmed = pair.trim()\n const eqIdx = trimmed.indexOf('=')\n if (eqIdx < 0) continue\n map.set(trimmed.slice(0, eqIdx), decodeURIComponent(trimmed.slice(eqIdx + 1)))\n }\n return map\n}\n\nexport function setCookie(name: string, value: string, maxAge?: number): void {\n let str = `${name}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`\n if (maxAge !== undefined && maxAge >= 0) str += `; Max-Age=${maxAge}`\n document.cookie = str\n}\n\nexport function deleteCookie(name: string): void {\n document.cookie = `${name}=; Path=/; Max-Age=0`\n}\n", "// packages/kywi-js/src/audience/transparency.ts\n//\n// The transparency surface: the single global control through which a visitor\n// sees THAT the page is personalized, WHICH audience it was personalized for,\n// and can switch audience, reset to automatic resolution, or turn\n// personalization off entirely (issue #105).\n//\n// Three states:\n// 1. nothing \u2014 not personalizing and no match available\n// 2. collapsed pill \u2014 small, unobtrusive, click/Enter expands\n// 3. expanded panel \u2014 audience name, switcher, reset, opt-out/opt-in\n//\n// Collapsing is NOT dismissal: there is no permanent suppression any more (a\n// promise of transparency the visitor can silence forever is not one). The\n// collapsed/expanded choice is remembered in localStorage; the legacy\n// `kywi_transparency_dismissed` flag is migrated to \"collapsed\".\n//\n// All styling lives in `@kywi-software/core`'s site/styles.css (token-driven,\n// overridable) \u2014 this module ships no stylesheet of its own.\n\nimport { COOKIE_NAMES, readCookies, setCookie, deleteCookie } from '../cookies.js'\n\nconst COLLAPSED_KEY = 'kywi_transparency_collapsed'\n/** Pre-#105 permanent-dismissal flag; read once and migrated to \"collapsed\". */\nconst LEGACY_DISMISSED_KEY = 'kywi_transparency_dismissed'\n\nconst ROOT_ID = 'kywi-transparency'\nconst PANEL_ID = 'kywi-transparency-panel'\nconst TITLE_ID = 'kywi-transparency-title'\nconst SWITCHER_LABEL_ID = 'kywi-transparency-switcher-label'\n\nconst DEFAULT_API_BASE = '/api/v1'\n\n/** An audience the visitor can be shown as, or switch to. */\nexport interface TransparencyAudience {\n id: string\n name: string\n}\n\nexport interface TransparencyState {\n /** The page is currently rendering an audience's variant content. */\n isPersonalized: boolean\n isOptedOut: boolean\n /** At least one audience matched \u2014 i.e. personalization is available here. */\n hasMatchAvailable: boolean\n /** The audience the page was personalized for (resolves the displayed name). */\n audienceId?: string | null\n /** Active audiences, by name \u2014 powers the name lookup and the switcher. */\n audiences?: TransparencyAudience[]\n /** Mounted CMS API base (e.g. `/api/v1`); the switcher posts to `{apiBase}/kywi/audience`. */\n apiBase?: string\n csrfToken?: string | null\n /**\n * `personalization.transparencyNotice.enabled`. When false the surface never\n * appears on its own; `openTransparencyPanel()` (e.g. a personalizationBadge\n * click) can still open it deliberately.\n */\n enabled?: boolean\n}\n\n// The last state boot handed us, so a programmatic open() can re-render the\n// panel with real data instead of an empty shell.\nlet lastState: TransparencyState | null = null\n// Set by openTransparencyPanel(): render even when the automatic gate says no.\nlet forcedOpen = false\n\n/* \u2500\u2500 storage (never let a blocked/full localStorage break the page) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nfunction readStorage(key: string): string | null {\n try { return localStorage.getItem(key) } catch { return null }\n}\nfunction writeStorage(key: string, value: string): void {\n try { localStorage.setItem(key, value) } catch { /* private mode / quota */ }\n}\nfunction removeStorage(key: string): void {\n try { localStorage.removeItem(key) } catch { /* private mode / quota */ }\n}\n\n/** True when the surface should render as the pill. Defaults to collapsed. */\nexport function isCollapsed(): boolean {\n if (readStorage(LEGACY_DISMISSED_KEY) === '1') {\n // Migration: a visitor who permanently dismissed the old bar gets the pill,\n // not silence. Rewriting the flag makes the migration a one-time cost.\n removeStorage(LEGACY_DISMISSED_KEY)\n writeStorage(COLLAPSED_KEY, '1')\n return true\n }\n return readStorage(COLLAPSED_KEY) !== '0'\n}\n\nfunction setCollapsed(collapsed: boolean): void {\n writeStorage(COLLAPSED_KEY, collapsed ? '1' : '0')\n}\n\n/* \u2500\u2500 visitor preferences \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport function optOut(): void {\n setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600)\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n}\n\nexport function optIn(): void {\n deleteCookie(COOKIE_NAMES.OPTOUT)\n}\n\n/** Clears the manual audience pin so resolution goes back to signals. */\nexport function resetToAutomatic(): void {\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n}\n\nfunction hasPin(): boolean {\n return readCookies().has(COOKIE_NAMES.AUDIENCE)\n}\n\n/**\n * Pins the visitor to `audienceId` via the public runtime route \u2014 the same\n * endpoint and payload the boot path already uses to persist a client-resolved\n * audience. The server re-validates the id against the active audiences.\n */\nexport async function pinAudience(\n audienceId: string,\n opts: { apiBase?: string | undefined; csrfToken?: string | null | undefined } = {},\n): Promise<void> {\n const apiBase = opts.apiBase ?? DEFAULT_API_BASE\n try {\n await fetch(`${apiBase}/kywi/audience`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(opts.csrfToken ? { 'X-CSRF-Token': opts.csrfToken } : {}) },\n body: JSON.stringify({ audienceId }),\n })\n } catch { /* offline / blocked \u2014 the reload below simply keeps the old state */ }\n}\n\nfunction reload(): void {\n try { window.location.reload() } catch { /* non-navigating test environments */ }\n}\n\n/* \u2500\u2500 rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nfunction removeSurface(): void {\n document.getElementById(ROOT_ID)?.remove()\n // Pre-#105 markup, in case a stale bar is still on the page.\n document.querySelector('.kywi-transparency-bar')?.remove()\n}\n\nfunction button(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.type = 'button'\n btn.className = className\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nfunction shouldRenderAutomatically(state: TransparencyState): boolean {\n if (state.enabled === false) return false\n return (state.isPersonalized && !state.isOptedOut) || (state.isOptedOut && state.hasMatchAvailable)\n}\n\nfunction audienceName(state: TransparencyState): string | null {\n if (!state.audienceId) return null\n return state.audiences?.find((a) => a.id === state.audienceId)?.name ?? null\n}\n\n/**\n * Renders (or removes) the transparency surface for `state`. Safe to call on\n * every boot; it replaces whatever is currently mounted.\n */\nexport function renderTransparencyPanel(state: TransparencyState): void {\n lastState = state\n if (typeof document === 'undefined') return\n removeSurface()\n if (!forcedOpen && !shouldRenderAutomatically(state)) return\n\n const active = state.isPersonalized && !state.isOptedOut\n const collapsed = forcedOpen ? false : isCollapsed()\n\n const root = document.createElement('div')\n root.id = ROOT_ID\n root.className = `kywi-transparency ${active ? 'kywi-transparency-active' : 'kywi-transparency-opted-out'}`\n root.dataset.state = collapsed ? 'collapsed' : 'expanded'\n\n /* pill */\n const pill = document.createElement('button')\n pill.type = 'button'\n pill.className = 'kywi-transparency-pill'\n pill.setAttribute('aria-expanded', String(!collapsed))\n pill.setAttribute('aria-controls', PANEL_ID)\n const pillIcon = document.createElement('span')\n pillIcon.className = 'kywi-transparency-pill-icon'\n pillIcon.setAttribute('aria-hidden', 'true')\n pillIcon.textContent = '\u2726'\n const pillLabel = document.createElement('span')\n pillLabel.className = 'kywi-transparency-pill-label'\n pillLabel.textContent = active ? 'Personalized' : 'Personalization off'\n pill.append(pillIcon, pillLabel)\n pill.addEventListener('click', () => expandPanel())\n pill.hidden = !collapsed\n root.appendChild(pill)\n\n /* panel */\n const panel = document.createElement('section')\n panel.id = PANEL_ID\n panel.className = 'kywi-transparency-panel'\n panel.setAttribute('role', 'dialog')\n panel.setAttribute('aria-labelledby', TITLE_ID)\n panel.hidden = collapsed\n\n const header = document.createElement('div')\n header.className = 'kywi-transparency-header'\n const title = document.createElement('h2')\n title.id = TITLE_ID\n title.className = 'kywi-transparency-title'\n const name = audienceName(state)\n title.textContent = !active\n ? 'Personalization is off'\n : name\n ? 'This page is personalized for:'\n : 'This page is personalized'\n header.appendChild(title)\n const collapseBtn = button('kywi-transparency-collapse', '\u2715', () => collapsePanel())\n collapseBtn.setAttribute('aria-label', 'Collapse')\n header.appendChild(collapseBtn)\n panel.appendChild(header)\n\n if (active) {\n const audience = document.createElement('p')\n audience.className = 'kywi-transparency-audience'\n if (name) {\n const strong = document.createElement('strong')\n strong.textContent = name\n audience.appendChild(strong)\n } else {\n audience.textContent = 'Based on your browsing context.'\n }\n panel.appendChild(audience)\n }\n\n const note = document.createElement('p')\n note.className = 'kywi-transparency-note'\n note.textContent = active\n ? 'Parts of this page are chosen to match this audience. You can switch, reset, or turn personalization off.'\n : 'Personalization is turned off, so you are seeing the default version of this page.'\n panel.appendChild(note)\n\n /* audience switcher \u2014 pointless while opted out (opt-out beats a pin) */\n const options = state.audiences ?? []\n if (active && options.length > 0) {\n const switcher = document.createElement('div')\n switcher.className = 'kywi-transparency-switcher'\n const switcherLabel = document.createElement('span')\n switcherLabel.id = SWITCHER_LABEL_ID\n switcherLabel.className = 'kywi-transparency-switcher-label'\n switcherLabel.textContent = 'See this page as'\n switcher.appendChild(switcherLabel)\n\n const group = document.createElement('div')\n group.className = 'kywi-transparency-options'\n group.setAttribute('role', 'group')\n group.setAttribute('aria-labelledby', SWITCHER_LABEL_ID)\n for (const option of options) {\n const isCurrent = option.id === state.audienceId\n const optionBtn = button('kywi-transparency-option', option.name, () => {\n if (isCurrent) return\n void pinAudience(option.id, { apiBase: state.apiBase, csrfToken: state.csrfToken }).then(reload)\n })\n optionBtn.dataset.kywiAudienceId = option.id\n optionBtn.setAttribute('aria-pressed', String(isCurrent))\n group.appendChild(optionBtn)\n }\n switcher.appendChild(group)\n panel.appendChild(switcher)\n }\n\n /* actions */\n const actions = document.createElement('div')\n actions.className = 'kywi-transparency-actions'\n if (state.isOptedOut) {\n actions.appendChild(button('kywi-transparency-opt-in', 'Enable personalization', () => { optIn(); reload() }))\n } else {\n if (hasPin()) {\n actions.appendChild(button('kywi-transparency-reset', 'Reset to automatic', () => { resetToAutomatic(); reload() }))\n }\n actions.appendChild(button('kywi-transparency-opt-out', 'Turn off personalization', () => { optOut(); reload() }))\n }\n panel.appendChild(actions)\n\n panel.addEventListener('keydown', (e) => {\n if ((e as KeyboardEvent).key === 'Escape') collapsePanel()\n })\n\n root.appendChild(panel)\n document.body.appendChild(root)\n}\n\nfunction currentSurface(): { root: HTMLElement; pill: HTMLElement; panel: HTMLElement } | null {\n const root = document.getElementById(ROOT_ID)\n if (!root) return null\n const pill = root.querySelector<HTMLElement>('.kywi-transparency-pill')\n const panel = root.querySelector<HTMLElement>('.kywi-transparency-panel')\n if (!pill || !panel) return null\n return { root, pill, panel }\n}\n\nfunction setExpanded(expanded: boolean): void {\n const surface = currentSurface()\n if (!surface) return\n surface.root.dataset.state = expanded ? 'expanded' : 'collapsed'\n surface.pill.hidden = expanded\n surface.pill.setAttribute('aria-expanded', String(expanded))\n surface.panel.hidden = !expanded\n const focusTarget = expanded\n ? surface.panel.querySelector<HTMLElement>('.kywi-transparency-collapse')\n : surface.pill\n focusTarget?.focus()\n}\n\n/** Expands the panel and remembers the choice. */\nexport function expandPanel(): void {\n setCollapsed(false)\n setExpanded(true)\n}\n\n/** Collapses back to the pill and remembers the choice \u2014 never full suppression. */\nexport function collapsePanel(): void {\n forcedOpen = false\n setCollapsed(true)\n setExpanded(false)\n}\n\n/**\n * Opens the transparency panel from anywhere \u2014 the programmatic entry point the\n * personalizationBadge module's status pill calls (#107), so opt-out and\n * audience switching live in exactly one surface. Renders the panel even when\n * the automatic gate (or `transparencyNotice.enabled: false`) would hide it,\n * because opening it is an explicit visitor action.\n */\nexport function openTransparencyPanel(): void {\n if (typeof document === 'undefined') return\n forcedOpen = true\n const state: TransparencyState = lastState ?? {\n isPersonalized: false,\n isOptedOut: readCookies().has(COOKIE_NAMES.OPTOUT),\n hasMatchAvailable: false,\n }\n renderTransparencyPanel(state)\n currentSurface()?.panel.querySelector<HTMLElement>('.kywi-transparency-collapse')?.focus()\n}\n\n/** Test seam: forget the cached boot state and any forced-open flag. */\nexport function resetTransparencyState(): void {\n lastState = null\n forcedOpen = false\n}\n", "// packages/kywi-js/src/audience/preview.ts\nimport { COOKIE_NAMES, readCookies, deleteCookie } from '../cookies.js'\n\nconst PREVIEW_KEY = 'kywi_preview_audience'\n\nexport function getPreviewAudienceId(): string | null { return sessionStorage.getItem(PREVIEW_KEY) }\nexport function setPreviewAudienceId(id: string): void { sessionStorage.setItem(PREVIEW_KEY, id) }\nexport function clearPreview(): void { sessionStorage.removeItem(PREVIEW_KEY) }\n\nexport function checkPreviewInit(): void {\n const cookies = readCookies()\n const initId = cookies.get(COOKIE_NAMES.PREVIEW_INIT)\n if (initId) { setPreviewAudienceId(initId); deleteCookie(COOKIE_NAMES.PREVIEW_INIT) }\n}\n\nexport function renderPreviewBanner(audienceName: string): void {\n document.querySelector('.kywi-preview-banner')?.remove()\n const banner = document.createElement('div')\n banner.className = 'kywi-preview-banner'\n banner.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-preview-text'\n text.textContent = 'Previewing as: '\n const strong = document.createElement('strong')\n strong.textContent = audienceName\n text.appendChild(strong)\n banner.appendChild(text)\n const exitBtn = document.createElement('button')\n exitBtn.className = 'kywi-preview-exit'\n exitBtn.type = 'button'\n exitBtn.textContent = 'Exit Preview'\n exitBtn.addEventListener('click', () => { clearPreview(); window.location.reload() })\n banner.appendChild(exitBtn)\n document.body.appendChild(banner)\n}\n", "// packages/kywi-js/src/audience/data-layer.ts\nimport type { KywiVisitor } from '../types.js'\n\nexport function populateDataLayer(visitor: KywiVisitor): void {\n const g = ((window as any).kywi ?? {}) as { visitor?: KywiVisitor }\n g.visitor = visitor\n ;(window as any).kywi = g\n}\n\nexport function fireKywiReady(): void { window.dispatchEvent(new CustomEvent('kywiReady')) }\n\nexport interface ServerMeta { audienceId: string | null; experimentId: string | null; variantId: string | null; visitorId: string }\n\nexport function readServerMeta(): ServerMeta {\n const m = (n: string) => document.querySelector(`meta[name=\"kywi:${n}\"]`)?.getAttribute('content') ?? null\n return { audienceId: m('audience-id'), experimentId: m('experiment-id'), variantId: m('variant-id'), visitorId: m('visitor-id') ?? '' }\n}\n", "// packages/kywi-js/src/audience/adapter-runner.ts\nimport type { VisitorSignals } from '@kywi-software/core/audiences/types'\n\ninterface PullAdapter {\n id: string\n side: 'client' | 'server-proxy'\n fields: string[]\n collect: (signals: Partial<VisitorSignals>) => Promise<Record<string, unknown>>\n}\n\nconst CACHE_PREFIX = 'kywi_adapter_'\n\nfunction getCached(adapterId: string): Record<string, unknown> | null {\n const raw = sessionStorage.getItem(CACHE_PREFIX + adapterId)\n if (!raw) return null\n try { return JSON.parse(raw) as Record<string, unknown> } catch { return null }\n}\n\nfunction setCache(adapterId: string, data: Record<string, unknown>): void {\n sessionStorage.setItem(CACHE_PREFIX + adapterId, JSON.stringify(data))\n}\n\nexport async function runClientAdapters(\n adapters: PullAdapter[], currentSignals: Partial<VisitorSignals>,\n apiBase = '/api/v1',\n): Promise<Record<string, unknown>> {\n const merged: Record<string, unknown> = {}\n\n const tasks = adapters.map(async (adapter) => {\n const cached = getCached(adapter.id)\n if (cached) return cached\n\n let result: Record<string, unknown>\n if (adapter.side === 'server-proxy') {\n // The proxy lives in the CMS runtime namespace (`{apiBase}/kywi/adapters/:id`),\n // alongside the audience-assignment and identity routes \u2014 not a bare\n // `/api/kywi/...` path, which would miss a handler mounted at `/api/v1`.\n const res = await fetch(`${apiBase}/kywi/adapters/${adapter.id}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ signals: currentSignals }),\n })\n const json = await res.json() as { data?: Record<string, unknown> }\n result = json.data ?? {}\n } else {\n result = await adapter.collect(currentSignals)\n }\n\n setCache(adapter.id, result)\n return result\n })\n\n const results = await Promise.all(tasks)\n for (const r of results) Object.assign(merged, r)\n return merged\n}\n", "// packages/kywi-js/src/audience/selfid-submit.ts\nimport { storeSelfId } from './selfid-collector.js'\nimport { evaluateClientSide } from './evaluate.js'\nimport { patchVariantContainers } from './dom-patcher.js'\nimport { populateDataLayer, fireKywiReady, readServerMeta } from './data-layer.js'\nimport { readCookies, COOKIE_NAMES } from '../cookies.js'\nimport type { Audience, VisitorSignals } from '@kywi-software/core/audiences/types'\n\nexport function handleSelfIdSubmit(\n responses: Record<string, string>,\n audiences?: Audience[],\n currentPath?: string,\n): void {\n // 1. Store responses (replaces previous)\n storeSelfId(responses)\n\n // 2. Re-evaluate if audiences provided\n if (audiences && currentPath) {\n const cookies = readCookies()\n const serverMeta = readServerMeta()\n const serverSignals: Partial<VisitorSignals> = {\n identity: { visitorId: serverMeta.visitorId || cookies.get(COOKIE_NAMES.VISITOR) || '', isKnown: cookies.has(COOKIE_NAMES.KNOWN), maLeadId: null },\n meta: { isOptedOut: cookies.has(COOKIE_NAMES.OPTOUT), isPreview: false, previewAudienceId: null, resolvedAt: 'server' },\n }\n const result = evaluateClientSide(audiences, serverSignals, currentPath)\n patchVariantContainers(result.winningAudienceId)\n populateDataLayer({\n visitorId: result.signals.identity.visitorId,\n audienceId: result.winningAudienceId,\n experimentId: serverMeta.experimentId,\n variantId: serverMeta.variantId,\n isPreview: false,\n isOptedOut: result.isOptedOut,\n })\n }\n}\n", "// packages/kywi-js/src/audience/selfid-widget.ts\nimport { storeSelfId } from './selfid-collector.js'\nimport { handleSelfIdSubmit } from './selfid-submit.js'\nimport type { Audience } from '@kywi-software/core/audiences/types'\n\nconst SHOWN_KEY = 'kywi_selfid_shown'\nconst MS_PER_DAY = 86_400_000\n\n/**\n * Display modes that render their own explicit dismiss control (#97, #106).\n * Every overlay mode is dismissible \u2014 an overlay a visitor cannot close is a\n * trap. Only `inline` is excluded: it is part of the host's page content and\n * has no viewport-covering surface to escape from.\n */\nconst DISMISSIBLE_MODES = new Set(['modal', 'slide-in', 'hello_bar_top', 'hello_bar_bottom', 'drawer'])\n\n/** Modes that float over the page and therefore close themselves on submit. */\nconst OVERLAY_MODES = DISMISSIBLE_MODES\n\n/**\n * Host mount contract for `inline` mode (#106): when the page contains an\n * element matching this selector, the widget renders INTO it instead of into\n * the runtime's own `#kywi-selfid-container` (which is appended to the end of\n * `<body>`, i.e. after the footer). Hosts opt in by putting\n * `<div data-kywi-selfid-mount></div>` wherever the card belongs.\n */\nexport const SELFID_MOUNT_SELECTOR = '[data-kywi-selfid-mount]'\n\n/** Body class + custom property published while a top hello bar is on screen. */\nexport const HELLO_BAR_TOP_CLASS = 'kywi-selfid-hello-bar-top-open'\nconst HELLO_BAR_HEIGHT_PROPERTY = '--kywi-selfid-hello-bar-height'\n\nconst MODAL_LABEL_ID = 'kywi-selfid-headline'\n\n/**\n * The host slot for `inline` mode, when one exists. Returns null for every\n * other display mode \u2014 modal/drawer/hello-bar/slide-in position themselves\n * against the viewport, so a content slot would be meaningless for them.\n */\nexport function resolveSelfIdMount(displayMode?: SelfIdWidgetConfig['displayMode']): HTMLElement | null {\n if (typeof document === 'undefined') return null\n if (displayMode && displayMode !== 'inline') return null\n return document.querySelector<HTMLElement>(SELFID_MOUNT_SELECTOR)\n}\n\n/** A picklist option: the value submitted, and the label shown to the visitor. */\nexport interface SelfIdFieldOption {\n value: string\n label: string\n}\n\nexport interface SelfIdFieldConfig {\n id: string\n label: string\n type: 'text' | 'select' | 'email'\n /**\n * Either `{value, label}` pairs (current server shape \u2014 see\n * resolveSelfIdWidget in the create-kywi-app scaffold) or bare strings (older\n * config shape, kept for backward compatibility). A bare string is treated as\n * both its own value and its own label.\n */\n options?: Array<string | SelfIdFieldOption>\n required?: boolean\n}\n\n/** Normalize a picklist option to `{value, label}`, treating a bare string as both. */\nfunction normalizeOption(opt: string | SelfIdFieldOption): SelfIdFieldOption {\n return typeof opt === 'string' ? { value: opt, label: opt } : opt\n}\n\n/** When the widget is shown, once frequency allows. Defaults to immediate. */\nexport type SelfIdWidgetTrigger =\n | { type: 'immediate' }\n | { type: 'scroll'; depth: number }\n | { type: 'delay'; seconds: number }\n | { type: 'manual' }\n\nexport interface SelfIdWidgetConfig {\n fields: SelfIdFieldConfig[]\n headline?: string\n subheadline?: string\n submitLabel?: string\n skipLabel?: string\n displayMode?: 'modal' | 'inline' | 'slide-in' | 'hello_bar_top' | 'hello_bar_bottom' | 'drawer'\n frequency?: 'once' | 'session' | 'daily' | 'always'\n trigger?: SelfIdWidgetTrigger\n /**\n * The full audience rule definitions to re-evaluate client-side after a\n * submission. These flow straight into `handleSelfIdSubmit` \u2192\n * `evaluateClientSide` \u2192 `resolveAudiences`, which iterates each audience's\n * `conditionGroups`, so full `Audience` objects are required (not id strings).\n */\n audiences?: Audience[]\n currentPath?: string\n}\n\nexport interface SelfIdWidget {\n shouldShow(): boolean\n markShown(): void\n render(container: HTMLElement): void\n handleSubmit(responses: Record<string, string>): void\n}\n\nconst FOCUSABLE_SELECTOR =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction focusableElements(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter((el) => !el.hidden)\n}\n\n/** Keeps Tab inside `root`, wrapping at both ends. */\nfunction trapTab(root: HTMLElement, e: KeyboardEvent): void {\n const focusable = focusableElements(root)\n if (focusable.length === 0) {\n e.preventDefault()\n root.focus()\n return\n }\n const first = focusable[0]!\n const last = focusable[focusable.length - 1]!\n const active = document.activeElement as HTMLElement | null\n const inside = active !== null && root.contains(active) && active !== root\n if (e.shiftKey) {\n if (!inside || active === first) { e.preventDefault(); last.focus() }\n } else if (!inside || active === last) {\n e.preventDefault()\n first.focus()\n }\n}\n\nexport function createSelfIdWidget(config: SelfIdWidgetConfig): SelfIdWidget {\n const frequency = config.frequency ?? 'once'\n const displayMode = config.displayMode ?? 'inline'\n const isModal = displayMode === 'modal'\n\n /** Undo callbacks for everything render() attached outside the container. */\n let cleanups: Array<() => void> = []\n\n function shouldShow(): boolean {\n if (frequency === 'always') return true\n if (frequency === 'session') return false\n\n const raw = localStorage.getItem(SHOWN_KEY)\n if (!raw) return true\n\n if (frequency === 'once') return false\n\n // 'daily' \u2014 true if more than 24h since last shown\n const ts = Number(raw)\n return !isNaN(ts) && Date.now() - ts > MS_PER_DAY\n }\n\n function markShown(): void {\n localStorage.setItem(SHOWN_KEY, String(Date.now()))\n }\n\n function handleSubmit(responses: Record<string, string>): void {\n storeSelfId(responses)\n // Attempt the immediate variant swap, but never let a personalization/resolver\n // error skip markShown() \u2014 otherwise a `frequency: 'once'` widget re-shows on\n // every subsequent page load forever (issue #80). The `finally` keeps the\n // frequency gate honored even if `handleSelfIdSubmit` throws.\n try {\n handleSelfIdSubmit(responses, config.audiences ?? [], config.currentPath ?? '/')\n } finally {\n markShown()\n }\n }\n\n /** Removes the widget and everything it attached to the document. */\n function teardown(container: HTMLElement): void {\n for (const undo of cleanups) undo()\n cleanups = []\n container.replaceChildren()\n container.className = ''\n container.removeAttribute('role')\n container.removeAttribute('aria-modal')\n container.removeAttribute('aria-label')\n container.removeAttribute('aria-labelledby')\n container.removeAttribute('tabindex')\n container.hidden = true\n }\n\n /**\n * Visitor closed the widget without answering. Dismissing honors the\n * frequency gate exactly like skipping does, so a `once` widget does not\n * reappear on the next page.\n */\n function dismiss(container: HTMLElement): void {\n markShown()\n teardown(container)\n }\n\n function render(container: HTMLElement): void {\n for (const undo of cleanups) undo()\n cleanups = []\n container.replaceChildren()\n container.hidden = false\n // Style hook uses kebab-case (kywi-selfid-hello-bar-top) even though the\n // config value is snake_case (hello_bar_top), matching the existing\n // kywi-selfid-slide-in convention.\n const displayModeClass = displayMode.replace(/_/g, '-')\n container.className = `kywi-selfid-widget kywi-selfid-${displayModeClass}`\n\n if (isModal) {\n // A real backdrop ELEMENT (the old ::before pseudo could not be clicked):\n // clicking it dismisses without submitting.\n const backdrop = document.createElement('div')\n backdrop.className = 'kywi-selfid-backdrop'\n backdrop.addEventListener('click', () => dismiss(container))\n ;(container.parentElement ?? document.body).appendChild(backdrop)\n cleanups.push(() => backdrop.remove())\n\n const previousOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n cleanups.push(() => { document.body.style.overflow = previousOverflow })\n\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') { e.preventDefault(); dismiss(container); return }\n if (e.key === 'Tab') trapTab(container, e)\n }\n document.addEventListener('keydown', onKeydown, true)\n cleanups.push(() => document.removeEventListener('keydown', onKeydown, true))\n\n container.setAttribute('role', 'dialog')\n container.setAttribute('aria-modal', 'true')\n if (config.headline) {\n container.setAttribute('aria-labelledby', MODAL_LABEL_ID)\n } else {\n container.setAttribute('aria-label', 'Personalize your experience')\n }\n container.tabIndex = -1\n }\n\n if (displayMode === 'hello_bar_top') {\n // Offset hook (#106): hosts push their own content down with\n // `body.kywi-selfid-hello-bar-top-open` and/or the measured height in\n // `--kywi-selfid-hello-bar-height` \u2014 no hardcoded header height anywhere.\n document.body.classList.add(HELLO_BAR_TOP_CLASS)\n const syncHeight = () => {\n document.documentElement.style.setProperty(HELLO_BAR_HEIGHT_PROPERTY, `${container.offsetHeight}px`)\n }\n window.addEventListener('resize', syncHeight)\n cleanups.push(() => {\n document.body.classList.remove(HELLO_BAR_TOP_CLASS)\n document.documentElement.style.removeProperty(HELLO_BAR_HEIGHT_PROPERTY)\n window.removeEventListener('resize', syncHeight)\n })\n // Measured once the card's children exist (i.e. after render() returns).\n queueMicrotask(syncHeight)\n }\n\n if (DISMISSIBLE_MODES.has(displayMode)) {\n const dismissBtn = document.createElement('button')\n dismissBtn.type = 'button'\n dismissBtn.className = 'kywi-selfid-dismiss'\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n dismissBtn.textContent = '\u00D7'\n dismissBtn.addEventListener('click', () => dismiss(container))\n container.appendChild(dismissBtn)\n }\n\n if (config.headline) {\n const h = document.createElement('h3')\n h.className = 'kywi-selfid-headline'\n h.textContent = config.headline\n if (isModal) h.id = MODAL_LABEL_ID\n container.appendChild(h)\n }\n\n if (config.subheadline) {\n const p = document.createElement('p')\n p.className = 'kywi-selfid-subheadline'\n p.textContent = config.subheadline\n container.appendChild(p)\n }\n\n const form = document.createElement('form')\n form.className = 'kywi-selfid-form'\n\n for (const field of config.fields) {\n const fieldWrap = document.createElement('div')\n fieldWrap.className = 'kywi-selfid-field'\n\n const label = document.createElement('label')\n label.htmlFor = `kywi-field-${field.id}`\n label.textContent = field.label\n fieldWrap.appendChild(label)\n\n let input: HTMLInputElement | HTMLSelectElement\n\n if (field.type === 'select') {\n const select = document.createElement('select')\n select.id = `kywi-field-${field.id}`\n select.name = field.id\n if (field.required) select.required = true\n if (field.options) {\n const placeholder = document.createElement('option')\n placeholder.value = ''\n placeholder.textContent = ''\n select.appendChild(placeholder)\n for (const opt of field.options) {\n const { value, label } = normalizeOption(opt)\n const option = document.createElement('option')\n option.value = value\n option.textContent = label\n select.appendChild(option)\n }\n }\n input = select\n } else {\n const inp = document.createElement('input')\n inp.id = `kywi-field-${field.id}`\n inp.name = field.id\n inp.type = field.type\n if (field.required) inp.required = true\n input = inp\n }\n\n fieldWrap.appendChild(input)\n form.appendChild(fieldWrap)\n }\n\n const actions = document.createElement('div')\n actions.className = 'kywi-selfid-actions'\n\n const submitBtn = document.createElement('button')\n submitBtn.type = 'submit'\n submitBtn.className = 'kywi-selfid-submit'\n submitBtn.textContent = config.submitLabel ?? 'Submit'\n actions.appendChild(submitBtn)\n\n if (config.skipLabel) {\n const skipBtn = document.createElement('button')\n skipBtn.type = 'button'\n skipBtn.className = 'kywi-selfid-skip'\n skipBtn.textContent = config.skipLabel\n skipBtn.addEventListener('click', () => dismiss(container))\n actions.appendChild(skipBtn)\n }\n\n form.appendChild(actions)\n\n form.addEventListener('submit', (e) => {\n e.preventDefault()\n const data = new FormData(form)\n const responses: Record<string, string> = {}\n data.forEach((value, key) => {\n responses[key] = String(value)\n })\n handleSubmit(responses)\n // An overlay must not stay on screen over the freshly personalized page \u2014\n // and for the modal, leaving it up would also leave the scroll lock on.\n if (OVERLAY_MODES.has(displayMode)) teardown(container)\n })\n\n container.appendChild(form)\n\n if (isModal) container.focus()\n }\n\n return { shouldShow, markShown, render, handleSubmit }\n}\n", "// packages/kywi-js/src/personalization/badge.ts\n//\n// The `personalizationBadge` layout module's runtime half (#107). It is a\n// PASSIVE status pill \u2014 \"Personalization active/off\", plus the audience name\n// when there is one \u2014 that opens the global transparency panel on click. It\n// deliberately embeds no opt-in/opt-out controls of its own: opting out and\n// switching audience live in exactly one surface (see audience/transparency.ts),\n// so a badge placed on a page can never disagree with the global panel.\n\nimport { COOKIE_NAMES, readCookies } from '../cookies.js'\nimport { openTransparencyPanel } from '../audience/transparency.js'\n\nexport interface PersonalizationBadgeInfo {\n /** The audience the page was personalized for, if any. */\n audienceName?: string | null\n}\n\nfunction isOptedOut(): boolean {\n return readCookies().has(COOKIE_NAMES.OPTOUT)\n}\n\nexport function renderPersonalizationBadge(info: PersonalizationBadgeInfo = {}): void {\n const containers = document.querySelectorAll('[data-kywi-personalization-badge]')\n if (containers.length === 0) return\n\n const optedOut = isOptedOut()\n\n for (const container of Array.from(containers)) {\n // Clear existing badge to avoid duplication\n container.querySelector('.kywi-personalization-badge')?.remove()\n\n const badge = document.createElement('div')\n badge.className = 'kywi-personalization-badge'\n\n const trigger = document.createElement('button')\n trigger.type = 'button'\n trigger.className = 'kywi-badge-open'\n trigger.setAttribute('aria-label', 'Personalization details')\n\n const status = document.createElement('span')\n status.className = 'kywi-badge-status'\n status.textContent = optedOut ? 'Personalization off' : 'Personalization active'\n trigger.appendChild(status)\n\n if (!optedOut && info.audienceName) {\n const audience = document.createElement('span')\n audience.className = 'kywi-badge-audience'\n audience.textContent = info.audienceName\n trigger.appendChild(audience)\n }\n\n trigger.addEventListener('click', () => openTransparencyPanel())\n badge.appendChild(trigger)\n container.appendChild(badge)\n }\n}\n", "// packages/kywi-js/src/audience/index.ts\nimport type { Audience, VisitorSignals } from '@kywi-software/core/audiences/types'\nimport { evaluateClientSide } from './evaluate.js'\nimport { patchVariantContainers } from './dom-patcher.js'\nimport { renderTransparencyPanel } from './transparency.js'\nimport { checkPreviewInit, getPreviewAudienceId, renderPreviewBanner } from './preview.js'\nimport { populateDataLayer, fireKywiReady, readServerMeta } from './data-layer.js'\nimport { readCookies, COOKIE_NAMES } from '../cookies.js'\nimport { runClientAdapters } from './adapter-runner.js'\nimport { Kywi } from '../index.js'\nimport { createSelfIdWidget, resolveSelfIdMount, type SelfIdWidgetConfig } from './selfid-widget.js'\nimport { renderPersonalizationBadge } from '../personalization/badge.js'\n\nexport interface AudienceBootConfig {\n audiences: Audience[]\n currentPath: string\n pageCategory?: string\n serverSignals?: Partial<VisitorSignals>\n adapters?: Array<{ id: string; side: 'client' | 'server-proxy'; fields: string[]; collect: (s: Partial<VisitorSignals>) => Promise<Record<string, unknown>> }>\n selfIdWidget?: SelfIdWidgetConfig\n /**\n * Base path of the mounted CMS API (e.g. `/api/v1`). Runtime calls\n * (server-proxy adapters, audience assignment) are made under `{apiBase}/kywi/*`.\n * Defaults to the same `{basePath}/api/v1` derivation the entity/feed factories\n * use, so it matches the reference app's mount out of the box.\n */\n apiBase?: string\n /**\n * `personalization.transparencyNotice.enabled`. When false, the global\n * transparency surface never appears on its own \u2014 the visitor can still open\n * it deliberately through a `personalizationBadge` module. Defaults to true;\n * the host page passes the resolved config value through.\n */\n transparencyNotice?: boolean\n}\n\n/** The mounted CMS API base \u2014 mirrors the derivation in Kywi.boot(). */\nfunction resolveApiBase(explicit?: string): string {\n if (explicit) return explicit\n const basePath = Kywi.context?.basePath\n if (!basePath || basePath === '/') return '/api/v1'\n return `${basePath}/api/v1`\n}\n\nexport async function bootAudienceEngine(config: AudienceBootConfig): Promise<void> {\n const { audiences, currentPath, pageCategory, serverSignals } = config\n const apiBase = resolveApiBase(config.apiBase)\n checkPreviewInit()\n const serverMeta = readServerMeta()\n const previewId = getPreviewAudienceId()\n\n // Audiences the visitor can be shown as \u2014 the switcher's option list and the\n // lookup that turns a resolved audience id into a name the visitor recognizes.\n const activeAudiences = audiences\n .filter((a) => a.status === 'active')\n .map((a) => ({ id: a.id, name: a.name }))\n const nameOf = (id: string | null): string | null =>\n id ? activeAudiences.find((a) => a.id === id)?.name ?? null : null\n\n if (previewId) {\n patchVariantContainers(previewId)\n // Show the audience's name, falling back to the raw id for an audience that\n // is not in this page's list (e.g. previewing a draft audience).\n renderPreviewBanner(nameOf(previewId) ?? previewId)\n renderPersonalizationBadge({ audienceName: nameOf(previewId) })\n populateDataLayer({ visitorId: serverMeta.visitorId, audienceId: previewId, experimentId: null, variantId: null, isPreview: true, isOptedOut: false })\n fireKywiReady()\n return\n }\n\n const cookies = readCookies()\n let merged: Partial<VisitorSignals> = {\n ...serverSignals,\n identity: { visitorId: serverMeta.visitorId || cookies.get(COOKIE_NAMES.VISITOR) || '', isKnown: cookies.has(COOKIE_NAMES.KNOWN), maLeadId: null },\n meta: { isOptedOut: cookies.has(COOKIE_NAMES.OPTOUT), isPreview: false, previewAudienceId: null, resolvedAt: 'server' },\n }\n\n // Run client-side adapters if configured\n if (config.adapters && config.adapters.length > 0) {\n const adapterResults = await runClientAdapters(config.adapters, merged, apiBase)\n merged.adapters = { ...merged.adapters, ...adapterResults }\n }\n\n const result = evaluateClientSide(audiences, merged, currentPath, pageCategory)\n\n // A manual pin (kywi_audience \u2014 written by the transparency panel's switcher,\n // or by this boot path persisting a client-resolved audience) beats signal\n // resolution, matching the server engine's precedence. Without this the client\n // would re-resolve from signals and immediately overwrite the visitor's own\n // choice on the very next page view.\n const pinnedId = cookies.get(COOKIE_NAMES.AUDIENCE) ?? null\n const isPinned = !result.isOptedOut && pinnedId !== null && activeAudiences.some((a) => a.id === pinnedId)\n const effectiveAudienceId = isPinned ? pinnedId : result.winningAudienceId\n\n patchVariantContainers(effectiveAudienceId)\n renderTransparencyPanel({\n isPersonalized: effectiveAudienceId !== null,\n isOptedOut: result.isOptedOut,\n hasMatchAvailable: result.allMatchedIds.length > 0,\n audienceId: effectiveAudienceId,\n audiences: activeAudiences,\n apiBase,\n csrfToken: Kywi.context?.csrfToken ?? null,\n enabled: config.transparencyNotice !== false,\n })\n // Render the status pill wherever a personalizationBadge module was placed.\n renderPersonalizationBadge({ audienceName: nameOf(effectiveAudienceId) })\n populateDataLayer({ visitorId: result.signals.identity.visitorId, audienceId: effectiveAudienceId, experimentId: serverMeta.experimentId, variantId: serverMeta.variantId, isPreview: false, isOptedOut: result.isOptedOut })\n fireKywiReady()\n\n if (!isPinned && result.winningAudienceId && result.winningAudienceId !== serverMeta.audienceId) {\n fetch(`${apiBase}/kywi/audience`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(Kywi.context?.csrfToken ? { 'X-CSRF-Token': Kywi.context.csrfToken } : {}) },\n body: JSON.stringify({ audienceId: result.winningAudienceId }),\n }).catch(() => {})\n }\n\n // Self-ID widget \u2014 mount when frequency allows, timed by its trigger.\n if (config.selfIdWidget) {\n const widget = createSelfIdWidget(config.selfIdWidget)\n if (widget.shouldShow()) {\n const doRender = () => {\n // Inline mode renders into the host's own slot when one is declared\n // ([data-kywi-selfid-mount]); otherwise it falls back to the runtime's\n // container at the end of <body>, like the overlay modes.\n const mount = resolveSelfIdMount(config.selfIdWidget!.displayMode)\n if (mount) { widget.render(mount); return }\n const existing = document.getElementById('kywi-selfid-container')\n const container = existing ?? document.createElement('div')\n if (!container.id) {\n container.id = 'kywi-selfid-container'\n document.body.appendChild(container)\n }\n widget.render(container)\n }\n scheduleSelfIdWidget(config.selfIdWidget.trigger, doRender)\n }\n }\n}\n\n/**\n * Show the self-ID widget per its trigger: immediately, after a delay, or once\n * the visitor scrolls past a depth fraction (0-1). `manual` never auto-shows \u2014\n * the host page decides. An absent trigger behaves as immediate.\n */\nfunction scheduleSelfIdWidget(trigger: SelfIdWidgetConfig['trigger'], render: () => void): void {\n if (!trigger || trigger.type === 'immediate') { render(); return }\n if (trigger.type === 'manual') return\n if (trigger.type === 'delay') {\n window.setTimeout(render, Math.max(0, trigger.seconds) * 1000)\n return\n }\n // scroll: fire once when scrolled past `depth` (fraction of scrollable height).\n const target = Math.min(Math.max(trigger.depth, 0), 1)\n let fired = false\n const onScroll = () => {\n if (fired) return\n const scrollable = document.documentElement.scrollHeight - window.innerHeight\n const progress = scrollable > 0 ? window.scrollY / scrollable : 1\n if (progress >= target) {\n fired = true\n window.removeEventListener('scroll', onScroll)\n render()\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n onScroll()\n}\n", "// packages/kywi-js/src/index.ts\nimport type { KywiContext, KywiModuleDefinition } from './types.js'\nimport { readContext } from './context.js'\nimport { createEntityFactory } from './entity.js'\nimport { createFeedFactory } from './feed.js'\nimport { renderFeed } from './render-feed.js'\nimport { initModules } from './module-system.js'\nimport { initFormHooks } from './form-hooks.js'\nimport { initNavMenus } from './nav/menu.js'\nimport { bootExperiments } from './experiments/index.js'\n\ntype PreInitCallback = (kywi: typeof Kywi) => void\nconst preInitCallbacks: PreInitCallback[] = []\nlet booted = false\n\nexport const Kywi = {\n version: '0.1.0',\n context: null as unknown as KywiContext,\n Module: {} as Record<string, KywiModuleDefinition>,\n preInit(fn: PreInitCallback): void {\n if (booted) { fn(Kywi) } else { preInitCallbacks.push(fn) }\n },\n UI: {\n extend(definition: KywiModuleDefinition): KywiModuleDefinition {\n return { ...definition }\n },\n },\n DisplayObject: {\n Form: {\n _hooks: {} as Record<string, (...args: unknown[]) => unknown>,\n extend(methods: Record<string, (...args: unknown[]) => unknown>): void {\n Object.assign(Kywi.DisplayObject.Form._hooks, methods)\n },\n },\n },\n getEntity: null as unknown as (type: string) => any,\n getFeed: null as unknown as (type: string) => any,\n renderFeed: null as unknown as (options: any) => void,\n boot(): void {\n if (booted) return\n Kywi.context = readContext()\n for (const fn of preInitCallbacks) { fn(Kywi) }\n const basePath = Kywi.context.basePath === '/' ? '/api/v1' : `${Kywi.context.basePath}/api/v1`\n Kywi.getEntity = createEntityFactory(basePath, Kywi.context.csrfToken)\n Kywi.getFeed = createFeedFactory(basePath, Kywi.context.csrfToken)\n Kywi.renderFeed = renderFeed\n initModules()\n initFormHooks()\n // Nav modules render fully usable without JS; this layers hover intent,\n // Escape/arrow keys and viewport-edge flipping on top (kywi-cms#111).\n initNavMenus()\n // A/B experiment beacons: confirm exposure of the server-rendered variant\n // and wire conversion signals (pageview / form-submit / kywi.track).\n bootExperiments({ context: Kywi.context })\n booted = true\n },\n}\n\nif (typeof globalThis !== 'undefined') { (globalThis as any).Kywi = Kywi }\nif (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => Kywi.boot())\n } else {\n Kywi.boot()\n }\n}\n\nexport { bootAudienceEngine } from './audience/index.js'\nexport {\n openTransparencyPanel,\n renderTransparencyPanel,\n type TransparencyState,\n type TransparencyAudience,\n} from './audience/transparency.js'\nexport { bootExperiments, type ExperimentRuntime, type ConversionSignal } from './experiments/index.js'\nexport { initNavMenus, enhanceNav, NAV_BREAKPOINT } from './nav/menu.js'\n"],
5
+ "mappings": "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",
6
6
  "names": ["isOptedOut", "audienceName", "label"]
7
7
  }