@syntrologie/adapt-search 2.8.0-canary.568

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../node_modules/@lit/context/src/lib/create-context.ts", "../../../sdk-contracts/dist/canvas-context.js", "../../../sdk-contracts/dist/detector-events.js", "../../../sdk-contracts/dist/mount-plumbing.js", "../../../sdk-contracts/dist/routes.js", "../../../sdk-contracts/dist/schemas.js", "../../../sdk-contracts/dist/telemetry-events.js", "../src/SearchSurfaceElement.ts", "../src/regions.ts", "../src/hrefSafety.ts", "../src/runtime.ts"],
4
+ "sourcesContent": ["/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * The Context type defines a type brand to associate a key value with the context value type\n */\nexport type Context<KeyType, ValueType> = KeyType & {__context__: ValueType};\n\n/**\n * @deprecated use Context instead\n */\nexport type ContextKey<KeyType, ValueType> = Context<KeyType, ValueType>;\n\n/**\n * A helper type which can extract a Context value type from a Context type\n */\nexport type ContextType<Key extends Context<unknown, unknown>> =\n Key extends Context<unknown, infer ValueType> ? ValueType : never;\n\n/**\n * Creates a typed Context.\n *\n * Contexts are compared with strict equality.\n *\n * If you want two separate `createContext()` calls to referer to the same\n * context, then use a key that will by equal under strict equality like a\n * string for `Symbol.for()`:\n *\n * ```ts\n * // true\n * createContext('my-context') === createContext('my-context')\n * // true\n * createContext(Symbol.for('my-context')) === createContext(Symbol.for('my-context'))\n * ```\n *\n * If you want a context to be unique so that it's guaranteed to not collide\n * with other contexts, use a key that's unique under strict equality, like\n * a `Symbol()` or object.:\n *\n * ```\n * // false\n * createContext({}) === createContext({})\n * // false\n * createContext(Symbol('my-context')) === createContext(Symbol('my-context'))\n * ```\n *\n * @param key a context key value\n * @template ValueType the type of value that can be provided by this context.\n * @returns the context key value cast to `Context<K, ValueType>`\n */\nexport function createContext<ValueType, K = unknown>(key: K) {\n return key as Context<K, ValueType>;\n}\n", "/**\n * Canvas runtime context \u2014 the shared @lit/context symbol both\n * runtime-sdk (the provider) and canvas-sdk / canvas authors (the\n * consumers) use to thread a narrow runtime handle through the canvas\n * element tree.\n *\n * Living here keeps the symbol identity stable across both packages.\n * If canvas-sdk created its own symbol with `createContext(...)`, it\n * would never match the one runtime-sdk publishes, and `<sc-mount>`\n * would silently see `undefined` instead of the widget registry.\n *\n * The shape declared here is a NARROW VIEW of `SmartCanvasRuntime`.\n * Canvas-side code reads only this subset. The runtime-sdk's\n * `SmartCanvasRuntime` type is a structural superset.\n */\nimport { createContext } from '@lit/context';\n/**\n * The @lit/context symbol. Both runtime-sdk's ContextProvider and\n * canvas-sdk's ContextConsumer must import THIS exact symbol \u2014 not a\n * symbol with the same string name \u2014 for context propagation to work.\n */\nexport const canvasRuntimeContext = createContext('syntrologie:canvas-runtime');\n", "/**\n * The prop shapes of every CANONICAL runtime-bus event \u2014 the producer/consumer\n * contract for the visitor-behavior signals that reach the chat agent.\n *\n * ## Why this module exists\n *\n * Two independent packages have to agree on these prop names and nothing was\n * holding them to it:\n *\n * producer `packages/event-processor/src/detectors/*` (rrweb detectors)\n * `packages/runtime-sdk/src/instrumentation/*` (bus instrumentation)\n * consumer `packages/adaptives/adaptive-chatbot/src/observer/allowlist.ts`\n *\n * Both sides passed `Record<string, unknown>` around, so a disagreement was not\n * a build error \u2014 it was an observation rendered into the model's prompt with\n * its content missing. `hovered on ''`. `idle`. Shipped for months\n * (BUG-1786923485), and once before that as a name mismatch (BUG-1784146789).\n *\n * ## The rule this module enforces\n *\n * `CanonicalBusEventProps` is the ONE declaration. Producers emit through\n * `detectorEvent()` (event-processor), which types `props` as\n * `CanonicalBusEventProps[N]`; consumers render through an exhaustive\n * `Record<CanonicalBusEventName, \u2026>` whose functions receive\n * `Partial<CanonicalBusEventProps[N]>`. Therefore:\n *\n * - renaming a key in a detector \u2192 producer fails `tsc`\n * - renaming a key in the summarizer \u2192 consumer fails `tsc`\n * - adding an event with no summarizer case \u2192 consumer fails `tsc` (missing\n * key in the exhaustive record)\n * - renaming a key HERE \u2192 both sides fail `tsc`\n *\n * None of those can degrade to an empty string at runtime.\n *\n * ## Deliberately dependency-free\n *\n * No zod, no `@lit/context`, no DOM types \u2014 `@syntrologie/event-processor` has\n * zero runtime dependencies and imports this via the `./detector-events`\n * subpath so it stays that way.\n *\n * ## Deliberately WITHOUT string index signatures\n *\n * An index signature on a props type makes `props.anyTypoAtAll` legal and\n * silently reintroduces the exact bug this module exists to prevent. The one\n * index signature below is a template-literal pattern (`attr__${string}`), so\n * arbitrary DOM attributes are still expressible while `text` / `tag_name`\n * typos remain errors.\n */\nexport const DETECTOR_EVENT_NAMES = [\n 'ui.hover',\n 'ui.idle',\n 'ui.hesitate',\n 'ui.rage_click',\n 'ui.scroll_thrash',\n 'ui.focus_bounce',\n];\nexport const CANONICAL_BUS_EVENT_NAMES = [\n ...DETECTOR_EVENT_NAMES,\n 'nav.section_viewed',\n 'nav.scroll_depth',\n];\nconst _canonicalExhaustive = true;\nconst _detectorExhaustive = true;\nvoid _canonicalExhaustive;\nvoid _detectorExhaustive;\n/** Runtime membership test \u2014 narrows an arbitrary event name to the contract. */\nexport function isCanonicalBusEvent(name) {\n return CANONICAL_BUS_EVENT_NAMES.includes(name);\n}\n", "/**\n * Mount contract types and helper for adaptive widget mountables.\n *\n * The `WidgetRegistry` in `@syntrologie/runtime-sdk` delivers props to each\n * mountable as `{ ...tile.props, instanceId, runtime, tileId? }` spread flat\n * (see `MountableContract.test.ts` in runtime-sdk for the end-to-end lockdown).\n *\n * Adaptives that strip plumbing manually maintain private blacklists that\n * silently drift when the contract grows (PR #2234 and #2238 documented this).\n * `stripMountPlumbing` centralizes the list so adding a new plumbing key in\n * the future is a one-line change here that every adaptive picks up automatically.\n *\n * Adaptives whose widget schemas use Zod `.strict()` MUST call this before\n * validating, or strict-mode will reject the runtime-injected keys and the\n * widget will silently render its empty/error state.\n */\nexport const MOUNT_PLUMBING_KEYS = ['instanceId', 'runtime', 'tileId'];\nexport function stripMountPlumbing(config) {\n if (!config || typeof config !== 'object') {\n return {};\n }\n const out = { ...config };\n for (const key of MOUNT_PLUMBING_KEYS) {\n delete out[key];\n }\n return out;\n}\n", "/**\n * Canonical route normalization. See `routes.md` for rules and\n * `normalize-route.cases.json` for the parity corpus shared with the\n * Python implementation in syntrologie_common/sdk/routing.py.\n *\n * Two exports \u2014 `normalizeRoute` for literal paths, `normalizeRoutePattern`\n * for activation patterns containing `*`, `**`, `:param`. Today they share\n * an implementation because the rules happen to be wildcard-safe (no\n * lowercase, unreserved-only decode, slash collapse preserves `**`).\n * The seam is preserved as separate exports so the API can diverge\n * without consumer churn if rules change.\n */\n// RFC 3986 reserved characters (gen-delims + sub-delims). When a `%XX`\n// sequence decodes to one of these bytes, we keep the percent-encoded\n// form \u2014 decoding would re-segment the path or change its meaning.\nconst RESERVED_BYTES = new Set([\n 0x21, // !\n 0x23, // #\n 0x24, // $\n 0x26, // &\n 0x27, // '\n 0x28, // (\n 0x29, // )\n 0x2a, // *\n 0x2b, // +\n 0x2c, // ,\n 0x2f, // /\n 0x3a, // :\n 0x3b, // ;\n 0x3d, // =\n 0x3f, // ?\n 0x40, // @\n 0x5b, // [\n 0x5d, // ]\n]);\nconst utf8Decoder = new TextDecoder('utf-8', { fatal: false });\n/** Decode `%XX` sequences for unreserved bytes only. Collapses\n * adjacent `%XX` runs into a UTF-8 decode so `%C3%A9` \u2192 `\u00E9`. */\nfunction decodeUnreservedOnly(input) {\n let out = '';\n let pending = [];\n const flushPending = () => {\n if (pending.length === 0)\n return;\n const bytes = new Uint8Array(pending);\n out += utf8Decoder.decode(bytes);\n pending = [];\n };\n let i = 0;\n while (i < input.length) {\n const ch = input[i];\n if (ch === '%' && i + 2 < input.length && isHex(input[i + 1]) && isHex(input[i + 2])) {\n const byte = parseInt(input.slice(i + 1, i + 3), 16);\n if (RESERVED_BYTES.has(byte)) {\n flushPending();\n // Keep raw, but normalize hex case to uppercase so the\n // canonical form is stable across input casing.\n out += `%${input.slice(i + 1, i + 3).toUpperCase()}`;\n i += 3;\n }\n else {\n pending.push(byte);\n i += 3;\n }\n }\n else {\n flushPending();\n out += ch;\n i += 1;\n }\n }\n flushPending();\n return out;\n}\nfunction isHex(c) {\n return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');\n}\n/** Strip query string and hash fragment. */\nfunction stripQueryAndHash(s) {\n const q = s.indexOf('?');\n if (q !== -1)\n s = s.slice(0, q);\n const h = s.indexOf('#');\n if (h !== -1)\n s = s.slice(0, h);\n return s;\n}\n/**\n * Normalize a literal path (e.g. `window.location.pathname`, an\n * action's `route` field, a wiki route key).\n *\n * Throws `TypeError` if the input is not an absolute path. Callers\n * that want a soft API should use {@link normalizeRouteWithChange}.\n */\nexport function normalizeRoute(path) {\n if (typeof path !== 'string' || path.length === 0) {\n throw new TypeError('normalizeRoute: input must be a non-empty string');\n }\n if (!path.startsWith('/')) {\n throw new TypeError(`normalizeRoute: input must be absolute (start with '/'); got ${JSON.stringify(path)}`);\n }\n let s = stripQueryAndHash(path);\n s = decodeUnreservedOnly(s);\n s = s.replace(/\\/+/g, '/');\n if (s.length > 1 && s.endsWith('/'))\n s = s.slice(0, -1);\n return s;\n}\n/**\n * Normalize an activation route pattern. Preserves `*`, `**`,\n * `:param` exactly. Today equivalent to {@link normalizeRoute} \u2014 kept\n * as a separate export so rules can diverge later without API churn.\n */\nexport function normalizeRoutePattern(pattern) {\n return normalizeRoute(pattern);\n}\n/**\n * Normalize a route and report whether the input was already\n * canonical. Used by authoring tools to decide whether to emit a\n * warning to the LLM.\n */\nexport function normalizeRouteWithChange(path) {\n const canonical = normalizeRoute(path);\n return { canonical, changed: canonical !== path };\n}\n/** Pattern-side counterpart of {@link normalizeRouteWithChange}. */\nexport function normalizeRoutePatternWithChange(pattern) {\n const canonical = normalizeRoutePattern(pattern);\n return { canonical, changed: canonical !== pattern };\n}\n/**\n * Case-insensitive comparison of two already-canonical paths. Use\n * this anywhere two routes are compared for equality (wiki lookups,\n * non-pattern action route gates) \u2014 preserves casing in the inputs\n * while honoring case-insensitive routing on the customer's site.\n */\nexport function routesMatch(a, b) {\n return a.toLowerCase() === b.toLowerCase();\n}\n", "/**\n * Shared Zod schemas for decision strategies, conditions, and event scoping.\n *\n * These are the canonical definitions \u2014 runtime-sdk and all adaptive packages\n * should import from here instead of duplicating.\n */\nimport { z } from 'zod';\nimport { normalizeRoute } from './routes.js';\n// =============================================================================\n// ANCHOR ID SCHEMA\n// =============================================================================\n// A selector containing \"{\" or \"}\" can never match a real DOM element via\n// querySelectorAll \u2014 those characters are exclusively CSS rule delimiters,\n// not valid selector syntax. They ARE, however, exactly what\n// content:hideBySelector's executor needs to escape the single CSS rule it\n// injects as raw text into a live <style> element\n// (`${selector} { ${prop}: ${value} !important; }` \u2014 see\n// executeHideBySelector in adaptive-content/src/runtime.ts): a selector\n// containing `}` closes that rule early and lets the rest of the string\n// splice in arbitrary attacker-controlled CSS anywhere on the host page\n// (defacement, CSS-based data exfiltration via attribute selectors,\n// clickjacking overlays). This constraint lives on THIS canonical AnchorIdZ\n// (not a hideBySelector-only variant, and not a second copy in a\n// downstream package) so that every action kind in every package \u2014 core\n// and adaptive \u2014 inherits it automatically: there is exactly one\n// `AnchorIdZ`, and every consumer imports it from here (SEC-067,\n// BUG-1786764688). No legitimate selector for any action kind needs a\n// literal brace.\nexport const NO_CSS_BREAKOUT_PATTERN = /^[^{}]*$/;\nexport const AnchorIdZ = z\n .object({\n selector: z\n .string()\n .regex(NO_CSS_BREAKOUT_PATTERN, {\n message: 'selector must not contain \"{\" or \"}\" \u2014 not valid CSS selector syntax, and content:hideBySelector injects this value directly into a <style> element where these characters would break out of the generated rule.',\n })\n .describe('CSS selector for the target element'),\n route: z\n .union([z.string(), z.array(z.string())])\n .superRefine((value, ctx) => {\n // Backend parity check (Finding 1, .superpowers/sdd/\n // duplicated-definitions-audit.md): the backend's\n // RouteCanonicalityCheck (platform/backend/app/services/\n // sdk_config_checks.py) rejects any actions[].anchorId.route that\n // isn't already in `normalize_route`'s canonical form (absolute,\n // no trailing slash, no doubled slashes, no query/hash, unreserved\n // percent-decoding only). Before this check, authoring accepted\n // configs the backend would 422 on (e.g. a trailing slash, or a\n // bare \"**\" missing the leading \"/\"). Reuses `normalizeRoute` from\n // ./routes.ts \u2014 the SAME function already parity-tested against\n // the Python implementation via normalize-route.cases.json \u2014 so\n // this is single-sourced, not a third reimplementation of the\n // canonicalization rule.\n for (const route of Array.isArray(value) ? value : [value]) {\n let canonical;\n try {\n canonical = normalizeRoute(route);\n }\n catch (err) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `route must be an absolute path starting with \"/\" (got ${JSON.stringify(route)}): ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n if (canonical !== route) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `route ${JSON.stringify(route)} is not canonical \u2014 use ${JSON.stringify(canonical)} (this must match what the backend's RouteCanonicalityCheck accepts)`,\n });\n }\n }\n })\n .describe('URL path(s) where this element exists'),\n})\n .strict()\n .describe('DOM element target. selector = CSS selector, route = URL path(s) where the element exists.');\n// =============================================================================\n// AUTHORING FIELDS \u2014 id / title / description / validation\n//\n// Shared fields every action carries. `id` is the action identifier the\n// runtime uses to dispatch, dedupe, and drop/replace actions \u2014 it is NOT\n// stripped before serving. `title` / `description` / `validation` are\n// authoring-only metadata stripped server-side in `to_runtime_config`\n// (platform/backend/app/domains/experiments/helpers.py).\n//\n// They all appear in the JSON Schema (and therefore in the tactician's\n// prompt) because the LLM needs to know they are valid action properties \u2014\n// otherwise schema validation would reject what the prompt commands.\n//\n// Each action variant should `.extend(AuthoringFieldsZ)` alongside any\n// triggerWhen/condition extensions.\n// =============================================================================\nexport const AuthoringFieldsZ = {\n id: z.string().optional().describe('Stable action identifier (e.g. \"act_3db6a14d2ab0\").'),\n title: z\n .string()\n .max(200)\n .optional()\n .describe('Authoring-only: short label shown on the action plan dashboard. Stripped before serving to the runtime SDK.'),\n description: z\n .string()\n .max(1000)\n .optional()\n .describe('Authoring-only: one-sentence explanation of what this action does and why. Stripped before serving to the runtime SDK.'),\n validation: z\n .array(z.string().max(500))\n .max(10)\n .optional()\n .describe('Authoring-only: ordered steps a reviewer can follow to trigger this action and visually confirm it works. Each entry is one step. Stripped before serving to the runtime SDK.'),\n};\n// =============================================================================\n// TRIGGER VOCABULARY \u2014 canonical lists of valid event names, metric keys, etc.\n// These flow through to the JSON schema as enums and are used by the LLM prompt.\n// =============================================================================\n/** Events that can be counted in event_count conditions.\n *\n * Every value here must be an event the runtime actually emits \u2014 either a\n * PostHog-autocapture normalization (ui.click/scroll/input/change/submit) or\n * an event-processor detector (ui.hover/idle/scroll_thrash/focus_bounce/\n * hesitate/rage_click). Do not add aspirational names; a trigger counting an\n * event nothing emits never fires.\n */\nexport const COUNTABLE_EVENTS = [\n // User interactions (from PostHog autocapture normalization)\n 'ui.click',\n 'ui.scroll',\n 'ui.input',\n 'ui.change',\n 'ui.submit',\n // Behavioral detectors (from event-processor)\n 'ui.hover',\n 'ui.idle',\n 'ui.scroll_thrash',\n 'ui.focus_bounce',\n 'ui.hesitate',\n 'ui.rage_click',\n // Navigation\n 'nav.page_view',\n 'nav.page_leave',\n];\nexport const CountableEventZ = z\n .enum(COUNTABLE_EVENTS)\n .describe('Event name to count. ui.* = user interactions and behavioral detectors (hesitate, rage_click, scroll_thrash, focus_bounce, idle, hover); nav.* = page navigation.');\n/** Valid session metric keys. */\nexport const SESSION_METRIC_KEYS = ['time_on_page', 'page_views', 'scroll_depth'];\nexport const SessionMetricKeyZ = z\n .enum(SESSION_METRIC_KEYS)\n .describe('Session metric key. time_on_page = seconds on current page, page_views = pages visited this session, scroll_depth = 0-100 percentage.');\n/** Element chain match field prefixes for counter filters. */\nexport const ELEMENT_MATCH_FIELDS = ['tag_name', '$el_text'];\n// Note: attr__* is a dynamic prefix (attr__data-id, attr__class, attr__href, etc.)\n// and cannot be enumerated. The match key is either one of ELEMENT_MATCH_FIELDS\n// or starts with \"attr__\".\n// =============================================================================\n// CONDITION SCHEMAS\n// =============================================================================\nexport const PageUrlConditionZ = z\n .object({\n type: z.literal('page_url'),\n url: z.string().describe('URL path to match (e.g. \"/pricing\", \"/dashboard\")'),\n})\n .describe('Fires when the current page URL matches. Use for page-specific actions. ' +\n 'Example: {\"type\": \"page_url\", \"url\": \"/pricing\"}');\nexport const RouteConditionZ = z\n .object({\n type: z.literal('route'),\n routeId: z.string().describe('Named route ID from the route filter'),\n})\n .describe('Fires when the current route matches a named route ID.');\nexport const AnchorVisibleConditionZ = z\n .object({\n type: z.literal('anchor_visible'),\n anchorId: z.string().describe('CSS selector of the anchor element'),\n state: z\n .enum(['visible', 'present', 'absent'])\n .describe('\"visible\" = in viewport, \"present\" = in DOM, \"absent\" = not in DOM'),\n})\n .describe(\"Fires based on a DOM element's visibility state. \" +\n 'Example: {\"type\": \"anchor_visible\", \"anchorId\": \"#cta-button\", \"state\": \"visible\"}');\nexport const EventOccurredConditionZ = z\n .object({\n type: z.literal('event_occurred'),\n eventName: z.string().describe('Event name (e.g. \"ui.click\", \"$pageview\")'),\n withinMs: z.number().optional().describe('Time window in ms. Omit = any time this session.'),\n})\n .describe('Fires when a specific event has occurred during this session. ' +\n 'Example: {\"type\": \"event_occurred\", \"eventName\": \"ui.click\", \"withinMs\": 5000}');\nexport const StateEqualsConditionZ = z\n .object({\n type: z.literal('state_equals'),\n key: z\n .string()\n .describe('Key in the SDK persistent state store (localStorage). Only valid for keys the host app explicitly sets via syntro.state.set().'),\n value: z.unknown().describe('Expected value to match against'),\n})\n .describe('Checks the SDK persistent state store (localStorage). ONLY for host-app state set via syntro.state.set() \u2014 ' +\n 'NOT for user attributes like region, device, or UTM params (those are handled by segment targeting). ' +\n 'Do NOT use this for targeting. If you do not know the valid state keys, do not use this condition type.');\nexport const ViewportConditionZ = z\n .object({\n type: z.literal('viewport'),\n minWidth: z.number().optional().describe('Minimum viewport width in pixels'),\n maxWidth: z.number().optional().describe('Maximum viewport width in pixels'),\n minHeight: z.number().optional().describe('Minimum viewport height in pixels'),\n maxHeight: z.number().optional().describe('Maximum viewport height in pixels'),\n})\n .describe('Fires based on viewport (screen) size. Use for responsive behavior. ' +\n 'Example: {\"type\": \"viewport\", \"minWidth\": 768} \u2014 fires on tablet and larger.');\nexport const SessionMetricConditionZ = z\n .object({\n type: z.literal('session_metric'),\n key: SessionMetricKeyZ,\n operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),\n threshold: z.number().describe('Numeric threshold to compare against'),\n})\n .describe('Fires when a session metric crosses a threshold. Valid keys: \"time_on_page\" (seconds), ' +\n '\"page_views\" (count), \"scroll_depth\" (0-100). ' +\n 'Example: {\"type\": \"session_metric\", \"key\": \"time_on_page\", \"operator\": \"gte\", \"threshold\": 30}');\nexport const DismissedConditionZ = z\n .object({\n type: z.literal('dismissed'),\n key: z.string().describe('Dismissal key (usually a tile or action ID)'),\n inverted: z\n .boolean()\n .optional()\n .describe('When true, fires if NOT dismissed (default behavior)'),\n})\n .describe('Checks if an item has been dismissed by the user. Use with inverted: true to show only if not dismissed.');\nexport const CooldownActiveConditionZ = z\n .object({\n type: z.literal('cooldown_active'),\n key: z.string().describe('Cooldown key'),\n inverted: z.boolean().optional().describe('When true, fires if cooldown is NOT active'),\n})\n .describe('Checks if a cooldown timer is currently active. Use to prevent showing the same intervention too frequently.');\nexport const FrequencyLimitConditionZ = z\n .object({\n type: z.literal('frequency_limit'),\n key: z.string().describe('Frequency counter key'),\n limit: z.number().describe('Maximum allowed count'),\n inverted: z.boolean().optional().describe('When true, fires if limit NOT reached'),\n})\n .describe('Checks if a frequency limit has been reached. Use to cap how many times an action fires per session.');\nexport const MatchOpZ = z\n .object({\n equals: z.union([z.string(), z.number(), z.boolean()]).optional(),\n contains: z.string().optional(),\n})\n .refine((operator) => Number(operator.equals !== undefined) + Number(operator.contains !== undefined) === 1, {\n message: 'Exactly one of equals or contains must be specified.',\n})\n .describe('Match operator for counter filters. Exactly one of equals or contains must be specified.');\nexport const CounterDefZ = z\n .object({\n events: z\n .array(CountableEventZ)\n .min(1)\n .describe('Event names to count. Use values from the countable events enum.'),\n match: z\n .record(z.string(), MatchOpZ)\n .optional()\n .describe('Property filters. Keys are event prop names or element-chain fields ' +\n '(tag_name, $el_text, attr__*). All entries AND together.'),\n})\n .describe('Defines what events to count. Registered as an accumulator predicate at config-load time.');\nexport const EventCountConditionZ = z\n .object({\n type: z.literal('event_count'),\n key: z.string().describe('Unique key for this counter (used for accumulator registration)'),\n operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),\n count: z.number().int().min(0).describe('Target count threshold'),\n withinMs: z\n .number()\n .positive()\n .optional()\n .describe('Time window in ms. Omit = count across entire session.'),\n counter: CounterDefZ.optional().describe('Inline counter definition. Defines what events to count.'),\n})\n .describe('Fires when accumulated event count crosses a threshold. Most powerful trigger type. ' +\n 'Example: {\"type\": \"event_count\", \"key\": \"pricing-clicks\", \"operator\": \"gte\", \"count\": 3, ' +\n '\"counter\": {\"events\": [\"ui.click\"], \"match\": {\"attr__data-cta\": {\"contains\": \"pricing\"}}}}');\nexport const ConditionZ = z.discriminatedUnion('type', [\n PageUrlConditionZ,\n RouteConditionZ,\n AnchorVisibleConditionZ,\n EventOccurredConditionZ,\n StateEqualsConditionZ,\n ViewportConditionZ,\n SessionMetricConditionZ,\n DismissedConditionZ,\n CooldownActiveConditionZ,\n FrequencyLimitConditionZ,\n EventCountConditionZ,\n]);\n// =============================================================================\n// STRATEGY SCHEMAS\n// =============================================================================\nexport const RuleZ = z\n .object({\n conditions: z\n .array(ConditionZ)\n .describe('Array of conditions \u2014 ALL must match (AND logic) for this rule to fire.'),\n value: z\n .unknown()\n .describe('Value returned when all conditions match. For triggerWhen: true = fire the action.'),\n})\n .describe('A single rule. ALL conditions must match (AND logic). Rules in a strategy are evaluated ' +\n 'top-to-bottom \u2014 first rule where all conditions match wins and returns its value.');\nexport const RuleStrategyZ = z\n .object({\n type: z.literal('rules'),\n rules: z\n .array(RuleZ)\n .describe('Ordered list of rules. Evaluated top-to-bottom \u2014 first match wins.'),\n default: z\n .unknown()\n .describe('Fallback value when no rule matches. For triggerWhen: false = do not fire by default.'),\n})\n .describe('Rule-based strategy. Evaluates rules top-to-bottom. First rule where ALL conditions match ' +\n 'returns its value. If no rule matches, returns default. ' +\n 'For triggerWhen: set value=true on matching rules, default=false.');\nexport const ScoreStrategyZ = z\n .object({\n type: z.literal('score'),\n field: z.string(),\n threshold: z.number(),\n above: z.unknown(),\n below: z.unknown(),\n})\n .describe('Score-based strategy. Compares a field value against a threshold.');\nexport const ModelStrategyZ = z\n .object({\n type: z.literal('model'),\n modelId: z.string(),\n inputs: z.array(z.string()),\n outputMapping: z.record(z.string(), z.unknown()),\n default: z.unknown(),\n})\n .describe('ML model strategy. Sends inputs to a model and maps outputs.');\nexport const ExternalStrategyZ = z\n .object({\n type: z.literal('external'),\n endpoint: z.string(),\n method: z.enum(['GET', 'POST']).optional(),\n default: z.unknown(),\n timeoutMs: z.number().optional(),\n})\n .describe('External API strategy. Calls an endpoint to determine the value.');\nexport const DecisionStrategyZ = z.discriminatedUnion('type', [\n RuleStrategyZ,\n ScoreStrategyZ,\n ModelStrategyZ,\n ExternalStrategyZ,\n]);\n/** Canonical Zod schema for the optional triggerWhen field on actions and adaptive items. */\nexport const TriggerWhenZ = DecisionStrategyZ.nullable().optional();\n// =============================================================================\n// TRIGGER DOCUMENTATION \u2014 examples and match field docs\n// Exported as constants so the schema generator can inject them into the\n// JSON schema. The Python prompt builder reads them from the schema.\n// =============================================================================\n/** Complete triggerWhen examples showing the full rules wrapper structure. */\nexport const TRIGGER_EXAMPLES = [\n {\n name: 'Click count on a specific element',\n description: 'Fire when user clicks an element with data-id=\"hero-cta\" 2+ times',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'event_count',\n key: 'cta-clicks',\n operator: 'gte',\n count: 2,\n counter: {\n events: ['ui.click'],\n match: { 'attr__data-id': { equals: 'hero-cta' } },\n },\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'Time on page threshold',\n description: 'Fire after user spends 30+ seconds on the page',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'session_metric',\n key: 'time_on_page',\n operator: 'gte',\n threshold: 30,\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'Element visible in viewport',\n description: 'Fire when a DOM element becomes visible',\n triggerWhen: {\n type: 'rules',\n rules: [\n {\n conditions: [\n {\n type: 'anchor_visible',\n anchorId: '#pricing-section',\n state: 'visible',\n },\n ],\n value: true,\n },\n ],\n default: false,\n },\n },\n {\n name: 'No trigger (fire immediately)',\n description: 'Action fires as soon as the segment matches \u2014 no in-session condition needed',\n triggerWhen: null,\n },\n];\n/** Documentation for counter.match field keys. */\nexport const MATCH_FIELD_DOCS = {\n tag_name: 'HTML tag name (e.g. \"button\", \"a\", \"input\")',\n $el_text: 'Visible text content of the element',\n 'attr__*': 'HTML attribute prefixed with attr__. Example: attr__data-id matches the data-id attribute, ' +\n 'attr__class matches the class attribute, attr__href matches the href attribute.',\n};\n// =============================================================================\n// EVENT SCOPE SCHEMA\n// =============================================================================\n/** Scopes a widget to specific events/URLs. */\nexport const EventScopeZ = z.object({\n events: z.array(z.string()),\n urlContains: z.string().optional(),\n props: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),\n});\n// =============================================================================\n// NOTIFY SCHEMA\n// =============================================================================\n/** Toast notification config for triggerWhen transitions. */\nexport const NotifyZ = z\n .object({\n title: z.string().optional().describe('Notification title'),\n body: z.string().optional().describe('Notification body text'),\n icon: z.string().optional().describe('Notification icon (emoji or URL)'),\n})\n .describe('Optional toast notification shown when this action triggers.')\n .nullable()\n .optional();\n", "/**\n * Telemetry catalog \u2014 the single source of truth for every `syntro_*` event\n * the runtime SDK emits and the backend queries (FEAT-1789150184).\n *\n * Names are `syntro_<subject>_<verb>`. Verbs are CLOSED: a new surface adds\n * subjects, never verbs. `scope` says which context must be active when the\n * event fires: `plan` (a config has been served) or `open` (the concierge is\n * open, so `open_id` and `surface` exist). `props` are the event's own\n * required properties; the envelope (variant_id, experiment_key, and while\n * open surface + open_id) is stamped by the core and not listed. The core\n * whitelists props to this list \u2014 anything else is dropped.\n *\n * `telemetry-events.json` is emitted from this file at build time and turned\n * into a Python enum for the backend (`make generate-types`).\n */\nexport const TELEMETRY_VERBS = [\n 'opened',\n 'closed',\n 'seen',\n 'triggered',\n 'interacted',\n 'paged',\n 'tapped',\n 'dismissed',\n 'sent',\n 'received',\n 'interrupted',\n 'toggled',\n 'served',\n];\n/**\n * What opened the concierge. `auto` = scroll handoff or a persisted-open\n * restore; `deep_link` = programmatic `open()`; `host` = the surface itself\n * gave the canvas the screen (an agent surface switching its card to\n * `fullscreen`). `host` is deliberately its own value: the SDK observes the\n * display-mode change, never the gesture behind it, so folding it into `fab`\n * or `auto` would assert intent nobody measured.\n */\nexport const CONCIERGE_OPEN_TRIGGERS = ['fab', 'auto', 'alert_chip', 'deep_link', 'host'];\n/**\n * What closed it. `fab` covers every pressed close affordance and programmatic\n * `close()`.\n *\n * `navigation` is NOT only \"the visitor clicked a link\". It is the catch-all\n * for every close that is not a gesture on the concierge itself, and today it\n * covers four distinct situations:\n * 1. a velvet nav-chip click / alert activate that navigates the host page;\n * 2. the empty-tileset auto-close (nothing left to show \u2014 not a gesture);\n * 3. the host removing the canvas element from the DOM while it was open;\n * 4. page unload (tab close / navigating away), emitted on `pagehide`.\n * Do not read `reason = 'navigation'` as intent. Splitting it is a catalog\n * change (the enum is spec-binding), so until that happens any \"why did they\n * leave?\" analysis must treat this value as \"ended without a gesture\".\n *\n * `host` is the agent-surface counterpart of the `host` open trigger: the\n * surface took the screen back and put the card inline again. It stays out of\n * `navigation` precisely so it does not inherit that value's ambiguity.\n */\nexport const CONCIERGE_CLOSE_REASONS = ['fab', 'escape', 'navigation', 'host'];\n/**\n * The in-app render container an open happened in, stamped on every\n * open-scope event. `overlay` is the bundled surface, `velvet` a custom\n * canvas mounted on the merchant's page, `inline` the canvas painted inside a\n * CHAT APP's card (surface type `mcp-app`).\n *\n * Closed, and pinned by the contract test, because every open-scope row the\n * backend has ever stored carries one of these: adding, removing or reusing a\n * value rewrites what the existing rows mean. Telegram is not a value here.\n * It renders through the same inline shell but reports as `overlay` or\n * `velvet`, the way it always has.\n */\nexport const TELEMETRY_SURFACES = ['velvet', 'overlay', 'inline'];\nexport const DECK_PAGE_METHODS = ['swipe', 'tap', 'auto'];\nexport const CHAT_SEND_VIAS = ['typed', 'intro_suggestion', 'pill', 'dive_deeper'];\n/**\n * Whether a search query looked like a single-term lookup or something the\n * takeover surface should reach for retrieval/ranking to answer. Stamped by\n * the interceptor's own classifier, never inferred downstream from the (never\n * emitted) query text.\n */\nexport const SEARCH_CLASSIFICATIONS = ['simple', 'complex'];\n/**\n * The layouts the search takeover surface can render results in. Closed to\n * what the surface actually ships, so a variant added here without a\n * renderer is a lie the catalog would otherwise let through.\n */\nexport const SEARCH_VARIANTS = ['grid', 'stacked', 'rail', 'hero', 'compare'];\n/**\n * How the visitor's search reached the interceptor. `enter` is a keydown on\n * the host's own search input; `submit` is the host's search form\n * submitting. These are the only two entry points the interceptor installs\n * on \u2014 no value here should exist that the SDK cannot itself produce.\n */\nexport const SEARCH_ENTRY_POINTS = ['enter', 'submit'];\n/**\n * Why the takeover fell back to the store's own native search instead of\n * rendering. `not_ready` = the adaptive or the platform adapter had not landed\n * yet; `error` = a request or a render threw, or a surface painted nothing;\n * `budget` = a latency budget was exceeded. Distinct from\n * `SEARCH_DISMISS_REASONS`: this enum is about the surface never taking over,\n * that one is about a takeover the visitor left.\n *\n * There is deliberately no `disabled`. A workspace the takeover is switched\n * off for never claims the shopper's Enter at all, so there is nothing to\n * report a fallback FROM \u2014 the store's search simply runs, as it does on\n * every storefront that has never heard of us. A value nothing can emit is a\n * value someone eventually reads as a real zero.\n */\nexport const SEARCH_FALLBACK_REASONS = ['not_ready', 'error', 'budget'];\n/**\n * Why an already-rendered search takeover closed. `escape` = Escape key or\n * an equivalent close gesture on our own panel; `navigation` = the visitor\n * followed a result or otherwise left the page; `native_link` = the visitor\n * used the surface's own \"see all results\" / native-search fallback link.\n * Revision 1 of this catalog reused `SEARCH_FALLBACK_REASONS` here, which is\n * wrong: a dismissal is a takeover that DID render, never a fallback.\n */\nexport const SEARCH_DISMISS_REASONS = ['escape', 'navigation', 'native_link'];\n/**\n * What kind of change a search follow-up represents relative to the search\n * already on screen. `refine` = the visitor typed a new/adjusted query;\n * `chip_removed` = a filter chip was cleared; `item_dismissed` = a single\n * result was dismissed from the surface without leaving it.\n */\nexport const SEARCH_DELTA_KINDS = ['refine', 'chip_removed', 'item_dismissed'];\nconst entry = (e) => e;\nexport const TELEMETRY_EVENTS = {\n // --- intervention metrics (April 2026) \u2014 wire names unchanged, all plan-scope\n syntro_config_served: entry({\n subject: 'config',\n verb: 'served',\n scope: 'plan',\n props: ['tiles', 'actions'],\n }),\n syntro_intervention_seen: entry({\n subject: 'intervention',\n verb: 'seen',\n scope: 'plan',\n props: ['intervention_id', 'intervention_kind'],\n }),\n syntro_intervention_triggered: entry({\n subject: 'intervention',\n verb: 'triggered',\n scope: 'plan',\n props: ['intervention_id', 'intervention_kind'],\n }),\n syntro_intervention_interacted: entry({\n subject: 'intervention',\n verb: 'interacted',\n scope: 'plan',\n props: ['intervention_id', 'intervention_kind', 'interaction_type'],\n }),\n // --- concierge (FEAT-1789150184) ---------------------------------------\n syntro_concierge_opened: entry({\n subject: 'concierge',\n verb: 'opened',\n scope: 'open',\n props: ['trigger', 'page_path'], // trigger: ConciergeOpenTrigger\n }),\n syntro_concierge_closed: entry({\n subject: 'concierge',\n verb: 'closed',\n scope: 'open',\n props: ['duration_ms', 'reason', 'messages_sent', 'tiles_dismissed', 'pages_viewed'], // reason: ConciergeCloseReason\n }),\n syntro_deck_paged: entry({\n subject: 'deck',\n verb: 'paged',\n scope: 'open',\n props: ['from_index', 'to_index', 'method'], // method: DeckPageMethod\n }),\n syntro_tile_dismissed: entry({\n subject: 'tile',\n verb: 'dismissed',\n scope: 'open',\n props: ['tile_id', 'tile_kind', 'visible_ms'],\n }),\n // The three chat atoms are OPEN-scope: they carry `surface` / `open_id` and\n // only make sense inside a concierge open. An INLINE chat bar (no concierge)\n // still dispatches them on every turn, and the core drops each one and\n // increments the `telemetry_dropped` health counter. That is EXPECTED on an\n // inline-chat host page, not a bug \u2014 `telemetry_dropped` there mixes \"real\n // defect\" with \"inline chat has no open scope\", so do not alert on it alone.\n syntro_chat_message_sent: entry({\n subject: 'chat_message',\n verb: 'sent',\n scope: 'open',\n props: ['turn', 'chars', 'via'], // via: ChatSendVia\n }),\n syntro_chat_reply_received: entry({\n subject: 'chat_reply',\n verb: 'received',\n scope: 'open',\n props: ['turn', 'ttft_ms', 'total_ms', 'mounts', 'cards'],\n }),\n syntro_chat_interrupted: entry({\n subject: 'chat',\n verb: 'interrupted',\n scope: 'open',\n props: ['turn', 'after_ms'],\n }),\n syntro_chat_maximize_toggled: entry({\n subject: 'chat_maximize',\n verb: 'toggled',\n scope: 'open',\n props: ['maximized'],\n }),\n syntro_chat_takeover_triggered: entry({\n subject: 'chat_takeover',\n verb: 'triggered',\n scope: 'open',\n props: ['turn'],\n }),\n // --- search takeover (2026-09-17) ---------------------------------------\n // All plan-scope: the search interceptor fires before any concierge open\n // exists. No prop here ever carries query text (SEE the contract test's\n // no-text-prop rule) \u2014 classification/signal_hits are the interceptor's\n // own derived signals, never the string itself.\n syntro_search_sent: entry({\n subject: 'search',\n verb: 'sent',\n scope: 'plan',\n props: ['classification', 'word_count', 'signal_hits', 'entry_point', 'platform'], // classification: SearchClassification, entry_point: SearchEntryPoint\n }),\n // `ms_to_skeleton` is intentionally the only timing prop: it is always\n // knowable the instant the surface mounts. `ms_to_first_content` is NOT\n // declared here (revision 1 defect) because a surface that never painted\n // content still fires this event, and a required prop it cannot supply\n // would make TelemetryCore.emit drop exactly the row worth measuring.\n syntro_search_surface_seen: entry({\n subject: 'search_surface',\n verb: 'seen',\n scope: 'plan',\n props: ['variant', 'classification', 'result_count', 'ms_to_skeleton'], // variant: SearchVariant, classification: SearchClassification\n }),\n syntro_search_result_tapped: entry({\n subject: 'search_result',\n verb: 'tapped',\n scope: 'plan',\n props: ['variant', 'region_id', 'module', 'position'], // variant: SearchVariant\n }),\n syntro_search_followup_sent: entry({\n subject: 'search_followup',\n verb: 'sent',\n scope: 'plan',\n props: ['delta_kind', 'variant'], // delta_kind: SearchDeltaKind, variant: SearchVariant\n }),\n // Declares `ms_since_boot` (not a \"since surface mounted\" timing prop) so a\n // not-ready fallback the takeover never rendered is still measurable \u2014\n // revision 1 emitted nothing on this path.\n syntro_search_native_served: entry({\n subject: 'search_native',\n verb: 'served',\n scope: 'plan',\n props: ['reason', 'platform', 'ms_since_boot'], // reason: SearchFallbackReason\n }),\n syntro_search_takeover_dismissed: entry({\n subject: 'search_takeover',\n verb: 'dismissed',\n scope: 'plan',\n props: ['variant', 'reason'], // variant: SearchVariant, reason: SearchDismissReason\n }),\n};\nexport const TELEMETRY_EVENT_NAMES = Object.keys(TELEMETRY_EVENTS);\n/** DOM bridge: components dispatch this (bubbles + composed) and the core listens at document. */\nexport const TELEMETRY_DOM_EVENT = 'syntro:telemetry';\n/**\n * Build the exact object written to `src/telemetry-events.json` at build time\n * (`scripts/emit-telemetry-catalog.mjs`), which `make app-generate-telemetry-events`\n * turns into the Python enum. Lives here \u2014 not in the script \u2014 so the shape is\n * declared once and `telemetry-events.contract.test.ts` can prove the committed\n * JSON has not drifted from this file.\n */\nexport function buildTelemetryCatalogJson() {\n return {\n verbs: [...TELEMETRY_VERBS],\n events: Object.fromEntries(Object.entries(TELEMETRY_EVENTS).map(([name, e]) => [\n name,\n {\n subject: e.subject,\n verb: e.verb,\n scope: e.scope,\n props: [...e.props],\n },\n ])),\n };\n}\nexport function isTelemetryEventName(name) {\n // ES2020 target: hasOwnProperty via the prototype, not the ES2022 static helper.\n // biome-ignore lint/suspicious/noPrototypeBuiltins: Object.hasOwn is ES2022; repo target is ES2020.\n return Object.prototype.hasOwnProperty.call(TELEMETRY_EVENTS, name);\n}\n", "/**\n * adaptive-search \u2014 `<syntro-search-surface>`\n *\n * The surface paints a layout skeleton the moment the shopper presses Enter,\n * then fills each named region in place as content arrives. Nothing ever\n * moves after the first paint: a shopper reading the first region must not\n * have it slide out from under them when the second one resolves.\n *\n * Shadow DOM, deliberately. This element covers a merchant's whole viewport\n * over their own markup, so their stylesheet must not reach in and ours must\n * not leak out. The `--sc-*` theme tokens inherit through the boundary, which\n * is how the surface ends up wearing the merchant's brand without this file\n * naming a single colour.\n *\n * The tag must start with `syntro-`: the search interceptor bails on any\n * element whose tag has that prefix, which is what keeps a shopper's Enter\n * inside our own follow-up bar from re-triggering the takeover.\n */\n\nimport { css, html, LitElement, nothing, type TemplateResult } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\n\nimport {\n countRegionProducts,\n readFollowupBarPayload,\n regionHasAnswer,\n renderRegionModule,\n SEE_STORE_RESULTS_EVENT,\n} from './regions';\nimport {\n type RegionRole,\n type SkeletonRegion,\n type SurfaceRegion,\n type SurfaceVariant,\n skeletonRegions,\n} from './variants';\n\nexport const SEARCH_SURFACE_TAG = 'syntro-search-surface';\n\n/** The label on the escape hatch. Plain words, and never an em dash. */\nconst SEE_STORE_RESULTS_LABEL = 'See store results';\n\n/** How many placeholder blocks each role's skeleton paints. */\nconst SKELETON_BLOCKS: Record<RegionRole, number> = {\n query: 0,\n primary: 6,\n secondary: 3,\n support: 2,\n converse: 1,\n};\n\nexport class SearchSurfaceElement extends LitElement {\n static override properties = {\n _variant: { state: true },\n _query: { state: true },\n _filled: { state: true },\n _suppressed: { state: true },\n _dismissed: { state: true },\n _frozen: { state: true },\n _announcement: { state: true },\n };\n\n // `declare` + constructor assignment, never a class-field initializer:\n // a field initializer shadows the reactive accessor Lit installs and the\n // element renders once and then silently ignores every later write.\n private declare _variant: SurfaceVariant | null;\n private declare _query: string;\n private declare _filled: Record<string, SurfaceRegion>;\n private declare _suppressed: readonly string[];\n /**\n * Handles the shopper hid, as a Set so the render path is a lookup rather\n * than a scan of every tile. Replaced, never mutated in place: Lit's dirty\n * check is identity-based and a mutated Set would not repaint.\n */\n private declare _dismissed: ReadonlySet<string>;\n private declare _frozen: boolean;\n private declare _announcement: string;\n\n constructor() {\n super();\n this._variant = null;\n this._query = '';\n this._filled = {};\n this._suppressed = [];\n this._dismissed = new Set<string>();\n this._frozen = false;\n this._announcement = '';\n }\n\n static override styles = css`\n :host {\n display: block;\n font-family: var(--sc-font-family, system-ui, -apple-system, sans-serif);\n color: var(--sc-tile-text-color, var(--sc-content-text-color, #1a1a1a));\n }\n\n .surface {\n display: grid;\n gap: var(--sc-tile-stack-gap, 1rem);\n padding: 1rem;\n box-sizing: border-box;\n min-height: 100%;\n background: var(--sc-canvas-background, var(--sc-content-background, #ffffff));\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n\n /* Sticky, never fixed. A fixed bar measures itself against the visual\n viewport, so it jumps when the mobile URL bar animates and hides under\n the soft keyboard. Sticky inside our own scroll container does not. */\n .region-query {\n position: sticky;\n top: 0;\n z-index: 1;\n background: var(--sc-canvas-background, var(--sc-content-background, #ffffff));\n padding-block: 0.5rem;\n }\n\n .region {\n min-width: 0;\n }\n\n .query-bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n }\n\n .followup {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n flex: 1 1 14rem;\n min-width: 0;\n }\n\n .followup-input {\n flex: 1 1 12rem;\n min-width: 0;\n min-height: 2.5rem;\n padding: 0.5rem 0.75rem;\n font: inherit;\n color: inherit;\n border: 1px solid var(--sc-tile-border, rgba(0, 0, 0, 0.2));\n border-radius: var(--sc-border-radius, 0.5rem);\n background: var(--sc-content-search-background, transparent);\n }\n\n .followup-notice {\n flex: 1 1 100%;\n margin: 0;\n font-size: var(--sc-tile-subtitle-size, 0.875rem);\n color: var(--sc-content-text-secondary-color, inherit);\n }\n\n .chips,\n .suggestions {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n\n .chip,\n .suggestion,\n .store-results {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n min-height: 1.75rem;\n min-width: 1.75rem;\n padding: 0.25rem 0.75rem;\n font: inherit;\n cursor: pointer;\n border-radius: var(--sc-border-radius, 0.5rem);\n border: 1px solid var(--sc-chip-border, rgba(0, 0, 0, 0.2));\n background: var(--sc-chip-background, transparent);\n color: var(--sc-chip-foreground, inherit);\n }\n\n .store-results {\n margin-inline-start: auto;\n border-color: var(--sc-color-primary, currentColor);\n color: var(--sc-color-primary, inherit);\n background: transparent;\n }\n\n .tiles {\n display: grid;\n gap: var(--sc-tile-gap, 0.75rem);\n }\n\n .tile {\n position: relative;\n min-width: 0;\n border: 1px solid var(--sc-tile-border, rgba(0, 0, 0, 0.12));\n border-radius: var(--sc-tile-border-radius, var(--sc-border-radius, 0.5rem));\n background: var(--sc-tile-background, transparent);\n }\n\n .tile-link {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n padding: var(--sc-tile-body-padding, 0.75rem);\n color: inherit;\n text-decoration: none;\n }\n\n .tile-image {\n width: 100%;\n max-width: 100%;\n aspect-ratio: 1 / 1;\n object-fit: cover;\n border-radius: inherit;\n }\n\n .tile-title {\n font-size: var(--sc-tile-title-size, 0.9375rem);\n font-weight: var(--sc-tile-title-weight, 600);\n color: var(--sc-tile-title-color, inherit);\n }\n\n .tile-price {\n font-size: var(--sc-tile-subtitle-size, 0.875rem);\n }\n\n .tile-dismiss {\n position: absolute;\n inset-block-start: 0.25rem;\n inset-inline-end: 0.25rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.75rem;\n min-height: 1.75rem;\n padding: 0;\n font: inherit;\n cursor: pointer;\n border: 0;\n border-radius: 50%;\n color: var(--sc-tile-dismiss-color, inherit);\n background: var(--sc-tile-dismiss-background, transparent);\n }\n\n .group-title,\n .hero-reason,\n .content-block {\n margin: 0 0 0.5rem;\n }\n\n .group-title {\n font-size: var(--sc-tile-title-size, 0.9375rem);\n font-weight: 600;\n }\n\n .compare-attributes {\n margin: 0.5rem 0 0;\n padding-inline-start: 1.1em;\n }\n\n .skeleton {\n display: grid;\n gap: var(--sc-tile-gap, 0.75rem);\n }\n\n .skeleton-block {\n height: 4rem;\n border-radius: var(--sc-tile-border-radius, var(--sc-border-radius, 0.5rem));\n background: var(--sc-tile-background, rgba(0, 0, 0, 0.06));\n opacity: 0.6;\n animation: syntro-search-pulse 1.4s ease-in-out infinite;\n }\n\n @keyframes syntro-search-pulse {\n 50% {\n opacity: 0.25;\n }\n }\n\n :focus-visible {\n outline: 2px solid var(--sc-color-primary, currentColor);\n outline-offset: 2px;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .skeleton-block {\n animation: none;\n }\n }\n\n @media (forced-colors: active) {\n .tile,\n .chip,\n .suggestion,\n .store-results,\n .followup-input {\n border: 1px solid CanvasText;\n }\n .skeleton-block {\n border: 1px solid CanvasText;\n background: Canvas;\n }\n }\n\n /* Every variant is a single column below this width. Above it, each one\n takes the shape the plan chose. */\n @media (min-width: 641px) {\n .tiles {\n grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));\n }\n\n .tiles-compact {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .surface[data-variant='rail'] {\n grid-template-columns: minmax(0, 16rem) minmax(0, 1fr);\n }\n\n .surface[data-variant='rail'] > [data-region-id='query-1'],\n .surface[data-variant='rail'] > [data-region-id='converse-1'] {\n grid-column: 1 / -1;\n }\n\n .surface[data-variant='rail'] > [data-region-id='secondary-1'] {\n grid-column: 1;\n grid-row: 2 / span 2;\n }\n\n .surface[data-variant='rail'] > [data-region-id='primary-1'] {\n grid-column: 2;\n grid-row: 2;\n }\n\n .surface[data-variant='rail'] > [data-region-id='support-1'] {\n grid-column: 2;\n grid-row: 3;\n }\n\n .surface[data-variant='compare'] {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n\n .surface[data-variant='compare'] > [data-region-id='query-1'],\n .surface[data-variant='compare'] > [data-region-id='secondary-1'],\n .surface[data-variant='compare'] > [data-region-id='converse-1'] {\n grid-column: 1 / -1;\n }\n\n .surface[data-variant='compare'] > [data-region-id='primary-1'] {\n grid-column: 1;\n }\n\n .surface[data-variant='compare'] > [data-region-id='primary-2'] {\n grid-column: 2;\n }\n\n .surface[data-variant='hero'] > [data-region-id='secondary-1'] .tiles {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n }\n `;\n\n /**\n * Paint the variant's skeleton. Ignored once the surface is frozen, because\n * a server plan that lands after the first content has painted would\n * otherwise throw away what the shopper is already reading.\n */\n showSkeleton(variant: SurfaceVariant, query: string): void {\n if (this._frozen) return;\n this._variant = variant;\n this._query = query;\n this._filled = {};\n this._suppressed = [];\n this._announcement = '';\n }\n\n /**\n * Fill one region in place. The region keeps its position, so the page does\n * not reflow around the shopper. A region id this variant does not own, or\n * one already retired by `suppressRegion`, has nowhere to paint.\n *\n * Returns whether the region actually painted. The runtime needs that answer\n * to tell \"the plan filled a region\" from \"the plan addressed a variant this\n * surface is not showing\": a dropped fill counted as content would leave the\n * shopper on a skeleton the SDK had already scored as a success.\n */\n fillRegion(region: SurfaceRegion): boolean {\n if (!this._variant) return false;\n if (this._suppressed.includes(region.id)) return false;\n if (!skeletonRegions(this._variant).some((slot) => slot.id === region.id)) return false;\n this.freeze();\n this._filled = { ...this._filled, [region.id]: region };\n this._announce();\n return true;\n }\n\n /** Content this renderer can display, including payload validation and dismissals. */\n getRegionContent(id: string): { productCount: number; hasAnswer: boolean } {\n const region = this._filled[id];\n return region\n ? {\n productCount: countRegionProducts(region, this._dismissed),\n hasAnswer: regionHasAnswer(region, this._dismissed),\n }\n : { productCount: 0, hasAnswer: false };\n }\n\n /**\n * Retire a slot the plan decided not to fill. The slot leaves the grid\n * entirely \u2014 no skeleton, no `aria-busy`, nothing for the live region to\n * count \u2014 and every other slot keeps its order. Left in place, a region that\n * is never going to fill pulses beside real results for as long as the\n * shopper reads them.\n *\n * Idempotent, ignored for an id this variant does not own, and allowed after\n * the surface has frozen: suppression is not a repaint, it only removes a\n * slot that was never going to say anything.\n */\n suppressRegion(id: string): void {\n if (this._suppressed.includes(id)) return;\n this._suppressed = [...this._suppressed, id];\n if (this._filled[id]) {\n const { [id]: _removed, ...rest } = this._filled;\n this._filled = rest;\n }\n // Only re-count once something has painted; before that the live region\n // stays silent and the skeleton is what says \"still loading\".\n if (this._frozen) this._announce();\n }\n\n /**\n * Hide one product, everywhere, for the rest of this surface.\n *\n * Optimistic on purpose: the shopper tapped the tile's own dismiss button,\n * so the tile goes now rather than after a round trip that may legitimately\n * come back with nothing to patch. And it OUTLIVES the payload it was tapped\n * in \u2014 a later repaint of the same region, or a whole new plan on a surface\n * with no server session, must not hand back the product just rejected.\n */\n dismissProduct(handle: string): void {\n if (!handle || this._dismissed.has(handle)) return;\n // A new Set, never a mutation: Lit's dirty check is identity-based.\n this._dismissed = new Set([...this._dismissed, handle]);\n if (this._frozen) this._announce();\n }\n\n /**\n * Drop one chip from the follow-up bar without waiting for a server repaint.\n *\n * Only reachable when the bar is showing server chips and the surface has no\n * live session to patch \u2014 an expired one, in practice. With a session the\n * server repaints the bar and this is never called.\n */\n removeChip(key: string): void {\n const filled = this._filledQueryRegion();\n if (!filled) return;\n const bar = readFollowupBarPayload(filled.payload);\n const chips = bar.chips.filter((chip) => chip.key !== key);\n if (chips.length === bar.chips.length) return;\n this._filled = { ...this._filled, [filled.id]: { ...filled, payload: { ...bar, chips } } };\n }\n\n /**\n * The container a widget mounts into for this region, or `null` when the\n * region paints no mountable module.\n *\n * The surface renders `search:chat` as an empty box and nothing else: the\n * conversation here is the SDK's own chat widget, mounted by the runtime\n * through its widget registry, never a second chat implementation living in\n * this package. This is the whole affordance that makes that possible.\n */\n mountTarget(regionId: string): HTMLElement | null {\n const section = Array.from(this.shadowRoot?.querySelectorAll('[data-region-role]') ?? []).find(\n (node) => node.getAttribute('data-region-id') === regionId\n );\n return section?.querySelector<HTMLElement>('[data-mount]') ?? null;\n }\n\n /** The query region as the plan filled it, if the plan filled it at all. */\n private _filledQueryRegion(): SurfaceRegion | null {\n if (!this._variant) return null;\n for (const slot of skeletonRegions(this._variant)) {\n if (slot.role !== 'query') continue;\n const filled = this._filled[slot.id];\n if (filled) return filled;\n }\n return null;\n }\n\n /** Hold the current variant for the rest of this turn. */\n freeze(): void {\n this._frozen = true;\n }\n\n /**\n * Only ever called after a region has filled, so \"nothing here\" is a\n * finished answer, not a loading state. The skeleton is what says \"still\n * loading\", and it says it visually while the live region stays silent.\n */\n private _announce(): void {\n const total = Object.values(this._filled).reduce(\n (sum, region) => sum + countRegionProducts(region, this._dismissed),\n 0\n );\n const count = total === 0 ? 'No results found.' : total === 1 ? '1 result' : `${total} results`;\n // The notice is the plan explaining ITSELF \u2014 \"Nothing under $5. Here are\n // the closest matches.\" A shopper reading the bar sees it; a shopper\n // listening would otherwise hear \"3 results\" and never learn why those\n // three. It rides the surface's ONE live region rather than a second one,\n // because two live regions racing is worse than either alone.\n const query = this._filledQueryRegion();\n const notice = query ? readFollowupBarPayload(query.payload).notice : '';\n this._announcement = notice ? `${notice} ${count}` : count;\n }\n\n private _onSeeStoreResults = (): void => {\n this.renderRoot.dispatchEvent(new CustomEvent(SEE_STORE_RESULTS_EVENT));\n };\n\n private _renderQueryRegion(slot: SkeletonRegion): TemplateResult {\n const filled = this._filled[slot.id];\n const module = filled?.module ?? 'search:followup-bar';\n // The follow-up bar always shows the shopper's own words, whether or not\n // the server echoed them back. Any other module the plan puts here keeps\n // its own payload untouched.\n const payload =\n module === 'search:followup-bar'\n ? (() => {\n const bar = readFollowupBarPayload(filled?.payload);\n return { ...bar, query: bar.query || this._query };\n })()\n : filled?.payload;\n const region: SurfaceRegion = { id: slot.id, role: slot.role, module, payload };\n return html`\n <section class=\"region region-query\" data-region-id=${slot.id} data-region-role=\"query\">\n <div class=\"query-bar\">\n ${renderRegionModule(region, this._dismissed)}\n <button\n class=\"store-results\"\n type=\"button\"\n data-action=\"see-store-results\"\n @click=${this._onSeeStoreResults}\n >\n ${SEE_STORE_RESULTS_LABEL}\n </button>\n </div>\n </section>\n `;\n }\n\n private _renderRegion(slot: SkeletonRegion): TemplateResult {\n if (slot.role === 'query') return this._renderQueryRegion(slot);\n const filled = this._filled[slot.id];\n return html`\n <section\n class=\"region\"\n data-region-id=${slot.id}\n data-region-role=${slot.role}\n data-skeleton=${filled ? nothing : 'true'}\n aria-busy=${filled ? nothing : 'true'}\n >\n ${filled ? renderRegionModule(filled, this._dismissed) : this._renderSkeleton(slot.role)}\n </section>\n `;\n }\n\n private _renderSkeleton(role: RegionRole): TemplateResult {\n const blocks = Array.from({ length: SKELETON_BLOCKS[role] });\n return html`\n <div class=\"skeleton\" aria-hidden=\"true\">\n ${blocks.map(() => html`<div class=\"skeleton-block\"></div>`)}\n </div>\n `;\n }\n\n override render(): TemplateResult | typeof nothing {\n if (!this._variant) return nothing;\n const slots = skeletonRegions(this._variant).filter(\n (slot) => !this._suppressed.includes(slot.id)\n );\n return html`\n <div class=\"surface\" data-variant=${this._variant}>\n <h2 class=\"sr-only\">Search results</h2>\n <p class=\"sr-only\" role=\"status\" aria-live=\"polite\">${this._announcement}</p>\n ${repeat(\n slots,\n (slot) => slot.id,\n (slot) => this._renderRegion(slot)\n )}\n </div>\n `;\n }\n}\n\n/** Define `<syntro-search-surface>` once. Safe to call from every entry point. */\nexport function registerSearchSurfaceElement(): void {\n if (typeof customElements === 'undefined') return;\n if (!customElements.get(SEARCH_SURFACE_TAG)) {\n customElements.define(SEARCH_SURFACE_TAG, SearchSurfaceElement);\n }\n}\n", "/**\n * adaptive-search \u2014 region modules\n *\n * One function per module the plan can put in a region. Everything here is\n * rendered with Lit `${}` interpolation only: never `unsafeHTML`, because\n * every string on this surface is either shopper-authored (the query, the\n * chips) or merchant catalogue text arriving over the wire.\n *\n * A module this build does not know renders nothing and throws nothing. The\n * plan service ships new modules on its own cadence; an older SDK on a\n * merchant's page must degrade to a quieter surface, never to a broken one.\n */\n\nimport { html, nothing, type TemplateResult } from 'lit';\n\nimport { safeProductHref, UNSAFE_HREF_FALLBACK } from './hrefSafety';\nimport type { SurfaceRegion } from './variants';\n\n// ============================================================================\n// Payload shapes\n// ============================================================================\n\n/** A product as the plan service and the store search API both describe one. */\nexport interface SearchProduct {\n handle: string;\n title: string;\n url: string;\n price?: string;\n imageUrl?: string;\n}\n\n/** A constraint the surface understood, shown as a removable chip. */\nexport interface SearchChip {\n key: string;\n label: string;\n}\n\n/** A follow-up the plan suggests, shown as a tappable button. */\nexport interface SearchSuggestion {\n value: string;\n label: string;\n}\n\n/** Follow-up bar payload: the shopper's words, what we understood, what next. */\nexport interface FollowupBarPayload {\n query?: string;\n chips?: SearchChip[];\n suggestions?: SearchSuggestion[];\n /**\n * A short line the plan wants under the chips, e.g. \"Nothing under $5. Here\n * are the closest matches.\" Merchant-neutral server prose, interpolated like\n * every other string here and never `unsafeHTML`.\n */\n notice?: string;\n}\n\n/** How a tile reports itself when it is tapped. */\nexport interface ResultTapDetail {\n handle: string;\n regionId: string;\n module: string;\n position: number;\n}\n\n/** The three shapes a follow-up takes. All patch the same server session. */\nexport type FollowupDetail =\n | { kind: 'refine'; value: string }\n | { kind: 'chip_removed'; value: string }\n | { kind: 'item_dismissed'; value: string };\n\n// ============================================================================\n// Events\n// ============================================================================\n\nexport const RESULT_TAP_EVENT = 'syntro:search:result-tap';\nexport const FOLLOWUP_EVENT = 'syntro:search:followup';\nexport const SEE_STORE_RESULTS_EVENT = 'syntro:search:see-store-results';\n\n/** Internal events stay inside our shadow root, including during capture. */\nfunction dispatchFrom(node: EventTarget, name: string, detail: unknown): void {\n node.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: false }));\n}\n\n// ============================================================================\n// Payload readers (every payload arrives as `unknown`)\n// ============================================================================\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === 'object' ? (value as Record<string, unknown>) : {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction readProduct(value: unknown): SearchProduct | null {\n const raw = asRecord(value);\n const handle = asString(raw.handle);\n const title = asString(raw.title);\n const url = asString(raw.url);\n if (!handle || !title || !url) return null;\n return { handle, title, url, price: asString(raw.price), imageUrl: asString(raw.imageUrl) };\n}\n\nfunction readProducts(value: unknown): SearchProduct[] {\n if (!Array.isArray(value)) return [];\n return value.map(readProduct).filter((product): product is SearchProduct => product !== null);\n}\n\nfunction readStrings(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0);\n}\n\nfunction readChips(value: unknown): SearchChip[] {\n if (!Array.isArray(value)) return [];\n return value\n .map((entry) => {\n const raw = asRecord(entry);\n const key = asString(raw.key);\n const label = asString(raw.label) ?? key;\n return key && label ? { key, label } : null;\n })\n .filter((chip): chip is SearchChip => chip !== null);\n}\n\nfunction readSuggestions(value: unknown): SearchSuggestion[] {\n if (!Array.isArray(value)) return [];\n return value\n .map((entry) => {\n const raw = asRecord(entry);\n const suggestion = asString(raw.value);\n const label = asString(raw.label) ?? suggestion;\n return suggestion && label ? { value: suggestion, label } : null;\n })\n .filter((entry): entry is SearchSuggestion => entry !== null);\n}\n\n/** Read the follow-up bar's payload. Exported so the surface can merge the query in. */\nexport function readFollowupBarPayload(payload: unknown): Required<FollowupBarPayload> {\n const raw = asRecord(payload);\n return {\n query: asString(raw.query) ?? '',\n chips: readChips(raw.chips),\n suggestions: readSuggestions(raw.suggestions),\n notice: asString(raw.notice) ?? '',\n };\n}\n\n/**\n * Handles the shopper has hidden. A dismissal is optimistic \u2014 the tile goes as\n * soon as it is tapped, before any server round trip \u2014 and it OUTLIVES the\n * payload it was tapped in: a later repaint of the same region, or a whole new\n * plan for a surface with no server session, would otherwise hand the shopper\n * back the product they just rejected.\n *\n * `visible` / `visibleOne` below apply this to what is RENDERED, which is what\n * hides a tile in a region that has already painted and is not repainted. The\n * runtime keeps the same rule over incoming payloads \u2014 `withoutDismissed` in\n * `runtime-sdk/src/search/SearchSurfaceController.ts` \u2014 so a dismissed product\n * is also out of `result_count`. Both are needed; neither replaces the other.\n */\nexport type DismissedHandles = ReadonlySet<string>;\n\nconst NONE_DISMISSED: DismissedHandles = new Set<string>();\n\nfunction visible(products: SearchProduct[], dismissed: DismissedHandles): SearchProduct[] {\n return dismissed.size === 0\n ? products\n : products.filter((product) => !dismissed.has(product.handle));\n}\n\nfunction visibleOne(\n product: SearchProduct | null,\n dismissed: DismissedHandles\n): SearchProduct | null {\n return product !== null && dismissed.has(product.handle) ? null : product;\n}\n\n/**\n * How many products a filled region put on screen. The surface announces the\n * running total through its live region, so this has to agree with what the\n * module above actually rendered \u2014 dismissals included, because a hidden tile\n * is not a result the shopper was shown.\n */\nexport function countRegionProducts(\n region: SurfaceRegion,\n dismissed: DismissedHandles = NONE_DISMISSED\n): number {\n const raw = asRecord(region.payload);\n switch (region.module) {\n case 'search:product-grid':\n case 'search:shortlist':\n case 'search:strip':\n return visible(readProducts(raw.products), dismissed).length;\n case 'search:group':\n return Array.isArray(raw.groups)\n ? raw.groups.reduce<number>(\n (total, group) =>\n total + visible(readProducts(asRecord(group).products), dismissed).length,\n 0\n )\n : 0;\n case 'search:hero':\n case 'search:compare':\n return visibleOne(readProduct(raw.product), dismissed) === null ? 0 : 1;\n default:\n return 0;\n }\n}\n\n/** Use the same payload readers as rendering to decide whether there is an answer. */\nexport function regionHasAnswer(\n region: SurfaceRegion,\n dismissed: DismissedHandles = NONE_DISMISSED\n): boolean {\n if (countRegionProducts(region, dismissed) > 0) return true;\n if (region.module !== 'search:content') return false;\n const raw = asRecord(region.payload);\n return readStrings(raw.blocks).length > 0 || asString(raw.body) !== undefined;\n}\n\n// ============================================================================\n// Tiles\n// ============================================================================\n\nfunction productTile(product: SearchProduct, region: SurfaceRegion, position: number) {\n const href = safeProductHref(product.url);\n const imageHref = product.imageUrl ? safeProductHref(product.imageUrl) : undefined;\n const detail: ResultTapDetail = {\n handle: product.handle,\n regionId: region.id,\n module: region.module,\n position,\n };\n return html`\n <div class=\"tile\">\n <a\n class=\"tile-link\"\n href=${href}\n data-handle=${product.handle}\n data-region-id=${region.id}\n data-position=${position}\n data-unsafe-url=${href === UNSAFE_HREF_FALLBACK ? 'true' : nothing}\n @click=${(event: Event) => {\n // Never preventDefault: the shopper asked to go to the product, and\n // the tap event is a report, not a gate.\n dispatchFrom(event.currentTarget as EventTarget, RESULT_TAP_EVENT, detail);\n }}\n >\n ${\n imageHref && imageHref !== UNSAFE_HREF_FALLBACK\n ? html`<img class=\"tile-image\" src=${imageHref} alt=\"\" loading=\"lazy\" />`\n : nothing\n }\n <span class=\"tile-title\">${product.title}</span>\n ${product.price ? html`<span class=\"tile-price\">${product.price}</span>` : nothing}\n </a>\n <button\n class=\"tile-dismiss\"\n type=\"button\"\n data-dismiss=${product.handle}\n aria-label=${`Hide ${product.title}`}\n @click=${(event: Event) => {\n const detail: FollowupDetail = { kind: 'item_dismissed', value: product.handle };\n dispatchFrom(event.currentTarget as EventTarget, FOLLOWUP_EVENT, detail);\n }}\n >\n <span aria-hidden=\"true\">\u2715</span>\n </button>\n </div>\n `;\n}\n\n/**\n * `positionOffset` keeps tile positions unique and increasing across every\n * list in one region. Two groups that both started at 0 would emit\n * `syntro:search:result-tap` with the same `{regionId, position}` for\n * different products, and position is the coordinate the ranking analysis\n * joins on.\n */\nfunction productList(\n products: SearchProduct[],\n region: SurfaceRegion,\n className: string,\n positionOffset = 0\n) {\n return html`\n <div class=${className}>\n ${products.map((product, index) => productTile(product, region, positionOffset + index))}\n </div>\n `;\n}\n\n// ============================================================================\n// Modules\n// ============================================================================\n\nfunction followupBar(region: SurfaceRegion) {\n const { query, chips, suggestions, notice } = readFollowupBarPayload(region.payload);\n return html`\n <div class=\"followup\">\n <input\n class=\"followup-input\"\n type=\"search\"\n aria-label=\"Refine your search\"\n .value=${query}\n @keydown=${(event: KeyboardEvent) => {\n if (event.key !== 'Enter') return;\n const input = event.currentTarget as HTMLInputElement;\n const detail: FollowupDetail = { kind: 'refine', value: input.value };\n dispatchFrom(input, FOLLOWUP_EVENT, detail);\n }}\n />\n <div class=\"chips\" role=\"group\" aria-label=\"What we understood\">\n ${chips.map(\n (chip) => html`\n <button\n class=\"chip\"\n type=\"button\"\n data-chip=${chip.key}\n aria-label=${`Remove ${chip.label}`}\n @click=${(event: Event) => {\n const detail: FollowupDetail = { kind: 'chip_removed', value: chip.key };\n dispatchFrom(event.currentTarget as EventTarget, FOLLOWUP_EVENT, detail);\n }}\n >\n <span>${chip.label}</span><span aria-hidden=\"true\">\u2715</span>\n </button>\n `\n )}\n </div>\n ${\n // Server prose, under the chips it explains: \"Nothing under $5. Here\n // are the closest matches.\" No node at all when the plan sent none,\n // so an empty line never pushes the results down.\n notice ? html`<p class=\"followup-notice\">${notice}</p>` : nothing\n }\n <div class=\"suggestions\" role=\"group\" aria-label=\"Suggested follow-ups\">\n ${suggestions.map(\n (suggestion) => html`\n <button\n class=\"suggestion\"\n type=\"button\"\n data-suggestion=${suggestion.value}\n @click=${(event: Event) => {\n const detail: FollowupDetail = { kind: 'refine', value: suggestion.value };\n dispatchFrom(event.currentTarget as EventTarget, FOLLOWUP_EVENT, detail);\n }}\n >\n ${suggestion.label}\n </button>\n `\n )}\n </div>\n </div>\n `;\n}\n\nfunction groupedPicks(region: SurfaceRegion, dismissed: DismissedHandles) {\n const raw = asRecord(region.payload);\n const groups = Array.isArray(raw.groups) ? raw.groups : [];\n let position = 0;\n return html`\n ${groups.map((group) => {\n const entry = asRecord(group);\n const title = asString(entry.title);\n const products = visible(readProducts(entry.products), dismissed);\n const offset = position;\n position += products.length;\n return html`\n <section class=\"group\">\n ${title ? html`<h3 class=\"group-title\">${title}</h3>` : nothing}\n ${productList(products, region, 'tiles', offset)}\n </section>\n `;\n })}\n `;\n}\n\nfunction heroProduct(region: SurfaceRegion, dismissed: DismissedHandles) {\n const raw = asRecord(region.payload);\n const product = visibleOne(readProduct(raw.product), dismissed);\n if (!product) return nothing;\n const reason = asString(raw.reason);\n return html`\n <div class=\"hero\">\n ${productTile(product, region, 0)}\n ${reason ? html`<p class=\"hero-reason\">${reason}</p>` : nothing}\n </div>\n `;\n}\n\nfunction compareColumn(region: SurfaceRegion, dismissed: DismissedHandles) {\n const raw = asRecord(region.payload);\n const product = visibleOne(readProduct(raw.product), dismissed);\n if (!product) return nothing;\n const attributes = readStrings(raw.attributes);\n return html`\n <div class=\"compare\">\n ${productTile(product, region, 0)}\n <ul class=\"compare-attributes\">\n ${attributes.map((attribute) => html`<li>${attribute}</li>`)}\n </ul>\n </div>\n `;\n}\n\nfunction compactList(region: SurfaceRegion, dismissed: DismissedHandles) {\n const raw = asRecord(region.payload);\n const title = asString(raw.title);\n return html`\n ${title ? html`<h3 class=\"group-title\">${title}</h3>` : nothing}\n ${productList(visible(readProducts(raw.products), dismissed), region, 'tiles tiles-compact')}\n `;\n}\n\nfunction contentBlocks(region: SurfaceRegion) {\n const raw = asRecord(region.payload);\n const title = asString(raw.title);\n const blocks = readStrings(raw.blocks);\n const body = asString(raw.body);\n return html`\n ${title ? html`<h3 class=\"group-title\">${title}</h3>` : nothing}\n ${blocks.map((block) => html`<p class=\"content-block\">${block}</p>`)}\n ${body ? html`<p class=\"content-block\">${body}</p>` : nothing}\n `;\n}\n\n/**\n * The chat module is an empty container on purpose: a later task mounts the\n * real chat widget into it through the runtime's own widget registry, so the\n * conversation on this surface is the same chat everywhere else, not a second\n * implementation of one.\n */\nfunction chatContainer() {\n return html`<div class=\"chat\" data-mount data-module=\"search:chat\"></div>`;\n}\n\n// ============================================================================\n// Dispatch\n// ============================================================================\n\n/** Render a region's module. An unknown module renders nothing and throws nothing. */\nexport function renderRegionModule(\n region: SurfaceRegion,\n dismissed: DismissedHandles = NONE_DISMISSED\n): TemplateResult | typeof nothing {\n switch (region.module) {\n case 'search:followup-bar':\n return followupBar(region);\n case 'search:product-grid':\n return productList(\n visible(readProducts(asRecord(region.payload).products), dismissed),\n region,\n 'tiles'\n );\n case 'search:group':\n return groupedPicks(region, dismissed);\n case 'search:hero':\n return heroProduct(region, dismissed);\n case 'search:compare':\n return compareColumn(region, dismissed);\n case 'search:shortlist':\n case 'search:strip':\n return compactList(region, dismissed);\n case 'search:content':\n return contentBlocks(region);\n case 'search:chat':\n return chatContainer();\n default:\n return nothing;\n }\n}\n", "/**\n * adaptive-search \u2014 product URL scheme guard\n *\n * Same rule and same reasoning as `isSafeNavigationHref` in\n * `packages/adaptives/adaptive-overlays/src/cta-navigation.ts`: parse with the\n * URL parser rather than matching string prefixes, because browsers strip\n * embedded control characters from a scheme before resolving it, so\n * `\"java\\tscript:alert(1)\"` slips straight past a\n * `.trim().toLowerCase().startsWith('javascript:')` check.\n *\n * It is copied rather than imported because that helper is internal to\n * adaptive-overlays (its package `exports` publish only `./runtime`,\n * `./schema` and `./cdn`), and every adaptive in this repo keeps its own\n * sanitizer for the same reason \u2014 see `adaptive-product/src/sanitizer.ts`,\n * `adaptive-overlays/src/sanitizer.ts`, `adaptive-content/src/sanitizer.ts`.\n */\n\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/** Where an unsafe or unparseable product URL points instead: nowhere. */\nexport const UNSAFE_HREF_FALLBACK = '#';\n\n/** True when `href` resolves to a scheme it is safe to navigate to. */\nexport function isSafeProductHref(href: unknown): href is string {\n if (typeof href !== 'string' || href.trim().length === 0) return false;\n let parsed: URL;\n try {\n // Stable synthetic base so relative paths, fragments and query strings\n // resolve to http(s) exactly as they would against a real storefront.\n parsed = new URL(href, 'https://syntro.local/');\n } catch {\n return false;\n }\n return ALLOWED_PROTOCOLS.has(parsed.protocol);\n}\n\n/**\n * The href to render for a product tile: the authored URL when its scheme is\n * safe, otherwise `'#'`.\n *\n * The tile keeps its anchor either way. A shopper who can reach a tile with\n * the keyboard must still be able to focus it and hear its name, and a tile\n * whose link we silently dropped is a tile that looks tappable and is not.\n * Callers mark the fallback case with `data-unsafe-url` so it is visible in\n * the DOM rather than looking like an ordinary link.\n */\nexport function safeProductHref(href: unknown): string {\n return isSafeProductHref(href) ? href : UNSAFE_HREF_FALLBACK;\n}\n", "/**\n * adaptive-search \u2014 Runtime manifest\n *\n * Registers `<syntro-search-surface>` as a side effect of importing this\n * module, and exposes the mountable the runtime's WidgetRegistry uses.\n */\n\nimport { type MountPlumbing, stripMountPlumbing } from '@syntrologie/sdk-contracts';\n\nimport { registerSearchSurfaceElement, type SearchSurfaceElement } from './SearchSurfaceElement';\nimport type { SearchSurfaceConfig } from './schema';\n\nregisterSearchSurfaceElement();\n\n/**\n * Mounts the surface and, when the interceptor already chose a variant,\n * paints its skeleton in the same frame. Later tasks keep the element handle\n * and stream regions into it with `fillRegion`.\n */\nexport const SearchSurfaceMountable = {\n mount(container: HTMLElement, config?: (SearchSurfaceConfig & MountPlumbing) | null) {\n const surfaceConfig = stripMountPlumbing<SearchSurfaceConfig>(config ?? null);\n const element = document.createElement('syntro-search-surface') as SearchSurfaceElement;\n container.appendChild(element);\n if (surfaceConfig?.variant) {\n element.showSkeleton(surfaceConfig.variant, surfaceConfig.query ?? '');\n }\n return () => element.remove();\n },\n};\n\nexport const runtime = {\n id: 'adaptive-search',\n version: '1.0.0',\n name: 'Adaptive Search',\n description: 'Draws every search result as a Syntro surface.',\n\n /** No DOM-mutation executors: this surface renders only. */\n executors: [],\n\n widgets: [\n {\n id: 'adaptive-search:surface',\n component: SearchSurfaceMountable,\n metadata: {\n name: 'Search Surface',\n description: 'The search results surface, painted per variant and filled region by region',\n icon: '\uD83D\uDD0E',\n /**\n * The surface replaces a whole results page, so it needs the\n * full-viewport slot. It is not self-sufficient anywhere else: the\n * scrolling and scroll containment it relies on come from\n * `overlay_full`'s own slot styles (`overflow: auto` plus\n * `overscroll-behavior: contain`), not from this element.\n */\n slots: ['overlay_full'],\n },\n },\n ],\n};\n\nexport default runtime;\n"],
5
+ "mappings": "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",
6
+ "names": ["createContext", "key", "i", "c", "s", "e", "html", "nothing", "entry", "detail", "html", "nothing"]
7
+ }