@kywi-software/js 0.6.0 → 0.6.2
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,3 +1,4 @@
|
|
|
1
|
+
import type { Audience } from '@kywi-software/core/audiences/types';
|
|
1
2
|
export interface SelfIdFieldConfig {
|
|
2
3
|
id: string;
|
|
3
4
|
label: string;
|
|
@@ -26,7 +27,13 @@ export interface SelfIdWidgetConfig {
|
|
|
26
27
|
displayMode?: 'modal' | 'inline' | 'slide-in';
|
|
27
28
|
frequency?: 'once' | 'session' | 'daily' | 'always';
|
|
28
29
|
trigger?: SelfIdWidgetTrigger;
|
|
29
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The full audience rule definitions to re-evaluate client-side after a
|
|
32
|
+
* submission. These flow straight into `handleSelfIdSubmit` →
|
|
33
|
+
* `evaluateClientSide` → `resolveAudiences`, which iterates each audience's
|
|
34
|
+
* `conditionGroups`, so full `Audience` objects are required (not id strings).
|
|
35
|
+
*/
|
|
36
|
+
audiences?: Audience[];
|
|
30
37
|
currentPath?: string;
|
|
31
38
|
}
|
|
32
39
|
export interface SelfIdWidget {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selfid-widget.d.ts","sourceRoot":"","sources":["../../src/audience/selfid-widget.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"selfid-widget.d.ts","sourceRoot":"","sources":["../../src/audience/selfid-widget.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAA;AAKnE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,8EAA8E;AAC9E,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAEtB,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC7C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;IACnD,OAAO,CAAC,EAAE,mBAAmB,CAAA;IAC7B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,IAAI,OAAO,CAAA;IACrB,SAAS,IAAI,IAAI,CAAA;IACjB,MAAM,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAA;IACpC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;CACtD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAuI3E"}
|
package/dist/kywi.esm.js
CHANGED
|
@@ -1032,8 +1032,11 @@ function createSelfIdWidget(config) {
|
|
|
1032
1032
|
}
|
|
1033
1033
|
function handleSubmit(responses) {
|
|
1034
1034
|
storeSelfId(responses);
|
|
1035
|
-
|
|
1036
|
-
|
|
1035
|
+
try {
|
|
1036
|
+
handleSelfIdSubmit(responses, config.audiences ?? [], config.currentPath ?? "/");
|
|
1037
|
+
} finally {
|
|
1038
|
+
markShown();
|
|
1039
|
+
}
|
|
1037
1040
|
}
|
|
1038
1041
|
function render(container) {
|
|
1039
1042
|
container.replaceChildren();
|
package/dist/kywi.esm.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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-styles.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'\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 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 Array.from(el.querySelectorAll('[data-kywi-variant]'))) {\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-styles.ts\n//\n// The transparency bar is injected into arbitrary host sites (any theme, any\n// reset, any CSS framework), so it can never rely on the host page shipping\n// `.kywi-transparency-*` rules \u2014 it has to carry its own, self-contained,\n// namespaced styles. This module injects a single `<style>` tag into\n// `<head>` the first time the bar is rendered and is a no-op after that.\n\nconst STYLE_ELEMENT_ID = 'kywi-transparency-styles'\n\nconst CSS = `\n.kywi-transparency-bar,\n.kywi-transparency-bar * {\n box-sizing: border-box;\n}\n.kywi-transparency-bar {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2147483000;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin: 0;\n padding: 12px 16px;\n background: rgba(23, 23, 28, 0.96);\n color: #f4f4f5;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n border-top: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.25);\n animation: kywi-transparency-in 220ms ease-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .kywi-transparency-bar { animation: none; }\n}\n@keyframes kywi-transparency-in {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.kywi-transparency-text {\n flex: 1 1 240px;\n color: #f4f4f5;\n}\n.kywi-transparency-bar button {\n appearance: none;\n -webkit-appearance: none;\n font-family: inherit;\n font-size: 12px;\n line-height: 1.4;\n cursor: pointer;\n border-radius: 999px;\n transition: background 120ms ease, border-color 120ms ease, color 120ms ease;\n}\n.kywi-transparency-opt-out,\n.kywi-transparency-opt-in {\n flex: 0 0 auto;\n padding: 6px 14px;\n border: 1px solid rgba(255, 255, 255, 0.35);\n background: transparent;\n color: #f4f4f5;\n font-weight: 600;\n}\n.kywi-transparency-opt-out:hover,\n.kywi-transparency-opt-in:hover {\n background: rgba(255, 255, 255, 0.12);\n border-color: rgba(255, 255, 255, 0.5);\n}\n.kywi-transparency-dismiss {\n flex: 0 0 auto;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 1px solid transparent;\n background: transparent;\n color: #d4d4d8;\n font-size: 13px;\n}\n.kywi-transparency-dismiss:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #f4f4f5;\n}\n.kywi-transparency-bar button:focus-visible {\n outline: 2px solid #7dd3fc;\n outline-offset: 2px;\n}\n@media (max-width: 480px) {\n .kywi-transparency-bar {\n padding: 10px 12px;\n }\n .kywi-transparency-text {\n flex-basis: 100%;\n }\n}\n`\n\n/** Injects the transparency bar's stylesheet into `<head>` exactly once. */\nexport function ensureTransparencyStyles(): void {\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ELEMENT_ID)) return\n const style = document.createElement('style')\n style.id = STYLE_ELEMENT_ID\n style.textContent = CSS\n document.head.appendChild(style)\n}\n", "// packages/kywi-js/src/audience/transparency.ts\nimport { COOKIE_NAMES, setCookie, deleteCookie } from '../cookies.js'\nimport { ensureTransparencyStyles } from './transparency-styles.js'\n\nconst DISMISSED_KEY = 'kywi_transparency_dismissed'\n\nexport function isDismissed(): boolean { return localStorage.getItem(DISMISSED_KEY) === '1' }\nexport function dismiss(): void { localStorage.setItem(DISMISSED_KEY, '1'); removeBar() }\n\nfunction removeBar(): void { document.querySelector('.kywi-transparency-bar')?.remove() }\n\nexport function optOut(): void { setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600); deleteCookie(COOKIE_NAMES.AUDIENCE) }\nexport function optIn(): void { deleteCookie(COOKIE_NAMES.OPTOUT) }\n\ninterface TransparencyState { isPersonalized: boolean; isOptedOut: boolean; hasMatchAvailable: boolean }\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderTransparencyBar(state: TransparencyState): void {\n removeBar()\n if (isDismissed()) return\n\n if ((state.isPersonalized && !state.isOptedOut) || (state.isOptedOut && state.hasMatchAvailable)) {\n ensureTransparencyStyles()\n }\n\n if (state.isPersonalized && !state.isOptedOut) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-active'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'This page has been personalized based on your browsing context.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-out', 'Opt out', () => { optOut(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n } else if (state.isOptedOut && state.hasMatchAvailable) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-opted-out'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'A personalized experience is available.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-in', 'Enable', () => { optIn(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n }\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'\n\nconst SHOWN_KEY = 'kywi_selfid_shown'\nconst MS_PER_DAY = 86_400_000\n\nexport interface SelfIdFieldConfig {\n id: string\n label: string\n type: 'text' | 'select' | 'email'\n options?: string[]\n required?: boolean\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'\n frequency?: 'once' | 'session' | 'daily' | 'always'\n trigger?: SelfIdWidgetTrigger\n audiences?: string[]\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\nexport function createSelfIdWidget(config: SelfIdWidgetConfig): SelfIdWidget {\n const frequency = config.frequency ?? 'once'\n const displayMode = config.displayMode ?? 'inline'\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 // FIXME (pre-existing, discovered while adding a declaration build to this\n // package): `config.audiences` is a list of audience IDs (see\n // apps/reference/components/personalization-runtime.tsx, which builds it\n // via `audiences.map(a => a.id)`), but `handleSelfIdSubmit` declares its\n // second parameter as `Audience[]` (full rule definitions) and passes it\n // straight into `evaluateClientSide` \u2192 `resolveAudiences`, which needs the\n // full objects to match rules. As written, client-side re-evaluation after\n // a self-ID submission can't actually match audiences by rule \u2014 this cast\n // only silences the type mismatch to match the real (ID-only) call site;\n // it does not fix the underlying re-evaluation gap.\n handleSelfIdSubmit(responses, (config.audiences ?? []) as unknown as Parameters<typeof handleSelfIdSubmit>[1], config.currentPath ?? '/')\n markShown()\n }\n\n function render(container: HTMLElement): void {\n container.replaceChildren()\n container.className = `kywi-selfid-widget kywi-selfid-${displayMode}`\n\n if (config.headline) {\n const h = document.createElement('h3')\n h.className = 'kywi-selfid-headline'\n h.textContent = config.headline\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 option = document.createElement('option')\n option.value = opt\n option.textContent = opt\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', () => {\n markShown()\n container.replaceChildren()\n })\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 })\n\n container.appendChild(form)\n }\n\n return { shouldShow, markShown, render, handleSubmit }\n}\n", "// packages/kywi-js/src/personalization/badge.ts\nimport { COOKIE_NAMES, readCookies, setCookie, deleteCookie } from '../cookies.js'\n\nfunction isOptedOut(): boolean {\n return readCookies().has(COOKIE_NAMES.OPTOUT)\n}\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderPersonalizationBadge(): void {\n const containers = document.querySelectorAll('[data-kywi-personalization-badge]')\n if (containers.length === 0) return\n\n for (const container of Array.from(containers)) {\n // Clear existing badge to avoid duplication\n const existing = container.querySelector('.kywi-personalization-badge')\n if (existing) existing.remove()\n\n const badge = document.createElement('div')\n badge.className = 'kywi-personalization-badge'\n\n const optedOut = isOptedOut()\n\n const status = document.createElement('span')\n status.className = 'kywi-badge-status'\n status.textContent = optedOut ? 'Personalization disabled' : 'Personalization active'\n badge.appendChild(status)\n\n if (optedOut) {\n badge.appendChild(createButton('kywi-badge-opt-in', 'Opt in', () => {\n deleteCookie(COOKIE_NAMES.OPTOUT)\n renderPersonalizationBadge()\n }))\n } else {\n badge.appendChild(createButton('kywi-badge-opt-out', 'Opt out', () => {\n setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600)\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n renderPersonalizationBadge()\n }))\n }\n\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 { renderTransparencyBar } 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, 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\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 if (previewId) {\n patchVariantContainers(previewId)\n renderPreviewBanner(previewId)\n renderPersonalizationBadge()\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 patchVariantContainers(result.winningAudienceId)\n renderTransparencyBar({ isPersonalized: result.winningAudienceId !== null, isOptedOut: result.isOptedOut, hasMatchAvailable: result.allMatchedIds.length > 0 })\n // Render the opt-out badge wherever a personalizationBadge module was placed.\n renderPersonalizationBadge()\n populateDataLayer({ visitorId: result.signals.identity.visitorId, audienceId: result.winningAudienceId, experimentId: serverMeta.experimentId, variantId: serverMeta.variantId, isPreview: false, isOptedOut: result.isOptedOut })\n fireKywiReady()\n\n if (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 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 { bootExperiments, type ExperimentRuntime, type ConversionSignal } from './experiments/index.js'\n"],
|
|
5
|
-
"mappings": "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",
|
|
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'\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 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 Array.from(el.querySelectorAll('[data-kywi-variant]'))) {\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-styles.ts\n//\n// The transparency bar is injected into arbitrary host sites (any theme, any\n// reset, any CSS framework), so it can never rely on the host page shipping\n// `.kywi-transparency-*` rules \u2014 it has to carry its own, self-contained,\n// namespaced styles. This module injects a single `<style>` tag into\n// `<head>` the first time the bar is rendered and is a no-op after that.\n\nconst STYLE_ELEMENT_ID = 'kywi-transparency-styles'\n\nconst CSS = `\n.kywi-transparency-bar,\n.kywi-transparency-bar * {\n box-sizing: border-box;\n}\n.kywi-transparency-bar {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2147483000;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin: 0;\n padding: 12px 16px;\n background: rgba(23, 23, 28, 0.96);\n color: #f4f4f5;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n border-top: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.25);\n animation: kywi-transparency-in 220ms ease-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .kywi-transparency-bar { animation: none; }\n}\n@keyframes kywi-transparency-in {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.kywi-transparency-text {\n flex: 1 1 240px;\n color: #f4f4f5;\n}\n.kywi-transparency-bar button {\n appearance: none;\n -webkit-appearance: none;\n font-family: inherit;\n font-size: 12px;\n line-height: 1.4;\n cursor: pointer;\n border-radius: 999px;\n transition: background 120ms ease, border-color 120ms ease, color 120ms ease;\n}\n.kywi-transparency-opt-out,\n.kywi-transparency-opt-in {\n flex: 0 0 auto;\n padding: 6px 14px;\n border: 1px solid rgba(255, 255, 255, 0.35);\n background: transparent;\n color: #f4f4f5;\n font-weight: 600;\n}\n.kywi-transparency-opt-out:hover,\n.kywi-transparency-opt-in:hover {\n background: rgba(255, 255, 255, 0.12);\n border-color: rgba(255, 255, 255, 0.5);\n}\n.kywi-transparency-dismiss {\n flex: 0 0 auto;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 1px solid transparent;\n background: transparent;\n color: #d4d4d8;\n font-size: 13px;\n}\n.kywi-transparency-dismiss:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #f4f4f5;\n}\n.kywi-transparency-bar button:focus-visible {\n outline: 2px solid #7dd3fc;\n outline-offset: 2px;\n}\n@media (max-width: 480px) {\n .kywi-transparency-bar {\n padding: 10px 12px;\n }\n .kywi-transparency-text {\n flex-basis: 100%;\n }\n}\n`\n\n/** Injects the transparency bar's stylesheet into `<head>` exactly once. */\nexport function ensureTransparencyStyles(): void {\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ELEMENT_ID)) return\n const style = document.createElement('style')\n style.id = STYLE_ELEMENT_ID\n style.textContent = CSS\n document.head.appendChild(style)\n}\n", "// packages/kywi-js/src/audience/transparency.ts\nimport { COOKIE_NAMES, setCookie, deleteCookie } from '../cookies.js'\nimport { ensureTransparencyStyles } from './transparency-styles.js'\n\nconst DISMISSED_KEY = 'kywi_transparency_dismissed'\n\nexport function isDismissed(): boolean { return localStorage.getItem(DISMISSED_KEY) === '1' }\nexport function dismiss(): void { localStorage.setItem(DISMISSED_KEY, '1'); removeBar() }\n\nfunction removeBar(): void { document.querySelector('.kywi-transparency-bar')?.remove() }\n\nexport function optOut(): void { setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600); deleteCookie(COOKIE_NAMES.AUDIENCE) }\nexport function optIn(): void { deleteCookie(COOKIE_NAMES.OPTOUT) }\n\ninterface TransparencyState { isPersonalized: boolean; isOptedOut: boolean; hasMatchAvailable: boolean }\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderTransparencyBar(state: TransparencyState): void {\n removeBar()\n if (isDismissed()) return\n\n if ((state.isPersonalized && !state.isOptedOut) || (state.isOptedOut && state.hasMatchAvailable)) {\n ensureTransparencyStyles()\n }\n\n if (state.isPersonalized && !state.isOptedOut) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-active'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'This page has been personalized based on your browsing context.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-out', 'Opt out', () => { optOut(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n } else if (state.isOptedOut && state.hasMatchAvailable) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-opted-out'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'A personalized experience is available.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-in', 'Enable', () => { optIn(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n }\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\nexport interface SelfIdFieldConfig {\n id: string\n label: string\n type: 'text' | 'select' | 'email'\n options?: string[]\n required?: boolean\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'\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\nexport function createSelfIdWidget(config: SelfIdWidgetConfig): SelfIdWidget {\n const frequency = config.frequency ?? 'once'\n const displayMode = config.displayMode ?? 'inline'\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 function render(container: HTMLElement): void {\n container.replaceChildren()\n container.className = `kywi-selfid-widget kywi-selfid-${displayMode}`\n\n if (config.headline) {\n const h = document.createElement('h3')\n h.className = 'kywi-selfid-headline'\n h.textContent = config.headline\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 option = document.createElement('option')\n option.value = opt\n option.textContent = opt\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', () => {\n markShown()\n container.replaceChildren()\n })\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 })\n\n container.appendChild(form)\n }\n\n return { shouldShow, markShown, render, handleSubmit }\n}\n", "// packages/kywi-js/src/personalization/badge.ts\nimport { COOKIE_NAMES, readCookies, setCookie, deleteCookie } from '../cookies.js'\n\nfunction isOptedOut(): boolean {\n return readCookies().has(COOKIE_NAMES.OPTOUT)\n}\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderPersonalizationBadge(): void {\n const containers = document.querySelectorAll('[data-kywi-personalization-badge]')\n if (containers.length === 0) return\n\n for (const container of Array.from(containers)) {\n // Clear existing badge to avoid duplication\n const existing = container.querySelector('.kywi-personalization-badge')\n if (existing) existing.remove()\n\n const badge = document.createElement('div')\n badge.className = 'kywi-personalization-badge'\n\n const optedOut = isOptedOut()\n\n const status = document.createElement('span')\n status.className = 'kywi-badge-status'\n status.textContent = optedOut ? 'Personalization disabled' : 'Personalization active'\n badge.appendChild(status)\n\n if (optedOut) {\n badge.appendChild(createButton('kywi-badge-opt-in', 'Opt in', () => {\n deleteCookie(COOKIE_NAMES.OPTOUT)\n renderPersonalizationBadge()\n }))\n } else {\n badge.appendChild(createButton('kywi-badge-opt-out', 'Opt out', () => {\n setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600)\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n renderPersonalizationBadge()\n }))\n }\n\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 { renderTransparencyBar } 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, 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\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 if (previewId) {\n patchVariantContainers(previewId)\n renderPreviewBanner(previewId)\n renderPersonalizationBadge()\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 patchVariantContainers(result.winningAudienceId)\n renderTransparencyBar({ isPersonalized: result.winningAudienceId !== null, isOptedOut: result.isOptedOut, hasMatchAvailable: result.allMatchedIds.length > 0 })\n // Render the opt-out badge wherever a personalizationBadge module was placed.\n renderPersonalizationBadge()\n populateDataLayer({ visitorId: result.signals.identity.visitorId, audienceId: result.winningAudienceId, experimentId: serverMeta.experimentId, variantId: serverMeta.variantId, isPreview: false, isOptedOut: result.isOptedOut })\n fireKywiReady()\n\n if (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 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 { bootExperiments, type ExperimentRuntime, type ConversionSignal } from './experiments/index.js'\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["isOptedOut", "createButton"]
|
|
7
7
|
}
|
package/dist/kywi.js
CHANGED
|
@@ -1060,8 +1060,11 @@ var Kywi = (() => {
|
|
|
1060
1060
|
}
|
|
1061
1061
|
function handleSubmit(responses) {
|
|
1062
1062
|
storeSelfId(responses);
|
|
1063
|
-
|
|
1064
|
-
|
|
1063
|
+
try {
|
|
1064
|
+
handleSelfIdSubmit(responses, config.audiences ?? [], config.currentPath ?? "/");
|
|
1065
|
+
} finally {
|
|
1066
|
+
markShown();
|
|
1067
|
+
}
|
|
1065
1068
|
}
|
|
1066
1069
|
function render(container) {
|
|
1067
1070
|
container.replaceChildren();
|
package/dist/kywi.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../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-styles.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"],
|
|
4
|
-
"sourcesContent": ["// 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 { bootExperiments, type ExperimentRuntime, type ConversionSignal } from './experiments/index.js'\n", "// 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'\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 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 Array.from(el.querySelectorAll('[data-kywi-variant]'))) {\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-styles.ts\n//\n// The transparency bar is injected into arbitrary host sites (any theme, any\n// reset, any CSS framework), so it can never rely on the host page shipping\n// `.kywi-transparency-*` rules \u2014 it has to carry its own, self-contained,\n// namespaced styles. This module injects a single `<style>` tag into\n// `<head>` the first time the bar is rendered and is a no-op after that.\n\nconst STYLE_ELEMENT_ID = 'kywi-transparency-styles'\n\nconst CSS = `\n.kywi-transparency-bar,\n.kywi-transparency-bar * {\n box-sizing: border-box;\n}\n.kywi-transparency-bar {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2147483000;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin: 0;\n padding: 12px 16px;\n background: rgba(23, 23, 28, 0.96);\n color: #f4f4f5;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n border-top: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.25);\n animation: kywi-transparency-in 220ms ease-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .kywi-transparency-bar { animation: none; }\n}\n@keyframes kywi-transparency-in {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.kywi-transparency-text {\n flex: 1 1 240px;\n color: #f4f4f5;\n}\n.kywi-transparency-bar button {\n appearance: none;\n -webkit-appearance: none;\n font-family: inherit;\n font-size: 12px;\n line-height: 1.4;\n cursor: pointer;\n border-radius: 999px;\n transition: background 120ms ease, border-color 120ms ease, color 120ms ease;\n}\n.kywi-transparency-opt-out,\n.kywi-transparency-opt-in {\n flex: 0 0 auto;\n padding: 6px 14px;\n border: 1px solid rgba(255, 255, 255, 0.35);\n background: transparent;\n color: #f4f4f5;\n font-weight: 600;\n}\n.kywi-transparency-opt-out:hover,\n.kywi-transparency-opt-in:hover {\n background: rgba(255, 255, 255, 0.12);\n border-color: rgba(255, 255, 255, 0.5);\n}\n.kywi-transparency-dismiss {\n flex: 0 0 auto;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 1px solid transparent;\n background: transparent;\n color: #d4d4d8;\n font-size: 13px;\n}\n.kywi-transparency-dismiss:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #f4f4f5;\n}\n.kywi-transparency-bar button:focus-visible {\n outline: 2px solid #7dd3fc;\n outline-offset: 2px;\n}\n@media (max-width: 480px) {\n .kywi-transparency-bar {\n padding: 10px 12px;\n }\n .kywi-transparency-text {\n flex-basis: 100%;\n }\n}\n`\n\n/** Injects the transparency bar's stylesheet into `<head>` exactly once. */\nexport function ensureTransparencyStyles(): void {\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ELEMENT_ID)) return\n const style = document.createElement('style')\n style.id = STYLE_ELEMENT_ID\n style.textContent = CSS\n document.head.appendChild(style)\n}\n", "// packages/kywi-js/src/audience/transparency.ts\nimport { COOKIE_NAMES, setCookie, deleteCookie } from '../cookies.js'\nimport { ensureTransparencyStyles } from './transparency-styles.js'\n\nconst DISMISSED_KEY = 'kywi_transparency_dismissed'\n\nexport function isDismissed(): boolean { return localStorage.getItem(DISMISSED_KEY) === '1' }\nexport function dismiss(): void { localStorage.setItem(DISMISSED_KEY, '1'); removeBar() }\n\nfunction removeBar(): void { document.querySelector('.kywi-transparency-bar')?.remove() }\n\nexport function optOut(): void { setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600); deleteCookie(COOKIE_NAMES.AUDIENCE) }\nexport function optIn(): void { deleteCookie(COOKIE_NAMES.OPTOUT) }\n\ninterface TransparencyState { isPersonalized: boolean; isOptedOut: boolean; hasMatchAvailable: boolean }\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderTransparencyBar(state: TransparencyState): void {\n removeBar()\n if (isDismissed()) return\n\n if ((state.isPersonalized && !state.isOptedOut) || (state.isOptedOut && state.hasMatchAvailable)) {\n ensureTransparencyStyles()\n }\n\n if (state.isPersonalized && !state.isOptedOut) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-active'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'This page has been personalized based on your browsing context.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-out', 'Opt out', () => { optOut(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n } else if (state.isOptedOut && state.hasMatchAvailable) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-opted-out'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'A personalized experience is available.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-in', 'Enable', () => { optIn(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n }\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'\n\nconst SHOWN_KEY = 'kywi_selfid_shown'\nconst MS_PER_DAY = 86_400_000\n\nexport interface SelfIdFieldConfig {\n id: string\n label: string\n type: 'text' | 'select' | 'email'\n options?: string[]\n required?: boolean\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'\n frequency?: 'once' | 'session' | 'daily' | 'always'\n trigger?: SelfIdWidgetTrigger\n audiences?: string[]\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\nexport function createSelfIdWidget(config: SelfIdWidgetConfig): SelfIdWidget {\n const frequency = config.frequency ?? 'once'\n const displayMode = config.displayMode ?? 'inline'\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 // FIXME (pre-existing, discovered while adding a declaration build to this\n // package): `config.audiences` is a list of audience IDs (see\n // apps/reference/components/personalization-runtime.tsx, which builds it\n // via `audiences.map(a => a.id)`), but `handleSelfIdSubmit` declares its\n // second parameter as `Audience[]` (full rule definitions) and passes it\n // straight into `evaluateClientSide` \u2192 `resolveAudiences`, which needs the\n // full objects to match rules. As written, client-side re-evaluation after\n // a self-ID submission can't actually match audiences by rule \u2014 this cast\n // only silences the type mismatch to match the real (ID-only) call site;\n // it does not fix the underlying re-evaluation gap.\n handleSelfIdSubmit(responses, (config.audiences ?? []) as unknown as Parameters<typeof handleSelfIdSubmit>[1], config.currentPath ?? '/')\n markShown()\n }\n\n function render(container: HTMLElement): void {\n container.replaceChildren()\n container.className = `kywi-selfid-widget kywi-selfid-${displayMode}`\n\n if (config.headline) {\n const h = document.createElement('h3')\n h.className = 'kywi-selfid-headline'\n h.textContent = config.headline\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 option = document.createElement('option')\n option.value = opt\n option.textContent = opt\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', () => {\n markShown()\n container.replaceChildren()\n })\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 })\n\n container.appendChild(form)\n }\n\n return { shouldShow, markShown, render, handleSubmit }\n}\n", "// packages/kywi-js/src/personalization/badge.ts\nimport { COOKIE_NAMES, readCookies, setCookie, deleteCookie } from '../cookies.js'\n\nfunction isOptedOut(): boolean {\n return readCookies().has(COOKIE_NAMES.OPTOUT)\n}\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderPersonalizationBadge(): void {\n const containers = document.querySelectorAll('[data-kywi-personalization-badge]')\n if (containers.length === 0) return\n\n for (const container of Array.from(containers)) {\n // Clear existing badge to avoid duplication\n const existing = container.querySelector('.kywi-personalization-badge')\n if (existing) existing.remove()\n\n const badge = document.createElement('div')\n badge.className = 'kywi-personalization-badge'\n\n const optedOut = isOptedOut()\n\n const status = document.createElement('span')\n status.className = 'kywi-badge-status'\n status.textContent = optedOut ? 'Personalization disabled' : 'Personalization active'\n badge.appendChild(status)\n\n if (optedOut) {\n badge.appendChild(createButton('kywi-badge-opt-in', 'Opt in', () => {\n deleteCookie(COOKIE_NAMES.OPTOUT)\n renderPersonalizationBadge()\n }))\n } else {\n badge.appendChild(createButton('kywi-badge-opt-out', 'Opt out', () => {\n setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600)\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n renderPersonalizationBadge()\n }))\n }\n\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 { renderTransparencyBar } 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, 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\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 if (previewId) {\n patchVariantContainers(previewId)\n renderPreviewBanner(previewId)\n renderPersonalizationBadge()\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 patchVariantContainers(result.winningAudienceId)\n renderTransparencyBar({ isPersonalized: result.winningAudienceId !== null, isOptedOut: result.isOptedOut, hasMatchAvailable: result.allMatchedIds.length > 0 })\n // Render the opt-out badge wherever a personalizationBadge module was placed.\n renderPersonalizationBadge()\n populateDataLayer({ visitorId: result.signals.identity.visitorId, audienceId: result.winningAudienceId, experimentId: serverMeta.experimentId, variantId: serverMeta.variantId, isPreview: false, isOptedOut: result.isOptedOut })\n fireKywiReady()\n\n if (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 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"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["// 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 { bootExperiments, type ExperimentRuntime, type ConversionSignal } from './experiments/index.js'\n", "// 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'\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 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 Array.from(el.querySelectorAll('[data-kywi-variant]'))) {\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-styles.ts\n//\n// The transparency bar is injected into arbitrary host sites (any theme, any\n// reset, any CSS framework), so it can never rely on the host page shipping\n// `.kywi-transparency-*` rules \u2014 it has to carry its own, self-contained,\n// namespaced styles. This module injects a single `<style>` tag into\n// `<head>` the first time the bar is rendered and is a no-op after that.\n\nconst STYLE_ELEMENT_ID = 'kywi-transparency-styles'\n\nconst CSS = `\n.kywi-transparency-bar,\n.kywi-transparency-bar * {\n box-sizing: border-box;\n}\n.kywi-transparency-bar {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2147483000;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 12px;\n margin: 0;\n padding: 12px 16px;\n background: rgba(23, 23, 28, 0.96);\n color: #f4f4f5;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n border-top: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.25);\n animation: kywi-transparency-in 220ms ease-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .kywi-transparency-bar { animation: none; }\n}\n@keyframes kywi-transparency-in {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.kywi-transparency-text {\n flex: 1 1 240px;\n color: #f4f4f5;\n}\n.kywi-transparency-bar button {\n appearance: none;\n -webkit-appearance: none;\n font-family: inherit;\n font-size: 12px;\n line-height: 1.4;\n cursor: pointer;\n border-radius: 999px;\n transition: background 120ms ease, border-color 120ms ease, color 120ms ease;\n}\n.kywi-transparency-opt-out,\n.kywi-transparency-opt-in {\n flex: 0 0 auto;\n padding: 6px 14px;\n border: 1px solid rgba(255, 255, 255, 0.35);\n background: transparent;\n color: #f4f4f5;\n font-weight: 600;\n}\n.kywi-transparency-opt-out:hover,\n.kywi-transparency-opt-in:hover {\n background: rgba(255, 255, 255, 0.12);\n border-color: rgba(255, 255, 255, 0.5);\n}\n.kywi-transparency-dismiss {\n flex: 0 0 auto;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 1px solid transparent;\n background: transparent;\n color: #d4d4d8;\n font-size: 13px;\n}\n.kywi-transparency-dismiss:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #f4f4f5;\n}\n.kywi-transparency-bar button:focus-visible {\n outline: 2px solid #7dd3fc;\n outline-offset: 2px;\n}\n@media (max-width: 480px) {\n .kywi-transparency-bar {\n padding: 10px 12px;\n }\n .kywi-transparency-text {\n flex-basis: 100%;\n }\n}\n`\n\n/** Injects the transparency bar's stylesheet into `<head>` exactly once. */\nexport function ensureTransparencyStyles(): void {\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ELEMENT_ID)) return\n const style = document.createElement('style')\n style.id = STYLE_ELEMENT_ID\n style.textContent = CSS\n document.head.appendChild(style)\n}\n", "// packages/kywi-js/src/audience/transparency.ts\nimport { COOKIE_NAMES, setCookie, deleteCookie } from '../cookies.js'\nimport { ensureTransparencyStyles } from './transparency-styles.js'\n\nconst DISMISSED_KEY = 'kywi_transparency_dismissed'\n\nexport function isDismissed(): boolean { return localStorage.getItem(DISMISSED_KEY) === '1' }\nexport function dismiss(): void { localStorage.setItem(DISMISSED_KEY, '1'); removeBar() }\n\nfunction removeBar(): void { document.querySelector('.kywi-transparency-bar')?.remove() }\n\nexport function optOut(): void { setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600); deleteCookie(COOKIE_NAMES.AUDIENCE) }\nexport function optIn(): void { deleteCookie(COOKIE_NAMES.OPTOUT) }\n\ninterface TransparencyState { isPersonalized: boolean; isOptedOut: boolean; hasMatchAvailable: boolean }\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderTransparencyBar(state: TransparencyState): void {\n removeBar()\n if (isDismissed()) return\n\n if ((state.isPersonalized && !state.isOptedOut) || (state.isOptedOut && state.hasMatchAvailable)) {\n ensureTransparencyStyles()\n }\n\n if (state.isPersonalized && !state.isOptedOut) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-active'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'This page has been personalized based on your browsing context.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-out', 'Opt out', () => { optOut(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n } else if (state.isOptedOut && state.hasMatchAvailable) {\n const bar = document.createElement('div')\n bar.className = 'kywi-transparency-bar kywi-transparency-opted-out'\n bar.setAttribute('role', 'status')\n const text = document.createElement('span')\n text.className = 'kywi-transparency-text'\n text.textContent = 'A personalized experience is available.'\n bar.appendChild(text)\n bar.appendChild(createButton('kywi-transparency-opt-in', 'Enable', () => { optIn(); window.location.reload() }))\n const dismissBtn = createButton('kywi-transparency-dismiss', '\\u2715', () => dismiss())\n dismissBtn.setAttribute('aria-label', 'Dismiss')\n bar.appendChild(dismissBtn)\n document.body.appendChild(bar)\n }\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\nexport interface SelfIdFieldConfig {\n id: string\n label: string\n type: 'text' | 'select' | 'email'\n options?: string[]\n required?: boolean\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'\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\nexport function createSelfIdWidget(config: SelfIdWidgetConfig): SelfIdWidget {\n const frequency = config.frequency ?? 'once'\n const displayMode = config.displayMode ?? 'inline'\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 function render(container: HTMLElement): void {\n container.replaceChildren()\n container.className = `kywi-selfid-widget kywi-selfid-${displayMode}`\n\n if (config.headline) {\n const h = document.createElement('h3')\n h.className = 'kywi-selfid-headline'\n h.textContent = config.headline\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 option = document.createElement('option')\n option.value = opt\n option.textContent = opt\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', () => {\n markShown()\n container.replaceChildren()\n })\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 })\n\n container.appendChild(form)\n }\n\n return { shouldShow, markShown, render, handleSubmit }\n}\n", "// packages/kywi-js/src/personalization/badge.ts\nimport { COOKIE_NAMES, readCookies, setCookie, deleteCookie } from '../cookies.js'\n\nfunction isOptedOut(): boolean {\n return readCookies().has(COOKIE_NAMES.OPTOUT)\n}\n\nfunction createButton(className: string, text: string, onClick: () => void): HTMLButtonElement {\n const btn = document.createElement('button')\n btn.className = className\n btn.type = 'button'\n btn.textContent = text\n btn.addEventListener('click', onClick)\n return btn\n}\n\nexport function renderPersonalizationBadge(): void {\n const containers = document.querySelectorAll('[data-kywi-personalization-badge]')\n if (containers.length === 0) return\n\n for (const container of Array.from(containers)) {\n // Clear existing badge to avoid duplication\n const existing = container.querySelector('.kywi-personalization-badge')\n if (existing) existing.remove()\n\n const badge = document.createElement('div')\n badge.className = 'kywi-personalization-badge'\n\n const optedOut = isOptedOut()\n\n const status = document.createElement('span')\n status.className = 'kywi-badge-status'\n status.textContent = optedOut ? 'Personalization disabled' : 'Personalization active'\n badge.appendChild(status)\n\n if (optedOut) {\n badge.appendChild(createButton('kywi-badge-opt-in', 'Opt in', () => {\n deleteCookie(COOKIE_NAMES.OPTOUT)\n renderPersonalizationBadge()\n }))\n } else {\n badge.appendChild(createButton('kywi-badge-opt-out', 'Opt out', () => {\n setCookie(COOKIE_NAMES.OPTOUT, '1', 365 * 24 * 3600)\n deleteCookie(COOKIE_NAMES.AUDIENCE)\n renderPersonalizationBadge()\n }))\n }\n\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 { renderTransparencyBar } 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, 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\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 if (previewId) {\n patchVariantContainers(previewId)\n renderPreviewBanner(previewId)\n renderPersonalizationBadge()\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 patchVariantContainers(result.winningAudienceId)\n renderTransparencyBar({ isPersonalized: result.winningAudienceId !== null, isOptedOut: result.isOptedOut, hasMatchAvailable: result.allMatchedIds.length > 0 })\n // Render the opt-out badge wherever a personalizationBadge module was placed.\n renderPersonalizationBadge()\n populateDataLayer({ visitorId: result.signals.identity.visitorId, audienceId: result.winningAudienceId, experimentId: serverMeta.experimentId, variantId: serverMeta.variantId, isPreview: false, isOptedOut: result.isOptedOut })\n fireKywiReady()\n\n if (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 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"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["isOptedOut", "createButton"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kywi-software/js",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Kywi CMS browser runtime — audience personalization, experiments, forms, and feed rendering for the public site (loaded as kywi.js).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"tsx": "^4.7.0",
|
|
39
39
|
"typescript": "^5.5.0",
|
|
40
40
|
"vitest": "^1.6.0",
|
|
41
|
-
"@kywi-software/core": "0.6.
|
|
41
|
+
"@kywi-software/core": "0.6.2"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc --emitDeclarationOnly && tsx build.ts",
|