featuredrop 1.2.0 → 1.4.0

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.
Files changed (84) hide show
  1. package/README.md +171 -0
  2. package/dist/admin.cjs +212 -0
  3. package/dist/admin.cjs.map +1 -0
  4. package/dist/admin.d.cts +176 -0
  5. package/dist/admin.d.ts +176 -0
  6. package/dist/admin.js +207 -0
  7. package/dist/admin.js.map +1 -0
  8. package/dist/angular.cjs +13 -3
  9. package/dist/angular.cjs.map +1 -1
  10. package/dist/angular.d.cts +4 -0
  11. package/dist/angular.d.ts +4 -0
  12. package/dist/angular.js +13 -3
  13. package/dist/angular.js.map +1 -1
  14. package/dist/bridges.cjs +422 -0
  15. package/dist/bridges.cjs.map +1 -0
  16. package/dist/bridges.d.cts +194 -0
  17. package/dist/bridges.d.ts +194 -0
  18. package/dist/bridges.js +395 -0
  19. package/dist/bridges.js.map +1 -0
  20. package/dist/ci.cjs +328 -0
  21. package/dist/ci.cjs.map +1 -0
  22. package/dist/ci.d.cts +176 -0
  23. package/dist/ci.d.ts +176 -0
  24. package/dist/ci.js +324 -0
  25. package/dist/ci.js.map +1 -0
  26. package/dist/featuredrop.cjs +162 -20
  27. package/dist/featuredrop.cjs.map +1 -1
  28. package/dist/flags.cjs +51 -0
  29. package/dist/flags.cjs.map +1 -0
  30. package/dist/flags.d.cts +48 -0
  31. package/dist/flags.d.ts +48 -0
  32. package/dist/flags.js +47 -0
  33. package/dist/flags.js.map +1 -0
  34. package/dist/index.cjs +2599 -660
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +743 -206
  37. package/dist/index.d.ts +743 -206
  38. package/dist/index.js +2555 -668
  39. package/dist/index.js.map +1 -1
  40. package/dist/preact.cjs +747 -221
  41. package/dist/preact.cjs.map +1 -1
  42. package/dist/preact.d.cts +67 -120
  43. package/dist/preact.d.ts +67 -120
  44. package/dist/preact.js +713 -207
  45. package/dist/preact.js.map +1 -1
  46. package/dist/react.cjs +747 -221
  47. package/dist/react.cjs.map +1 -1
  48. package/dist/react.d.cts +67 -120
  49. package/dist/react.d.ts +67 -120
  50. package/dist/react.js +713 -207
  51. package/dist/react.js.map +1 -1
  52. package/dist/schema.cjs +78 -1
  53. package/dist/schema.cjs.map +1 -1
  54. package/dist/schema.d.cts +142 -0
  55. package/dist/schema.d.ts +142 -0
  56. package/dist/schema.js +78 -1
  57. package/dist/schema.js.map +1 -1
  58. package/dist/solid.cjs +13 -3
  59. package/dist/solid.cjs.map +1 -1
  60. package/dist/solid.d.cts +4 -0
  61. package/dist/solid.d.ts +4 -0
  62. package/dist/solid.js +13 -3
  63. package/dist/solid.js.map +1 -1
  64. package/dist/svelte.cjs +13 -3
  65. package/dist/svelte.cjs.map +1 -1
  66. package/dist/svelte.js +13 -3
  67. package/dist/svelte.js.map +1 -1
  68. package/dist/testing.cjs +136 -15
  69. package/dist/testing.cjs.map +1 -1
  70. package/dist/testing.d.cts +22 -0
  71. package/dist/testing.d.ts +22 -0
  72. package/dist/testing.js +136 -15
  73. package/dist/testing.js.map +1 -1
  74. package/dist/vue.cjs +36 -5
  75. package/dist/vue.cjs.map +1 -1
  76. package/dist/vue.js +16 -5
  77. package/dist/vue.js.map +1 -1
  78. package/dist/web-components.cjs +14 -4
  79. package/dist/web-components.cjs.map +1 -1
  80. package/dist/web-components.d.cts +4 -0
  81. package/dist/web-components.d.ts +4 -0
  82. package/dist/web-components.js +14 -4
  83. package/dist/web-components.js.map +1 -1
  84. package/package.json +59 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/semver.ts","../src/triggers.ts","../src/core.ts","../src/adapters/local-storage.ts","../src/web-components/index.ts"],"names":["isNew"],"mappings":"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","file":"web-components.cjs","sourcesContent":["// Minimal semver comparison utilities (no build metadata sorting needed)\n\nexport type Comparator = \">=\" | \"<=\" | \">\" | \"<\" | \"=\";\n\nexport interface SemverParts {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nconst SEMVER_REGEX = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?/;\n\nexport function parseSemver(input: string): SemverParts | null {\n const match = input.trim().match(SEMVER_REGEX);\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\nexport function compareSemver(a: string, b: string): number {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa || !pb) return 0;\n\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (pa[key] !== pb[key]) return pa[key] - pb[key];\n }\n\n // Handle prerelease: absence > presence, otherwise lexicographic\n const aPre = pa.prerelease;\n const bPre = pb.prerelease;\n if (aPre.length === 0 && bPre.length === 0) return 0;\n if (aPre.length === 0) return 1;\n if (bPre.length === 0) return -1;\n\n const len = Math.max(aPre.length, bPre.length);\n for (let i = 0; i < len; i++) {\n const ai = aPre[i];\n const bi = bPre[i];\n if (ai === undefined) return -1;\n if (bi === undefined) return 1;\n const aNum = Number(ai);\n const bNum = Number(bi);\n const aIsNum = Number.isInteger(aNum);\n const bIsNum = Number.isInteger(bNum);\n if (aIsNum && bIsNum && aNum !== bNum) return aNum - bNum;\n if (aIsNum !== bIsNum) return aIsNum ? -1 : 1;\n if (ai !== bi) return ai < bi ? -1 : 1;\n }\n return 0;\n}\n\nfunction parseComparator(comp: string): { op: Comparator; version: string } | null {\n const match = comp.trim().match(/^(>=|<=|>|<|=)?\\\\s*(.+)$/);\n if (!match) return null;\n const op = (match[1] as Comparator) || \">=\";\n const version = match[2];\n if (!parseSemver(version)) return null;\n return { op, version };\n}\n\nfunction satisfiesComparator(version: string, comp: { op: Comparator; version: string }): boolean {\n const diff = compareSemver(version, comp.version);\n switch (comp.op) {\n case \">\":\n return diff > 0;\n case \">=\":\n return diff >= 0;\n case \"<\":\n return diff < 0;\n case \"<=\":\n return diff <= 0;\n case \"=\":\n return diff === 0;\n default:\n return false;\n }\n}\n\n// Space-separated comparator list (AND semantics), e.g. \">=2.5.0 <3.0.0\"\nexport function satisfiesRange(version: string, range: string): boolean {\n const parts = range.split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return true;\n for (const part of parts) {\n const comp = parseComparator(part);\n if (!comp) return false;\n if (!satisfiesComparator(version, comp)) return false;\n }\n return true;\n}\n","import type { FeatureEntry, FeatureTrigger, TriggerContext } from \"./types\";\n\nfunction wildcardToRegExp(value: string): RegExp {\n const escaped = value.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = `^${escaped.replace(/\\*/g, \".*\")}$`;\n return new RegExp(pattern);\n}\n\nfunction matchPath(path: string, pattern: string | RegExp): boolean {\n if (pattern instanceof RegExp) return pattern.test(path);\n if (!pattern) return false;\n if (pattern.includes(\"*\")) return wildcardToRegExp(pattern).test(path);\n return path === pattern || path.startsWith(pattern);\n}\n\nexport function isTriggerMatch(trigger: FeatureTrigger | undefined, context?: TriggerContext): boolean {\n if (!trigger) return true;\n if (!context) return false;\n\n if (trigger.type === \"page\") {\n const path = context.path;\n if (!path) return false;\n return matchPath(path, trigger.match);\n }\n\n if (trigger.type === \"usage\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.event] ?? 0;\n return count >= (trigger.minActions ?? 1);\n }\n\n if (trigger.type === \"time\") {\n const elapsedMs = context.elapsedMs ?? 0;\n return elapsedMs >= trigger.minSeconds * 1000;\n }\n\n if (trigger.type === \"milestone\") {\n return context.milestones?.has(trigger.event) ?? false;\n }\n\n if (trigger.type === \"frustration\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.pattern] ?? 0;\n return count >= (trigger.threshold ?? 1);\n }\n\n if (trigger.type === \"scroll\") {\n return (context.scrollPercent ?? 0) >= (trigger.minPercent ?? 50);\n }\n\n try {\n return trigger.evaluate(context);\n } catch {\n return false;\n }\n}\n\nexport class TriggerEngine {\n private context: TriggerContext;\n\n constructor(initial?: TriggerContext) {\n this.context = {\n path: initial?.path,\n events: new Set(initial?.events ?? []),\n milestones: new Set(initial?.milestones ?? []),\n usage: { ...(initial?.usage ?? {}) },\n elapsedMs: initial?.elapsedMs ?? 0,\n scrollPercent: initial?.scrollPercent ?? 0,\n metadata: { ...(initial?.metadata ?? {}) },\n };\n }\n\n setPath(path: string): void {\n this.context.path = path;\n }\n\n trackEvent(event: string): void {\n const next = new Set(this.context.events ?? new Set<string>());\n next.add(event);\n this.context.events = next;\n }\n\n trackUsage(event: string, delta = 1): void {\n const usage = { ...(this.context.usage ?? {}) };\n usage[event] = (usage[event] ?? 0) + Math.max(1, delta);\n this.context.usage = usage;\n }\n\n trackMilestone(event: string): void {\n const next = new Set(this.context.milestones ?? new Set<string>());\n next.add(event);\n this.context.milestones = next;\n }\n\n setElapsedMs(elapsedMs: number): void {\n this.context.elapsedMs = Math.max(0, elapsedMs);\n }\n\n setScrollPercent(scrollPercent: number): void {\n const clamped = Math.max(0, Math.min(100, scrollPercent));\n this.context.scrollPercent = clamped;\n }\n\n setMetadata(next: Record<string, unknown>): void {\n this.context.metadata = { ...next };\n }\n\n getContext(): TriggerContext {\n return {\n path: this.context.path,\n events: new Set(this.context.events ?? []),\n milestones: new Set(this.context.milestones ?? []),\n usage: { ...(this.context.usage ?? {}) },\n elapsedMs: this.context.elapsedMs,\n scrollPercent: this.context.scrollPercent,\n metadata: { ...(this.context.metadata ?? {}) },\n };\n }\n\n evaluate(trigger: FeatureTrigger | undefined): boolean {\n return isTriggerMatch(trigger, this.context);\n }\n\n evaluateFeature(feature: Pick<FeatureEntry, \"trigger\">): boolean {\n return this.evaluate(feature.trigger);\n }\n}\n","import type {\n AudienceMatchFn,\n AudienceRule,\n FeatureEntry,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n FeatureDependencyState,\n TriggerContext,\n} from \"./types\";\nimport { compareSemver, satisfiesRange } from \"./semver\";\nimport { isTriggerMatch } from \"./triggers\";\n\n/**\n * Default audience matching logic.\n *\n * For each specified field (plan, role, region), checks if the user's\n * value is included in the allowed list. Fields use AND logic between them,\n * OR logic within each field's array. The `custom` field is ignored by\n * the default matcher — use a custom `AudienceMatchFn` for that.\n */\nexport function matchesAudience(\n audience: AudienceRule,\n userContext: UserContext,\n): boolean {\n if (audience.plan && audience.plan.length > 0) {\n if (!userContext.plan || !audience.plan.includes(userContext.plan)) {\n return false;\n }\n }\n if (audience.role && audience.role.length > 0) {\n if (!userContext.role || !audience.role.includes(userContext.role)) {\n return false;\n }\n }\n if (audience.region && audience.region.length > 0) {\n if (!userContext.region || !audience.region.includes(userContext.region)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Check if a feature's audience allows the given user context.\n *\n * - No `audience` field → visible to all\n * - Empty `audience` ({}) → visible to all\n * - `audience` specified but no `userContext` → hidden (safe default)\n * - Otherwise, delegate to `matchFn` (or default `matchesAudience`)\n */\nfunction isAudienceMatch(\n feature: FeatureEntry,\n userContext?: UserContext,\n matchFn?: AudienceMatchFn,\n): boolean {\n // No audience restriction → show to everyone\n if (!feature.audience) return true;\n\n // Check if audience is empty (no fields with values)\n const { plan, role, region, custom } = feature.audience;\n const hasRules =\n (plan && plan.length > 0) ||\n (role && role.length > 0) ||\n (region && region.length > 0) ||\n (custom && Object.keys(custom).length > 0);\n if (!hasRules) return true;\n\n // Audience specified but no user context → hidden (safe default)\n if (!userContext) return false;\n\n // Use custom matcher if provided, otherwise default\n if (matchFn) return matchFn(feature.audience, userContext);\n return matchesAudience(feature.audience, userContext);\n}\n\nfunction isVersionMatch(feature: FeatureEntry, appVersion?: string): boolean {\n const v = feature.version;\n if (!v || typeof v === \"string\") return true; // string = display only\n if (!appVersion) return false; // Safe default when constraints exist\n if (!v.introduced && !v.showNewUntil && !v.deprecatedAt && !v.showIn) return true;\n\n // Range check\n if (v.showIn && !satisfiesRange(appVersion, v.showIn)) return false;\n\n if (v.introduced && compareSemver(appVersion, v.introduced) < 0) return false;\n if (v.deprecatedAt && compareSemver(appVersion, v.deprecatedAt) >= 0) return false;\n\n // showNewUntil gates \"new\" state only\n if (v.showNewUntil && compareSemver(appVersion, v.showNewUntil) >= 0) return false;\n\n return true;\n}\n\nfunction isDependencyMatch(\n feature: FeatureEntry,\n dismissedIds: ReadonlySet<string>,\n dependencyState?: FeatureDependencyState,\n): boolean {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return true;\n\n const seenIds = dependencyState?.seenIds;\n const clickedIds = dependencyState?.clickedIds;\n const dismissedDependencyIds = dependencyState?.dismissedIds ?? dismissedIds;\n\n if (dependsOn.seen && dependsOn.seen.length > 0) {\n for (const id of dependsOn.seen) {\n const seen = seenIds?.has(id) ?? false;\n if (!seen && !dismissedDependencyIds.has(id)) return false;\n }\n }\n\n if (dependsOn.clicked && dependsOn.clicked.length > 0) {\n for (const id of dependsOn.clicked) {\n if (!(clickedIds?.has(id) ?? false)) return false;\n }\n }\n\n if (dependsOn.dismissed && dependsOn.dismissed.length > 0) {\n for (const id of dependsOn.dismissed) {\n if (!dismissedDependencyIds.has(id)) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if a single feature should show as \"new\".\n *\n * A feature is \"new\" when ALL of these are true:\n * 1. Current time is before `showNewUntil`\n * 2. Feature was released after the watermark (or no watermark exists)\n * 3. Feature has not been individually dismissed\n * 4. If `publishAt` is set, current time must be after it (scheduled publishing)\n * 5. If `audience` is set, user must match the targeting rules\n */\nexport function isNew(\n feature: FeatureEntry,\n watermark: string | null,\n dismissedIds: ReadonlySet<string>,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): boolean {\n // Already dismissed by the user on this device\n if (dismissedIds.has(feature.id)) return false;\n\n // Audience targeting — check before time-based checks\n if (!isAudienceMatch(feature, userContext, matchAudience)) return false;\n\n // Dependency targeting — defer features until prerequisites are satisfied\n if (!isDependencyMatch(feature, dismissedIds, dependencyState)) return false;\n\n // Version targeting — requires appVersion when constraints exist\n if (!isVersionMatch(feature, appVersion)) return false;\n\n // Contextual trigger rules — show only when trigger condition is satisfied.\n if (!isTriggerMatch(feature.trigger, triggerContext)) return false;\n\n const nowMs = now.getTime();\n\n // Scheduled publishing — hidden until publishAt\n if (feature.publishAt) {\n const publishMs = new Date(feature.publishAt).getTime();\n if (nowMs < publishMs) return false;\n }\n\n const showUntilMs = new Date(feature.showNewUntil).getTime();\n\n // Past the display window\n if (nowMs >= showUntilMs) return false;\n\n // If there's a watermark, feature must have been released after it\n if (watermark) {\n const watermarkMs = new Date(watermark).getTime();\n const releasedMs = new Date(feature.releasedAt).getTime();\n if (releasedMs <= watermarkMs) return false;\n }\n\n return true;\n}\n\n/**\n * Get all features that are currently \"new\" for this user.\n */\nexport function getNewFeatures(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter((f) =>\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ),\n );\n}\n\n/**\n * Get the count of new features.\n */\nexport function getNewFeatureCount(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): number {\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ).length;\n}\n\n/**\n * Check if a specific sidebar key has a new feature.\n */\nexport function hasNewFeature(\n manifest: FeatureManifest,\n sidebarKey: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): boolean {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.some(\n (f) =>\n f.sidebarKey === sidebarKey &&\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ),\n );\n}\n\n/**\n * Get all features sorted by priority (critical first) then by release date (newest first).\n */\nexport function getNewFeaturesSorted(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): FeatureEntry[] {\n const priorityOrder = { critical: 0, normal: 1, low: 2 };\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ).sort(\n (a, b) => {\n const pa = priorityOrder[a.priority ?? \"normal\"];\n const pb = priorityOrder[b.priority ?? \"normal\"];\n if (pa !== pb) return pa - pb;\n return (\n new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime()\n );\n },\n );\n}\n","import type { StorageAdapter } from \"../types\";\n\nexport interface LocalStorageAdapterOptions {\n /** Key prefix for localStorage entries. Default: \"featuredrop\" */\n prefix?: string;\n /** Server-side watermark (ISO string). Typically from user profile. */\n watermark?: string | null;\n /** Callback when dismissAll is called. Use for server-side watermark updates. */\n onDismissAll?: (now: Date) => Promise<void>;\n}\n\nconst DISMISSED_SUFFIX = \":dismissed\";\n\n/**\n * localStorage-based storage adapter.\n *\n * Architecture:\n * - **Watermark** comes from the server (passed at construction time)\n * - **Per-feature dismissals** are stored in localStorage (zero server writes)\n * - **dismissAll()** optionally calls a server callback, then clears localStorage\n *\n * Gracefully handles SSR environments where `window`/`localStorage` is unavailable.\n */\nexport class LocalStorageAdapter implements StorageAdapter {\n private readonly prefix: string;\n private readonly watermarkValue: string | null;\n private readonly onDismissAllCallback?: (now: Date) => Promise<void>;\n private readonly dismissedKey: string;\n\n constructor(options: LocalStorageAdapterOptions = {}) {\n this.prefix = options.prefix ?? \"featuredrop\";\n this.watermarkValue = options.watermark ?? null;\n this.onDismissAllCallback = options.onDismissAll;\n this.dismissedKey = `${this.prefix}${DISMISSED_SUFFIX}`;\n }\n\n getWatermark(): string | null {\n return this.watermarkValue;\n }\n\n getDismissedIds(): ReadonlySet<string> {\n try {\n if (typeof window === \"undefined\") return new Set();\n const raw = localStorage.getItem(this.dismissedKey);\n if (!raw) return new Set();\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) return new Set(parsed as string[]);\n return new Set();\n } catch {\n return new Set();\n }\n }\n\n dismiss(id: string): void {\n try {\n if (typeof window === \"undefined\") return;\n const raw = localStorage.getItem(this.dismissedKey);\n const existing: string[] = raw ? (JSON.parse(raw) as string[]) : [];\n if (!existing.includes(id)) {\n existing.push(id);\n localStorage.setItem(this.dismissedKey, JSON.stringify(existing));\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n }\n\n async dismissAll(now: Date): Promise<void> {\n try {\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(this.dismissedKey);\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n\n if (this.onDismissAllCallback) {\n await this.onDismissAllCallback(now);\n }\n }\n}\n","import { getNewFeaturesSorted, hasNewFeature } from \"../core\";\nimport { LocalStorageAdapter } from \"../adapters\";\nimport type {\n AudienceMatchFn,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n} from \"../types\";\n\nconst SafeHTMLElement: typeof HTMLElement = typeof HTMLElement === \"undefined\"\n ? (class {} as unknown as typeof HTMLElement)\n : HTMLElement;\n\nexport interface WebComponentsConfig {\n manifest: FeatureManifest;\n storage?: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nexport interface RegisterWebComponentsOptions {\n badgeTag?: string;\n changelogTag?: string;\n}\n\ninterface RuntimeConfig {\n manifest: FeatureManifest;\n storage: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nlet runtimeConfig: RuntimeConfig | null = null;\nlet defaultStorage: StorageAdapter | null = null;\nconst badgeInstances = new Set<FeatureDropBadgeElement>();\nconst changelogInstances = new Set<FeatureDropChangelogElement>();\n\nfunction getDefaultStorage(): StorageAdapter {\n if (!defaultStorage) {\n defaultStorage = new LocalStorageAdapter({ prefix: \"featuredrop:web-components\" });\n }\n return defaultStorage;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n}\n\nfunction getRuntimeConfig(): RuntimeConfig | null {\n return runtimeConfig;\n}\n\nfunction renderAllComponents(): void {\n for (const badge of badgeInstances) badge.render();\n for (const changelog of changelogInstances) changelog.render();\n}\n\nexport function configureFeatureDropWebComponents(config: WebComponentsConfig): void {\n runtimeConfig = {\n manifest: config.manifest,\n storage: config.storage ?? getDefaultStorage(),\n userContext: config.userContext,\n matchAudience: config.matchAudience,\n appVersion: config.appVersion,\n };\n renderAllComponents();\n}\n\nexport function refreshFeatureDropWebComponents(): void {\n renderAllComponents();\n}\n\nexport class FeatureDropBadgeElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"sidebar-key\", \"variant\"];\n }\n\n connectedCallback(): void {\n badgeInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n this.render();\n }\n\n disconnectedCallback(): void {\n badgeInstances.delete(this);\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const sidebarKey = this.getAttribute(\"sidebar-key\");\n const variant = this.getAttribute(\"variant\") ?? \"pill\";\n const config = getRuntimeConfig();\n if (!sidebarKey || !config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const isNew = hasNewFeature(\n config.manifest,\n sidebarKey,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n if (!isNew) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const count = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n ).filter((entry) => entry.sidebarKey === sidebarKey).length;\n\n const content = variant === \"dot\"\n ? `<span class=\"dot\" part=\"dot\"></span>`\n : variant === \"count\"\n ? `<span class=\"count\" part=\"count\">${count}</span>`\n : `<span class=\"pill\" part=\"pill\">New</span>`;\n\n this.shadowRoot.innerHTML = `\n <style>\n .pill { display: inline-block; border-radius: 999px; padding: 2px 8px; font-size: 12px; font-weight: 600; background: #f59e0b; color: #fff; }\n .count { display: inline-grid; place-items: center; min-width: 18px; height: 18px; border-radius: 999px; font-size: 11px; font-weight: 700; background: #dc2626; color: #fff; padding: 0 6px; }\n .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; }\n </style>\n ${content}\n `;\n }\n}\n\nexport class FeatureDropChangelogElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"title\", \"trigger-label\", \"position\"];\n }\n\n private isOpen = false;\n private cleanupClick: (() => void) | null = null;\n\n connectedCallback(): void {\n changelogInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n const onClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n const actionTarget = target.closest(\"[data-action]\") as HTMLElement | null;\n if (!actionTarget) return;\n const action = actionTarget.getAttribute(\"data-action\");\n if (action === \"toggle\") {\n this.isOpen = !this.isOpen;\n this.render();\n return;\n }\n if (action === \"dismiss-all\") {\n void this.dismissAll();\n return;\n }\n if (action === \"dismiss-one\") {\n const id = actionTarget.getAttribute(\"data-id\");\n if (id) this.dismissOne(id);\n }\n };\n this.shadowRoot?.addEventListener(\"click\", onClick);\n this.cleanupClick = () => this.shadowRoot?.removeEventListener(\"click\", onClick);\n this.render();\n }\n\n disconnectedCallback(): void {\n changelogInstances.delete(this);\n this.cleanupClick?.();\n this.cleanupClick = null;\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n private dismissOne(id: string): void {\n const config = getRuntimeConfig();\n if (!config) return;\n config.storage.dismiss(id);\n renderAllComponents();\n }\n\n private async dismissAll(): Promise<void> {\n const config = getRuntimeConfig();\n if (!config) return;\n await config.storage.dismissAll(new Date());\n renderAllComponents();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const config = getRuntimeConfig();\n if (!config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const title = this.getAttribute(\"title\") ?? \"What's New\";\n const triggerLabel = this.getAttribute(\"trigger-label\") ?? \"What's New\";\n const position = this.getAttribute(\"position\") === \"left\" ? \"left: 16px;\" : \"right: 16px;\";\n const entries = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n\n const list = entries.length === 0\n ? `<p class=\"empty\">You're all caught up.</p>`\n : entries\n .map((entry) => `\n <li class=\"item\">\n <div class=\"item-title\">${escapeHtml(entry.label)}</div>\n ${entry.description ? `<p class=\"item-desc\">${escapeHtml(entry.description)}</p>` : \"\"}\n <button data-action=\"dismiss-one\" data-id=\"${escapeHtml(entry.id)}\" class=\"ghost\">Mark read</button>\n </li>\n `)\n .join(\"\");\n\n this.shadowRoot.innerHTML = `\n <style>\n .trigger { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 8px 12px; cursor: pointer; font-weight: 600; font-size: 13px; }\n .panel { position: fixed; top: 70px; ${position} width: min(92vw, 360px); max-height: 70vh; overflow: auto; border: 1px solid #e5e7eb; border-radius: 12px; background: #fff; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.16); z-index: 10000; }\n .header { display: flex; align-items: center; justify-content: space-between; padding: 12px; border-bottom: 1px solid #e5e7eb; }\n .title { margin: 0; font-size: 14px; }\n .list { list-style: none; margin: 0; padding: 10px 12px 12px; display: grid; gap: 10px; }\n .item { border: 1px solid #e5e7eb; border-radius: 10px; padding: 10px; }\n .item-title { font-size: 13px; font-weight: 700; margin-bottom: 4px; }\n .item-desc { margin: 0 0 8px; color: #4b5563; font-size: 12px; }\n .empty { margin: 0; padding: 14px 12px; color: #6b7280; font-size: 13px; }\n .ghost { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 5px 8px; cursor: pointer; font-size: 12px; }\n </style>\n <button data-action=\"toggle\" class=\"trigger\">${escapeHtml(triggerLabel)} (${entries.length})</button>\n ${this.isOpen ? `\n <section class=\"panel\">\n <div class=\"header\">\n <h3 class=\"title\">${escapeHtml(title)}</h3>\n <button data-action=\"dismiss-all\" class=\"ghost\">Mark all read</button>\n </div>\n <ul class=\"list\">${list}</ul>\n </section>\n ` : \"\"}\n `;\n }\n}\n\nexport function registerFeatureDropWebComponents(\n options: RegisterWebComponentsOptions = {},\n): { badgeTag: string; changelogTag: string } {\n const badgeTag = options.badgeTag ?? \"feature-drop-badge\";\n const changelogTag = options.changelogTag ?? \"feature-drop-changelog\";\n\n if (typeof customElements === \"undefined\") {\n return { badgeTag, changelogTag };\n }\n\n if (!customElements.get(badgeTag)) {\n customElements.define(badgeTag, FeatureDropBadgeElement);\n }\n if (!customElements.get(changelogTag)) {\n customElements.define(changelogTag, FeatureDropChangelogElement);\n }\n\n return { badgeTag, changelogTag };\n}\n"]}
1
+ {"version":3,"sources":["../src/semver.ts","../src/triggers.ts","../src/core.ts","../src/adapters/local-storage.ts","../src/web-components/index.ts"],"names":["isNew"],"mappings":"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","file":"web-components.cjs","sourcesContent":["// Minimal semver comparison utilities (no build metadata sorting needed)\n\nexport type Comparator = \">=\" | \"<=\" | \">\" | \"<\" | \"=\";\n\nexport interface SemverParts {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nconst SEMVER_REGEX = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?/;\n\nexport function parseSemver(input: string): SemverParts | null {\n const match = input.trim().match(SEMVER_REGEX);\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\nexport function compareSemver(a: string, b: string): number {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa || !pb) return 0;\n\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (pa[key] !== pb[key]) return pa[key] - pb[key];\n }\n\n // Handle prerelease: absence > presence, otherwise lexicographic\n const aPre = pa.prerelease;\n const bPre = pb.prerelease;\n if (aPre.length === 0 && bPre.length === 0) return 0;\n if (aPre.length === 0) return 1;\n if (bPre.length === 0) return -1;\n\n const len = Math.max(aPre.length, bPre.length);\n for (let i = 0; i < len; i++) {\n const ai = aPre[i];\n const bi = bPre[i];\n if (ai === undefined) return -1;\n if (bi === undefined) return 1;\n const aNum = Number(ai);\n const bNum = Number(bi);\n const aIsNum = Number.isInteger(aNum);\n const bIsNum = Number.isInteger(bNum);\n if (aIsNum && bIsNum && aNum !== bNum) return aNum - bNum;\n if (aIsNum !== bIsNum) return aIsNum ? -1 : 1;\n if (ai !== bi) return ai < bi ? -1 : 1;\n }\n return 0;\n}\n\nfunction parseComparator(comp: string): { op: Comparator; version: string } | null {\n const match = comp.trim().match(/^(>=|<=|>|<|=)?\\\\s*(.+)$/);\n if (!match) return null;\n const op = (match[1] as Comparator) || \">=\";\n const version = match[2];\n if (!parseSemver(version)) return null;\n return { op, version };\n}\n\nfunction satisfiesComparator(version: string, comp: { op: Comparator; version: string }): boolean {\n const diff = compareSemver(version, comp.version);\n switch (comp.op) {\n case \">\":\n return diff > 0;\n case \">=\":\n return diff >= 0;\n case \"<\":\n return diff < 0;\n case \"<=\":\n return diff <= 0;\n case \"=\":\n return diff === 0;\n default:\n return false;\n }\n}\n\n// Space-separated comparator list (AND semantics), e.g. \">=2.5.0 <3.0.0\"\nexport function satisfiesRange(version: string, range: string): boolean {\n const parts = range.split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return true;\n for (const part of parts) {\n const comp = parseComparator(part);\n if (!comp) return false;\n if (!satisfiesComparator(version, comp)) return false;\n }\n return true;\n}\n","import type { FeatureEntry, FeatureTrigger, TriggerContext } from \"./types\";\n\nfunction wildcardToRegExp(value: string): RegExp {\n const escaped = value.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = `^${escaped.replace(/\\*/g, \".*\")}$`;\n return new RegExp(pattern);\n}\n\nfunction matchPath(path: string, pattern: string | RegExp): boolean {\n if (pattern instanceof RegExp) return pattern.test(path);\n if (!pattern) return false;\n if (pattern.includes(\"*\")) return wildcardToRegExp(pattern).test(path);\n return path === pattern || path.startsWith(pattern);\n}\n\nexport function isTriggerMatch(trigger: FeatureTrigger | undefined, context?: TriggerContext): boolean {\n if (!trigger) return true;\n if (!context) return false;\n\n if (trigger.type === \"page\") {\n const path = context.path;\n if (!path) return false;\n return matchPath(path, trigger.match);\n }\n\n if (trigger.type === \"usage\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.event] ?? 0;\n return count >= (trigger.minActions ?? 1);\n }\n\n if (trigger.type === \"time\") {\n const elapsedMs = context.elapsedMs ?? 0;\n return elapsedMs >= trigger.minSeconds * 1000;\n }\n\n if (trigger.type === \"milestone\") {\n return context.milestones?.has(trigger.event) ?? false;\n }\n\n if (trigger.type === \"frustration\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.pattern] ?? 0;\n return count >= (trigger.threshold ?? 1);\n }\n\n if (trigger.type === \"scroll\") {\n return (context.scrollPercent ?? 0) >= (trigger.minPercent ?? 50);\n }\n\n try {\n return trigger.evaluate(context);\n } catch {\n return false;\n }\n}\n\nexport class TriggerEngine {\n private context: TriggerContext;\n\n constructor(initial?: TriggerContext) {\n this.context = {\n path: initial?.path,\n events: new Set(initial?.events ?? []),\n milestones: new Set(initial?.milestones ?? []),\n usage: { ...(initial?.usage ?? {}) },\n elapsedMs: initial?.elapsedMs ?? 0,\n scrollPercent: initial?.scrollPercent ?? 0,\n metadata: { ...(initial?.metadata ?? {}) },\n };\n }\n\n setPath(path: string): void {\n this.context.path = path;\n }\n\n trackEvent(event: string): void {\n const next = new Set(this.context.events ?? new Set<string>());\n next.add(event);\n this.context.events = next;\n }\n\n trackUsage(event: string, delta = 1): void {\n const usage = { ...(this.context.usage ?? {}) };\n usage[event] = (usage[event] ?? 0) + Math.max(1, delta);\n this.context.usage = usage;\n }\n\n trackMilestone(event: string): void {\n const next = new Set(this.context.milestones ?? new Set<string>());\n next.add(event);\n this.context.milestones = next;\n }\n\n setElapsedMs(elapsedMs: number): void {\n this.context.elapsedMs = Math.max(0, elapsedMs);\n }\n\n setScrollPercent(scrollPercent: number): void {\n const clamped = Math.max(0, Math.min(100, scrollPercent));\n this.context.scrollPercent = clamped;\n }\n\n setMetadata(next: Record<string, unknown>): void {\n this.context.metadata = { ...next };\n }\n\n getContext(): TriggerContext {\n return {\n path: this.context.path,\n events: new Set(this.context.events ?? []),\n milestones: new Set(this.context.milestones ?? []),\n usage: { ...(this.context.usage ?? {}) },\n elapsedMs: this.context.elapsedMs,\n scrollPercent: this.context.scrollPercent,\n metadata: { ...(this.context.metadata ?? {}) },\n };\n }\n\n evaluate(trigger: FeatureTrigger | undefined): boolean {\n return isTriggerMatch(trigger, this.context);\n }\n\n evaluateFeature(feature: Pick<FeatureEntry, \"trigger\">): boolean {\n return this.evaluate(feature.trigger);\n }\n}\n","import type {\n AudienceMatchFn,\n AudienceRule,\n FeatureEntry,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n FeatureDependencyState,\n FeatureFlagBridge,\n TriggerContext,\n} from \"./types\";\nimport { compareSemver, satisfiesRange } from \"./semver\";\nimport { isTriggerMatch } from \"./triggers\";\n\n/**\n * Default audience matching logic.\n *\n * For each specified field (plan, role, region), checks if the user's\n * value is included in the allowed list. Fields use AND logic between them,\n * OR logic within each field's array. The `custom` field is ignored by\n * the default matcher — use a custom `AudienceMatchFn` for that.\n */\nexport function matchesAudience(\n audience: AudienceRule,\n userContext: UserContext,\n): boolean {\n if (audience.plan && audience.plan.length > 0) {\n if (!userContext.plan || !audience.plan.includes(userContext.plan)) {\n return false;\n }\n }\n if (audience.role && audience.role.length > 0) {\n if (!userContext.role || !audience.role.includes(userContext.role)) {\n return false;\n }\n }\n if (audience.region && audience.region.length > 0) {\n if (!userContext.region || !audience.region.includes(userContext.region)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Check if a feature's audience allows the given user context.\n *\n * - No `audience` field → visible to all\n * - Empty `audience` ({}) → visible to all\n * - `audience` specified but no `userContext` → hidden (safe default)\n * - Otherwise, delegate to `matchFn` (or default `matchesAudience`)\n */\nfunction isAudienceMatch(\n feature: FeatureEntry,\n userContext?: UserContext,\n matchFn?: AudienceMatchFn,\n): boolean {\n // No audience restriction → show to everyone\n if (!feature.audience) return true;\n\n // Check if audience is empty (no fields with values)\n const { plan, role, region, custom } = feature.audience;\n const hasRules =\n (plan && plan.length > 0) ||\n (role && role.length > 0) ||\n (region && region.length > 0) ||\n (custom && Object.keys(custom).length > 0);\n if (!hasRules) return true;\n\n // Audience specified but no user context → hidden (safe default)\n if (!userContext) return false;\n\n // Use custom matcher if provided, otherwise default\n if (matchFn) return matchFn(feature.audience, userContext);\n return matchesAudience(feature.audience, userContext);\n}\n\nfunction isVersionMatch(feature: FeatureEntry, appVersion?: string): boolean {\n const v = feature.version;\n if (!v || typeof v === \"string\") return true; // string = display only\n if (!appVersion) return false; // Safe default when constraints exist\n if (!v.introduced && !v.showNewUntil && !v.deprecatedAt && !v.showIn) return true;\n\n // Range check\n if (v.showIn && !satisfiesRange(appVersion, v.showIn)) return false;\n\n if (v.introduced && compareSemver(appVersion, v.introduced) < 0) return false;\n if (v.deprecatedAt && compareSemver(appVersion, v.deprecatedAt) >= 0) return false;\n\n // showNewUntil gates \"new\" state only\n if (v.showNewUntil && compareSemver(appVersion, v.showNewUntil) >= 0) return false;\n\n return true;\n}\n\nfunction isFlagMatch(\n feature: FeatureEntry,\n flagBridge?: FeatureFlagBridge,\n userContext?: UserContext,\n): boolean {\n if (!feature.flagKey) return true;\n if (!flagBridge) return false;\n try {\n return flagBridge.isEnabled(feature.flagKey, userContext);\n } catch {\n return false;\n }\n}\n\nfunction isProductMatch(feature: FeatureEntry, product?: string): boolean {\n if (!feature.product || feature.product === \"*\") return true;\n if (!product) return false;\n return feature.product === product;\n}\n\nfunction isDependencyMatch(\n feature: FeatureEntry,\n dismissedIds: ReadonlySet<string>,\n dependencyState?: FeatureDependencyState,\n): boolean {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return true;\n\n const seenIds = dependencyState?.seenIds;\n const clickedIds = dependencyState?.clickedIds;\n const dismissedDependencyIds = dependencyState?.dismissedIds ?? dismissedIds;\n\n if (dependsOn.seen && dependsOn.seen.length > 0) {\n for (const id of dependsOn.seen) {\n const seen = seenIds?.has(id) ?? false;\n if (!seen && !dismissedDependencyIds.has(id)) return false;\n }\n }\n\n if (dependsOn.clicked && dependsOn.clicked.length > 0) {\n for (const id of dependsOn.clicked) {\n if (!(clickedIds?.has(id) ?? false)) return false;\n }\n }\n\n if (dependsOn.dismissed && dependsOn.dismissed.length > 0) {\n for (const id of dependsOn.dismissed) {\n if (!dismissedDependencyIds.has(id)) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if a single feature should show as \"new\".\n *\n * A feature is \"new\" when ALL of these are true:\n * 1. Current time is before `showNewUntil`\n * 2. Feature was released after the watermark (or no watermark exists)\n * 3. Feature has not been individually dismissed\n * 4. If `publishAt` is set, current time must be after it (scheduled publishing)\n * 5. If `audience` is set, user must match the targeting rules\n * 6. If `flagKey` is set, the flag bridge must resolve it as enabled\n * 7. If `product` is set, it must match the current product scope\n */\nexport function isNew(\n feature: FeatureEntry,\n watermark: string | null,\n dismissedIds: ReadonlySet<string>,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): boolean {\n // Already dismissed by the user on this device\n if (dismissedIds.has(feature.id)) return false;\n\n // Audience targeting — check before time-based checks\n if (!isAudienceMatch(feature, userContext, matchAudience)) return false;\n\n // Dependency targeting — defer features until prerequisites are satisfied\n if (!isDependencyMatch(feature, dismissedIds, dependencyState)) return false;\n\n // Version targeting — requires appVersion when constraints exist\n if (!isVersionMatch(feature, appVersion)) return false;\n\n // Feature flag targeting — hide flagged entries unless enabled\n if (!isFlagMatch(feature, flagBridge, userContext)) return false;\n\n // Multi-product targeting — hide entries for other product scopes\n if (!isProductMatch(feature, product)) return false;\n\n // Contextual trigger rules — show only when trigger condition is satisfied.\n if (!isTriggerMatch(feature.trigger, triggerContext)) return false;\n\n const nowMs = now.getTime();\n\n // Scheduled publishing — hidden until publishAt\n if (feature.publishAt) {\n const publishMs = new Date(feature.publishAt).getTime();\n if (nowMs < publishMs) return false;\n }\n\n const showUntilMs = new Date(feature.showNewUntil).getTime();\n\n // Past the display window\n if (nowMs >= showUntilMs) return false;\n\n // If there's a watermark, feature must have been released after it\n if (watermark) {\n const watermarkMs = new Date(watermark).getTime();\n const releasedMs = new Date(feature.releasedAt).getTime();\n if (releasedMs <= watermarkMs) return false;\n }\n\n return true;\n}\n\n/**\n * Get all features that are currently \"new\" for this user.\n */\nexport function getNewFeatures(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter((f) =>\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ),\n );\n}\n\n/**\n * Get the count of new features.\n */\nexport function getNewFeatureCount(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): number {\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ).length;\n}\n\n/**\n * Check if a specific sidebar key has a new feature.\n */\nexport function hasNewFeature(\n manifest: FeatureManifest,\n sidebarKey: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): boolean {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.some(\n (f) =>\n f.sidebarKey === sidebarKey &&\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ),\n );\n}\n\n/**\n * Get all features sorted by priority (critical first) then by release date (newest first).\n */\nexport function getNewFeaturesSorted(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): FeatureEntry[] {\n const priorityOrder = { critical: 0, normal: 1, low: 2 };\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ).sort(\n (a, b) => {\n const pa = priorityOrder[a.priority ?? \"normal\"];\n const pb = priorityOrder[b.priority ?? \"normal\"];\n if (pa !== pb) return pa - pb;\n return (\n new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime()\n );\n },\n );\n}\n","import type { StorageAdapter } from \"../types\";\n\nexport interface LocalStorageAdapterOptions {\n /** Key prefix for localStorage entries. Default: \"featuredrop\" */\n prefix?: string;\n /** Server-side watermark (ISO string). Typically from user profile. */\n watermark?: string | null;\n /** Callback when dismissAll is called. Use for server-side watermark updates. */\n onDismissAll?: (now: Date) => Promise<void>;\n}\n\nconst DISMISSED_SUFFIX = \":dismissed\";\n\n/**\n * localStorage-based storage adapter.\n *\n * Architecture:\n * - **Watermark** comes from the server (passed at construction time)\n * - **Per-feature dismissals** are stored in localStorage (zero server writes)\n * - **dismissAll()** optionally calls a server callback, then clears localStorage\n *\n * Gracefully handles SSR environments where `window`/`localStorage` is unavailable.\n */\nexport class LocalStorageAdapter implements StorageAdapter {\n private readonly prefix: string;\n private readonly watermarkValue: string | null;\n private readonly onDismissAllCallback?: (now: Date) => Promise<void>;\n private readonly dismissedKey: string;\n\n constructor(options: LocalStorageAdapterOptions = {}) {\n this.prefix = options.prefix ?? \"featuredrop\";\n this.watermarkValue = options.watermark ?? null;\n this.onDismissAllCallback = options.onDismissAll;\n this.dismissedKey = `${this.prefix}${DISMISSED_SUFFIX}`;\n }\n\n getWatermark(): string | null {\n return this.watermarkValue;\n }\n\n getDismissedIds(): ReadonlySet<string> {\n try {\n if (typeof window === \"undefined\") return new Set();\n const raw = localStorage.getItem(this.dismissedKey);\n if (!raw) return new Set();\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) return new Set(parsed as string[]);\n return new Set();\n } catch {\n return new Set();\n }\n }\n\n dismiss(id: string): void {\n try {\n if (typeof window === \"undefined\") return;\n const raw = localStorage.getItem(this.dismissedKey);\n const existing: string[] = raw ? (JSON.parse(raw) as string[]) : [];\n if (!existing.includes(id)) {\n existing.push(id);\n localStorage.setItem(this.dismissedKey, JSON.stringify(existing));\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n }\n\n async dismissAll(now: Date): Promise<void> {\n try {\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(this.dismissedKey);\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n\n if (this.onDismissAllCallback) {\n await this.onDismissAllCallback(now);\n }\n }\n}\n","import { getNewFeaturesSorted, hasNewFeature } from \"../core\";\nimport { LocalStorageAdapter } from \"../adapters\";\nimport type {\n AudienceMatchFn,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n} from \"../types\";\n\nconst SafeHTMLElement: typeof HTMLElement = typeof HTMLElement === \"undefined\"\n ? (class {} as unknown as typeof HTMLElement)\n : HTMLElement;\n\nexport interface WebComponentsConfig {\n manifest: FeatureManifest;\n storage?: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nexport interface RegisterWebComponentsOptions {\n badgeTag?: string;\n changelogTag?: string;\n}\n\ninterface RuntimeConfig {\n manifest: FeatureManifest;\n storage: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nlet runtimeConfig: RuntimeConfig | null = null;\nlet defaultStorage: StorageAdapter | null = null;\nconst badgeInstances = new Set<FeatureDropBadgeElement>();\nconst changelogInstances = new Set<FeatureDropChangelogElement>();\n\nfunction getDefaultStorage(): StorageAdapter {\n if (!defaultStorage) {\n defaultStorage = new LocalStorageAdapter({ prefix: \"featuredrop:web-components\" });\n }\n return defaultStorage;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n}\n\nfunction getRuntimeConfig(): RuntimeConfig | null {\n return runtimeConfig;\n}\n\nfunction renderAllComponents(): void {\n for (const badge of badgeInstances) badge.render();\n for (const changelog of changelogInstances) changelog.render();\n}\n\nexport function configureFeatureDropWebComponents(config: WebComponentsConfig): void {\n runtimeConfig = {\n manifest: config.manifest,\n storage: config.storage ?? getDefaultStorage(),\n userContext: config.userContext,\n matchAudience: config.matchAudience,\n appVersion: config.appVersion,\n };\n renderAllComponents();\n}\n\nexport function refreshFeatureDropWebComponents(): void {\n renderAllComponents();\n}\n\nexport class FeatureDropBadgeElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"sidebar-key\", \"variant\"];\n }\n\n connectedCallback(): void {\n badgeInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n this.render();\n }\n\n disconnectedCallback(): void {\n badgeInstances.delete(this);\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const sidebarKey = this.getAttribute(\"sidebar-key\");\n const variant = this.getAttribute(\"variant\") ?? \"pill\";\n const config = getRuntimeConfig();\n if (!sidebarKey || !config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const isNew = hasNewFeature(\n config.manifest,\n sidebarKey,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n if (!isNew) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const count = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n ).filter((entry) => entry.sidebarKey === sidebarKey).length;\n\n const content = variant === \"dot\"\n ? `<span class=\"dot\" part=\"dot\"></span>`\n : variant === \"count\"\n ? `<span class=\"count\" part=\"count\">${count}</span>`\n : `<span class=\"pill\" part=\"pill\">New</span>`;\n\n this.shadowRoot.innerHTML = `\n <style>\n .pill { display: inline-block; border-radius: 999px; padding: 2px 8px; font-size: 12px; font-weight: 600; background: #f59e0b; color: #fff; }\n .count { display: inline-grid; place-items: center; min-width: 18px; height: 18px; border-radius: 999px; font-size: 11px; font-weight: 700; background: #dc2626; color: #fff; padding: 0 6px; }\n .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; }\n </style>\n ${content}\n `;\n }\n}\n\nexport class FeatureDropChangelogElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"title\", \"trigger-label\", \"position\"];\n }\n\n private isOpen = false;\n private cleanupClick: (() => void) | null = null;\n\n connectedCallback(): void {\n changelogInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n const onClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n const actionTarget = target.closest(\"[data-action]\") as HTMLElement | null;\n if (!actionTarget) return;\n const action = actionTarget.getAttribute(\"data-action\");\n if (action === \"toggle\") {\n this.isOpen = !this.isOpen;\n this.render();\n return;\n }\n if (action === \"dismiss-all\") {\n void this.dismissAll();\n return;\n }\n if (action === \"dismiss-one\") {\n const id = actionTarget.getAttribute(\"data-id\");\n if (id) this.dismissOne(id);\n }\n };\n this.shadowRoot?.addEventListener(\"click\", onClick);\n this.cleanupClick = () => this.shadowRoot?.removeEventListener(\"click\", onClick);\n this.render();\n }\n\n disconnectedCallback(): void {\n changelogInstances.delete(this);\n this.cleanupClick?.();\n this.cleanupClick = null;\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n private dismissOne(id: string): void {\n const config = getRuntimeConfig();\n if (!config) return;\n config.storage.dismiss(id);\n renderAllComponents();\n }\n\n private async dismissAll(): Promise<void> {\n const config = getRuntimeConfig();\n if (!config) return;\n await config.storage.dismissAll(new Date());\n renderAllComponents();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const config = getRuntimeConfig();\n if (!config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const title = this.getAttribute(\"title\") ?? \"What's New\";\n const triggerLabel = this.getAttribute(\"trigger-label\") ?? \"What's New\";\n const position = this.getAttribute(\"position\") === \"left\" ? \"left: 16px;\" : \"right: 16px;\";\n const entries = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n\n const list = entries.length === 0\n ? `<p class=\"empty\">You're all caught up.</p>`\n : entries\n .map((entry) => `\n <li class=\"item\">\n <div class=\"item-title\">${escapeHtml(entry.label)}</div>\n ${entry.description ? `<p class=\"item-desc\">${escapeHtml(entry.description)}</p>` : \"\"}\n <button data-action=\"dismiss-one\" data-id=\"${escapeHtml(entry.id)}\" class=\"ghost\">Mark read</button>\n </li>\n `)\n .join(\"\");\n\n this.shadowRoot.innerHTML = `\n <style>\n .trigger { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 8px 12px; cursor: pointer; font-weight: 600; font-size: 13px; }\n .panel { position: fixed; top: 70px; ${position} width: min(92vw, 360px); max-height: 70vh; overflow: auto; border: 1px solid #e5e7eb; border-radius: 12px; background: #fff; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.16); z-index: 10000; }\n .header { display: flex; align-items: center; justify-content: space-between; padding: 12px; border-bottom: 1px solid #e5e7eb; }\n .title { margin: 0; font-size: 14px; }\n .list { list-style: none; margin: 0; padding: 10px 12px 12px; display: grid; gap: 10px; }\n .item { border: 1px solid #e5e7eb; border-radius: 10px; padding: 10px; }\n .item-title { font-size: 13px; font-weight: 700; margin-bottom: 4px; }\n .item-desc { margin: 0 0 8px; color: #4b5563; font-size: 12px; }\n .empty { margin: 0; padding: 14px 12px; color: #6b7280; font-size: 13px; }\n .ghost { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 5px 8px; cursor: pointer; font-size: 12px; }\n </style>\n <button data-action=\"toggle\" class=\"trigger\">${escapeHtml(triggerLabel)} (${entries.length})</button>\n ${this.isOpen ? `\n <section class=\"panel\">\n <div class=\"header\">\n <h3 class=\"title\">${escapeHtml(title)}</h3>\n <button data-action=\"dismiss-all\" class=\"ghost\">Mark all read</button>\n </div>\n <ul class=\"list\">${list}</ul>\n </section>\n ` : \"\"}\n `;\n }\n}\n\nexport function registerFeatureDropWebComponents(\n options: RegisterWebComponentsOptions = {},\n): { badgeTag: string; changelogTag: string } {\n const badgeTag = options.badgeTag ?? \"feature-drop-badge\";\n const changelogTag = options.changelogTag ?? \"feature-drop-changelog\";\n\n if (typeof customElements === \"undefined\") {\n return { badgeTag, changelogTag };\n }\n\n if (!customElements.get(badgeTag)) {\n customElements.define(badgeTag, FeatureDropBadgeElement);\n }\n if (!customElements.get(changelogTag)) {\n customElements.define(changelogTag, FeatureDropChangelogElement);\n }\n\n return { badgeTag, changelogTag };\n}\n"]}
@@ -126,8 +126,12 @@ interface FeatureEntry {
126
126
  sidebarKey?: string;
127
127
  /** Optional grouping category (e.g. "ai", "billing", "core") */
128
128
  category?: string;
129
+ /** Optional product scope (`"*"`, `"askverdict"`, etc.) for multi-product manifests */
130
+ product?: string;
129
131
  /** Optional URL to link to (e.g. docs page, changelog entry) */
130
132
  url?: string;
133
+ /** Optional feature flag key; requires a flag bridge to evaluate */
134
+ flagKey?: string;
131
135
  /** Entry type — determines default icon/color in UI components */
132
136
  type?: FeatureType;
133
137
  /** Priority level — critical entries get special treatment in UI */
@@ -126,8 +126,12 @@ interface FeatureEntry {
126
126
  sidebarKey?: string;
127
127
  /** Optional grouping category (e.g. "ai", "billing", "core") */
128
128
  category?: string;
129
+ /** Optional product scope (`"*"`, `"askverdict"`, etc.) for multi-product manifests */
130
+ product?: string;
129
131
  /** Optional URL to link to (e.g. docs page, changelog entry) */
130
132
  url?: string;
133
+ /** Optional feature flag key; requires a flag bridge to evaluate */
134
+ flagKey?: string;
131
135
  /** Entry type — determines default icon/color in UI components */
132
136
  type?: FeatureType;
133
137
  /** Priority level — critical entries get special treatment in UI */
@@ -117,6 +117,14 @@ function isVersionMatch(feature, appVersion) {
117
117
  if (v.showNewUntil && compareSemver(appVersion, v.showNewUntil) >= 0) return false;
118
118
  return true;
119
119
  }
120
+ function isFlagMatch(feature, flagBridge, userContext) {
121
+ if (!feature.flagKey) return true;
122
+ return false;
123
+ }
124
+ function isProductMatch(feature, product) {
125
+ if (!feature.product || feature.product === "*") return true;
126
+ return false;
127
+ }
120
128
  function isDependencyMatch(feature, dismissedIds, dependencyState) {
121
129
  const dependsOn = feature.dependsOn;
122
130
  if (!dependsOn) return true;
@@ -138,11 +146,13 @@ function isDependencyMatch(feature, dismissedIds, dependencyState) {
138
146
  }
139
147
  return true;
140
148
  }
141
- function isNew(feature, watermark, dismissedIds, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext) {
149
+ function isNew(feature, watermark, dismissedIds, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext, flagBridge, product) {
142
150
  if (dismissedIds.has(feature.id)) return false;
143
151
  if (!isAudienceMatch(feature, userContext, matchAudience)) return false;
144
152
  if (!isDependencyMatch(feature, dismissedIds)) return false;
145
153
  if (!isVersionMatch(feature, appVersion)) return false;
154
+ if (!isFlagMatch(feature)) return false;
155
+ if (!isProductMatch(feature)) return false;
146
156
  if (!isTriggerMatch(feature.trigger)) return false;
147
157
  const nowMs = now.getTime();
148
158
  if (feature.publishAt) {
@@ -158,7 +168,7 @@ function isNew(feature, watermark, dismissedIds, now = /* @__PURE__ */ new Date(
158
168
  }
159
169
  return true;
160
170
  }
161
- function getNewFeatures(manifest, storage, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext) {
171
+ function getNewFeatures(manifest, storage, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext, flagBridge, product) {
162
172
  const watermark = storage.getWatermark();
163
173
  const dismissedIds = storage.getDismissedIds();
164
174
  return manifest.filter(
@@ -172,7 +182,7 @@ function getNewFeatures(manifest, storage, now = /* @__PURE__ */ new Date(), use
172
182
  appVersion)
173
183
  );
174
184
  }
175
- function hasNewFeature(manifest, sidebarKey, storage, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext) {
185
+ function hasNewFeature(manifest, sidebarKey, storage, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext, flagBridge, product) {
176
186
  const watermark = storage.getWatermark();
177
187
  const dismissedIds = storage.getDismissedIds();
178
188
  return manifest.some(
@@ -186,7 +196,7 @@ function hasNewFeature(manifest, sidebarKey, storage, now = /* @__PURE__ */ new
186
196
  appVersion)
187
197
  );
188
198
  }
189
- function getNewFeaturesSorted(manifest, storage, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext) {
199
+ function getNewFeaturesSorted(manifest, storage, now = /* @__PURE__ */ new Date(), userContext, matchAudience, appVersion, dependencyState, triggerContext, flagBridge, product) {
190
200
  const priorityOrder = { critical: 0, normal: 1, low: 2 };
191
201
  return getNewFeatures(
192
202
  manifest,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/semver.ts","../src/triggers.ts","../src/core.ts","../src/adapters/local-storage.ts","../src/web-components/index.ts"],"names":["isNew"],"mappings":"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","file":"web-components.js","sourcesContent":["// Minimal semver comparison utilities (no build metadata sorting needed)\n\nexport type Comparator = \">=\" | \"<=\" | \">\" | \"<\" | \"=\";\n\nexport interface SemverParts {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nconst SEMVER_REGEX = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?/;\n\nexport function parseSemver(input: string): SemverParts | null {\n const match = input.trim().match(SEMVER_REGEX);\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\nexport function compareSemver(a: string, b: string): number {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa || !pb) return 0;\n\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (pa[key] !== pb[key]) return pa[key] - pb[key];\n }\n\n // Handle prerelease: absence > presence, otherwise lexicographic\n const aPre = pa.prerelease;\n const bPre = pb.prerelease;\n if (aPre.length === 0 && bPre.length === 0) return 0;\n if (aPre.length === 0) return 1;\n if (bPre.length === 0) return -1;\n\n const len = Math.max(aPre.length, bPre.length);\n for (let i = 0; i < len; i++) {\n const ai = aPre[i];\n const bi = bPre[i];\n if (ai === undefined) return -1;\n if (bi === undefined) return 1;\n const aNum = Number(ai);\n const bNum = Number(bi);\n const aIsNum = Number.isInteger(aNum);\n const bIsNum = Number.isInteger(bNum);\n if (aIsNum && bIsNum && aNum !== bNum) return aNum - bNum;\n if (aIsNum !== bIsNum) return aIsNum ? -1 : 1;\n if (ai !== bi) return ai < bi ? -1 : 1;\n }\n return 0;\n}\n\nfunction parseComparator(comp: string): { op: Comparator; version: string } | null {\n const match = comp.trim().match(/^(>=|<=|>|<|=)?\\\\s*(.+)$/);\n if (!match) return null;\n const op = (match[1] as Comparator) || \">=\";\n const version = match[2];\n if (!parseSemver(version)) return null;\n return { op, version };\n}\n\nfunction satisfiesComparator(version: string, comp: { op: Comparator; version: string }): boolean {\n const diff = compareSemver(version, comp.version);\n switch (comp.op) {\n case \">\":\n return diff > 0;\n case \">=\":\n return diff >= 0;\n case \"<\":\n return diff < 0;\n case \"<=\":\n return diff <= 0;\n case \"=\":\n return diff === 0;\n default:\n return false;\n }\n}\n\n// Space-separated comparator list (AND semantics), e.g. \">=2.5.0 <3.0.0\"\nexport function satisfiesRange(version: string, range: string): boolean {\n const parts = range.split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return true;\n for (const part of parts) {\n const comp = parseComparator(part);\n if (!comp) return false;\n if (!satisfiesComparator(version, comp)) return false;\n }\n return true;\n}\n","import type { FeatureEntry, FeatureTrigger, TriggerContext } from \"./types\";\n\nfunction wildcardToRegExp(value: string): RegExp {\n const escaped = value.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = `^${escaped.replace(/\\*/g, \".*\")}$`;\n return new RegExp(pattern);\n}\n\nfunction matchPath(path: string, pattern: string | RegExp): boolean {\n if (pattern instanceof RegExp) return pattern.test(path);\n if (!pattern) return false;\n if (pattern.includes(\"*\")) return wildcardToRegExp(pattern).test(path);\n return path === pattern || path.startsWith(pattern);\n}\n\nexport function isTriggerMatch(trigger: FeatureTrigger | undefined, context?: TriggerContext): boolean {\n if (!trigger) return true;\n if (!context) return false;\n\n if (trigger.type === \"page\") {\n const path = context.path;\n if (!path) return false;\n return matchPath(path, trigger.match);\n }\n\n if (trigger.type === \"usage\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.event] ?? 0;\n return count >= (trigger.minActions ?? 1);\n }\n\n if (trigger.type === \"time\") {\n const elapsedMs = context.elapsedMs ?? 0;\n return elapsedMs >= trigger.minSeconds * 1000;\n }\n\n if (trigger.type === \"milestone\") {\n return context.milestones?.has(trigger.event) ?? false;\n }\n\n if (trigger.type === \"frustration\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.pattern] ?? 0;\n return count >= (trigger.threshold ?? 1);\n }\n\n if (trigger.type === \"scroll\") {\n return (context.scrollPercent ?? 0) >= (trigger.minPercent ?? 50);\n }\n\n try {\n return trigger.evaluate(context);\n } catch {\n return false;\n }\n}\n\nexport class TriggerEngine {\n private context: TriggerContext;\n\n constructor(initial?: TriggerContext) {\n this.context = {\n path: initial?.path,\n events: new Set(initial?.events ?? []),\n milestones: new Set(initial?.milestones ?? []),\n usage: { ...(initial?.usage ?? {}) },\n elapsedMs: initial?.elapsedMs ?? 0,\n scrollPercent: initial?.scrollPercent ?? 0,\n metadata: { ...(initial?.metadata ?? {}) },\n };\n }\n\n setPath(path: string): void {\n this.context.path = path;\n }\n\n trackEvent(event: string): void {\n const next = new Set(this.context.events ?? new Set<string>());\n next.add(event);\n this.context.events = next;\n }\n\n trackUsage(event: string, delta = 1): void {\n const usage = { ...(this.context.usage ?? {}) };\n usage[event] = (usage[event] ?? 0) + Math.max(1, delta);\n this.context.usage = usage;\n }\n\n trackMilestone(event: string): void {\n const next = new Set(this.context.milestones ?? new Set<string>());\n next.add(event);\n this.context.milestones = next;\n }\n\n setElapsedMs(elapsedMs: number): void {\n this.context.elapsedMs = Math.max(0, elapsedMs);\n }\n\n setScrollPercent(scrollPercent: number): void {\n const clamped = Math.max(0, Math.min(100, scrollPercent));\n this.context.scrollPercent = clamped;\n }\n\n setMetadata(next: Record<string, unknown>): void {\n this.context.metadata = { ...next };\n }\n\n getContext(): TriggerContext {\n return {\n path: this.context.path,\n events: new Set(this.context.events ?? []),\n milestones: new Set(this.context.milestones ?? []),\n usage: { ...(this.context.usage ?? {}) },\n elapsedMs: this.context.elapsedMs,\n scrollPercent: this.context.scrollPercent,\n metadata: { ...(this.context.metadata ?? {}) },\n };\n }\n\n evaluate(trigger: FeatureTrigger | undefined): boolean {\n return isTriggerMatch(trigger, this.context);\n }\n\n evaluateFeature(feature: Pick<FeatureEntry, \"trigger\">): boolean {\n return this.evaluate(feature.trigger);\n }\n}\n","import type {\n AudienceMatchFn,\n AudienceRule,\n FeatureEntry,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n FeatureDependencyState,\n TriggerContext,\n} from \"./types\";\nimport { compareSemver, satisfiesRange } from \"./semver\";\nimport { isTriggerMatch } from \"./triggers\";\n\n/**\n * Default audience matching logic.\n *\n * For each specified field (plan, role, region), checks if the user's\n * value is included in the allowed list. Fields use AND logic between them,\n * OR logic within each field's array. The `custom` field is ignored by\n * the default matcher — use a custom `AudienceMatchFn` for that.\n */\nexport function matchesAudience(\n audience: AudienceRule,\n userContext: UserContext,\n): boolean {\n if (audience.plan && audience.plan.length > 0) {\n if (!userContext.plan || !audience.plan.includes(userContext.plan)) {\n return false;\n }\n }\n if (audience.role && audience.role.length > 0) {\n if (!userContext.role || !audience.role.includes(userContext.role)) {\n return false;\n }\n }\n if (audience.region && audience.region.length > 0) {\n if (!userContext.region || !audience.region.includes(userContext.region)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Check if a feature's audience allows the given user context.\n *\n * - No `audience` field → visible to all\n * - Empty `audience` ({}) → visible to all\n * - `audience` specified but no `userContext` → hidden (safe default)\n * - Otherwise, delegate to `matchFn` (or default `matchesAudience`)\n */\nfunction isAudienceMatch(\n feature: FeatureEntry,\n userContext?: UserContext,\n matchFn?: AudienceMatchFn,\n): boolean {\n // No audience restriction → show to everyone\n if (!feature.audience) return true;\n\n // Check if audience is empty (no fields with values)\n const { plan, role, region, custom } = feature.audience;\n const hasRules =\n (plan && plan.length > 0) ||\n (role && role.length > 0) ||\n (region && region.length > 0) ||\n (custom && Object.keys(custom).length > 0);\n if (!hasRules) return true;\n\n // Audience specified but no user context → hidden (safe default)\n if (!userContext) return false;\n\n // Use custom matcher if provided, otherwise default\n if (matchFn) return matchFn(feature.audience, userContext);\n return matchesAudience(feature.audience, userContext);\n}\n\nfunction isVersionMatch(feature: FeatureEntry, appVersion?: string): boolean {\n const v = feature.version;\n if (!v || typeof v === \"string\") return true; // string = display only\n if (!appVersion) return false; // Safe default when constraints exist\n if (!v.introduced && !v.showNewUntil && !v.deprecatedAt && !v.showIn) return true;\n\n // Range check\n if (v.showIn && !satisfiesRange(appVersion, v.showIn)) return false;\n\n if (v.introduced && compareSemver(appVersion, v.introduced) < 0) return false;\n if (v.deprecatedAt && compareSemver(appVersion, v.deprecatedAt) >= 0) return false;\n\n // showNewUntil gates \"new\" state only\n if (v.showNewUntil && compareSemver(appVersion, v.showNewUntil) >= 0) return false;\n\n return true;\n}\n\nfunction isDependencyMatch(\n feature: FeatureEntry,\n dismissedIds: ReadonlySet<string>,\n dependencyState?: FeatureDependencyState,\n): boolean {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return true;\n\n const seenIds = dependencyState?.seenIds;\n const clickedIds = dependencyState?.clickedIds;\n const dismissedDependencyIds = dependencyState?.dismissedIds ?? dismissedIds;\n\n if (dependsOn.seen && dependsOn.seen.length > 0) {\n for (const id of dependsOn.seen) {\n const seen = seenIds?.has(id) ?? false;\n if (!seen && !dismissedDependencyIds.has(id)) return false;\n }\n }\n\n if (dependsOn.clicked && dependsOn.clicked.length > 0) {\n for (const id of dependsOn.clicked) {\n if (!(clickedIds?.has(id) ?? false)) return false;\n }\n }\n\n if (dependsOn.dismissed && dependsOn.dismissed.length > 0) {\n for (const id of dependsOn.dismissed) {\n if (!dismissedDependencyIds.has(id)) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if a single feature should show as \"new\".\n *\n * A feature is \"new\" when ALL of these are true:\n * 1. Current time is before `showNewUntil`\n * 2. Feature was released after the watermark (or no watermark exists)\n * 3. Feature has not been individually dismissed\n * 4. If `publishAt` is set, current time must be after it (scheduled publishing)\n * 5. If `audience` is set, user must match the targeting rules\n */\nexport function isNew(\n feature: FeatureEntry,\n watermark: string | null,\n dismissedIds: ReadonlySet<string>,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): boolean {\n // Already dismissed by the user on this device\n if (dismissedIds.has(feature.id)) return false;\n\n // Audience targeting — check before time-based checks\n if (!isAudienceMatch(feature, userContext, matchAudience)) return false;\n\n // Dependency targeting — defer features until prerequisites are satisfied\n if (!isDependencyMatch(feature, dismissedIds, dependencyState)) return false;\n\n // Version targeting — requires appVersion when constraints exist\n if (!isVersionMatch(feature, appVersion)) return false;\n\n // Contextual trigger rules — show only when trigger condition is satisfied.\n if (!isTriggerMatch(feature.trigger, triggerContext)) return false;\n\n const nowMs = now.getTime();\n\n // Scheduled publishing — hidden until publishAt\n if (feature.publishAt) {\n const publishMs = new Date(feature.publishAt).getTime();\n if (nowMs < publishMs) return false;\n }\n\n const showUntilMs = new Date(feature.showNewUntil).getTime();\n\n // Past the display window\n if (nowMs >= showUntilMs) return false;\n\n // If there's a watermark, feature must have been released after it\n if (watermark) {\n const watermarkMs = new Date(watermark).getTime();\n const releasedMs = new Date(feature.releasedAt).getTime();\n if (releasedMs <= watermarkMs) return false;\n }\n\n return true;\n}\n\n/**\n * Get all features that are currently \"new\" for this user.\n */\nexport function getNewFeatures(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter((f) =>\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ),\n );\n}\n\n/**\n * Get the count of new features.\n */\nexport function getNewFeatureCount(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): number {\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ).length;\n}\n\n/**\n * Check if a specific sidebar key has a new feature.\n */\nexport function hasNewFeature(\n manifest: FeatureManifest,\n sidebarKey: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): boolean {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.some(\n (f) =>\n f.sidebarKey === sidebarKey &&\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ),\n );\n}\n\n/**\n * Get all features sorted by priority (critical first) then by release date (newest first).\n */\nexport function getNewFeaturesSorted(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n): FeatureEntry[] {\n const priorityOrder = { critical: 0, normal: 1, low: 2 };\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n ).sort(\n (a, b) => {\n const pa = priorityOrder[a.priority ?? \"normal\"];\n const pb = priorityOrder[b.priority ?? \"normal\"];\n if (pa !== pb) return pa - pb;\n return (\n new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime()\n );\n },\n );\n}\n","import type { StorageAdapter } from \"../types\";\n\nexport interface LocalStorageAdapterOptions {\n /** Key prefix for localStorage entries. Default: \"featuredrop\" */\n prefix?: string;\n /** Server-side watermark (ISO string). Typically from user profile. */\n watermark?: string | null;\n /** Callback when dismissAll is called. Use for server-side watermark updates. */\n onDismissAll?: (now: Date) => Promise<void>;\n}\n\nconst DISMISSED_SUFFIX = \":dismissed\";\n\n/**\n * localStorage-based storage adapter.\n *\n * Architecture:\n * - **Watermark** comes from the server (passed at construction time)\n * - **Per-feature dismissals** are stored in localStorage (zero server writes)\n * - **dismissAll()** optionally calls a server callback, then clears localStorage\n *\n * Gracefully handles SSR environments where `window`/`localStorage` is unavailable.\n */\nexport class LocalStorageAdapter implements StorageAdapter {\n private readonly prefix: string;\n private readonly watermarkValue: string | null;\n private readonly onDismissAllCallback?: (now: Date) => Promise<void>;\n private readonly dismissedKey: string;\n\n constructor(options: LocalStorageAdapterOptions = {}) {\n this.prefix = options.prefix ?? \"featuredrop\";\n this.watermarkValue = options.watermark ?? null;\n this.onDismissAllCallback = options.onDismissAll;\n this.dismissedKey = `${this.prefix}${DISMISSED_SUFFIX}`;\n }\n\n getWatermark(): string | null {\n return this.watermarkValue;\n }\n\n getDismissedIds(): ReadonlySet<string> {\n try {\n if (typeof window === \"undefined\") return new Set();\n const raw = localStorage.getItem(this.dismissedKey);\n if (!raw) return new Set();\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) return new Set(parsed as string[]);\n return new Set();\n } catch {\n return new Set();\n }\n }\n\n dismiss(id: string): void {\n try {\n if (typeof window === \"undefined\") return;\n const raw = localStorage.getItem(this.dismissedKey);\n const existing: string[] = raw ? (JSON.parse(raw) as string[]) : [];\n if (!existing.includes(id)) {\n existing.push(id);\n localStorage.setItem(this.dismissedKey, JSON.stringify(existing));\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n }\n\n async dismissAll(now: Date): Promise<void> {\n try {\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(this.dismissedKey);\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n\n if (this.onDismissAllCallback) {\n await this.onDismissAllCallback(now);\n }\n }\n}\n","import { getNewFeaturesSorted, hasNewFeature } from \"../core\";\nimport { LocalStorageAdapter } from \"../adapters\";\nimport type {\n AudienceMatchFn,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n} from \"../types\";\n\nconst SafeHTMLElement: typeof HTMLElement = typeof HTMLElement === \"undefined\"\n ? (class {} as unknown as typeof HTMLElement)\n : HTMLElement;\n\nexport interface WebComponentsConfig {\n manifest: FeatureManifest;\n storage?: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nexport interface RegisterWebComponentsOptions {\n badgeTag?: string;\n changelogTag?: string;\n}\n\ninterface RuntimeConfig {\n manifest: FeatureManifest;\n storage: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nlet runtimeConfig: RuntimeConfig | null = null;\nlet defaultStorage: StorageAdapter | null = null;\nconst badgeInstances = new Set<FeatureDropBadgeElement>();\nconst changelogInstances = new Set<FeatureDropChangelogElement>();\n\nfunction getDefaultStorage(): StorageAdapter {\n if (!defaultStorage) {\n defaultStorage = new LocalStorageAdapter({ prefix: \"featuredrop:web-components\" });\n }\n return defaultStorage;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n}\n\nfunction getRuntimeConfig(): RuntimeConfig | null {\n return runtimeConfig;\n}\n\nfunction renderAllComponents(): void {\n for (const badge of badgeInstances) badge.render();\n for (const changelog of changelogInstances) changelog.render();\n}\n\nexport function configureFeatureDropWebComponents(config: WebComponentsConfig): void {\n runtimeConfig = {\n manifest: config.manifest,\n storage: config.storage ?? getDefaultStorage(),\n userContext: config.userContext,\n matchAudience: config.matchAudience,\n appVersion: config.appVersion,\n };\n renderAllComponents();\n}\n\nexport function refreshFeatureDropWebComponents(): void {\n renderAllComponents();\n}\n\nexport class FeatureDropBadgeElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"sidebar-key\", \"variant\"];\n }\n\n connectedCallback(): void {\n badgeInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n this.render();\n }\n\n disconnectedCallback(): void {\n badgeInstances.delete(this);\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const sidebarKey = this.getAttribute(\"sidebar-key\");\n const variant = this.getAttribute(\"variant\") ?? \"pill\";\n const config = getRuntimeConfig();\n if (!sidebarKey || !config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const isNew = hasNewFeature(\n config.manifest,\n sidebarKey,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n if (!isNew) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const count = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n ).filter((entry) => entry.sidebarKey === sidebarKey).length;\n\n const content = variant === \"dot\"\n ? `<span class=\"dot\" part=\"dot\"></span>`\n : variant === \"count\"\n ? `<span class=\"count\" part=\"count\">${count}</span>`\n : `<span class=\"pill\" part=\"pill\">New</span>`;\n\n this.shadowRoot.innerHTML = `\n <style>\n .pill { display: inline-block; border-radius: 999px; padding: 2px 8px; font-size: 12px; font-weight: 600; background: #f59e0b; color: #fff; }\n .count { display: inline-grid; place-items: center; min-width: 18px; height: 18px; border-radius: 999px; font-size: 11px; font-weight: 700; background: #dc2626; color: #fff; padding: 0 6px; }\n .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; }\n </style>\n ${content}\n `;\n }\n}\n\nexport class FeatureDropChangelogElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"title\", \"trigger-label\", \"position\"];\n }\n\n private isOpen = false;\n private cleanupClick: (() => void) | null = null;\n\n connectedCallback(): void {\n changelogInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n const onClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n const actionTarget = target.closest(\"[data-action]\") as HTMLElement | null;\n if (!actionTarget) return;\n const action = actionTarget.getAttribute(\"data-action\");\n if (action === \"toggle\") {\n this.isOpen = !this.isOpen;\n this.render();\n return;\n }\n if (action === \"dismiss-all\") {\n void this.dismissAll();\n return;\n }\n if (action === \"dismiss-one\") {\n const id = actionTarget.getAttribute(\"data-id\");\n if (id) this.dismissOne(id);\n }\n };\n this.shadowRoot?.addEventListener(\"click\", onClick);\n this.cleanupClick = () => this.shadowRoot?.removeEventListener(\"click\", onClick);\n this.render();\n }\n\n disconnectedCallback(): void {\n changelogInstances.delete(this);\n this.cleanupClick?.();\n this.cleanupClick = null;\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n private dismissOne(id: string): void {\n const config = getRuntimeConfig();\n if (!config) return;\n config.storage.dismiss(id);\n renderAllComponents();\n }\n\n private async dismissAll(): Promise<void> {\n const config = getRuntimeConfig();\n if (!config) return;\n await config.storage.dismissAll(new Date());\n renderAllComponents();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const config = getRuntimeConfig();\n if (!config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const title = this.getAttribute(\"title\") ?? \"What's New\";\n const triggerLabel = this.getAttribute(\"trigger-label\") ?? \"What's New\";\n const position = this.getAttribute(\"position\") === \"left\" ? \"left: 16px;\" : \"right: 16px;\";\n const entries = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n\n const list = entries.length === 0\n ? `<p class=\"empty\">You're all caught up.</p>`\n : entries\n .map((entry) => `\n <li class=\"item\">\n <div class=\"item-title\">${escapeHtml(entry.label)}</div>\n ${entry.description ? `<p class=\"item-desc\">${escapeHtml(entry.description)}</p>` : \"\"}\n <button data-action=\"dismiss-one\" data-id=\"${escapeHtml(entry.id)}\" class=\"ghost\">Mark read</button>\n </li>\n `)\n .join(\"\");\n\n this.shadowRoot.innerHTML = `\n <style>\n .trigger { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 8px 12px; cursor: pointer; font-weight: 600; font-size: 13px; }\n .panel { position: fixed; top: 70px; ${position} width: min(92vw, 360px); max-height: 70vh; overflow: auto; border: 1px solid #e5e7eb; border-radius: 12px; background: #fff; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.16); z-index: 10000; }\n .header { display: flex; align-items: center; justify-content: space-between; padding: 12px; border-bottom: 1px solid #e5e7eb; }\n .title { margin: 0; font-size: 14px; }\n .list { list-style: none; margin: 0; padding: 10px 12px 12px; display: grid; gap: 10px; }\n .item { border: 1px solid #e5e7eb; border-radius: 10px; padding: 10px; }\n .item-title { font-size: 13px; font-weight: 700; margin-bottom: 4px; }\n .item-desc { margin: 0 0 8px; color: #4b5563; font-size: 12px; }\n .empty { margin: 0; padding: 14px 12px; color: #6b7280; font-size: 13px; }\n .ghost { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 5px 8px; cursor: pointer; font-size: 12px; }\n </style>\n <button data-action=\"toggle\" class=\"trigger\">${escapeHtml(triggerLabel)} (${entries.length})</button>\n ${this.isOpen ? `\n <section class=\"panel\">\n <div class=\"header\">\n <h3 class=\"title\">${escapeHtml(title)}</h3>\n <button data-action=\"dismiss-all\" class=\"ghost\">Mark all read</button>\n </div>\n <ul class=\"list\">${list}</ul>\n </section>\n ` : \"\"}\n `;\n }\n}\n\nexport function registerFeatureDropWebComponents(\n options: RegisterWebComponentsOptions = {},\n): { badgeTag: string; changelogTag: string } {\n const badgeTag = options.badgeTag ?? \"feature-drop-badge\";\n const changelogTag = options.changelogTag ?? \"feature-drop-changelog\";\n\n if (typeof customElements === \"undefined\") {\n return { badgeTag, changelogTag };\n }\n\n if (!customElements.get(badgeTag)) {\n customElements.define(badgeTag, FeatureDropBadgeElement);\n }\n if (!customElements.get(changelogTag)) {\n customElements.define(changelogTag, FeatureDropChangelogElement);\n }\n\n return { badgeTag, changelogTag };\n}\n"]}
1
+ {"version":3,"sources":["../src/semver.ts","../src/triggers.ts","../src/core.ts","../src/adapters/local-storage.ts","../src/web-components/index.ts"],"names":["isNew"],"mappings":";AAWA,IAAM,YAAA,GAAe,4CAAA;AAEd,SAAS,YAAY,KAAA,EAAmC;AAC7D,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,EAAK,CAAE,MAAM,YAAY,CAAA;AAC7C,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,IACtB,KAAA,EAAO,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,IACtB,KAAA,EAAO,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,IACtB,UAAA,EAAY,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,GAAI;AAAC,GAChD;AACF;AAEO,SAAS,aAAA,CAAc,GAAW,CAAA,EAAmB;AAC1D,EAAA,MAAM,EAAA,GAAK,YAAY,CAAC,CAAA;AACxB,EAAA,MAAM,EAAA,GAAK,YAAY,CAAC,CAAA;AACxB,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,EAAA,EAAI,OAAO,CAAA;AAEvB,EAAA,KAAA,MAAW,GAAA,IAAO,CAAC,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA,EAAY;AACtD,IAAA,IAAI,EAAA,CAAG,GAAG,CAAA,KAAM,EAAA,CAAG,GAAG,CAAA,EAAG,OAAO,EAAA,CAAG,GAAG,CAAA,GAAI,EAAA,CAAG,GAAG,CAAA;AAAA,EAClD;AAGA,EAAA,MAAM,OAAO,EAAA,CAAG,UAAA;AAChB,EAAA,MAAM,OAAO,EAAA,CAAG,UAAA;AAChB,EAAA,IAAI,KAAK,MAAA,KAAW,CAAA,IAAK,IAAA,CAAK,MAAA,KAAW,GAAG,OAAO,CAAA;AACnD,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA;AAC9B,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAE9B,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,MAAA,EAAQ,KAAK,MAAM,CAAA;AAC7C,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,IAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,IAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,IAAA,IAAI,EAAA,KAAO,QAAW,OAAO,EAAA;AAC7B,IAAA,IAAI,EAAA,KAAO,QAAW,OAAO,CAAA;AAC7B,IAAA,MAAM,IAAA,GAAO,OAAO,EAAE,CAAA;AACtB,IAAA,MAAM,IAAA,GAAO,OAAO,EAAE,CAAA;AACtB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,IAAI,CAAA;AACpC,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,IAAI,CAAA;AACpC,IAAA,IAAI,MAAA,IAAU,MAAA,IAAU,IAAA,KAAS,IAAA,SAAa,IAAA,GAAO,IAAA;AACrD,IAAA,IAAI,MAAA,KAAW,MAAA,EAAQ,OAAO,MAAA,GAAS,EAAA,GAAK,CAAA;AAC5C,IAAA,IAAI,EAAA,KAAO,EAAA,EAAI,OAAO,EAAA,GAAK,KAAK,EAAA,GAAK,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,CAAA;AACT;AAEA,SAAS,gBAAgB,IAAA,EAA0D;AACjF,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,MAAM,0BAA0B,CAAA;AAC1D,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,EAAA,MAAM,EAAA,GAAM,KAAA,CAAM,CAAC,CAAA,IAAoB,IAAA;AACvC,EAAA,MAAM,OAAA,GAAU,MAAM,CAAC,CAAA;AACvB,EAAA,IAAI,CAAC,WAAA,CAAY,OAAO,CAAA,EAAG,OAAO,IAAA;AAClC,EAAA,OAAO,EAAE,IAAI,OAAA,EAAQ;AACvB;AAEA,SAAS,mBAAA,CAAoB,SAAiB,IAAA,EAAoD;AAChG,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,OAAA,EAAS,IAAA,CAAK,OAAO,CAAA;AAChD,EAAA,QAAQ,KAAK,EAAA;AAAI,IACf,KAAK,GAAA;AACH,MAAA,OAAO,IAAA,GAAO,CAAA;AAAA,IAChB,KAAK,IAAA;AACH,MAAA,OAAO,IAAA,IAAQ,CAAA;AAAA,IACjB,KAAK,GAAA;AACH,MAAA,OAAO,IAAA,GAAO,CAAA;AAAA,IAChB,KAAK,IAAA;AACH,MAAA,OAAO,IAAA,IAAQ,CAAA;AAAA,IACjB,KAAK,GAAA;AACH,MAAA,OAAO,IAAA,KAAS,CAAA;AAAA,IAClB;AACE,MAAA,OAAO,KAAA;AAAA;AAEb;AAGO,SAAS,cAAA,CAAe,SAAiB,KAAA,EAAwB;AACtE,EAAA,MAAM,QAAQ,KAAA,CAAM,KAAA,CAAM,KAAK,CAAA,CAAE,OAAO,OAAO,CAAA;AAC/C,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,IAAA,GAAO,gBAAgB,IAAI,CAAA;AACjC,IAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,IAAA,IAAI,CAAC,mBAAA,CAAoB,OAAA,EAAS,IAAI,GAAG,OAAO,KAAA;AAAA,EAClD;AACA,EAAA,OAAO,IAAA;AACT;AC/EO,SAAS,cAAA,CAAe,SAAqC,OAAA,EAAmC;AACrG,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAc,OAAO,KAAA;AAsCvB;;;ACjCO,SAAS,eAAA,CACd,UACA,WAAA,EACS;AACT,EAAA,IAAI,QAAA,CAAS,IAAA,IAAQ,QAAA,CAAS,IAAA,CAAK,SAAS,CAAA,EAAG;AAC7C,IAAA,IAAI,CAAC,YAAY,IAAA,IAAQ,CAAC,SAAS,IAAA,CAAK,QAAA,CAAS,WAAA,CAAY,IAAI,CAAA,EAAG;AAClE,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAI,QAAA,CAAS,IAAA,IAAQ,QAAA,CAAS,IAAA,CAAK,SAAS,CAAA,EAAG;AAC7C,IAAA,IAAI,CAAC,YAAY,IAAA,IAAQ,CAAC,SAAS,IAAA,CAAK,QAAA,CAAS,WAAA,CAAY,IAAI,CAAA,EAAG;AAClE,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAI,QAAA,CAAS,MAAA,IAAU,QAAA,CAAS,MAAA,CAAO,SAAS,CAAA,EAAG;AACjD,IAAA,IAAI,CAAC,YAAY,MAAA,IAAU,CAAC,SAAS,MAAA,CAAO,QAAA,CAAS,WAAA,CAAY,MAAM,CAAA,EAAG;AACxE,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAUA,SAAS,eAAA,CACP,OAAA,EACA,WAAA,EACA,OAAA,EACS;AAET,EAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,EAAU,OAAO,IAAA;AAG9B,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,MAAA,KAAW,OAAA,CAAQ,QAAA;AAC/C,EAAA,MAAM,WACH,IAAA,IAAQ,IAAA,CAAK,SAAS,CAAA,IACtB,IAAA,IAAQ,KAAK,MAAA,GAAS,CAAA,IACtB,MAAA,IAAU,MAAA,CAAO,SAAS,CAAA,IAC1B,MAAA,IAAU,OAAO,IAAA,CAAK,MAAM,EAAE,MAAA,GAAS,CAAA;AAC1C,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAGtB,EAAA,IAAI,CAAC,aAAa,OAAO,KAAA;AAGzB,EAAA,IAAI,OAAA,EAAS,OAAO,OAAA,CAAQ,OAAA,CAAQ,UAAU,WAAW,CAAA;AACzD,EAAA,OAAO,eAAA,CAAgB,OAAA,CAAQ,QAAA,EAAU,WAAW,CAAA;AACtD;AAEA,SAAS,cAAA,CAAe,SAAuB,UAAA,EAA8B;AAC3E,EAAA,MAAM,IAAI,OAAA,CAAQ,OAAA;AAClB,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,UAAU,OAAO,IAAA;AACxC,EAAA,IAAI,CAAC,YAAY,OAAO,KAAA;AACxB,EAAA,IAAI,CAAC,CAAA,CAAE,UAAA,IAAc,CAAC,CAAA,CAAE,YAAA,IAAgB,CAAC,CAAA,CAAE,YAAA,IAAgB,CAAC,CAAA,CAAE,MAAA,EAAQ,OAAO,IAAA;AAG7E,EAAA,IAAI,CAAA,CAAE,UAAU,CAAC,cAAA,CAAe,YAAY,CAAA,CAAE,MAAM,GAAG,OAAO,KAAA;AAE9D,EAAA,IAAI,CAAA,CAAE,cAAc,aAAA,CAAc,UAAA,EAAY,EAAE,UAAU,CAAA,GAAI,GAAG,OAAO,KAAA;AACxE,EAAA,IAAI,CAAA,CAAE,gBAAgB,aAAA,CAAc,UAAA,EAAY,EAAE,YAAY,CAAA,IAAK,GAAG,OAAO,KAAA;AAG7E,EAAA,IAAI,CAAA,CAAE,gBAAgB,aAAA,CAAc,UAAA,EAAY,EAAE,YAAY,CAAA,IAAK,GAAG,OAAO,KAAA;AAE7E,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,WAAA,CACP,OAAA,EACA,UAAA,EACA,WAAA,EACS;AACT,EAAA,IAAI,CAAC,OAAA,CAAQ,OAAA,EAAS,OAAO,IAAA;AAC7B,EAAiB,OAAO,KAAA;AAM1B;AAEA,SAAS,cAAA,CAAe,SAAuB,OAAA,EAA2B;AACxE,EAAA,IAAI,CAAC,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,OAAA,KAAY,KAAK,OAAO,IAAA;AACxD,EAAc,OAAO,KAAA;AAEvB;AAEA,SAAS,iBAAA,CACP,OAAA,EACA,YAAA,EACA,eAAA,EACS;AACT,EAAA,MAAM,YAAY,OAAA,CAAQ,SAAA;AAC1B,EAAA,IAAI,CAAC,WAAW,OAAO,IAAA;AAIvB,EAAA,MAAM,sBAAA,GAA0D,YAAA;AAEhE,EAAA,IAAI,SAAA,CAAU,IAAA,IAAQ,SAAA,CAAU,IAAA,CAAK,SAAS,CAAA,EAAG;AAC/C,IAAA,KAAA,MAAW,EAAA,IAAM,UAAU,IAAA,EAAM;AAE/B,MAAA,IAAa,CAAC,uBAAuB,GAAA,CAAI,EAAE,GAAG,OAAO,KAAA;AAAA,IACvD;AAAA,EACF;AAEA,EAAA,IAAI,SAAA,CAAU,OAAA,IAAW,SAAA,CAAU,OAAA,CAAQ,SAAS,CAAA,EAAG;AACrD,IAAA,KAAA,MAAW,EAAA,IAAM,UAAU,OAAA,EAAS;AAClC,MAAqC,OAAO,KAAA;AAAA,IAC9C;AAAA,EACF;AAEA,EAAA,IAAI,SAAA,CAAU,SAAA,IAAa,SAAA,CAAU,SAAA,CAAU,SAAS,CAAA,EAAG;AACzD,IAAA,KAAA,MAAW,EAAA,IAAM,UAAU,SAAA,EAAW;AACpC,MAAA,IAAI,CAAC,sBAAA,CAAuB,GAAA,CAAI,EAAE,GAAG,OAAO,KAAA;AAAA,IAC9C;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAcO,SAAS,KAAA,CACd,OAAA,EACA,SAAA,EACA,YAAA,EACA,sBAAY,IAAI,IAAA,EAAK,EACrB,WAAA,EACA,aAAA,EACA,UAAA,EACA,eAAA,EACA,cAAA,EACA,YACA,OAAA,EACS;AAET,EAAA,IAAI,YAAA,CAAa,GAAA,CAAI,OAAA,CAAQ,EAAE,GAAG,OAAO,KAAA;AAGzC,EAAA,IAAI,CAAC,eAAA,CAAgB,OAAA,EAAS,WAAA,EAAa,aAAa,GAAG,OAAO,KAAA;AAGlE,EAAA,IAAI,CAAC,iBAAA,CAAkB,OAAA,EAAS,YAA6B,GAAG,OAAO,KAAA;AAGvE,EAAA,IAAI,CAAC,cAAA,CAAe,OAAA,EAAS,UAAU,GAAG,OAAO,KAAA;AAGjD,EAAA,IAAI,CAAC,WAAA,CAAY,OAAgC,GAAG,OAAO,KAAA;AAG3D,EAAA,IAAI,CAAC,cAAA,CAAe,OAAgB,GAAG,OAAO,KAAA;AAG9C,EAAA,IAAI,CAAC,cAAA,CAAe,OAAA,CAAQ,OAAuB,GAAG,OAAO,KAAA;AAE7D,EAAA,MAAM,KAAA,GAAQ,IAAI,OAAA,EAAQ;AAG1B,EAAA,IAAI,QAAQ,SAAA,EAAW;AACrB,IAAA,MAAM,YAAY,IAAI,IAAA,CAAK,OAAA,CAAQ,SAAS,EAAE,OAAA,EAAQ;AACtD,IAAA,IAAI,KAAA,GAAQ,WAAW,OAAO,KAAA;AAAA,EAChC;AAEA,EAAA,MAAM,cAAc,IAAI,IAAA,CAAK,OAAA,CAAQ,YAAY,EAAE,OAAA,EAAQ;AAG3D,EAAA,IAAI,KAAA,IAAS,aAAa,OAAO,KAAA;AAGjC,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,MAAM,WAAA,GAAc,IAAI,IAAA,CAAK,SAAS,EAAE,OAAA,EAAQ;AAChD,IAAA,MAAM,aAAa,IAAI,IAAA,CAAK,OAAA,CAAQ,UAAU,EAAE,OAAA,EAAQ;AACxD,IAAA,IAAI,UAAA,IAAc,aAAa,OAAO,KAAA;AAAA,EACxC;AAEA,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,cAAA,CACd,QAAA,EACA,OAAA,EACA,GAAA,mBAAY,IAAI,IAAA,EAAK,EACrB,WAAA,EACA,aAAA,EACA,UAAA,EACA,eAAA,EACA,cAAA,EACA,YACA,OAAA,EACgB;AAChB,EAAA,MAAM,SAAA,GAAY,QAAQ,YAAA,EAAa;AACvC,EAAA,MAAM,YAAA,GAAe,QAAQ,eAAA,EAAgB;AAC7C,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IAAO,CAAC,CAAA,KACtB,KAAA;AAAA,MACE,CAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,GAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAA;AAAA,MACA,UAKF;AAAA,GACF;AACF;AAkCO,SAAS,aAAA,CACd,QAAA,EACA,UAAA,EACA,OAAA,EACA,sBAAY,IAAI,IAAA,EAAK,EACrB,WAAA,EACA,aAAA,EACA,UAAA,EACA,eAAA,EACA,cAAA,EACA,YACA,OAAA,EACS;AACT,EAAA,MAAM,SAAA,GAAY,QAAQ,YAAA,EAAa;AACvC,EAAA,MAAM,YAAA,GAAe,QAAQ,eAAA,EAAgB;AAC7C,EAAA,OAAO,QAAA,CAAS,IAAA;AAAA,IACd,CAAC,CAAA,KACC,CAAA,CAAE,UAAA,KAAe,UAAA,IACjB,KAAA;AAAA,MACE,CAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,GAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAA;AAAA,MACA,UAKF;AAAA,GACJ;AACF;AAKO,SAAS,oBAAA,CACd,QAAA,EACA,OAAA,EACA,GAAA,mBAAY,IAAI,IAAA,EAAK,EACrB,WAAA,EACA,aAAA,EACA,UAAA,EACA,eAAA,EACA,cAAA,EACA,YACA,OAAA,EACgB;AAChB,EAAA,MAAM,gBAAgB,EAAE,QAAA,EAAU,GAAG,MAAA,EAAQ,CAAA,EAAG,KAAK,CAAA,EAAE;AACvD,EAAA,OAAO,cAAA;AAAA,IACL,QAAA;AAAA,IACA,OAAA;AAAA,IACA,GAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA,UAKF,CAAA,CAAE,IAAA;AAAA,IACA,CAAC,GAAG,CAAA,KAAM;AACR,MAAA,MAAM,EAAA,GAAK,aAAA,CAAc,CAAA,CAAE,QAAA,IAAY,QAAQ,CAAA;AAC/C,MAAA,MAAM,EAAA,GAAK,aAAA,CAAc,CAAA,CAAE,QAAA,IAAY,QAAQ,CAAA;AAC/C,MAAA,IAAI,EAAA,KAAO,EAAA,EAAI,OAAO,EAAA,GAAK,EAAA;AAC3B,MAAA,OACE,IAAI,IAAA,CAAK,CAAA,CAAE,UAAU,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAI,IAAA,CAAK,CAAA,CAAE,UAAU,CAAA,CAAE,OAAA,EAAQ;AAAA,IAEtE;AAAA,GACF;AACF;;;ACxVA,IAAM,gBAAA,GAAmB,YAAA;AAYlB,IAAM,sBAAN,MAAoD;AAAA,EACxC,MAAA;AAAA,EACA,cAAA;AAAA,EACA,oBAAA;AAAA,EACA,YAAA;AAAA,EAEjB,WAAA,CAAY,OAAA,GAAsC,EAAC,EAAG;AACpD,IAAA,IAAA,CAAK,MAAA,GAAS,QAAQ,MAAA,IAAU,aAAA;AAChC,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAQ,SAAA,IAAa,IAAA;AAC3C,IAAA,IAAA,CAAK,uBAAuB,OAAA,CAAQ,YAAA;AACpC,IAAA,IAAA,CAAK,YAAA,GAAe,CAAA,EAAG,IAAA,CAAK,MAAM,GAAG,gBAAgB,CAAA,CAAA;AAAA,EACvD;AAAA,EAEA,YAAA,GAA8B;AAC5B,IAAA,OAAO,IAAA,CAAK,cAAA;AAAA,EACd;AAAA,EAEA,eAAA,GAAuC;AACrC,IAAA,IAAI;AACF,MAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,2BAAW,GAAA,EAAI;AAClD,MAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,YAAY,CAAA;AAClD,MAAA,IAAI,CAAC,GAAA,EAAK,uBAAO,IAAI,GAAA,EAAI;AACzB,MAAA,MAAM,MAAA,GAAkB,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AACtC,MAAA,IAAI,MAAM,OAAA,CAAQ,MAAM,GAAG,OAAO,IAAI,IAAI,MAAkB,CAAA;AAC5D,MAAA,2BAAW,GAAA,EAAI;AAAA,IACjB,CAAA,CAAA,MAAQ;AACN,MAAA,2BAAW,GAAA,EAAI;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,QAAQ,EAAA,EAAkB;AACxB,IAAA,IAAI;AACF,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,MAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,YAAY,CAAA;AAClD,MAAA,MAAM,WAAqB,GAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,IAAiB,EAAC;AAClE,MAAA,IAAI,CAAC,QAAA,CAAS,QAAA,CAAS,EAAE,CAAA,EAAG;AAC1B,QAAA,QAAA,CAAS,KAAK,EAAE,CAAA;AAChB,QAAA,YAAA,CAAa,QAAQ,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,MAClE;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,GAAA,EAA0B;AACzC,IAAA,IAAI;AACF,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,YAAA,CAAa,UAAA,CAAW,KAAK,YAAY,CAAA;AAAA,MAC3C;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAEA,IAAA,IAAI,KAAK,oBAAA,EAAsB;AAC7B,MAAA,MAAM,IAAA,CAAK,qBAAqB,GAAG,CAAA;AAAA,IACrC;AAAA,EACF;AACF,CAAA;;;ACvEA,IAAM,eAAA,GAAsC,OAAO,WAAA,KAAgB,WAAA,GAC9D,MAAM;AAAC,CAAA,GACR,WAAA;AAuBJ,IAAI,aAAA,GAAsC,IAAA;AAC1C,IAAI,cAAA,GAAwC,IAAA;AAC5C,IAAM,cAAA,uBAAqB,GAAA,EAA6B;AACxD,IAAM,kBAAA,uBAAyB,GAAA,EAAiC;AAEhE,SAAS,iBAAA,GAAoC;AAC3C,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,cAAA,GAAiB,IAAI,mBAAA,CAAoB,EAAE,MAAA,EAAQ,8BAA8B,CAAA;AAAA,EACnF;AACA,EAAA,OAAO,cAAA;AACT;AAEA,SAAS,WAAW,KAAA,EAAuB;AACzC,EAAA,OAAO,MACJ,UAAA,CAAW,GAAA,EAAK,OAAO,CAAA,CACvB,UAAA,CAAW,KAAK,MAAM,CAAA,CACtB,WAAW,GAAA,EAAK,MAAM,EACtB,UAAA,CAAW,GAAA,EAAK,QAAQ,CAAA,CACxB,UAAA,CAAW,KAAK,QAAQ,CAAA;AAC7B;AAEA,SAAS,gBAAA,GAAyC;AAChD,EAAA,OAAO,aAAA;AACT;AAEA,SAAS,mBAAA,GAA4B;AACnC,EAAA,KAAA,MAAW,KAAA,IAAS,cAAA,EAAgB,KAAA,CAAM,MAAA,EAAO;AACjD,EAAA,KAAA,MAAW,SAAA,IAAa,kBAAA,EAAoB,SAAA,CAAU,MAAA,EAAO;AAC/D;AAEO,SAAS,kCAAkC,MAAA,EAAmC;AACnF,EAAA,aAAA,GAAgB;AAAA,IACd,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,OAAA,EAAS,MAAA,CAAO,OAAA,IAAW,iBAAA,EAAkB;AAAA,IAC7C,aAAa,MAAA,CAAO,WAAA;AAAA,IACpB,eAAe,MAAA,CAAO,aAAA;AAAA,IACtB,YAAY,MAAA,CAAO;AAAA,GACrB;AACA,EAAA,mBAAA,EAAoB;AACtB;AAEO,SAAS,+BAAA,GAAwC;AACtD,EAAA,mBAAA,EAAoB;AACtB;AAEO,IAAM,uBAAA,GAAN,cAAsC,eAAA,CAAgB;AAAA,EAC3D,WAAW,kBAAA,GAA+B;AACxC,IAAA,OAAO,CAAC,eAAe,SAAS,CAAA;AAAA,EAClC;AAAA,EAEA,iBAAA,GAA0B;AACxB,IAAA,cAAA,CAAe,IAAI,IAAI,CAAA;AACvB,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,IAAc,cAAA,IAAkB,IAAA,EAAM;AAC9C,MAAA,IAAA,CAAK,YAAA,CAAa,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA;AAAA,IACpC;AACA,IAAA,IAAA,CAAK,MAAA,EAAO;AAAA,EACd;AAAA,EAEA,oBAAA,GAA6B;AAC3B,IAAA,cAAA,CAAe,OAAO,IAAI,CAAA;AAAA,EAC5B;AAAA,EAEA,wBAAA,GAAiC;AAC/B,IAAA,IAAA,CAAK,MAAA,EAAO;AAAA,EACd;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACtB,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,YAAA,CAAa,aAAa,CAAA;AAClD,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,IAAK,MAAA;AAChD,IAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,IAAA,IAAI,CAAC,UAAA,IAAc,CAAC,MAAA,EAAQ;AAC1B,MAAA,IAAA,CAAK,WAAW,SAAA,GAAY,EAAA;AAC5B,MAAA;AAAA,IACF;AAEA,IAAA,MAAMA,MAAAA,GAAQ,aAAA;AAAA,MACZ,MAAA,CAAO,QAAA;AAAA,MACP,UAAA;AAAA,MACA,MAAA,CAAO,OAAA;AAAA,0BACH,IAAA,EAAK;AAAA,MACT,MAAA,CAAO,WAAA;AAAA,MACP,MAAA,CAAO,aAAA;AAAA,MACP,MAAA,CAAO;AAAA,KACT;AACA,IAAA,IAAI,CAACA,MAAAA,EAAO;AACV,MAAA,IAAA,CAAK,WAAW,SAAA,GAAY,EAAA;AAC5B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,oBAAA;AAAA,MACZ,MAAA,CAAO,QAAA;AAAA,MACP,MAAA,CAAO,OAAA;AAAA,0BACH,IAAA,EAAK;AAAA,MACT,MAAA,CAAO,WAAA;AAAA,MACP,MAAA,CAAO,aAAA;AAAA,MACP,MAAA,CAAO;AAAA,MACP,MAAA,CAAO,CAAC,UAAU,KAAA,CAAM,UAAA,KAAe,UAAU,CAAA,CAAE,MAAA;AAErD,IAAA,MAAM,OAAA,GAAU,YAAY,KAAA,GACxB,CAAA,oCAAA,CAAA,GACA,YAAY,OAAA,GACV,CAAA,iCAAA,EAAoC,KAAK,CAAA,OAAA,CAAA,GACzC,CAAA,yCAAA,CAAA;AAEN,IAAA,IAAA,CAAK,WAAW,SAAA,GAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAA,EAMxB,OAAO;AAAA,IAAA,CAAA;AAAA,EAEb;AACF;AAEO,IAAM,2BAAA,GAAN,cAA0C,eAAA,CAAgB;AAAA,EAC/D,WAAW,kBAAA,GAA+B;AACxC,IAAA,OAAO,CAAC,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAA;AAAA,EAC9C;AAAA,EAEQ,MAAA,GAAS,KAAA;AAAA,EACT,YAAA,GAAoC,IAAA;AAAA,EAE5C,iBAAA,GAA0B;AACxB,IAAA,kBAAA,CAAmB,IAAI,IAAI,CAAA;AAC3B,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,IAAc,cAAA,IAAkB,IAAA,EAAM;AAC9C,MAAA,IAAA,CAAK,YAAA,CAAa,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA;AAAA,IACpC;AACA,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAAuB;AACtC,MAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,MAAA,IAAI,CAAC,MAAA,EAAQ;AACb,MAAA,MAAM,YAAA,GAAe,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA;AACnD,MAAA,IAAI,CAAC,YAAA,EAAc;AACnB,MAAA,MAAM,MAAA,GAAS,YAAA,CAAa,YAAA,CAAa,aAAa,CAAA;AACtD,MAAA,IAAI,WAAW,QAAA,EAAU;AACvB,QAAA,IAAA,CAAK,MAAA,GAAS,CAAC,IAAA,CAAK,MAAA;AACpB,QAAA,IAAA,CAAK,MAAA,EAAO;AACZ,QAAA;AAAA,MACF;AACA,MAAA,IAAI,WAAW,aAAA,EAAe;AAC5B,QAAA,KAAK,KAAK,UAAA,EAAW;AACrB,QAAA;AAAA,MACF;AACA,MAAA,IAAI,WAAW,aAAA,EAAe;AAC5B,QAAA,MAAM,EAAA,GAAK,YAAA,CAAa,YAAA,CAAa,SAAS,CAAA;AAC9C,QAAA,IAAI,EAAA,EAAI,IAAA,CAAK,UAAA,CAAW,EAAE,CAAA;AAAA,MAC5B;AAAA,IACF,CAAA;AACA,IAAA,IAAA,CAAK,UAAA,EAAY,gBAAA,CAAiB,OAAA,EAAS,OAAO,CAAA;AAClD,IAAA,IAAA,CAAK,eAAe,MAAM,IAAA,CAAK,UAAA,EAAY,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC/E,IAAA,IAAA,CAAK,MAAA,EAAO;AAAA,EACd;AAAA,EAEA,oBAAA,GAA6B;AAC3B,IAAA,kBAAA,CAAmB,OAAO,IAAI,CAAA;AAC9B,IAAA,IAAA,CAAK,YAAA,IAAe;AACpB,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAAA,EACtB;AAAA,EAEA,wBAAA,GAAiC;AAC/B,IAAA,IAAA,CAAK,MAAA,EAAO;AAAA,EACd;AAAA,EAEQ,WAAW,EAAA,EAAkB;AACnC,IAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAA,CAAO,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACzB,IAAA,mBAAA,EAAoB;AAAA,EACtB;AAAA,EAEA,MAAc,UAAA,GAA4B;AACxC,IAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,MAAM,MAAA,CAAO,OAAA,CAAQ,UAAA,iBAAW,IAAI,MAAM,CAAA;AAC1C,IAAA,mBAAA,EAAoB;AAAA,EACtB;AAAA,EAEA,MAAA,GAAe;AACb,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACtB,IAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,IAAA,CAAK,WAAW,SAAA,GAAY,EAAA;AAC5B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,YAAA,CAAa,OAAO,CAAA,IAAK,YAAA;AAC5C,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,CAAa,eAAe,CAAA,IAAK,YAAA;AAC3D,IAAA,MAAM,WAAW,IAAA,CAAK,YAAA,CAAa,UAAU,CAAA,KAAM,SAAS,aAAA,GAAgB,cAAA;AAC5E,IAAA,MAAM,OAAA,GAAU,oBAAA;AAAA,MACd,MAAA,CAAO,QAAA;AAAA,MACP,MAAA,CAAO,OAAA;AAAA,0BACH,IAAA,EAAK;AAAA,MACT,MAAA,CAAO,WAAA;AAAA,MACP,MAAA,CAAO,aAAA;AAAA,MACP,MAAA,CAAO;AAAA,KACT;AAEA,IAAA,MAAM,IAAA,GAAO,QAAQ,MAAA,KAAW,CAAA,GAC5B,+CACA,OAAA,CACC,GAAA,CAAI,CAAC,KAAA,KAAU;AAAA;AAAA,oCAAA,EAEc,UAAA,CAAW,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,YAAA,EAC/C,KAAA,CAAM,cAAc,CAAA,qBAAA,EAAwB,UAAA,CAAW,MAAM,WAAW,CAAC,SAAS,EAAE;AAAA,uDAAA,EACzC,UAAA,CAAW,KAAA,CAAM,EAAE,CAAC,CAAA;AAAA;AAAA,QAAA,CAEpE,CAAA,CACA,KAAK,EAAE,CAAA;AAEZ,IAAA,IAAA,CAAK,WAAW,SAAA,GAAY;AAAA;AAAA;AAAA,6CAAA,EAGe,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mDAAA,EAUF,UAAA,CAAW,YAAY,CAAC,CAAA,EAAA,EAAK,QAAQ,MAAM,CAAA;AAAA,MAAA,EACxF,KAAK,MAAA,GAAS;AAAA;AAAA;AAAA,8BAAA,EAGU,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA;AAAA;AAAA,2BAAA,EAGpB,IAAI,CAAA;AAAA;AAAA,MAAA,CAAA,GAEvB,EAAE;AAAA,IAAA,CAAA;AAAA,EAEV;AACF;AAEO,SAAS,gCAAA,CACd,OAAA,GAAwC,EAAC,EACG;AAC5C,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,oBAAA;AACrC,EAAA,MAAM,YAAA,GAAe,QAAQ,YAAA,IAAgB,wBAAA;AAE7C,EAAA,IAAI,OAAO,mBAAmB,WAAA,EAAa;AACzC,IAAA,OAAO,EAAE,UAAU,YAAA,EAAa;AAAA,EAClC;AAEA,EAAA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,QAAQ,CAAA,EAAG;AACjC,IAAA,cAAA,CAAe,MAAA,CAAO,UAAU,uBAAuB,CAAA;AAAA,EACzD;AACA,EAAA,IAAI,CAAC,cAAA,CAAe,GAAA,CAAI,YAAY,CAAA,EAAG;AACrC,IAAA,cAAA,CAAe,MAAA,CAAO,cAAc,2BAA2B,CAAA;AAAA,EACjE;AAEA,EAAA,OAAO,EAAE,UAAU,YAAA,EAAa;AAClC","file":"web-components.js","sourcesContent":["// Minimal semver comparison utilities (no build metadata sorting needed)\n\nexport type Comparator = \">=\" | \"<=\" | \">\" | \"<\" | \"=\";\n\nexport interface SemverParts {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nconst SEMVER_REGEX = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?/;\n\nexport function parseSemver(input: string): SemverParts | null {\n const match = input.trim().match(SEMVER_REGEX);\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\nexport function compareSemver(a: string, b: string): number {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa || !pb) return 0;\n\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (pa[key] !== pb[key]) return pa[key] - pb[key];\n }\n\n // Handle prerelease: absence > presence, otherwise lexicographic\n const aPre = pa.prerelease;\n const bPre = pb.prerelease;\n if (aPre.length === 0 && bPre.length === 0) return 0;\n if (aPre.length === 0) return 1;\n if (bPre.length === 0) return -1;\n\n const len = Math.max(aPre.length, bPre.length);\n for (let i = 0; i < len; i++) {\n const ai = aPre[i];\n const bi = bPre[i];\n if (ai === undefined) return -1;\n if (bi === undefined) return 1;\n const aNum = Number(ai);\n const bNum = Number(bi);\n const aIsNum = Number.isInteger(aNum);\n const bIsNum = Number.isInteger(bNum);\n if (aIsNum && bIsNum && aNum !== bNum) return aNum - bNum;\n if (aIsNum !== bIsNum) return aIsNum ? -1 : 1;\n if (ai !== bi) return ai < bi ? -1 : 1;\n }\n return 0;\n}\n\nfunction parseComparator(comp: string): { op: Comparator; version: string } | null {\n const match = comp.trim().match(/^(>=|<=|>|<|=)?\\\\s*(.+)$/);\n if (!match) return null;\n const op = (match[1] as Comparator) || \">=\";\n const version = match[2];\n if (!parseSemver(version)) return null;\n return { op, version };\n}\n\nfunction satisfiesComparator(version: string, comp: { op: Comparator; version: string }): boolean {\n const diff = compareSemver(version, comp.version);\n switch (comp.op) {\n case \">\":\n return diff > 0;\n case \">=\":\n return diff >= 0;\n case \"<\":\n return diff < 0;\n case \"<=\":\n return diff <= 0;\n case \"=\":\n return diff === 0;\n default:\n return false;\n }\n}\n\n// Space-separated comparator list (AND semantics), e.g. \">=2.5.0 <3.0.0\"\nexport function satisfiesRange(version: string, range: string): boolean {\n const parts = range.split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return true;\n for (const part of parts) {\n const comp = parseComparator(part);\n if (!comp) return false;\n if (!satisfiesComparator(version, comp)) return false;\n }\n return true;\n}\n","import type { FeatureEntry, FeatureTrigger, TriggerContext } from \"./types\";\n\nfunction wildcardToRegExp(value: string): RegExp {\n const escaped = value.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = `^${escaped.replace(/\\*/g, \".*\")}$`;\n return new RegExp(pattern);\n}\n\nfunction matchPath(path: string, pattern: string | RegExp): boolean {\n if (pattern instanceof RegExp) return pattern.test(path);\n if (!pattern) return false;\n if (pattern.includes(\"*\")) return wildcardToRegExp(pattern).test(path);\n return path === pattern || path.startsWith(pattern);\n}\n\nexport function isTriggerMatch(trigger: FeatureTrigger | undefined, context?: TriggerContext): boolean {\n if (!trigger) return true;\n if (!context) return false;\n\n if (trigger.type === \"page\") {\n const path = context.path;\n if (!path) return false;\n return matchPath(path, trigger.match);\n }\n\n if (trigger.type === \"usage\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.event] ?? 0;\n return count >= (trigger.minActions ?? 1);\n }\n\n if (trigger.type === \"time\") {\n const elapsedMs = context.elapsedMs ?? 0;\n return elapsedMs >= trigger.minSeconds * 1000;\n }\n\n if (trigger.type === \"milestone\") {\n return context.milestones?.has(trigger.event) ?? false;\n }\n\n if (trigger.type === \"frustration\") {\n const usage = context.usage ?? {};\n const count = usage[trigger.pattern] ?? 0;\n return count >= (trigger.threshold ?? 1);\n }\n\n if (trigger.type === \"scroll\") {\n return (context.scrollPercent ?? 0) >= (trigger.minPercent ?? 50);\n }\n\n try {\n return trigger.evaluate(context);\n } catch {\n return false;\n }\n}\n\nexport class TriggerEngine {\n private context: TriggerContext;\n\n constructor(initial?: TriggerContext) {\n this.context = {\n path: initial?.path,\n events: new Set(initial?.events ?? []),\n milestones: new Set(initial?.milestones ?? []),\n usage: { ...(initial?.usage ?? {}) },\n elapsedMs: initial?.elapsedMs ?? 0,\n scrollPercent: initial?.scrollPercent ?? 0,\n metadata: { ...(initial?.metadata ?? {}) },\n };\n }\n\n setPath(path: string): void {\n this.context.path = path;\n }\n\n trackEvent(event: string): void {\n const next = new Set(this.context.events ?? new Set<string>());\n next.add(event);\n this.context.events = next;\n }\n\n trackUsage(event: string, delta = 1): void {\n const usage = { ...(this.context.usage ?? {}) };\n usage[event] = (usage[event] ?? 0) + Math.max(1, delta);\n this.context.usage = usage;\n }\n\n trackMilestone(event: string): void {\n const next = new Set(this.context.milestones ?? new Set<string>());\n next.add(event);\n this.context.milestones = next;\n }\n\n setElapsedMs(elapsedMs: number): void {\n this.context.elapsedMs = Math.max(0, elapsedMs);\n }\n\n setScrollPercent(scrollPercent: number): void {\n const clamped = Math.max(0, Math.min(100, scrollPercent));\n this.context.scrollPercent = clamped;\n }\n\n setMetadata(next: Record<string, unknown>): void {\n this.context.metadata = { ...next };\n }\n\n getContext(): TriggerContext {\n return {\n path: this.context.path,\n events: new Set(this.context.events ?? []),\n milestones: new Set(this.context.milestones ?? []),\n usage: { ...(this.context.usage ?? {}) },\n elapsedMs: this.context.elapsedMs,\n scrollPercent: this.context.scrollPercent,\n metadata: { ...(this.context.metadata ?? {}) },\n };\n }\n\n evaluate(trigger: FeatureTrigger | undefined): boolean {\n return isTriggerMatch(trigger, this.context);\n }\n\n evaluateFeature(feature: Pick<FeatureEntry, \"trigger\">): boolean {\n return this.evaluate(feature.trigger);\n }\n}\n","import type {\n AudienceMatchFn,\n AudienceRule,\n FeatureEntry,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n FeatureDependencyState,\n FeatureFlagBridge,\n TriggerContext,\n} from \"./types\";\nimport { compareSemver, satisfiesRange } from \"./semver\";\nimport { isTriggerMatch } from \"./triggers\";\n\n/**\n * Default audience matching logic.\n *\n * For each specified field (plan, role, region), checks if the user's\n * value is included in the allowed list. Fields use AND logic between them,\n * OR logic within each field's array. The `custom` field is ignored by\n * the default matcher — use a custom `AudienceMatchFn` for that.\n */\nexport function matchesAudience(\n audience: AudienceRule,\n userContext: UserContext,\n): boolean {\n if (audience.plan && audience.plan.length > 0) {\n if (!userContext.plan || !audience.plan.includes(userContext.plan)) {\n return false;\n }\n }\n if (audience.role && audience.role.length > 0) {\n if (!userContext.role || !audience.role.includes(userContext.role)) {\n return false;\n }\n }\n if (audience.region && audience.region.length > 0) {\n if (!userContext.region || !audience.region.includes(userContext.region)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Check if a feature's audience allows the given user context.\n *\n * - No `audience` field → visible to all\n * - Empty `audience` ({}) → visible to all\n * - `audience` specified but no `userContext` → hidden (safe default)\n * - Otherwise, delegate to `matchFn` (or default `matchesAudience`)\n */\nfunction isAudienceMatch(\n feature: FeatureEntry,\n userContext?: UserContext,\n matchFn?: AudienceMatchFn,\n): boolean {\n // No audience restriction → show to everyone\n if (!feature.audience) return true;\n\n // Check if audience is empty (no fields with values)\n const { plan, role, region, custom } = feature.audience;\n const hasRules =\n (plan && plan.length > 0) ||\n (role && role.length > 0) ||\n (region && region.length > 0) ||\n (custom && Object.keys(custom).length > 0);\n if (!hasRules) return true;\n\n // Audience specified but no user context → hidden (safe default)\n if (!userContext) return false;\n\n // Use custom matcher if provided, otherwise default\n if (matchFn) return matchFn(feature.audience, userContext);\n return matchesAudience(feature.audience, userContext);\n}\n\nfunction isVersionMatch(feature: FeatureEntry, appVersion?: string): boolean {\n const v = feature.version;\n if (!v || typeof v === \"string\") return true; // string = display only\n if (!appVersion) return false; // Safe default when constraints exist\n if (!v.introduced && !v.showNewUntil && !v.deprecatedAt && !v.showIn) return true;\n\n // Range check\n if (v.showIn && !satisfiesRange(appVersion, v.showIn)) return false;\n\n if (v.introduced && compareSemver(appVersion, v.introduced) < 0) return false;\n if (v.deprecatedAt && compareSemver(appVersion, v.deprecatedAt) >= 0) return false;\n\n // showNewUntil gates \"new\" state only\n if (v.showNewUntil && compareSemver(appVersion, v.showNewUntil) >= 0) return false;\n\n return true;\n}\n\nfunction isFlagMatch(\n feature: FeatureEntry,\n flagBridge?: FeatureFlagBridge,\n userContext?: UserContext,\n): boolean {\n if (!feature.flagKey) return true;\n if (!flagBridge) return false;\n try {\n return flagBridge.isEnabled(feature.flagKey, userContext);\n } catch {\n return false;\n }\n}\n\nfunction isProductMatch(feature: FeatureEntry, product?: string): boolean {\n if (!feature.product || feature.product === \"*\") return true;\n if (!product) return false;\n return feature.product === product;\n}\n\nfunction isDependencyMatch(\n feature: FeatureEntry,\n dismissedIds: ReadonlySet<string>,\n dependencyState?: FeatureDependencyState,\n): boolean {\n const dependsOn = feature.dependsOn;\n if (!dependsOn) return true;\n\n const seenIds = dependencyState?.seenIds;\n const clickedIds = dependencyState?.clickedIds;\n const dismissedDependencyIds = dependencyState?.dismissedIds ?? dismissedIds;\n\n if (dependsOn.seen && dependsOn.seen.length > 0) {\n for (const id of dependsOn.seen) {\n const seen = seenIds?.has(id) ?? false;\n if (!seen && !dismissedDependencyIds.has(id)) return false;\n }\n }\n\n if (dependsOn.clicked && dependsOn.clicked.length > 0) {\n for (const id of dependsOn.clicked) {\n if (!(clickedIds?.has(id) ?? false)) return false;\n }\n }\n\n if (dependsOn.dismissed && dependsOn.dismissed.length > 0) {\n for (const id of dependsOn.dismissed) {\n if (!dismissedDependencyIds.has(id)) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if a single feature should show as \"new\".\n *\n * A feature is \"new\" when ALL of these are true:\n * 1. Current time is before `showNewUntil`\n * 2. Feature was released after the watermark (or no watermark exists)\n * 3. Feature has not been individually dismissed\n * 4. If `publishAt` is set, current time must be after it (scheduled publishing)\n * 5. If `audience` is set, user must match the targeting rules\n * 6. If `flagKey` is set, the flag bridge must resolve it as enabled\n * 7. If `product` is set, it must match the current product scope\n */\nexport function isNew(\n feature: FeatureEntry,\n watermark: string | null,\n dismissedIds: ReadonlySet<string>,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): boolean {\n // Already dismissed by the user on this device\n if (dismissedIds.has(feature.id)) return false;\n\n // Audience targeting — check before time-based checks\n if (!isAudienceMatch(feature, userContext, matchAudience)) return false;\n\n // Dependency targeting — defer features until prerequisites are satisfied\n if (!isDependencyMatch(feature, dismissedIds, dependencyState)) return false;\n\n // Version targeting — requires appVersion when constraints exist\n if (!isVersionMatch(feature, appVersion)) return false;\n\n // Feature flag targeting — hide flagged entries unless enabled\n if (!isFlagMatch(feature, flagBridge, userContext)) return false;\n\n // Multi-product targeting — hide entries for other product scopes\n if (!isProductMatch(feature, product)) return false;\n\n // Contextual trigger rules — show only when trigger condition is satisfied.\n if (!isTriggerMatch(feature.trigger, triggerContext)) return false;\n\n const nowMs = now.getTime();\n\n // Scheduled publishing — hidden until publishAt\n if (feature.publishAt) {\n const publishMs = new Date(feature.publishAt).getTime();\n if (nowMs < publishMs) return false;\n }\n\n const showUntilMs = new Date(feature.showNewUntil).getTime();\n\n // Past the display window\n if (nowMs >= showUntilMs) return false;\n\n // If there's a watermark, feature must have been released after it\n if (watermark) {\n const watermarkMs = new Date(watermark).getTime();\n const releasedMs = new Date(feature.releasedAt).getTime();\n if (releasedMs <= watermarkMs) return false;\n }\n\n return true;\n}\n\n/**\n * Get all features that are currently \"new\" for this user.\n */\nexport function getNewFeatures(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): FeatureEntry[] {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.filter((f) =>\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ),\n );\n}\n\n/**\n * Get the count of new features.\n */\nexport function getNewFeatureCount(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): number {\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ).length;\n}\n\n/**\n * Check if a specific sidebar key has a new feature.\n */\nexport function hasNewFeature(\n manifest: FeatureManifest,\n sidebarKey: string,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): boolean {\n const watermark = storage.getWatermark();\n const dismissedIds = storage.getDismissedIds();\n return manifest.some(\n (f) =>\n f.sidebarKey === sidebarKey &&\n isNew(\n f,\n watermark,\n dismissedIds,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ),\n );\n}\n\n/**\n * Get all features sorted by priority (critical first) then by release date (newest first).\n */\nexport function getNewFeaturesSorted(\n manifest: FeatureManifest,\n storage: StorageAdapter,\n now: Date = new Date(),\n userContext?: UserContext,\n matchAudience?: AudienceMatchFn,\n appVersion?: string,\n dependencyState?: FeatureDependencyState,\n triggerContext?: TriggerContext,\n flagBridge?: FeatureFlagBridge,\n product?: string,\n): FeatureEntry[] {\n const priorityOrder = { critical: 0, normal: 1, low: 2 };\n return getNewFeatures(\n manifest,\n storage,\n now,\n userContext,\n matchAudience,\n appVersion,\n dependencyState,\n triggerContext,\n flagBridge,\n product,\n ).sort(\n (a, b) => {\n const pa = priorityOrder[a.priority ?? \"normal\"];\n const pb = priorityOrder[b.priority ?? \"normal\"];\n if (pa !== pb) return pa - pb;\n return (\n new Date(b.releasedAt).getTime() - new Date(a.releasedAt).getTime()\n );\n },\n );\n}\n","import type { StorageAdapter } from \"../types\";\n\nexport interface LocalStorageAdapterOptions {\n /** Key prefix for localStorage entries. Default: \"featuredrop\" */\n prefix?: string;\n /** Server-side watermark (ISO string). Typically from user profile. */\n watermark?: string | null;\n /** Callback when dismissAll is called. Use for server-side watermark updates. */\n onDismissAll?: (now: Date) => Promise<void>;\n}\n\nconst DISMISSED_SUFFIX = \":dismissed\";\n\n/**\n * localStorage-based storage adapter.\n *\n * Architecture:\n * - **Watermark** comes from the server (passed at construction time)\n * - **Per-feature dismissals** are stored in localStorage (zero server writes)\n * - **dismissAll()** optionally calls a server callback, then clears localStorage\n *\n * Gracefully handles SSR environments where `window`/`localStorage` is unavailable.\n */\nexport class LocalStorageAdapter implements StorageAdapter {\n private readonly prefix: string;\n private readonly watermarkValue: string | null;\n private readonly onDismissAllCallback?: (now: Date) => Promise<void>;\n private readonly dismissedKey: string;\n\n constructor(options: LocalStorageAdapterOptions = {}) {\n this.prefix = options.prefix ?? \"featuredrop\";\n this.watermarkValue = options.watermark ?? null;\n this.onDismissAllCallback = options.onDismissAll;\n this.dismissedKey = `${this.prefix}${DISMISSED_SUFFIX}`;\n }\n\n getWatermark(): string | null {\n return this.watermarkValue;\n }\n\n getDismissedIds(): ReadonlySet<string> {\n try {\n if (typeof window === \"undefined\") return new Set();\n const raw = localStorage.getItem(this.dismissedKey);\n if (!raw) return new Set();\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) return new Set(parsed as string[]);\n return new Set();\n } catch {\n return new Set();\n }\n }\n\n dismiss(id: string): void {\n try {\n if (typeof window === \"undefined\") return;\n const raw = localStorage.getItem(this.dismissedKey);\n const existing: string[] = raw ? (JSON.parse(raw) as string[]) : [];\n if (!existing.includes(id)) {\n existing.push(id);\n localStorage.setItem(this.dismissedKey, JSON.stringify(existing));\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n }\n\n async dismissAll(now: Date): Promise<void> {\n try {\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(this.dismissedKey);\n }\n } catch {\n // localStorage unavailable — silent fail\n }\n\n if (this.onDismissAllCallback) {\n await this.onDismissAllCallback(now);\n }\n }\n}\n","import { getNewFeaturesSorted, hasNewFeature } from \"../core\";\nimport { LocalStorageAdapter } from \"../adapters\";\nimport type {\n AudienceMatchFn,\n FeatureManifest,\n StorageAdapter,\n UserContext,\n} from \"../types\";\n\nconst SafeHTMLElement: typeof HTMLElement = typeof HTMLElement === \"undefined\"\n ? (class {} as unknown as typeof HTMLElement)\n : HTMLElement;\n\nexport interface WebComponentsConfig {\n manifest: FeatureManifest;\n storage?: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nexport interface RegisterWebComponentsOptions {\n badgeTag?: string;\n changelogTag?: string;\n}\n\ninterface RuntimeConfig {\n manifest: FeatureManifest;\n storage: StorageAdapter;\n userContext?: UserContext;\n matchAudience?: AudienceMatchFn;\n appVersion?: string;\n}\n\nlet runtimeConfig: RuntimeConfig | null = null;\nlet defaultStorage: StorageAdapter | null = null;\nconst badgeInstances = new Set<FeatureDropBadgeElement>();\nconst changelogInstances = new Set<FeatureDropChangelogElement>();\n\nfunction getDefaultStorage(): StorageAdapter {\n if (!defaultStorage) {\n defaultStorage = new LocalStorageAdapter({ prefix: \"featuredrop:web-components\" });\n }\n return defaultStorage;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n}\n\nfunction getRuntimeConfig(): RuntimeConfig | null {\n return runtimeConfig;\n}\n\nfunction renderAllComponents(): void {\n for (const badge of badgeInstances) badge.render();\n for (const changelog of changelogInstances) changelog.render();\n}\n\nexport function configureFeatureDropWebComponents(config: WebComponentsConfig): void {\n runtimeConfig = {\n manifest: config.manifest,\n storage: config.storage ?? getDefaultStorage(),\n userContext: config.userContext,\n matchAudience: config.matchAudience,\n appVersion: config.appVersion,\n };\n renderAllComponents();\n}\n\nexport function refreshFeatureDropWebComponents(): void {\n renderAllComponents();\n}\n\nexport class FeatureDropBadgeElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"sidebar-key\", \"variant\"];\n }\n\n connectedCallback(): void {\n badgeInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n this.render();\n }\n\n disconnectedCallback(): void {\n badgeInstances.delete(this);\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const sidebarKey = this.getAttribute(\"sidebar-key\");\n const variant = this.getAttribute(\"variant\") ?? \"pill\";\n const config = getRuntimeConfig();\n if (!sidebarKey || !config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const isNew = hasNewFeature(\n config.manifest,\n sidebarKey,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n if (!isNew) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const count = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n ).filter((entry) => entry.sidebarKey === sidebarKey).length;\n\n const content = variant === \"dot\"\n ? `<span class=\"dot\" part=\"dot\"></span>`\n : variant === \"count\"\n ? `<span class=\"count\" part=\"count\">${count}</span>`\n : `<span class=\"pill\" part=\"pill\">New</span>`;\n\n this.shadowRoot.innerHTML = `\n <style>\n .pill { display: inline-block; border-radius: 999px; padding: 2px 8px; font-size: 12px; font-weight: 600; background: #f59e0b; color: #fff; }\n .count { display: inline-grid; place-items: center; min-width: 18px; height: 18px; border-radius: 999px; font-size: 11px; font-weight: 700; background: #dc2626; color: #fff; padding: 0 6px; }\n .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #f59e0b; }\n </style>\n ${content}\n `;\n }\n}\n\nexport class FeatureDropChangelogElement extends SafeHTMLElement {\n static get observedAttributes(): string[] {\n return [\"title\", \"trigger-label\", \"position\"];\n }\n\n private isOpen = false;\n private cleanupClick: (() => void) | null = null;\n\n connectedCallback(): void {\n changelogInstances.add(this);\n if (!this.shadowRoot && \"attachShadow\" in this) {\n this.attachShadow({ mode: \"open\" });\n }\n const onClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n const actionTarget = target.closest(\"[data-action]\") as HTMLElement | null;\n if (!actionTarget) return;\n const action = actionTarget.getAttribute(\"data-action\");\n if (action === \"toggle\") {\n this.isOpen = !this.isOpen;\n this.render();\n return;\n }\n if (action === \"dismiss-all\") {\n void this.dismissAll();\n return;\n }\n if (action === \"dismiss-one\") {\n const id = actionTarget.getAttribute(\"data-id\");\n if (id) this.dismissOne(id);\n }\n };\n this.shadowRoot?.addEventListener(\"click\", onClick);\n this.cleanupClick = () => this.shadowRoot?.removeEventListener(\"click\", onClick);\n this.render();\n }\n\n disconnectedCallback(): void {\n changelogInstances.delete(this);\n this.cleanupClick?.();\n this.cleanupClick = null;\n }\n\n attributeChangedCallback(): void {\n this.render();\n }\n\n private dismissOne(id: string): void {\n const config = getRuntimeConfig();\n if (!config) return;\n config.storage.dismiss(id);\n renderAllComponents();\n }\n\n private async dismissAll(): Promise<void> {\n const config = getRuntimeConfig();\n if (!config) return;\n await config.storage.dismissAll(new Date());\n renderAllComponents();\n }\n\n render(): void {\n if (!this.shadowRoot) return;\n const config = getRuntimeConfig();\n if (!config) {\n this.shadowRoot.innerHTML = \"\";\n return;\n }\n\n const title = this.getAttribute(\"title\") ?? \"What's New\";\n const triggerLabel = this.getAttribute(\"trigger-label\") ?? \"What's New\";\n const position = this.getAttribute(\"position\") === \"left\" ? \"left: 16px;\" : \"right: 16px;\";\n const entries = getNewFeaturesSorted(\n config.manifest,\n config.storage,\n new Date(),\n config.userContext,\n config.matchAudience,\n config.appVersion,\n );\n\n const list = entries.length === 0\n ? `<p class=\"empty\">You're all caught up.</p>`\n : entries\n .map((entry) => `\n <li class=\"item\">\n <div class=\"item-title\">${escapeHtml(entry.label)}</div>\n ${entry.description ? `<p class=\"item-desc\">${escapeHtml(entry.description)}</p>` : \"\"}\n <button data-action=\"dismiss-one\" data-id=\"${escapeHtml(entry.id)}\" class=\"ghost\">Mark read</button>\n </li>\n `)\n .join(\"\");\n\n this.shadowRoot.innerHTML = `\n <style>\n .trigger { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 8px 12px; cursor: pointer; font-weight: 600; font-size: 13px; }\n .panel { position: fixed; top: 70px; ${position} width: min(92vw, 360px); max-height: 70vh; overflow: auto; border: 1px solid #e5e7eb; border-radius: 12px; background: #fff; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.16); z-index: 10000; }\n .header { display: flex; align-items: center; justify-content: space-between; padding: 12px; border-bottom: 1px solid #e5e7eb; }\n .title { margin: 0; font-size: 14px; }\n .list { list-style: none; margin: 0; padding: 10px 12px 12px; display: grid; gap: 10px; }\n .item { border: 1px solid #e5e7eb; border-radius: 10px; padding: 10px; }\n .item-title { font-size: 13px; font-weight: 700; margin-bottom: 4px; }\n .item-desc { margin: 0 0 8px; color: #4b5563; font-size: 12px; }\n .empty { margin: 0; padding: 14px 12px; color: #6b7280; font-size: 13px; }\n .ghost { border: 1px solid #d1d5db; background: #fff; border-radius: 8px; padding: 5px 8px; cursor: pointer; font-size: 12px; }\n </style>\n <button data-action=\"toggle\" class=\"trigger\">${escapeHtml(triggerLabel)} (${entries.length})</button>\n ${this.isOpen ? `\n <section class=\"panel\">\n <div class=\"header\">\n <h3 class=\"title\">${escapeHtml(title)}</h3>\n <button data-action=\"dismiss-all\" class=\"ghost\">Mark all read</button>\n </div>\n <ul class=\"list\">${list}</ul>\n </section>\n ` : \"\"}\n `;\n }\n}\n\nexport function registerFeatureDropWebComponents(\n options: RegisterWebComponentsOptions = {},\n): { badgeTag: string; changelogTag: string } {\n const badgeTag = options.badgeTag ?? \"feature-drop-badge\";\n const changelogTag = options.changelogTag ?? \"feature-drop-changelog\";\n\n if (typeof customElements === \"undefined\") {\n return { badgeTag, changelogTag };\n }\n\n if (!customElements.get(badgeTag)) {\n customElements.define(badgeTag, FeatureDropBadgeElement);\n }\n if (!customElements.get(changelogTag)) {\n customElements.define(changelogTag, FeatureDropChangelogElement);\n }\n\n return { badgeTag, changelogTag };\n}\n"]}