{"version":3,"sources":["../src/core/priority-queue.ts","../src/core/frequency.ts","../src/core/resolve-schedule.ts","../src/core/scheduler.ts","../src/lib/announcements-engine/eligibility.ts","../src/lib/announcements-engine/reducer.ts","../src/lib/announcements-engine/types.ts","../src/lib/announcements-engine/analytics.ts","../src/lib/announcements-engine/persistence.ts","../src/lib/announcements-engine/create-announcements-engine.ts","../src/lib/announcements-engine/create-announcements-handle.ts"],"names":["PriorityQueue","config","id","priority","weight","item","index","order","a","b","createComparator","weights","weightA","weightB","createAnnouncementComparator","sequenceById","seqA","seqB","canShowByFrequency","state","rule","coreCanShowByFrequency","canShowAfterDismissal","coreCanShowAfterDismissal","getViewLimit","coreGetViewLimit","loadScheduling","__require","mod","M","resolveScheduleActive","schedule","now","load","scheduling","AnnouncementScheduler","isScheduleActive","userContext","matchesAudience","evaluateAnnouncementAudience","audience","segments","coreEvaluateAudience","computeEligibleIds","configs","ids","FORCE_SHOW_BYPASS","createInitialState","announcementsReducer","action","newAnnouncements","newConfigs","announcement","queueChanged","i","partialState","current","DEFAULT_QUEUE_CONFIG","getAnnouncementAnalyticsMetadata","metadata","STORAGE_KEY_PREFIX","getStorageKey","prefix","EMPTY_STATE","emptyAnnouncementsState","seedAnnouncementsState","createAnnouncementsEngine","options","initialAnnouncements","storage","storageKey","analytics","onShow","onDismiss","onComplete","queueConfig","eligibleIds","scheduler","listeners","createListeners","timers","booted","destroyed","dispatch","next","persist","restore","data","parsed","persistCurrent","emitShown","trigger","segmentAdmits","showInternal","before","advanceQueue","nextId","scheduleAdvance","timer","recomputeEligibility","changed","autoShow","eligible","st","cfg","t","restored","c","r","reason","createAnnouncementsHandle","seed","createHandle"],"mappings":"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","file":"chunk-7PZZZIGS.cjs","sourcesContent":["import type {\n  EngineAnnouncementConfig as AnnouncementConfig,\n  AnnouncementPriority,\n  PriorityOrder,\n  QueueConfig,\n  QueueItem,\n} from '../lib/announcements-engine/types'\n\n/**\n * Priority queue implementation for announcement ordering\n */\nexport class PriorityQueue {\n  private items: QueueItem[] = []\n  private config: QueueConfig\n  private sequenceCounter = 0\n\n  constructor(config: QueueConfig) {\n    this.config = config\n  }\n\n  /**\n   * Add an item to the queue\n   */\n  enqueue(id: string, priority: AnnouncementPriority): void {\n    const weight = this.config.priorityWeights[priority]\n    const item: QueueItem = {\n      id,\n      priority,\n      addedAt: Date.now(),\n      weight,\n      sequence: this.sequenceCounter++,\n    }\n\n    this.items.push(item)\n    this.sort()\n  }\n\n  /**\n   * Remove and return the highest priority item\n   */\n  dequeue(): QueueItem | undefined {\n    return this.items.shift()\n  }\n\n  /**\n   * Peek at the highest priority item without removing\n   */\n  peek(): QueueItem | undefined {\n    return this.items[0]\n  }\n\n  /**\n   * Remove a specific item by ID\n   */\n  remove(id: string): boolean {\n    const index = this.items.findIndex((item) => item.id === id)\n    if (index !== -1) {\n      this.items.splice(index, 1)\n      return true\n    }\n    return false\n  }\n\n  /**\n   * Check if an item is in the queue\n   */\n  has(id: string): boolean {\n    return this.items.some((item) => item.id === id)\n  }\n\n  /**\n   * Get position of an item in the queue (0-indexed)\n   */\n  getPosition(id: string): number {\n    return this.items.findIndex((item) => item.id === id)\n  }\n\n  /**\n   * Get all item IDs in order\n   */\n  getIds(): string[] {\n    return this.items.map((item) => item.id)\n  }\n\n  /**\n   * Get queue size\n   */\n  get size(): number {\n    return this.items.length\n  }\n\n  /**\n   * Check if queue is empty\n   */\n  get isEmpty(): boolean {\n    return this.items.length === 0\n  }\n\n  /**\n   * Clear the queue\n   */\n  clear(): void {\n    this.items = []\n  }\n\n  /**\n   * Update configuration and re-sort\n   */\n  updateConfig(config: QueueConfig): void {\n    this.config = config\n    // Update weights for existing items\n    this.items = this.items.map((item) => ({\n      ...item,\n      weight: this.config.priorityWeights[item.priority],\n    }))\n    this.sort()\n  }\n\n  /**\n   * Sort items based on priority order\n   */\n  private sort(): void {\n    const order = this.config.priorityOrder\n\n    this.items.sort((a, b) => {\n      switch (order) {\n        case 'priority':\n          // Higher weight = higher priority, comes first\n          // If same weight, earlier added comes first (use sequence for reliable ordering)\n          if (a.weight !== b.weight) {\n            return b.weight - a.weight\n          }\n          return a.sequence - b.sequence\n\n        case 'fifo':\n          // First in, first out - lower sequence comes first\n          return a.sequence - b.sequence\n\n        case 'lifo':\n          // Last in, first out - higher sequence comes first\n          return b.sequence - a.sequence\n\n        default:\n          return 0\n      }\n    })\n  }\n}\n\n/**\n * Create a comparator function for a given priority order\n */\nexport function createComparator(\n  order: PriorityOrder,\n  weights: Record<AnnouncementPriority, number>\n): (a: QueueItem, b: QueueItem) => number {\n  return (a, b) => {\n    switch (order) {\n      case 'priority': {\n        const weightA = weights[a.priority]\n        const weightB = weights[b.priority]\n        if (weightA !== weightB) {\n          return weightB - weightA\n        }\n        return a.sequence - b.sequence\n      }\n      case 'fifo':\n        return a.sequence - b.sequence\n      case 'lifo':\n        return b.sequence - a.sequence\n      default:\n        return 0\n    }\n  }\n}\n\n/**\n * Comparator for announcements at the provider boundary.\n *\n * Phase 3 (refactor train) — replaces the inline `priorityOrder` literal in\n * `<AnnouncementsProvider>` that duplicated `QueueConfig.priorityWeights` and\n * ignored the `priorityOrder: 'priority' | 'fifo' | 'lifo'` setting.\n *\n * Works on a lightweight pick of `AnnouncementConfig` because the provider\n * doesn't have `QueueItem`s yet — they're only minted when the scheduler\n * enqueues. The `sequenceById` map carries the original insertion order from\n * the filtered announcements list so `fifo` / `lifo` can break ties\n * deterministically.\n */\nexport function createAnnouncementComparator(\n  order: PriorityOrder,\n  weights: Record<AnnouncementPriority, number>,\n  sequenceById: ReadonlyMap<string, number>\n): (\n  a: Pick<AnnouncementConfig, 'id' | 'priority'>,\n  b: Pick<AnnouncementConfig, 'id' | 'priority'>\n) => number {\n  return (a, b) => {\n    const seqA = sequenceById.get(a.id) ?? 0\n    const seqB = sequenceById.get(b.id) ?? 0\n    switch (order) {\n      case 'priority': {\n        const weightA = weights[a.priority ?? 'normal']\n        const weightB = weights[b.priority ?? 'normal']\n        if (weightA !== weightB) {\n          // Higher weight = higher priority, comes first\n          return weightB - weightA\n        }\n        // Tie-break by insertion order (FIFO)\n        return seqA - seqB\n      }\n      case 'fifo':\n        return seqA - seqB\n      case 'lifo':\n        return seqB - seqA\n      default:\n        return 0\n    }\n  }\n}\n","/**\n * Phase 3a lifted these helpers to `@tour-kit/core`. This module keeps the\n * named exports intact so existing imports (`import { canShowByFrequency }\n * from '@tour-kit/announcements'` via the package barrel) keep resolving.\n * Bodies are thin shims that delegate to core — `AnnouncementState` already\n * satisfies `FrequencyState` (`viewCount`, `isDismissed`, `lastViewedAt`).\n *\n * @deprecated Prefer `import { canShowByFrequency } from '@tour-kit/core'` in\n * new code. Re-exports here remain through 1.x.\n */\nimport {\n  type FrequencyRule,\n  canShowAfterDismissal as coreCanShowAfterDismissal,\n  canShowByFrequency as coreCanShowByFrequency,\n  getViewLimit as coreGetViewLimit,\n} from '@tour-kit/core/engine'\nimport type { AnnouncementState } from '../lib/announcements-engine/types'\n\nexport function canShowByFrequency(\n  state: AnnouncementState,\n  rule: FrequencyRule | undefined\n): boolean {\n  return coreCanShowByFrequency(state, rule)\n}\n\nexport function canShowAfterDismissal(rule: FrequencyRule | undefined): boolean {\n  return coreCanShowAfterDismissal(rule)\n}\n\nexport function getViewLimit(rule: FrequencyRule | undefined): number {\n  return coreGetViewLimit(rule)\n}\n","import type { Schedule } from '@tour-kit/scheduling/engine'\n\n/**\n * Resolve an `AnnouncementConfig.schedule` $ref to a real schedule evaluation.\n *\n * `@tour-kit/scheduling` is an OPTIONAL peer (`peerDependenciesMeta.optional`),\n * so it must NOT be a hard module-load import — a consumer who never sets a\n * `schedule` may not have it installed. We resolve `isScheduleActive` lazily at\n * call time and DEGRADE OPEN: if the peer is absent (or anything throws) we\n * return `true`, so content is never suppressed merely because the optional dep\n * is missing. The field is only read when `config.schedule` is set, by which\n * point a correct consumer already depends on scheduling for the `Schedule`\n * type itself.\n *\n * Note: in a pure-ESM browser bundle without a `require` shim this degrades\n * open (the schedule is treated as active). CJS, bundlers that provide\n * `require`, and the test runner all resolve it for real.\n */\ntype IsScheduleActive = (schedule: Schedule, options: { now: Date }) => { isActive: boolean }\n\ninterface SchedulingModule {\n  isScheduleActive: IsScheduleActive\n}\n\n// Reached through a runtime require so `@tour-kit/scheduling` stays optional.\n// Typed locally because these browser packages don't pull in `@types/node`.\ndeclare const require: undefined | ((id: string) => unknown)\n\n/** Load the optional scheduling peer, or `null` if it isn't installed. */\nexport function loadScheduling(): SchedulingModule | null {\n  if (typeof require !== 'function') return null\n  try {\n    const mod = require('@tour-kit/scheduling') as Partial<SchedulingModule>\n    return typeof mod.isScheduleActive === 'function' ? (mod as SchedulingModule) : null\n  } catch {\n    return null\n  }\n}\n\n/**\n * `load` is injectable purely as a test seam for the degrade-open contract; in\n * production it defaults to {@link loadScheduling}.\n */\nexport function resolveScheduleActive(\n  schedule: Schedule,\n  now: Date,\n  load: () => SchedulingModule | null = loadScheduling\n): boolean {\n  try {\n    const scheduling = load()\n    if (!scheduling) return true // optional peer absent → don't suppress content\n    return scheduling.isScheduleActive(schedule, { now }).isActive\n  } catch {\n    return true // any failure degrades open — never suppress on the optional path\n  }\n}\n","import type {\n  EngineAnnouncementConfig as AnnouncementConfig,\n  AnnouncementState,\n  IsScheduleActive,\n  QueueConfig,\n} from '../lib/announcements-engine/types'\nimport { matchesAudience } from './audience'\nimport { canShowByFrequency } from './frequency'\nimport { PriorityQueue } from './priority-queue'\nimport { resolveScheduleActive } from './resolve-schedule'\n\n/**\n * Announcement scheduler manages the queue and determines when announcements should show\n */\nexport class AnnouncementScheduler {\n  private queue: PriorityQueue\n  private config: QueueConfig\n  private activeCount = 0\n  /** Injected optional-peer loader; `undefined` keeps the default require path. */\n  private loadScheduling: (() => { isScheduleActive: IsScheduleActive }) | undefined\n\n  /**\n   * `isScheduleActive` is the optional `@tour-kit/scheduling` peer, injected\n   * (v3 Phase 3, plan Decision 7b). It is a SECOND, optional argument so every\n   * existing caller and the existing scheduler suites are untouched.\n   *\n   * Left undefined, `resolveScheduleActive` falls back to its call-time\n   * `require('@tour-kit/scheduling')` — which degrades OPEN whenever `require`\n   * is absent, i.e. in every ESM build. An ESM consumer of `/engine` passes\n   * `isScheduleActive` from `@tour-kit/scheduling/engine` to get real gating.\n   */\n  constructor(config: QueueConfig, isScheduleActive?: IsScheduleActive) {\n    this.config = config\n    this.queue = new PriorityQueue(config)\n    // NOTE: `resolveScheduleActive`'s third parameter is a LOADER, not an\n    // `IsScheduleActive` (§0 C15). Passing the function directly would have\n    // `load()` call it with no arguments; it throws on `schedule.type`, the\n    // resolver's `catch` swallows it and the gate silently degrades open —\n    // exactly the always-active failure this seam exists to eliminate.\n    this.loadScheduling = isScheduleActive ? () => ({ isScheduleActive }) : undefined\n  }\n\n  /**\n   * Check if an announcement can be shown\n   */\n  canShow(\n    config: AnnouncementConfig,\n    state: AnnouncementState,\n    userContext?: Record<string, unknown>,\n    now: Date = new Date()\n  ): boolean {\n    if (state.isDismissed) {\n      return false\n    }\n\n    // Completion is terminal, same as dismissal — a completed announcement must\n    // not re-show until `reset()` clears `completedAt`. Without this, completing\n    // an announcement whose frequency permits re-show (e.g. `'always'`, the\n    // default) lets the auto-show effect immediately re-display it. `forceShow()`\n    // bypasses this gate by design.\n    if (state.completedAt) {\n      return false\n    }\n\n    // Check frequency rules\n    if (!canShowByFrequency(state, config.frequency)) {\n      return false\n    }\n\n    // Check audience targeting — only the legacy array shape goes through\n    // `matchesAudience` here. The segment-shape `{ segment: string }` branch is\n    // resolved upstream by `useFilteredAnnouncements` (Phase 3c) which prunes\n    // ineligible announcements before they reach the scheduler. Treating an\n    // array+undefined as \"match\" keeps backward compat unchanged.\n    if (Array.isArray(config.audience) && !matchesAudience(config.audience, userContext)) {\n      return false\n    }\n\n    // Schedule gating via the optional @tour-kit/scheduling peer. The resolver\n    // degrades open (returns true) when the peer is absent, so wiring this never\n    // turns scheduling into a hard dependency.\n    if (config.schedule && !resolveScheduleActive(config.schedule, now, this.loadScheduling)) {\n      return false\n    }\n\n    return true\n  }\n\n  /**\n   * Try to queue an announcement\n   * Returns true if queued, false if should show immediately or can't show\n   */\n  shouldQueue(\n    config: AnnouncementConfig,\n    state: AnnouncementState,\n    userContext?: Record<string, unknown>\n  ): boolean {\n    if (!this.canShow(config, state, userContext)) {\n      return false\n    }\n\n    // If already in queue, don't add again\n    if (this.queue.has(config.id)) {\n      return false\n    }\n\n    // If at max concurrent and stackBehavior is 'queue', should queue\n    if (this.activeCount >= this.config.maxConcurrent) {\n      if (this.config.stackBehavior === 'queue') {\n        return true\n      }\n      // 'replace' behavior means show immediately (replace current)\n      // 'stack' behavior means show immediately (stack on top)\n      return false\n    }\n\n    return false\n  }\n\n  /**\n   * Add an announcement to the queue\n   */\n  enqueue(config: AnnouncementConfig): number {\n    const priority = config.priority ?? 'normal'\n    this.queue.enqueue(config.id, priority)\n    return this.queue.getPosition(config.id)\n  }\n\n  /**\n   * Get the next announcement to show\n   */\n  getNext(): string | undefined {\n    const item = this.queue.dequeue()\n    return item?.id\n  }\n\n  /**\n   * Peek at the next announcement without removing\n   */\n  peekNext(): string | undefined {\n    const item = this.queue.peek()\n    return item?.id\n  }\n\n  /**\n   * Remove an announcement from the queue\n   */\n  remove(id: string): boolean {\n    return this.queue.remove(id)\n  }\n\n  /**\n   * Check if an announcement is queued\n   */\n  isQueued(id: string): boolean {\n    return this.queue.has(id)\n  }\n\n  /**\n   * Get queue position for an announcement (0-indexed, -1 if not queued)\n   */\n  getQueuePosition(id: string): number {\n    return this.queue.getPosition(id)\n  }\n\n  /**\n   * Get all queued announcement IDs in order\n   */\n  getQueuedIds(): string[] {\n    return this.queue.getIds()\n  }\n\n  /**\n   * Get queue size\n   */\n  get queueSize(): number {\n    return this.queue.size\n  }\n\n  /**\n   * Check if more announcements can be shown\n   */\n  canShowMore(): boolean {\n    return this.activeCount < this.config.maxConcurrent\n  }\n\n  /**\n   * Mark an announcement as active (being shown)\n   */\n  markActive(): void {\n    this.activeCount++\n  }\n\n  /**\n   * Mark an announcement as inactive (hidden/dismissed)\n   */\n  markInactive(): void {\n    this.activeCount = Math.max(0, this.activeCount - 1)\n  }\n\n  /**\n   * Get current active count\n   */\n  get currentActiveCount(): number {\n    return this.activeCount\n  }\n\n  /**\n   * Clear the queue\n   */\n  clearQueue(): void {\n    this.queue.clear()\n  }\n\n  /**\n   * Reset active count\n   */\n  resetActive(): void {\n    this.activeCount = 0\n  }\n\n  /**\n   * Update configuration\n   */\n  updateConfig(config: QueueConfig): void {\n    this.config = config\n    this.queue.updateConfig(config)\n  }\n\n  /**\n   * Get delay between announcements\n   */\n  get delayBetween(): number {\n    return this.config.delayBetween\n  }\n\n  /**\n   * Check if auto-show is enabled\n   */\n  get autoShow(): boolean {\n    return this.config.autoShow\n  }\n\n  /**\n   * Read-only view of the active queue configuration.\n   *\n   * Phase 3 (refactor train) — exposed so callers (notably the provider's\n   * auto-show effect) can drive ordering from `priorityWeights` /\n   * `priorityOrder` without reaching into the private `config` field.\n   */\n  get queueConfig(): Readonly<QueueConfig> {\n    return this.config\n  }\n}\n","/**\n * Segment eligibility, owned by the engine (plan Decision 7a).\n *\n * `useFilteredAnnouncements` read `useSegments()` from core's React barrel and\n * its `filteredIds` set gated three provider paths — auto-show, `show(id)` and\n * `canShow(id)` — while `REGISTER` used the UNFILTERED list. That asymmetry is\n * why the hints pattern (binding filters, engine receives the filtered list)\n * does not fit: it would make excluded ids unknown to the engine and change\n * what `getConfig`/`getState` return for them.\n *\n * So the engine owns eligibility and the binding forwards one signal:\n * `setSegments(segments)`. The default is `{}`, and core's `evaluateAudience`\n * returns `segments[name] === true`, so every segment audience fails CLOSED\n * until admitted — which is exactly today's behaviour with no\n * `<SegmentationProvider>` mounted.\n */\nimport { evaluateAudience as coreEvaluateAudience } from '@tour-kit/core/engine'\nimport type { AudienceProp } from '@tour-kit/core/engine'\nimport type { EngineAnnouncementConfig } from './types'\n\n/**\n * Resolve a single announcement's audience for the segment-shape branch only.\n *\n * Returns `true` (let through) for `undefined` and array-shape audiences — the\n * array branch is re-checked downstream by the scheduler against `userContext`,\n * which is the legacy contract we must preserve. Only segment-shape audiences\n * are resolved here, because those need a segment map the scheduler has no\n * access to.\n *\n * Moved from `hooks/use-filtered-announcements.tsx` unchanged. It is a public\n * root export (`index.ts`), so the hook file re-exports it under the same name\n * and nothing moves for consumers.\n */\nexport function evaluateAnnouncementAudience(\n  audience: AudienceProp | undefined,\n  segments: Record<string, boolean>\n): boolean {\n  if (!audience) return true\n  // Array-shape audiences are forwarded to the scheduler unchanged — it owns\n  // the legacy `matchesAudience(audience, userContext)` evaluation against the\n  // provider's `userContext` prop. (See memory #204 / phase-1 Open Question 1.)\n  if (Array.isArray(audience)) return true\n  // After the two guards above, `AudienceProp = AudienceCondition[] | { segment: string }`\n  // narrows to the segment branch — delegate to core for warn-once + segment lookup.\n  // `userContext` is intentionally `undefined`; arrays never reach here.\n  return coreEvaluateAudience(audience, segments, undefined, 'useFilteredAnnouncements')\n}\n\n/**\n * The ids a given segment map admits, derived from configs rather than stored.\n *\n * Recomputed by all three of the inputs the provider's auto-show effect read:\n * `setAnnouncements`, `setUserContext` and `setSegments`.\n */\nexport function computeEligibleIds(\n  configs: Iterable<EngineAnnouncementConfig>,\n  segments: Record<string, boolean>\n): Set<string> {\n  const ids = new Set<string>()\n  for (const config of configs) {\n    if (evaluateAnnouncementAudience(config.audience, segments)) ids.add(config.id)\n  }\n  return ids\n}\n","/**\n * The announcements reducer, moved verbatim from `announcements-provider.tsx`\n * in v3 Phase 3 Task 3.2. Pure `(state, action) => state`, no React, no DOM.\n *\n * The local `AnnouncementsState` / `AnnouncementsAction` declarations that sat\n * beside it are gone: they live in `./types` now, parameterised by `TConfig`\n * so the React side can widen `configs` to configs carrying `ReactNode`.\n */\nimport type {\n  AnnouncementState,\n  AnnouncementsAction,\n  AnnouncementsEngineState,\n  EngineAnnouncementConfig,\n} from './types'\n\n/**\n * Whitelist of gates `forceShow(id)` may bypass.\n *\n * Phase 0 §4 sign-off; pinned by a literal-array test in\n * `__tests__/force-show.test.tsx`. New gates added to `show()` MUST default to\n * \"respect, don't bypass\" — adding a gate name here is a deliberate API change\n * and breaks the pinned test, forcing a review.\n *\n * The `<LicenseGate require=\"pro\">` wrapper is intentionally NOT a member of\n * this list — `forceShow` must not strip the license soft-gate watermark. See\n * `apps/docs/content/docs/guides/imperative-control.mdx`.\n */\nexport const FORCE_SHOW_BYPASS = [\n  'frequency',\n  'cooldown',\n  'viewCount',\n  'isDismissed',\n  'audience',\n] as const\n\nexport type ForceShowBypassKey = (typeof FORCE_SHOW_BYPASS)[number]\n\n/** A fresh, segment-closed engine state. Every arm below spreads `...state`,\n * so `eligibleIds` rides along untouched — it is written only by the engine's\n * own `recomputeEligibility`, never by an action. */\nexport function createInitialState(id: string): AnnouncementState {\n  return {\n    id,\n    isActive: false,\n    isVisible: false,\n    isDismissed: false,\n    viewCount: 0,\n    lastViewedAt: null,\n    dismissedAt: null,\n    dismissalReason: null,\n    completedAt: null,\n  }\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: reducer handling multiple action types\nexport function announcementsReducer<TConfig extends EngineAnnouncementConfig>(\n  state: AnnouncementsEngineState<TConfig>,\n  action: AnnouncementsAction<TConfig>\n): AnnouncementsEngineState<TConfig> {\n  switch (action.type) {\n    case 'REGISTER': {\n      const newAnnouncements = new Map(state.announcements)\n      const newConfigs = new Map(state.configs)\n\n      if (!newAnnouncements.has(action.config.id)) {\n        newAnnouncements.set(action.config.id, createInitialState(action.config.id))\n      }\n      newConfigs.set(action.config.id, action.config)\n\n      return { ...state, announcements: newAnnouncements, configs: newConfigs }\n    }\n\n    case 'UNREGISTER': {\n      const newAnnouncements = new Map(state.announcements)\n      const newConfigs = new Map(state.configs)\n      newAnnouncements.delete(action.id)\n      newConfigs.delete(action.id)\n\n      return {\n        ...state,\n        announcements: newAnnouncements,\n        configs: newConfigs,\n        activeAnnouncement:\n          state.activeAnnouncement === action.id ? null : state.activeAnnouncement,\n        queue: state.queue.filter((id) => id !== action.id),\n      }\n    }\n\n    case 'SHOW': {\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.id)\n\n      if (announcement && !announcement.isDismissed) {\n        newAnnouncements.set(action.id, {\n          ...announcement,\n          isActive: true,\n          isVisible: true,\n          viewCount: announcement.viewCount + 1,\n          lastViewedAt: action.at,\n        })\n        return {\n          ...state,\n          announcements: newAnnouncements,\n          activeAnnouncement: action.id,\n        }\n      }\n      return state\n    }\n\n    case 'FORCE_SHOW': {\n      // Mirror SHOW but bypass the isDismissed guard and clear the dismissal\n      // record. Every other gate (frequency/cooldown/viewCount/audience) is\n      // enforced in `show()` and skipped by `forceShow()` per Phase 0 §4.\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.id)\n\n      if (!announcement) return state\n\n      newAnnouncements.set(action.id, {\n        ...announcement,\n        isActive: true,\n        isVisible: true,\n        viewCount: announcement.viewCount + 1,\n        lastViewedAt: action.at,\n        isDismissed: false,\n        dismissedAt: null,\n        dismissalReason: null,\n      })\n      return {\n        ...state,\n        announcements: newAnnouncements,\n        activeAnnouncement: action.id,\n      }\n    }\n\n    case 'HIDE': {\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.id)\n\n      if (announcement) {\n        newAnnouncements.set(action.id, {\n          ...announcement,\n          isActive: false,\n          isVisible: false,\n        })\n        return {\n          ...state,\n          announcements: newAnnouncements,\n          activeAnnouncement:\n            state.activeAnnouncement === action.id ? null : state.activeAnnouncement,\n        }\n      }\n      return state\n    }\n\n    case 'DISMISS': {\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.id)\n\n      if (announcement) {\n        newAnnouncements.set(action.id, {\n          ...announcement,\n          isActive: false,\n          isVisible: false,\n          isDismissed: true,\n          dismissedAt: action.at,\n          dismissalReason: action.reason,\n        })\n        return {\n          ...state,\n          announcements: newAnnouncements,\n          activeAnnouncement:\n            state.activeAnnouncement === action.id ? null : state.activeAnnouncement,\n          queue: state.queue.filter((id) => id !== action.id),\n        }\n      }\n      return state\n    }\n\n    case 'COMPLETE': {\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.id)\n\n      if (announcement) {\n        newAnnouncements.set(action.id, {\n          ...announcement,\n          isActive: false,\n          isVisible: false,\n          completedAt: action.at,\n        })\n        return {\n          ...state,\n          announcements: newAnnouncements,\n          activeAnnouncement:\n            state.activeAnnouncement === action.id ? null : state.activeAnnouncement,\n        }\n      }\n      return state\n    }\n\n    case 'RESET': {\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.id)\n\n      if (announcement) {\n        newAnnouncements.set(action.id, {\n          ...announcement,\n          isDismissed: false,\n          dismissedAt: null,\n          dismissalReason: null,\n          viewCount: 0,\n          lastViewedAt: null,\n          completedAt: null,\n        })\n        return { ...state, announcements: newAnnouncements }\n      }\n      return state\n    }\n\n    case 'RESET_ALL': {\n      const newAnnouncements = new Map(state.announcements)\n      newAnnouncements.forEach((announcement, id) => {\n        newAnnouncements.set(id, {\n          ...announcement,\n          isDismissed: false,\n          dismissedAt: null,\n          dismissalReason: null,\n          viewCount: 0,\n          lastViewedAt: null,\n          completedAt: null,\n        })\n      })\n      return { ...state, announcements: newAnnouncements }\n    }\n\n    case 'SET_ACTIVE': {\n      return { ...state, activeAnnouncement: action.id }\n    }\n\n    case 'ADVANCE_QUEUE': {\n      // The ONLY arm that writes `state.queue` (plan Decision 5). When `show`\n      // is set it applies the promotion in the SAME pass, so no snapshot ever\n      // exists in which the promoted id has left the queue without arriving.\n      const queueChanged =\n        state.queue.length !== action.queue.length ||\n        state.queue.some((id, i) => id !== action.queue[i])\n\n      if (!action.show) {\n        return queueChanged ? { ...state, queue: action.queue } : state\n      }\n\n      const newAnnouncements = new Map(state.announcements)\n      const announcement = newAnnouncements.get(action.show)\n      if (!announcement || announcement.isDismissed) {\n        return queueChanged ? { ...state, queue: action.queue } : state\n      }\n\n      newAnnouncements.set(action.show, {\n        ...announcement,\n        isActive: true,\n        isVisible: true,\n        viewCount: announcement.viewCount + 1,\n        lastViewedAt: action.at,\n      })\n      return {\n        ...state,\n        announcements: newAnnouncements,\n        activeAnnouncement: action.show,\n        queue: action.queue,\n      }\n    }\n\n    case 'RESTORE_STATE': {\n      const newAnnouncements = new Map(state.announcements)\n      action.states.forEach((partialState, id) => {\n        const current = newAnnouncements.get(id)\n        if (current) {\n          newAnnouncements.set(id, { ...current, ...partialState })\n        }\n      })\n      return { ...state, announcements: newAnnouncements }\n    }\n\n    default:\n      return state\n  }\n}\n","/**\n * React-free type surface for `@tour-kit/announcements/engine`.\n *\n * v3 Phase 3, Task 3.1. Every type the engine barrel reaches lives here, and\n * nothing here may reach `../../types/` — that barrel type-imports ReactNode,\n * and a type import leaves no trace in the emitted JS, so a `dist:size` gate\n * and a JS closure scan both stay green while React sits in the declaration\n * chain (recipe gap 18). The source walk in `no-react-in-engine-dist.test.ts`\n * is what catches it.\n *\n * NOTE — do not write the bare specifier in prose here. rollup-dts preserves\n * doc comments into `dist/engine/index.d.ts`, so a comment quoting it trips\n * the declaration-closure guard. Measured 2026-09-10: this very block did.\n *\n * The direction of dependency is the point: `../../types/announcement.ts`\n * imports FROM here and widens `title`/`description` to `ReactNode`. The\n * engine never learns that those fields exist.\n */\nimport type { AudienceProp, FrequencyRule } from '@tour-kit/core/engine'\nimport type { Schedule } from '@tour-kit/scheduling/engine'\n\n/** Announcement display variants. React-free — a string union. */\nexport type AnnouncementVariant = 'modal' | 'slideout' | 'banner' | 'toast' | 'spotlight'\n\n/** Announcement priority levels */\nexport type AnnouncementPriority = 'low' | 'normal' | 'high' | 'critical'\n\n/** Dismissal reasons for analytics and state tracking */\nexport type DismissalReason =\n  | 'close_button'\n  | 'overlay_click'\n  | 'escape_key'\n  | 'primary_action'\n  | 'secondary_action'\n  | 'auto_dismiss'\n  | 'programmatic'\n\n/** Queue priority ordering */\nexport type PriorityOrder = 'priority' | 'fifo' | 'lifo'\n\n/** Behavior when a new announcement is added while one is active */\nexport type StackBehavior = 'queue' | 'replace' | 'stack'\n\n/**\n * Per-announcement runtime state. Measured React-free before the extraction —\n * this interface moved verbatim.\n */\nexport interface AnnouncementState {\n  id: string\n  isActive: boolean\n  isVisible: boolean\n  isDismissed: boolean\n  viewCount: number\n  lastViewedAt: Date | null\n  dismissedAt: Date | null\n  dismissalReason: DismissalReason | null\n  completedAt: Date | null\n}\n\n/** Queue configuration */\nexport interface QueueConfig {\n  /** Maximum number of announcements that can be shown concurrently */\n  maxConcurrent: number\n  /** How to order announcements in the queue */\n  priorityOrder: PriorityOrder\n  /** Behavior when new announcements are added */\n  stackBehavior: StackBehavior\n  /** Default delay between announcements (ms) */\n  delayBetween: number\n  /** Priority weights for ordering (higher = more important) */\n  priorityWeights: Record<AnnouncementPriority, number>\n  /** Whether to auto-show queued announcements */\n  autoShow: boolean\n}\n\n/** Default queue configuration */\nexport const DEFAULT_QUEUE_CONFIG: QueueConfig = {\n  maxConcurrent: 1,\n  priorityOrder: 'priority',\n  stackBehavior: 'queue',\n  delayBetween: 500,\n  priorityWeights: {\n    critical: 1000,\n    high: 100,\n    normal: 10,\n    low: 1,\n  },\n  autoShow: true,\n}\n\n/** Queue item with metadata */\nexport interface QueueItem {\n  id: string\n  priority: AnnouncementPriority\n  addedAt: number\n  weight: number\n  /** Monotonic sequence number for ordering items with same timestamp */\n  sequence: number\n}\n\n/**\n * The half of `AnnouncementConfig` the engine reads.\n *\n * `title`, `description`, `media`, `primaryAction` and `secondaryAction` are\n * deliberately absent: they are presentation, they carry `ReactNode`, and the\n * scheduler/reducer/eligibility never look at them. `AnnouncementConfig`\n * extends this and adds them back on the React side (plan Decision 4).\n *\n * `variant` is optional here and required there — narrowing an optional\n * property in an extending interface is legal, and it lets an engine-only\n * consumer register `{ id }` without inventing a presentation choice.\n */\nexport interface EngineAnnouncementConfig {\n  /** Unique identifier */\n  id: string\n  /** Display variant — presentation metadata the engine only forwards to analytics */\n  variant?: AnnouncementVariant\n  /** Priority for queue ordering */\n  priority?: AnnouncementPriority\n  /** Frequency rule for showing this announcement */\n  frequency?: FrequencyRule\n  /**\n   * Schedule configuration. Typed from `@tour-kit/scheduling/engine`, never the\n   * main entry — the main entry's `.d.ts` names `react` four times, which would\n   * put React in this engine's declaration closure (plan Decision 7b item 2).\n   */\n  schedule?: Schedule\n  /** Audience targeting — an inline condition array or a `{ segment }` reference */\n  audience?: AudienceProp\n  /** Free-form category tag */\n  category?: string\n  /** Custom metadata */\n  metadata?: Record<string, unknown>\n  /** Show automatically on register or when eligibility changes. Default `true`. */\n  autoShow?: boolean\n  /** Callback when announcement is shown */\n  onShow?: () => void\n  /** Callback when announcement is dismissed */\n  onDismiss?: (reason: DismissalReason) => void\n  /** Callback when primary action is completed */\n  onComplete?: () => void\n}\n\n/**\n * Engine state, with ONE generic parameter carrying the config map.\n *\n * `announcements` is React-free already, so unlike checklists this needs no\n * indexed-access trick — the whole of the React contamination is `configs`.\n */\nexport interface AnnouncementsEngineState<\n  TConfig extends EngineAnnouncementConfig = EngineAnnouncementConfig,\n> {\n  announcements: Map<string, AnnouncementState>\n  configs: Map<string, TConfig>\n  activeAnnouncement: string | null\n  queue: string[]\n  /**\n   * The ids the current segment map admits (plan Decision 7a).\n   *\n   * In the SNAPSHOT rather than beside it, because a consumer renders it —\n   * \"can I show this?\" is a question the Vue example puts on screen. Notifying\n   * without a new state object is not enough: `getState()` would return the\n   * same reference and both `useSyncExternalStore` (Object.is) and Vue's\n   * `shallowRef` would ignore it. Found by the Vue e2e.\n   */\n  eligibleIds: ReadonlySet<string>\n}\n\n/**\n * The reducer's action union, discriminated on `type`.\n *\n * Every arm that stamps a timestamp carries `at`, so the ENGINE's injected\n * clock is the only clock. Before this, the reducer called `new Date()` while\n * the engine called `now()` for the SAME three fields — `lastViewedAt`,\n * `dismissedAt`, `completedAt` — so state and the persisted blob recorded\n * different times for one event, and an injected `now` silently controlled\n * nothing a frequency rule reads.\n */\nexport type AnnouncementsAction<\n  TConfig extends EngineAnnouncementConfig = EngineAnnouncementConfig,\n> =\n  | { type: 'REGISTER'; config: TConfig }\n  | { type: 'UNREGISTER'; id: string }\n  | { type: 'SHOW'; id: string; at: Date }\n  | { type: 'FORCE_SHOW'; id: string; at: Date }\n  | { type: 'HIDE'; id: string }\n  | { type: 'DISMISS'; id: string; reason: DismissalReason; at: Date }\n  | { type: 'COMPLETE'; id: string; at: Date }\n  | { type: 'RESET'; id: string }\n  | { type: 'RESET_ALL' }\n  | { type: 'SET_ACTIVE'; id: string | null }\n  /**\n   * The single writer of `state.queue` (plan Decision 5). Carries the id to\n   * promote so the re-sync and the SHOW land in ONE reducer pass — a two-step\n   * advance leaves a frame where the promoted id is neither queued nor active,\n   * and that frame is what a binding renders.\n   */\n  | { type: 'ADVANCE_QUEUE'; queue: string[]; show?: string | null; at: Date }\n  | { type: 'RESTORE_STATE'; states: Map<string, Partial<AnnouncementState>> }\n\n/**\n * The optional-peer seam (plan Decision 7b).\n *\n * Mirrors `@tour-kit/scheduling/engine`'s own `isScheduleActive`, whose second\n * parameter is optional — so that export is assignable here and a consumer\n * passes it straight through with no adapter.\n */\nexport type IsScheduleActive = (schedule: Schedule, options: { now: Date }) => { isActive: boolean }\n\n/** Storage adapter interface for persistence — a subset of `Storage`. */\nexport interface AnnouncementStorageAdapter {\n  getItem(key: string): string | null | Promise<string | null>\n  setItem(key: string, value: string): void | Promise<void>\n  removeItem(key: string): void | Promise<void>\n}\n","/**\n * Analytics payload derivation, moved verbatim from\n * `announcements-provider.tsx` in v3 Phase 3 Task 3.2.\n *\n * The engine takes an injected `analytics` CALLBACK, never `@tour-kit/analytics`\n * itself — `useAnalyticsOptional` is a React hook and the package is on the\n * engine guard's forbidden list (plan Decision 9).\n */\nimport type { EngineAnnouncementConfig } from './types'\n\nexport function getAnnouncementAnalyticsMetadata(\n  config: EngineAnnouncementConfig,\n  metadata?: Record<string, unknown>\n): Record<string, unknown> {\n  return {\n    announcementId: config.id,\n    variant: config.variant,\n    priority: config.priority ?? 'normal',\n    category: config.category,\n    announcementMetadata: config.metadata,\n    ...metadata,\n  }\n}\n","/**\n * Storage key helpers, moved verbatim from `announcements-provider.tsx` in\n * v3 Phase 3 Task 3.2. No React, no DOM — the adapter is injected.\n */\nexport const STORAGE_KEY_PREFIX = 'tour-kit:announcements:'\n\nexport function getStorageKey(prefix: string, id: string): string {\n  return `${prefix}${id}`\n}\n","/**\n * `createAnnouncementsEngine()` — the React-free half of\n * `<AnnouncementsProvider>` (v3 Phase 3, Task 3.3).\n *\n * Step-3 contract (quoted at `core/src/lib/tour-engine/create-tour-engine.ts:16`):\n * the constructor is INERT — no storage read, no `window`, no timer — so a\n * module-scope construction in an SSR bundle cannot throw. `boot()` is the\n * first thing that touches anything. `getState()` is reference-stable across\n * no-op dispatches, `subscribe()` is synchronous, `destroy()` is terminal.\n *\n * Three seams are injected, each defaulting to today's behaviour:\n *   - `analytics`  a callback, never `@tour-kit/analytics` (a React hook)\n *   - `now`        for deterministic frequency/schedule tests\n *   - `isScheduleActive`  the optional `@tour-kit/scheduling` peer (Decision 7b)\n * and one signal is forwarded by the binding: `setSegments()` (Decision 7a).\n */\nimport { createListeners } from '@tour-kit/core/engine'\nimport { createAnnouncementComparator } from '../../core/priority-queue'\nimport { AnnouncementScheduler } from '../../core/scheduler'\nimport { getAnnouncementAnalyticsMetadata } from './analytics'\nimport { computeEligibleIds } from './eligibility'\nimport { STORAGE_KEY_PREFIX, getStorageKey } from './persistence'\nimport { announcementsReducer } from './reducer'\nimport {\n  type AnnouncementState,\n  type AnnouncementStorageAdapter,\n  type AnnouncementsAction,\n  type AnnouncementsEngineState,\n  DEFAULT_QUEUE_CONFIG,\n  type DismissalReason,\n  type EngineAnnouncementConfig,\n  type IsScheduleActive,\n  type QueueConfig,\n} from './types'\n\n/**\n * The three events the engine emits. A literal union rather than `string`, so\n * the binding can forward straight into `@tour-kit/analytics`' `track` —\n * whose parameter is the narrower `TourEventName` — with no cast at the\n * boundary. (All three are members of that union; measured.)\n */\nexport type AnnouncementsAnalyticsEvent =\n  | 'announcement_shown'\n  | 'announcement_dismissed'\n  | 'announcement_completed'\n\n/** The analytics shape the engine needs — a callback, not a package. */\nexport interface AnnouncementsAnalytics {\n  track(\n    event: AnnouncementsAnalyticsEvent,\n    payload: { tourId: string; metadata: Record<string, unknown> }\n  ): void\n}\n\nexport interface AnnouncementsEngineOptions<TConfig extends EngineAnnouncementConfig> {\n  announcements?: TConfig[]\n  queueConfig?: Partial<QueueConfig>\n  storage?: AnnouncementStorageAdapter | null\n  storageKey?: string\n  userContext?: Record<string, unknown>\n  /** Segment map. `{}` fails every segment audience CLOSED — today's default. */\n  segments?: Record<string, boolean>\n  analytics?: AnnouncementsAnalytics | null\n  now?: () => Date\n  /**\n   * The optional `@tour-kit/scheduling` peer. Default is the scheduler's own\n   * call-time `require`, which degrades OPEN when `require` is absent — i.e.\n   * in every ESM build. An ESM consumer passes `isScheduleActive` from\n   * `@tour-kit/scheduling/engine` to get real gating (Decision 7b).\n   */\n  isScheduleActive?: IsScheduleActive\n  onShow?: (id: string) => void\n  onDismiss?: (id: string, reason: DismissalReason) => void\n  onComplete?: (id: string) => void\n  /**\n   * A pre-built seed. `createAnnouncementsHandle` passes the SAME object it\n   * serves as its pre-verb snapshot — two equal-but-distinct objects make\n   * `Object.is` false and every consumer renders twice on construction\n   * (Phase 2's finding).\n   */\n  initialState?: AnnouncementsEngineState<TConfig>\n}\n\nexport interface AnnouncementsEngine<TConfig extends EngineAnnouncementConfig> {\n  getState: () => AnnouncementsEngineState<TConfig>\n  subscribe: (listener: () => void) => () => void\n  destroy: () => void\n  boot: () => void\n  register: (config: TConfig) => void\n  unregister: (id: string) => void\n  setAnnouncements: (configs: TConfig[]) => void\n  setUserContext: (userContext: Record<string, unknown> | undefined) => void\n  setSegments: (segments: Record<string, boolean>) => void\n  setQueueConfig: (queueConfig: Partial<QueueConfig>) => void\n  show: (id: string) => void\n  forceShow: (id: string) => void\n  hide: (id: string) => void\n  dismiss: (id: string, reason?: DismissalReason) => void\n  complete: (id: string) => void\n  reset: (id: string) => void\n  resetAll: () => void\n  getAnnouncementState: (id: string) => AnnouncementState | undefined\n  getConfig: (id: string) => TConfig | undefined\n  canShow: (id: string) => boolean\n  showNext: () => void\n  clearQueue: () => void\n  /** The eligible-id set, for the binding's own filtered list. */\n  getEligibleIds: () => ReadonlySet<string>\n}\n\n/**\n * The frozen empty snapshot. `useSyncExternalStore` compares with `Object.is`,\n * and a module constant cannot be generic — so it is built at `never` and\n * handed out through an identity function (plan Decision 4 / Phase 2's rule).\n */\nconst EMPTY_STATE: AnnouncementsEngineState<never> = Object.freeze({\n  announcements: new Map<string, AnnouncementState>(),\n  configs: new Map<string, never>(),\n  activeAnnouncement: null,\n  queue: [] as string[],\n  eligibleIds: new Set<string>() as ReadonlySet<string>,\n})\n\nexport function emptyAnnouncementsState<\n  TConfig extends EngineAnnouncementConfig,\n>(): AnnouncementsEngineState<TConfig> {\n  return EMPTY_STATE as unknown as AnnouncementsEngineState<TConfig>\n}\n\n/**\n * A storage-free, boot-free seed so a binding's FIRST render already carries\n * the configs. One reducer pass, no side effects — the shape Phase 2 landed as\n * `seedChecklistsState`.\n */\nexport function seedAnnouncementsState<TConfig extends EngineAnnouncementConfig>(\n  configs: TConfig[],\n  segments: Record<string, boolean> = {}\n): AnnouncementsEngineState<TConfig> {\n  let state = emptyAnnouncementsState<TConfig>()\n  for (const config of configs) state = announcementsReducer(state, { type: 'REGISTER', config })\n  // Seeded here rather than aligned afterwards: the handle serves THIS object as\n  // its pre-verb snapshot and hands the SAME one to the engine, so any later\n  // `{ ...state }` would break that identity and make every consumer render twice.\n  return configs.length > 0\n    ? { ...state, eligibleIds: computeEligibleIds(configs, segments) }\n    : state\n}\n\nexport function createAnnouncementsEngine<TConfig extends EngineAnnouncementConfig>(\n  options: AnnouncementsEngineOptions<TConfig> = {}\n): AnnouncementsEngine<TConfig> {\n  const {\n    announcements: initialAnnouncements = [],\n    storage = null,\n    storageKey = STORAGE_KEY_PREFIX,\n    analytics = null,\n    now = () => new Date(),\n    isScheduleActive,\n    onShow,\n    onDismiss,\n    onComplete,\n  } = options\n\n  let configs = initialAnnouncements\n  let userContext = options.userContext\n  let segments = options.segments ?? {}\n  let queueConfig: QueueConfig = { ...DEFAULT_QUEUE_CONFIG, ...options.queueConfig }\n  let eligibleIds: ReadonlySet<string> = computeEligibleIds(configs, segments)\n\n  // Inert: `new AnnouncementScheduler` allocates a PriorityQueue and nothing else.\n  const scheduler = new AnnouncementScheduler(queueConfig, isScheduleActive)\n  const listeners = createListeners('announcements-engine')\n  const timers = new Set<ReturnType<typeof setTimeout>>()\n\n  let state = options.initialState ?? seedAnnouncementsState<TConfig>(configs, segments)\n  let booted = false\n  let destroyed = false\n\n  const dispatch = (action: AnnouncementsAction<TConfig>): void => {\n    // `destroy()` is TERMINAL, and that means for verbs, not just for the\n    // fan-out. Clearing the listener set alone leaves `show()` still mutating\n    // state after teardown: nobody is told, but the next `getState()` reports\n    // it — a torn-down engine that keeps changing its answer. Caught by the\n    // plain-Node case in `subpath-resolution.test.ts`.\n    if (destroyed) return\n    const next = announcementsReducer(state, action)\n    if (next === state) return\n    state = next\n    listeners.notify()\n  }\n\n  // ── persistence ────────────────────────────────────────────────────────────\n  const persist = (id: string, s: AnnouncementState): void => {\n    if (!storage) return\n    try {\n      storage.setItem(\n        getStorageKey(storageKey, id),\n        JSON.stringify({\n          viewCount: s.viewCount,\n          lastViewedAt: s.lastViewedAt?.toISOString() ?? null,\n          isDismissed: s.isDismissed,\n          dismissedAt: s.dismissedAt?.toISOString() ?? null,\n          dismissalReason: s.dismissalReason,\n          completedAt: s.completedAt?.toISOString() ?? null,\n        })\n      )\n    } catch {\n      // Storage might be full or unavailable\n    }\n  }\n\n  const restore = (id: string): Partial<AnnouncementState> | null => {\n    if (!storage) return null\n    try {\n      const data = storage.getItem(getStorageKey(storageKey, id))\n      if (!data || typeof data !== 'string') return null\n      const parsed = JSON.parse(data)\n      return {\n        viewCount: parsed.viewCount ?? 0,\n        lastViewedAt: parsed.lastViewedAt ? new Date(parsed.lastViewedAt) : null,\n        isDismissed: parsed.isDismissed ?? false,\n        dismissedAt: parsed.dismissedAt ? new Date(parsed.dismissedAt) : null,\n        dismissalReason: parsed.dismissalReason ?? null,\n        completedAt: parsed.completedAt ? new Date(parsed.completedAt) : null,\n      }\n    } catch {\n      return null\n    }\n  }\n\n  // ── the show pipeline's side effects, shared by every entry point ──────────\n  /**\n   * Persist whatever the reducer just produced for `id`.\n   *\n   * The engine used to rebuild the post-dispatch state by hand in four places\n   * — the show pipeline, `forceShow`, `dismiss` and `complete` — which meant\n   * the same transition was computed twice, once authoritatively in the\n   * reducer and once here for storage. Two computations of one fact is the\n   * shape of the desync this phase exists to remove; now there is one.\n   */\n  const persistCurrent = (id: string): void => {\n    const current = state.announcements.get(id)\n    if (current) persist(id, current)\n  }\n\n  /** The side effects that follow a SHOW. Call AFTER the dispatch. */\n  const emitShown = (config: TConfig, trigger: string): void => {\n    persistCurrent(config.id)\n    analytics?.track('announcement_shown', {\n      tourId: config.id,\n      metadata: getAnnouncementAnalyticsMetadata(config, {\n        trigger,\n        viewCount: state.announcements.get(config.id)?.viewCount ?? 0,\n      }),\n    })\n    config.onShow?.()\n    onShow?.(config.id)\n  }\n\n  /** Segment-shape audiences are refused until `setSegments` admits them. */\n  const segmentAdmits = (config: TConfig): boolean =>\n    !(config.audience && !Array.isArray(config.audience) && !eligibleIds.has(config.id))\n\n  const showInternal = (id: string, trigger: string): boolean => {\n    const before = state.announcements.get(id)\n    const config = state.configs.get(id)\n    if (!before || !config) return false\n    if (!segmentAdmits(config)) return false\n    if (!scheduler.canShow(config, before, userContext)) return false\n\n    if (scheduler.shouldQueue(config, before, userContext)) {\n      scheduler.enqueue(config)\n      dispatch({ type: 'ADVANCE_QUEUE', queue: scheduler.getQueuedIds(), at: now() })\n      return false\n    }\n\n    scheduler.markActive()\n    dispatch({ type: 'SHOW', id, at: now() })\n    emitShown(config, trigger)\n    return true\n  }\n\n  /**\n   * Advance to the next queued announcement, in ONE transition (Decision 5).\n   *\n   * `scheduler.getNext()` MUTATES the scheduler — it dequeues. The provider\n   * then re-synced `state.queue` with a separate dispatch and showed with a\n   * third, so a subscriber could observe a frame in which the promoted id had\n   * left the queue and not yet arrived. Here the gates run first and a single\n   * `ADVANCE_QUEUE` carries both the new queue and the id to promote, so that\n   * frame cannot exist and the advance costs one notification.\n   */\n  const advanceQueue = (): void => {\n    const nextId = scheduler.getNext()\n    if (!nextId) return\n\n    const before = state.announcements.get(nextId)\n    const config = state.configs.get(nextId)\n\n    // Every refusal path still re-syncs the queue, because `getNext()` already\n    // dequeued — dropping the re-sync is the original desync.\n    if (\n      !before ||\n      !config ||\n      !segmentAdmits(config) ||\n      !scheduler.canShow(config, before, userContext)\n    ) {\n      dispatch({ type: 'ADVANCE_QUEUE', queue: scheduler.getQueuedIds(), at: now() })\n      return\n    }\n\n    if (scheduler.shouldQueue(config, before, userContext)) {\n      scheduler.enqueue(config)\n      dispatch({ type: 'ADVANCE_QUEUE', queue: scheduler.getQueuedIds(), at: now() })\n      return\n    }\n\n    scheduler.markActive()\n    dispatch({ type: 'ADVANCE_QUEUE', queue: scheduler.getQueuedIds(), show: nextId, at: now() })\n    emitShown(config, 'queue')\n  }\n\n  const scheduleAdvance = (): void => {\n    if (!(scheduler.autoShow && scheduler.queueSize > 0)) return\n    const timer = setTimeout(() => {\n      timers.delete(timer)\n      advanceQueue()\n    }, scheduler.delayBetween)\n    timers.add(timer)\n  }\n\n  /**\n   * Recompute the eligible set and notify if it MOVED.\n   *\n   * Eligibility is engine state a consumer renders — \"can I show this?\" is a\n   * question the Vue example puts on screen — but it does not live in the\n   * reducer, so a `dispatch` cannot carry it. Without this diff, revoking a\n   * segment recomputes correctly and tells nobody: `autoShow()` has nothing to\n   * do, no reducer action fires, no subscriber runs, and the UI keeps showing\n   * the stale answer. Found by the Vue e2e, which is exactly the consumer this\n   * subpath exists for. The diff keeps it from notifying on every no-op.\n   */\n  const recomputeEligibility = (): void => {\n    const next = computeEligibleIds(configs, segments)\n    const changed = next.size !== eligibleIds.size || [...next].some((id) => !eligibleIds.has(id))\n    eligibleIds = next\n    if (!changed || destroyed) return\n    // A NEW state object, not just a notify. `useSyncExternalStore` compares\n    // with `Object.is` and Vue's `shallowRef` does the same, so notifying while\n    // handing back the identical reference is a no-op at every consumer. The\n    // diff above is what keeps this from allocating on every no-op call.\n    state = { ...state, eligibleIds: next }\n    listeners.notify()\n  }\n\n  /** The auto-show pass — the engine port of the provider's `:432` effect. */\n  const autoShow = (): void => {\n    if (state.announcements.size === 0) return\n\n    const eligible: TConfig[] = []\n    for (const config of configs) {\n      if (config.autoShow === false) continue\n      if (!eligibleIds.has(config.id)) continue\n      const st = state.announcements.get(config.id)\n      if (!st) continue\n      if (st.isActive || st.isVisible) continue\n      if (scheduler.isQueued(config.id)) continue\n      if (!scheduler.canShow(config, st, userContext)) continue\n      eligible.push(config)\n    }\n    if (eligible.length === 0) return\n\n    const cfg = scheduler.queueConfig\n    const sequenceById = new Map(configs.map((a, index) => [a.id, index]))\n    eligible.sort(\n      createAnnouncementComparator(cfg.priorityOrder, cfg.priorityWeights, sequenceById)\n    )\n\n    for (const config of eligible) {\n      const st = state.announcements.get(config.id)\n      if (!st) continue\n      if (scheduler.shouldQueue(config, st, userContext)) {\n        scheduler.enqueue(config)\n        dispatch({ type: 'ADVANCE_QUEUE', queue: scheduler.getQueuedIds(), at: now() })\n        continue\n      }\n      scheduler.markActive()\n      dispatch({ type: 'SHOW', id: config.id, at: now() })\n      emitShown(config, 'auto')\n    }\n  }\n\n  return {\n    getState: () => state,\n    subscribe: listeners.add,\n\n    destroy: () => {\n      if (destroyed) return\n      destroyed = true\n      for (const t of timers) clearTimeout(t)\n      timers.clear()\n      listeners.clear()\n    },\n\n    boot: () => {\n      if (booted || destroyed) return\n      booted = true\n      const restored = new Map<string, Partial<AnnouncementState>>()\n      for (const config of configs) {\n        dispatch({ type: 'REGISTER', config })\n        const r = restore(config.id)\n        if (r) restored.set(config.id, r)\n      }\n      if (restored.size > 0) dispatch({ type: 'RESTORE_STATE', states: restored })\n      autoShow()\n    },\n\n    register: (config) => {\n      dispatch({ type: 'REGISTER', config })\n      if (!configs.some((c) => c.id === config.id)) configs = [...configs, config]\n      recomputeEligibility()\n    },\n\n    unregister: (id) => {\n      dispatch({ type: 'UNREGISTER', id })\n      scheduler.remove(id)\n      configs = configs.filter((c) => c.id !== id)\n      recomputeEligibility()\n    },\n\n    setAnnouncements: (next) => {\n      configs = next\n      recomputeEligibility()\n      const restored = new Map<string, Partial<AnnouncementState>>()\n      for (const config of next) {\n        dispatch({ type: 'REGISTER', config })\n        if (!booted) continue\n        const r = restore(config.id)\n        if (r) restored.set(config.id, r)\n      }\n      if (restored.size > 0) dispatch({ type: 'RESTORE_STATE', states: restored })\n      if (booted) autoShow()\n    },\n\n    setUserContext: (next) => {\n      userContext = next\n      if (booted) autoShow()\n    },\n\n    setSegments: (next) => {\n      segments = next\n      recomputeEligibility()\n      if (booted) autoShow()\n    },\n\n    setQueueConfig: (next) => {\n      queueConfig = { ...DEFAULT_QUEUE_CONFIG, ...next }\n      scheduler.updateConfig(queueConfig)\n    },\n\n    show: (id) => void showInternal(id, 'manual'),\n\n    forceShow: (id) => {\n      // The dismissal-clearing half lives in the reducer's FORCE_SHOW arm; the\n      // side effects are the same ones every other show path runs.\n      if (!state.announcements.has(id)) return\n      const config = state.configs.get(id)\n      if (!config) return\n      scheduler.markActive()\n      dispatch({ type: 'FORCE_SHOW', id, at: now() })\n      emitShown(config, 'forced')\n    },\n\n    hide: (id) => {\n      dispatch({ type: 'HIDE', id })\n      scheduler.markInactive()\n    },\n\n    dismiss: (id, reason: DismissalReason = 'programmatic') => {\n      const before = state.announcements.get(id)\n      const config = state.configs.get(id)\n      if (!before) return\n\n      dispatch({ type: 'DISMISS', id, reason, at: now() })\n      scheduler.markInactive()\n      scheduler.remove(id)\n      dispatch({ type: 'ADVANCE_QUEUE', queue: scheduler.getQueuedIds(), at: now() })\n\n      persistCurrent(id)\n      if (config) {\n        analytics?.track('announcement_dismissed', {\n          tourId: id,\n          metadata: getAnnouncementAnalyticsMetadata(config, { reason }),\n        })\n      }\n      config?.onDismiss?.(reason)\n      onDismiss?.(id, reason)\n      scheduleAdvance()\n    },\n\n    complete: (id) => {\n      const before = state.announcements.get(id)\n      const config = state.configs.get(id)\n      if (!before) return\n\n      dispatch({ type: 'COMPLETE', id, at: now() })\n      scheduler.markInactive()\n      persistCurrent(id)\n      if (config) {\n        analytics?.track('announcement_completed', {\n          tourId: id,\n          metadata: getAnnouncementAnalyticsMetadata(config),\n        })\n      }\n      config?.onComplete?.()\n      onComplete?.(id)\n      scheduleAdvance()\n    },\n\n    reset: (id) => {\n      dispatch({ type: 'RESET', id })\n      try {\n        storage?.removeItem(getStorageKey(storageKey, id))\n      } catch {\n        // Ignore storage errors\n      }\n    },\n\n    resetAll: () => {\n      const ids = [...state.announcements.keys()]\n      dispatch({ type: 'RESET_ALL' })\n      for (const id of ids) {\n        try {\n          storage?.removeItem(getStorageKey(storageKey, id))\n        } catch {\n          // Ignore storage errors\n        }\n      }\n    },\n\n    getAnnouncementState: (id) => state.announcements.get(id),\n    getConfig: (id) => state.configs.get(id),\n\n    canShow: (id) => {\n      const st = state.announcements.get(id)\n      const config = state.configs.get(id)\n      if (!st || !config) return false\n      if (!segmentAdmits(config)) return false\n      return scheduler.canShow(config, st, userContext)\n    },\n\n    showNext: advanceQueue,\n\n    clearQueue: () => {\n      scheduler.clearQueue()\n      dispatch({ type: 'ADVANCE_QUEUE', queue: [], at: now() })\n    },\n\n    getEligibleIds: () => state.eligibleIds,\n  }\n}\n","/**\n * `createAnnouncementsHandle()` — the binding contract (v3 Phase 3, Task 3.4).\n *\n * Composed from core's generic `createHandle<E, S>`; NOT from\n * `createEngineHandle`, which hand-forwards seventeen `TourEngine` verbs and is\n * a facade over that one engine (recipe step 6, gap 15). No second lifecycle is\n * written here.\n *\n * The handle gives a binding three things `createAnnouncementsEngine` cannot:\n * construction on the FIRST VERB rather than during render (StrictMode\n * double-invokes render, and child effects run before parent effects), a\n * deferred `release()` that a verb in the same tick can take back, and a\n * snapshot to serve before the engine exists.\n */\nimport { createHandle } from '@tour-kit/core/engine'\nimport type { Handle } from '@tour-kit/core/engine'\nimport {\n  type AnnouncementsEngine,\n  type AnnouncementsEngineOptions,\n  createAnnouncementsEngine,\n  seedAnnouncementsState,\n} from './create-announcements-engine'\nimport type { AnnouncementsEngineState, EngineAnnouncementConfig } from './types'\n\nexport type AnnouncementsHandle<TConfig extends EngineAnnouncementConfig> = Handle<\n  AnnouncementsEngine<TConfig>,\n  AnnouncementsEngineState<TConfig>\n>\n\nexport function createAnnouncementsHandle<TConfig extends EngineAnnouncementConfig>(\n  options: AnnouncementsEngineOptions<TConfig> = {}\n): AnnouncementsHandle<TConfig> {\n  // ONE seed object, shared by the handle's pre-verb snapshot and the engine's\n  // own initial state. Phase 2 found that building two makes every consumer\n  // render twice: the values are equal but `Object.is` is false, so\n  // `useSyncExternalStore` re-renders the moment the engine is constructed.\n  const seed = seedAnnouncementsState<TConfig>(options.announcements ?? [], options.segments)\n\n  return createHandle<AnnouncementsEngine<TConfig>, AnnouncementsEngineState<TConfig>>(\n    () => createAnnouncementsEngine({ ...options, initialState: seed }),\n    seed\n  )\n}\n"]}