@at-flux/astro-feature-flags 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/badge-layout.ts","../src/inline-script.ts","../src/dev-inline-runtimes.ts","../src/dev-outline-css.ts","../src/production-html-cull.ts","../src/dev-head-inject.ts","../src/route-prefix-js.ts","../src/index.ts"],"sourcesContent":["export type ElementBadgeVerticalAnchor = \"top\" | \"bottom\";\n\n/** Horizontal placement of the element pill: `end` = top-right (LTR), `start` = top-left, `center` = centred. */\nexport type ElementBadgeHorizontalAlign = \"start\" | \"center\" | \"end\";\n\n/** Subset of dev CSS options used for element-badge geometry (also on `DevOutlineCssOptions`). */\nexport interface ElementBadgeLayoutOptions {\n /**\n * Horizontal alignment along the element’s top or bottom edge. Default `end` (top-right in LTR).\n * Ignored when `elementBadgeHorizontalPercent` is set.\n */\n elementBadgeHorizontalAlign?: ElementBadgeHorizontalAlign;\n /**\n * Optional: anchor at a percentage along the element width (0–100), with the pill centred on that point (`translateX(-50%)`).\n * When set, overrides `elementBadgeHorizontalAlign`.\n */\n elementBadgeHorizontalPercent?: number;\n /**\n * Vertical shift as a percentage of the **badge’s own height** (CSS transform %).\n * With anchor `top`, moves the badge upward. Default `80` (~20% of the pill overlaps the element top edge).\n */\n elementBadgeVerticalShiftPercent?: number;\n /** Anchor the badge to the top or bottom edge of the element. Default `top`. */\n elementBadgeVerticalAnchor?: ElementBadgeVerticalAnchor;\n}\n\nexport type NormalizedElementBadgeLayout =\n | {\n mode: \"align\";\n horizontalAlign: ElementBadgeHorizontalAlign;\n verticalShiftPercent: number;\n verticalAnchor: ElementBadgeVerticalAnchor;\n }\n | {\n mode: \"percent\";\n horizontalPercent: number;\n verticalShiftPercent: number;\n verticalAnchor: ElementBadgeVerticalAnchor;\n };\n\nfunction clampPercent(n: number, fallback: number): number {\n if (typeof n !== \"number\" || Number.isNaN(n)) return fallback;\n return Math.min(100, Math.max(0, n));\n}\n\nexport function normalizeElementBadgeLayout(\n input: ElementBadgeLayoutOptions | undefined,\n): NormalizedElementBadgeLayout {\n const v = clampPercent(input?.elementBadgeVerticalShiftPercent ?? 80, 80);\n const anchor =\n input?.elementBadgeVerticalAnchor === \"bottom\" ? \"bottom\" : \"top\";\n const hp = input?.elementBadgeHorizontalPercent;\n if (hp !== undefined && hp !== null && typeof hp === \"number\") {\n return {\n mode: \"percent\",\n horizontalPercent: clampPercent(hp, 50),\n verticalShiftPercent: v,\n verticalAnchor: anchor,\n };\n }\n const align: ElementBadgeHorizontalAlign =\n input?.elementBadgeHorizontalAlign === \"start\" ||\n input?.elementBadgeHorizontalAlign === \"center\"\n ? input.elementBadgeHorizontalAlign\n : \"end\";\n return {\n mode: \"align\",\n horizontalAlign: align,\n verticalShiftPercent: v,\n verticalAnchor: anchor,\n };\n}\n\nconst INSET = \"0.35rem\";\n\n/**\n * `left` / `right` / `top` | `bottom` / `transform` for the element `::before` badge (no trailing newline).\n */\nexport function elementBadgePositionBlock(\n layout: NormalizedElementBadgeLayout,\n): string {\n const { verticalShiftPercent: v, verticalAnchor } = layout;\n const y =\n verticalAnchor === \"top\"\n ? `translateY(calc(-1 * ${v}%))`\n : `translateY(${v}%)`;\n\n if (layout.mode === \"percent\") {\n const h = layout.horizontalPercent;\n if (verticalAnchor === \"top\") {\n return ` left: ${h}%;\n right: auto;\n top: 0;\n bottom: auto;\n transform: translateX(-50%) ${y};`;\n }\n return ` left: ${h}%;\n right: auto;\n bottom: 0;\n top: auto;\n transform: translateX(-50%) ${y};`;\n }\n\n const { horizontalAlign } = layout;\n if (horizontalAlign === \"center\") {\n if (verticalAnchor === \"top\") {\n return ` left: 50%;\n right: auto;\n top: 0;\n bottom: auto;\n transform: translateX(-50%) ${y};`;\n }\n return ` left: 50%;\n right: auto;\n bottom: 0;\n top: auto;\n transform: translateX(-50%) ${y};`;\n }\n if (horizontalAlign === \"start\") {\n if (verticalAnchor === \"top\") {\n return ` left: ${INSET};\n right: auto;\n top: 0;\n bottom: auto;\n transform: ${y};`;\n }\n return ` left: ${INSET};\n right: auto;\n bottom: 0;\n top: auto;\n transform: ${y};`;\n }\n /* end — top-right / bottom-right */\n if (verticalAnchor === \"top\") {\n return ` left: auto;\n right: ${INSET};\n top: 0;\n bottom: auto;\n transform: ${y};`;\n }\n return ` left: auto;\n right: ${INSET};\n bottom: 0;\n top: auto;\n transform: ${y};`;\n}\n","export function compactInlineScript(source: string): string {\n const lines = source\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line, idx, arr) => line.length > 0 || (idx > 0 && idx < arr.length - 1));\n return lines.join(\"\\n\").trim();\n}\n\nexport function inlineInvoke<Payload>(\n fn: (payload: Payload) => void,\n payload: Payload,\n): string {\n return compactInlineScript(`(${fn.toString()})(${JSON.stringify(payload)});`);\n}\n","type HeadInlinePayload = {\n featureFlagStyles: string;\n routeFlags: Record<string, string[]>;\n flagNameToToken: Record<string, string>;\n};\n\ntype BootstrapPayload = {\n flagTokens: string[];\n colors: Record<string, string>;\n outlineDefaults: Record<string, boolean>;\n badgeDefaults: Record<string, boolean>;\n routeFlags: Record<string, string[]>;\n flagNameToToken: Record<string, string>;\n namespace: string;\n};\n\nexport function affHeadInlineRuntime(payload: HeadInlinePayload): void {\n const toPrefix = (pattern: string): string => {\n let p = String(pattern || \"\").trim();\n if (p.endsWith(\"/**\")) p = p.slice(0, -3);\n else if (p.endsWith(\"/*\")) p = p.slice(0, -2);\n else if (p.length > 1 && p.endsWith(\"*\")) p = p.slice(0, -1);\n return p.endsWith(\"/\") ? p : `${p}/`;\n };\n try {\n const { featureFlagStyles, routeFlags: RF, flagNameToToken: M } = payload;\n const s = document.createElement(\"style\");\n s.setAttribute(\"data-astro-feature-flags\", \"\");\n s.textContent = featureFlagStyles;\n (document.head || document.documentElement).appendChild(s);\n\n const affPath = () => {\n let p = typeof location !== \"undefined\" && location.pathname ? location.pathname : \"/\";\n if (!p.endsWith(\"/\")) p += \"/\";\n return p;\n };\n\n const affFlagNames = (pathname: string) => {\n let p = pathname || \"/\";\n if (!p.endsWith(\"/\")) p += \"/\";\n const out: string[] = [];\n const seen = new Set<string>();\n for (const rp in RF) {\n if (!Object.prototype.hasOwnProperty.call(RF, rp)) continue;\n const route = toPrefix(rp);\n if (!(p === route || p.indexOf(route) === 0)) continue;\n const fns = RF[rp] || [];\n for (let i = 0; i < fns.length; i++) {\n const fn = fns[i];\n if (fn && !seen.has(fn)) {\n seen.add(fn);\n out.push(fn);\n }\n }\n }\n return out;\n };\n\n const affTokens = (pathname: string) =>\n affFlagNames(pathname)\n .map((name) => M[name])\n .filter(Boolean);\n\n const affSyncDisabledOverlay = () => {\n const root = document.documentElement;\n if (!document.body) return;\n const names = affFlagNames(affPath());\n const disabled: string[] = [];\n for (let i = 0; i < names.length; i++) {\n const tk = M[names[i]];\n if (!tk) continue;\n if (root.getAttribute(`data-ff-enabled-${tk}`) === \"off\") disabled.push(tk);\n }\n const id = \"aff-route-disabled-overlay\";\n let el = document.getElementById(id);\n if (!disabled.length) {\n if (el) el.remove();\n root.removeAttribute(\"data-aff-route-disabled\");\n return;\n }\n root.setAttribute(\"data-aff-route-disabled\", \"\");\n if (!el) {\n el = document.createElement(\"div\");\n el.id = id;\n el.className = \"aff-route-disabled-overlay\";\n const p = document.createElement(\"p\");\n el.appendChild(p);\n document.body.appendChild(el);\n }\n const pEl = el.querySelector(\"p\") || el;\n const flagsText = disabled.join(\", \");\n const line1 =\n disabled.length === 1\n ? `Page disabled: ${flagsText} flag is disabled.`\n : `Page disabled: ${flagsText} flags are disabled.`;\n const line2 =\n \"In production builds, pages with disabled flags like this will not be emitted\";\n pEl.textContent = `${line1}\\n${line2}`;\n };\n\n const affApply = () => {\n document.documentElement.setAttribute(\"data-ff-route\", affTokens(affPath()).join(\" \"));\n affSyncDisabledOverlay();\n };\n\n affApply();\n if (typeof MutationObserver === \"function\") {\n const obs = new MutationObserver((muts) => {\n for (let i = 0; i < muts.length; i++) {\n const a = muts[i] && muts[i].attributeName;\n if (a === \"data-ff-route\" || (a && a.indexOf(\"data-ff-enabled-\") === 0)) {\n affSyncDisabledOverlay();\n break;\n }\n }\n });\n obs.observe(document.documentElement, { attributes: true });\n }\n document.addEventListener(\"astro:page-load\", affApply);\n document.addEventListener(\"astro:after-swap\", affApply);\n } catch {\n // no-op in injected runtime\n }\n}\n\nexport function affDevBootstrapRuntime(payload: BootstrapPayload): void {\n const toPrefix = (pattern: string): string => {\n let p = String(pattern || \"\").trim();\n if (p.endsWith(\"/**\")) p = p.slice(0, -3);\n else if (p.endsWith(\"/*\")) p = p.slice(0, -2);\n else if (p.length > 1 && p.endsWith(\"*\")) p = p.slice(0, -1);\n return p.endsWith(\"/\") ? p : `${p}/`;\n };\n const T = payload.flagTokens;\n const C = payload.colors;\n const OD = payload.outlineDefaults;\n const BD = payload.badgeDefaults;\n const RF = payload.routeFlags;\n const F2T = payload.flagNameToToken;\n const N = payload.namespace;\n const K = `${N}.dev.v1`;\n\n const root = document.documentElement;\n const isEnabled = (tk: string) => root.getAttribute(`data-ff-enabled-${tk}`) !== \"off\";\n const currentTokenColor = (\n tk: string,\n cols: Record<string, string>,\n ): string => {\n const cssVar = root.style.getPropertyValue(`--${N}-c-${tk}`).trim();\n return cssVar || cols[tk] || C[tk] || \"#94a3b8\";\n };\n const unique = (a: string[]) => [...new Set(a.filter(Boolean))];\n\n const comboTokens = (el: Element): string[] => {\n let out: string[] = [];\n const raw = (el.getAttribute(`data-${N}`) || \"\").trim();\n if (raw) out = out.concat(raw.split(/\\s+/).filter(Boolean));\n for (let i = 0; i < T.length; i++) {\n const tk = T[i];\n if (el.hasAttribute(`data-${N}-${tk}`)) out.push(tk);\n }\n return unique(out);\n };\n\n const stripBooleanFlagAttrs = (el: Element) => {\n for (let i = 0; i < T.length; i++) {\n el.removeAttribute(`data-${N}-${T[i]}`);\n }\n };\n const clearComboVisualState = (el: HTMLElement) => {\n el.removeAttribute(\"data-ff-label\");\n el.style.removeProperty(\"--ff-combo-gradient\");\n el.style.removeProperty(\"--ff-combo-gradient-soft\");\n el.style.removeProperty(\"--ff-combo-outline\");\n el.style.removeProperty(\"--ff-combo-text\");\n el.style.removeProperty(\"--ff-combo-badge-border\");\n el.style.removeProperty(\"--ff-combo-badge-gradient\");\n };\n\n const applyCombo = (el: HTMLElement, cols: Record<string, string>) => {\n const allTokens = comboTokens(el);\n const hasCombo = allTokens.length >= 2;\n const hasDisabledInCombo = hasCombo && allTokens.some((tk) => !isEnabled(tk));\n const visual = allTokens.filter((tk) => isEnabled(tk));\n if (hasDisabledInCombo) {\n // Fail-closed for combos: if any member token is disabled, hide the whole element.\n // Keep all combo tokens mirrored in data-<ns> so enabled-off CSS selectors can hide it.\n stripBooleanFlagAttrs(el);\n el.setAttribute(`data-${N}`, allTokens.join(\" \"));\n clearComboVisualState(el);\n return;\n }\n if (visual.length < 2) {\n clearComboVisualState(el);\n if (hasCombo) {\n // Only normalize attrs for true combos. Single-flag shorthand markers\n // (e.g. data-ff-wip) must stay intact so re-enabling can recover styling.\n stripBooleanFlagAttrs(el);\n if (visual.length === 1) {\n el.setAttribute(`data-${N}`, visual[0]!);\n } else {\n el.removeAttribute(`data-${N}`);\n }\n }\n return;\n }\n stripBooleanFlagAttrs(el);\n // Mirror all enabled tokens into the primary namespace attribute so `[data-<ns>*=\" \"]`\n // matches (required for boolean-only combos like data-ff-a + data-ff-b).\n el.setAttribute(`data-${N}`, visual.join(\" \"));\n el.setAttribute(\"data-ff-label\", visual.join(\" | \"));\n const strong = visual.map((tk) => currentTokenColor(tk, cols));\n const soft = strong.map((c) => `color-mix(in oklab, white 86%, ${c} 14%)`);\n el.style.setProperty(\"--ff-combo-gradient\", `linear-gradient(90deg, ${strong.join(\", \")})`);\n el.style.setProperty(\"--ff-combo-gradient-soft\", `linear-gradient(90deg, ${soft.join(\", \")})`);\n el.style.setProperty(\"--ff-combo-outline\", strong[0] || \"#64748b\");\n el.style.setProperty(\"--ff-combo-text\", strong[0] || \"#111827\");\n el.style.setProperty(\n \"--ff-combo-badge-border\",\n `color-mix(in oklab, ${strong[0] || \"#64748b\"} 35%, transparent)`,\n );\n el.style.setProperty(\"--ff-combo-badge-gradient\", `linear-gradient(90deg, ${soft.join(\", \")})`);\n };\n\n const routeTokensForPath = (path: string): string[] => {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const rp in RF) {\n if (!Object.prototype.hasOwnProperty.call(RF, rp)) continue;\n const cnd = toPrefix(rp);\n if (!(path === cnd || path.indexOf(cnd) === 0)) continue;\n const fns = RF[rp] || [];\n for (let i = 0; i < fns.length; i++) {\n const tk = F2T[fns[i]];\n if (tk && !seen.has(tk)) {\n seen.add(tk);\n out.push(tk);\n }\n }\n }\n return out;\n };\n\n const routeLabelFor = (path: string, toks: string[]): string => {\n if (!toks.length) return \"\";\n const byFlag: Record<string, string[]> = {};\n for (const rp in RF) {\n if (!Object.prototype.hasOwnProperty.call(RF, rp)) continue;\n const cnd = toPrefix(rp);\n if (!(path === cnd || path.indexOf(cnd) === 0)) continue;\n const fns = RF[rp] || [];\n for (let i = 0; i < fns.length; i++) {\n const tk = F2T[fns[i]];\n if (!tk) continue;\n if (!byFlag[tk]) byFlag[tk] = [];\n byFlag[tk].push(rp);\n }\n }\n return `Page: ${toks\n .map((tk) => `${tk} - ${(byFlag[tk] || []).join(\", \") || \"matched\"}`)\n .join(\" | \")}`;\n };\n\n const affSyncRouteChrome = (path: string) => {\n if (!document.body) return;\n // Keep every matched route token on <html> so per-token toolbar rules\n // (`[data-ff-route~=\"tk\"]`) still apply; gradients use enabled-only below.\n const routeAll = routeTokensForPath(path);\n if (!routeAll.length) {\n document.getElementById(\"aff-route-frame\")?.remove();\n document.getElementById(\"aff-route-badge\")?.remove();\n root.removeAttribute(\"data-ff-route\");\n root.removeAttribute(\"data-ff-route-label\");\n return;\n }\n root.setAttribute(\"data-ff-route\", routeAll.join(\" \"));\n root.setAttribute(\"data-ff-route-label\", routeLabelFor(path, routeAll));\n if (!document.getElementById(\"aff-route-frame\")) {\n const frame = document.createElement(\"div\");\n frame.id = \"aff-route-frame\";\n frame.className = \"aff-route-frame\";\n frame.setAttribute(\"aria-hidden\", \"true\");\n document.body.appendChild(frame);\n }\n let badge = document.getElementById(\"aff-route-badge\");\n if (!badge) {\n badge = document.createElement(\"div\");\n badge.id = \"aff-route-badge\";\n badge.className = \"aff-route-badge\";\n badge.setAttribute(\"role\", \"status\");\n document.body.appendChild(badge);\n }\n badge.textContent = root.getAttribute(\"data-ff-route-label\") || \"\";\n badge.setAttribute(\"aria-label\", badge.textContent || \"\");\n };\n\n try {\n (window as Window & { __AFF__?: unknown }).__AFF__ = {\n tokens: T,\n colors: C,\n namespace: N,\n };\n const raw = localStorage.getItem(K) || localStorage.getItem(\"aff.dev.v1\");\n const st = raw ? JSON.parse(raw) : {};\n const o = st.outline || st.chrome || {};\n const e = st.enabled || st.render || {};\n const b = st.badge || {};\n const cols = st.colors || {};\n\n for (let i = 0; i < T.length; i++) {\n const t = T[i];\n const od = OD[t] !== false;\n const bd = BD[t] !== false;\n if (o[t] === false || (!od && o[t] !== true))\n root.setAttribute(`data-ff-outline-${t}`, \"off\");\n else root.removeAttribute(`data-ff-outline-${t}`);\n if (e[t] === false) root.setAttribute(`data-ff-enabled-${t}`, \"off\");\n else root.removeAttribute(`data-ff-enabled-${t}`);\n if (b[t] === false || (!bd && b[t] !== true))\n root.setAttribute(`data-ff-badge-${t}`, \"off\");\n else root.removeAttribute(`data-ff-badge-${t}`);\n const col = cols[t] || C[t];\n const vn = `--${N}-c-${t}`;\n if (col) root.style.setProperty(vn, col);\n else root.style.removeProperty(vn);\n }\n\n const applyAll = () => {\n const map = new Set<HTMLElement>();\n document\n .querySelectorAll<HTMLElement>(`[data-${N}]`)\n .forEach((el) => map.add(el));\n for (let i = 0; i < T.length; i++) {\n document\n .querySelectorAll<HTMLElement>(`[data-${N}-${T[i]}]`)\n .forEach((el) => map.add(el));\n }\n map.forEach((el) => applyCombo(el, cols));\n };\n\n const affAfterNav = () => {\n if (!document.body) return;\n let p = window.location?.pathname || \"/\";\n if (!p.endsWith(\"/\")) p += \"/\";\n const toks = routeTokensForPath(p).filter((tk) => isEnabled(tk));\n if (toks.length) {\n const strong = toks.map((tk) => currentTokenColor(tk, cols));\n const soft = strong.map((c) => `color-mix(in oklab, white 86%, ${c} 14%)`);\n root.style.setProperty(`--${N}-route-gradient`, `linear-gradient(90deg, ${soft.join(\", \")})`);\n root.style.setProperty(\"--ff-route-outline-gradient\", `linear-gradient(90deg, ${strong.join(\", \")})`);\n root.style.setProperty(\"--ff-route-badge-gradient\", `linear-gradient(90deg, ${soft.join(\", \")})`);\n root.style.setProperty(\n \"--ff-route-badge-border\",\n `color-mix(in oklab, ${strong[0] || \"#64748b\"} 35%, transparent)`,\n );\n root.style.setProperty(\"--ff-route-outline\", strong[0] || \"#64748b\");\n root.style.setProperty(\"--ff-route-text\", strong[0] || \"#111827\");\n } else {\n root.style.removeProperty(`--${N}-route-gradient`);\n root.style.removeProperty(\"--ff-route-outline-gradient\");\n root.style.removeProperty(\"--ff-route-badge-gradient\");\n root.style.removeProperty(\"--ff-route-badge-border\");\n root.style.removeProperty(\"--ff-route-outline\");\n root.style.removeProperty(\"--ff-route-text\");\n }\n applyAll();\n affSyncRouteChrome(p);\n };\n\n affAfterNav();\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", affAfterNav, { once: true });\n }\n document.addEventListener(\"astro:page-load\", affAfterNav);\n document.addEventListener(\"astro:after-swap\", affAfterNav);\n if (typeof MutationObserver === \"function\") {\n const obs = new MutationObserver((muts) => {\n for (let i = 0; i < muts.length; i++) {\n const a = muts[i]?.attributeName;\n if (!a) continue;\n if (\n a === \"style\" ||\n a.indexOf(\"data-ff-enabled-\") === 0 ||\n a.indexOf(\"data-ff-outline-\") === 0 ||\n a.indexOf(\"data-ff-badge-\") === 0\n ) {\n affAfterNav();\n break;\n }\n }\n });\n obs.observe(root, { attributes: true });\n }\n } catch {\n // no-op in injected runtime\n }\n}\n","import {\n elementBadgePositionBlock,\n normalizeElementBadgeLayout,\n} from \"./badge-layout\";\nimport type { ElementBadgeLayoutOptions } from \"./badge-layout\";\nimport { inlineInvoke } from \"./inline-script\";\nimport { affDevBootstrapRuntime } from \"./dev-inline-runtimes\";\nimport type { ResolvedFeatureRuntime } from \"./runtime\";\nimport { toToken } from \"./runtime\";\n\nexport type DevOutlineHiddenStrategy = \"visibility\" | \"display\";\n\nexport interface DevOutlineCssOptions extends ElementBadgeLayoutOptions {\n outlineWidth?: string;\n /** Fallback when no per-token colour is set. */\n outlineColor?: string;\n /** Per-flag-token outline / badge / route-badge colour (overrides JSON `colors`). */\n outlineColorByToken?: Record<string, string>;\n outlineOffset?: string;\n borderRadius?: string;\n\n /** Default pill text for the `wip` flag token in the dev toolbar. */\n badgeLabelWip?: string;\n /** @deprecated Use {@link badgeLabelWip}. */\n badgeLabelDev?: string;\n badgeLabelByToken?: Record<string, string>;\n\n hiddenStrategy?: DevOutlineHiddenStrategy;\n\n /**\n * @deprecated Unused: badge does not use container queries.\n */\n badgeMinInlineSize?: string;\n}\ntype NormalizedDevOutlineCssOptions = {\n outlineWidth: string;\n outlineColor: string;\n outlineColorByToken: Record<string, string>;\n outlineOffset: string;\n borderRadius: string;\n badgeLabelWip: string;\n badgeLabelByToken: Record<string, string>;\n hiddenStrategy: DevOutlineHiddenStrategy;\n badgeMinInlineSize: string;\n};\n\nconst defaultDevOutlineCssOptions: Omit<\n NormalizedDevOutlineCssOptions,\n \"outlineColorByToken\"\n> = {\n outlineWidth: \"2px\",\n outlineColor: \"rgb(220 38 38)\",\n outlineOffset: \"-2px\",\n borderRadius: \"0.5rem\",\n badgeLabelWip: \"wip\",\n badgeLabelByToken: {},\n hiddenStrategy: \"visibility\",\n badgeMinInlineSize: \"8rem\",\n};\n\nfunction normalizeCssOptions(\n css: DevOutlineCssOptions | undefined,\n runtime: ResolvedFeatureRuntime,\n): NormalizedDevOutlineCssOptions {\n const byToken = {\n ...runtime.flagColorsByToken,\n ...(css?.outlineColorByToken ?? {}),\n };\n const badgeLabelWip =\n css?.badgeLabelWip ?? css?.badgeLabelDev ?? defaultDevOutlineCssOptions.badgeLabelWip;\n return {\n ...defaultDevOutlineCssOptions,\n ...(css ?? {}),\n outlineColorByToken: byToken,\n badgeLabelWip,\n badgeLabelByToken: {\n ...defaultDevOutlineCssOptions.badgeLabelByToken,\n ...(css?.badgeLabelByToken ?? {}),\n },\n };\n}\n\nfunction colorForToken(\n token: string,\n opts: NormalizedDevOutlineCssOptions,\n): string {\n return opts.outlineColorByToken[token] ?? opts.outlineColor;\n}\n\n/** CSS variable per token, set on &lt;html&gt; from ff.json + dev-toolbar overrides. */\nfunction featureColorVar(token: string, namespace: string): string {\n const ns = toToken(namespace) || \"ff\";\n return `--${ns}-c-${token}`;\n}\n\n/**\n * Dev-only styles: `data-ff=\"token\"` (or space-separated tokens) gates outlines/badges.\n * `html[data-ff-route=\"<token>\"]` (dev) adds a fixed top-right route badge (label only).\n * Toolbar toggles: `data-ff-enabled-*`, `data-ff-outline-*`, `data-ff-badge-*`, `--<namespace>-c-*`.\n */\nexport function createFeatureFlagStyles(\n runtime: ResolvedFeatureRuntime,\n css?: DevOutlineCssOptions,\n): string {\n const nsAttr = `data-${toToken(runtime.namespace) || \"ff\"}`;\n const selectorsForFlag = (flag: string) => {\n const token = toToken(flag);\n const valueSelectors = [`[${nsAttr}~=\"${token}\"]`];\n if (flag !== token) valueSelectors.push(`[${nsAttr}~=\"${flag}\"]`);\n const baseSelectors = [...valueSelectors, `[${nsAttr}-${token}]`];\n return {\n token,\n baseSelectors,\n selOutline: baseSelectors.map((s) => `${s}:not([${nsAttr}*=\" \"])`).join(\", \"),\n selIs: `:is(${baseSelectors.join(\", \")})`,\n };\n };\n const opts = normalizeCssOptions(css, runtime);\n const badgeLayout = normalizeElementBadgeLayout(css);\n const badgePos = elementBadgePositionBlock(badgeLayout);\n const chunks: string[] = [];\n\n for (const flag of Object.keys(runtime.flags)) {\n const { token, selOutline, selIs } = selectorsForFlag(flag);\n /** Combo hosts use `[${nsAttr}*=\" \"]` + `data-ff-label`; skip per-token ::before so combo rules win. */\n const selIsSingleBadge = `${selIs}:not([${nsAttr}*=\" \"])`;\n const col = colorForToken(token, opts);\n const v = featureColorVar(token, runtime.namespace);\n const label =\n opts.badgeLabelByToken[token] ??\n (token === \"wip\" ? opts.badgeLabelWip : token);\n const labelEscaped = String(label).replace(/'/g, \"\\\\'\");\n\n chunks.push(`\nhtml {\n --aff-outline-c-${token}: transparent;\n}\nhtml:not([data-ff-outline-${token}=\"off\"]) {\n --aff-outline-c-${token}: var(${v}, ${col});\n}\n${selOutline} {\n position: relative;\n outline: ${opts.outlineWidth} solid var(--aff-outline-c-${token});\n outline-offset: ${opts.outlineOffset};\n border-radius: ${opts.borderRadius};\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}::before {\n box-sizing: border-box;\n position: absolute;\n inset: auto;\n margin: 0;\n width: max-content;\n max-width: min(18rem, calc(100% - 0.75rem));\n pointer-events: auto;\n z-index: 20;\n${badgePos}\n display: block;\n content: '${labelEscaped}';\n border: 1px solid color-mix(in oklab, var(${v}, ${col}) 60%, transparent);\n border-radius: 9999px;\n padding: 0.125rem 0.45rem;\n font-size: 0.625rem;\n line-height: 1.2;\n letter-spacing: 0.02em;\n font-weight: 600;\n color: var(${v}, ${col});\n background: color-mix(in oklab, white 85%, var(${v}, ${col}) 15%);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n transition: opacity 0.14s ease, background 0.14s ease, border-color 0.14s ease;\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}:hover::before {\n opacity: 0.16;\n background: color-mix(in oklab, white 94%, var(${v}, ${col}) 6%);\n border-color: color-mix(in oklab, var(${v}, ${col}) 35%, transparent);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-align=\"start\"]::before {\n left: 0.35rem;\n right: auto;\n transform: translateY(calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-align=\"center\"]::before {\n left: 50%;\n right: auto;\n transform: translate(-50%, calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-align=\"end\"]::before {\n left: auto;\n right: 0.35rem;\n transform: translateY(calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-horizontal]::before {\n left: calc(attr(data-ff-horizontal number, 50) * 1%);\n right: auto;\n transform: translate(-50%, calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-horizontal][data-ff-anchor=\"bottom\"]::before {\n transform: translate(-50%, 80%);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"]::before {\n top: auto;\n bottom: 0;\n transform: translateY(80%);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"][data-ff-align=\"center\"]::before {\n transform: translate(-50%, 80%);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-vertical]::before {\n transform: translateY(calc(attr(data-ff-vertical number, 80) * -1%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-horizontal][data-ff-vertical]::before {\n transform: translate(-50%, calc(attr(data-ff-vertical number, 80) * -1%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"][data-ff-vertical]::before {\n transform: translateY(calc(attr(data-ff-vertical number, 80) * 1%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"][data-ff-horizontal][data-ff-vertical]::before {\n transform: translate(-50%, calc(attr(data-ff-vertical number, 80) * 1%));\n}\nhtml[data-ff-enabled-${token}=\"off\"] ${selIs} {\n display: none !important;\n}\n`);\n }\n\n // Multi-token value on a single element: show combined badge text and a gradient outline.\n chunks.push(`\n[${nsAttr}*=\" \"] {\n position: relative;\n outline: none !important;\n outline-offset: 0 !important;\n border-radius: ${opts.borderRadius};\n}\nhtml [${nsAttr}*=\" \"]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 10;\n box-sizing: border-box;\n padding: ${opts.outlineWidth};\n background: var(--ff-combo-gradient, linear-gradient(90deg, #fecaca, #bfdbfe, #bbf7d0));\n -webkit-mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\nhtml [${nsAttr}*=\" \"]::before {\n box-sizing: border-box;\n position: absolute;\n inset: auto;\n margin: 0;\n width: max-content;\n max-width: min(18rem, calc(100% - 0.75rem));\n pointer-events: auto;\n z-index: 20;\n${badgePos}\n display: block;\n content: attr(${nsAttr});\n background: var(--ff-combo-badge-gradient, var(--ff-combo-gradient-soft, linear-gradient(90deg, #fff1f2, #eff6ff, #f0fdf4))) !important;\n color: var(--ff-combo-text, #111827) !important;\n border: 1px solid var(--ff-combo-badge-border, color-mix(in oklab, #94a3b8 50%, transparent)) !important;\n border-radius: 9999px;\n padding: 0.125rem 0.45rem;\n font-size: 0.625rem;\n line-height: 1.2;\n letter-spacing: 0.02em;\n font-weight: 600;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n transition: opacity 0.14s ease, background 0.14s ease, border-color 0.14s ease;\n}\nhtml [${nsAttr}*=\" \"][data-ff-label]::before {\n content: attr(data-ff-label) !important;\n}\nhtml [${nsAttr}*=\" \"]:hover::before {\n opacity: 0.2;\n background: linear-gradient(90deg, #fff8f9, #f8fbff, #f8fff9);\n border-color: color-mix(in oklab, #94a3b8 35%, transparent);\n}\n`);\n\n // Combo chrome must be suppressed *after* generic combo rules so `!important` / order cannot be\n // overridden by `html [...][data-ff-label]::before { content: ... !important }`.\n for (const flag of Object.keys(runtime.flags)) {\n const { token, selIs } = selectorsForFlag(flag);\n chunks.push(`\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"]::before,\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"][data-ff-label]::before {\n display: none !important;\n content: none !important;\n}\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"]:hover::before,\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"][data-ff-label]:hover::before {\n display: none !important;\n opacity: 1 !important;\n background: none !important;\n border-color: transparent !important;\n}\nhtml[data-ff-outline-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"] {\n outline: none !important;\n outline-offset: 0 !important;\n}\nhtml[data-ff-outline-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"]::after {\n display: none !important;\n}\n`);\n }\n\n chunks.push(`\n.aff-route-frame {\n position: fixed;\n inset: 0.6rem;\n pointer-events: none;\n z-index: 10040;\n box-sizing: border-box;\n border-radius: 0.5rem;\n overflow: hidden;\n}\n.aff-route-frame::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n padding: 2px;\n background: var(--ff-route-outline-gradient, linear-gradient(90deg, #ef4444, #3b82f6, #22c55e));\n -webkit-mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\n.aff-route-badge {\n position: fixed;\n top: 0.75rem;\n right: 0.75rem;\n z-index: 10060;\n pointer-events: auto;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n max-width: min(34rem, calc(100vw - 1.5rem));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border: 1px solid var(--ff-route-badge-border, color-mix(in oklab, #94a3b8 55%, transparent));\n border-radius: 9999px;\n padding: 0.15rem 0.5rem;\n font-size: 0.625rem;\n line-height: 1.2;\n letter-spacing: 0.02em;\n font-weight: 600;\n color: var(--ff-route-text, #111827);\n background: var(--ff-route-badge-gradient, linear-gradient(90deg, #fff1f2));\n opacity: 1;\n transition: opacity 0.14s ease, border-color 0.14s ease, background 0.14s ease;\n}\n.aff-route-badge:hover {\n opacity: 0.2;\n border-color: color-mix(in oklab, #94a3b8 35%, transparent);\n}\n.aff-route-disabled-overlay {\n position: fixed;\n inset: 0;\n z-index: 10050;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: clamp(1rem, 4vw, 2.5rem);\n text-align: center;\n font: 600 0.95rem/1.45 system-ui, -apple-system, Segoe UI, sans-serif;\n color: #f8fafc;\n background: rgba(15, 23, 42, 0.52);\n backdrop-filter: blur(2px);\n pointer-events: auto;\n}\n.aff-route-disabled-overlay > p {\n margin: 0;\n max-width: min(44rem, calc(100vw - 2rem));\n white-space: pre-line;\n}\n`);\n\n for (const flag of Object.keys(runtime.flags)) {\n const token = toToken(flag);\n chunks.push(`\n[data-ff-route~=\"${token}\"][data-ff-outline-${token}=\"off\"] #aff-route-frame {\n display: none !important;\n}\n[data-ff-route~=\"${token}\"][data-ff-badge-${token}=\"off\"] #aff-route-badge {\n display: none !important;\n}\n[data-ff-route~=\"${token}\"][data-ff-enabled-${token}=\"off\"] #aff-route-frame {\n display: none !important;\n}\n[data-ff-route~=\"${token}\"][data-ff-enabled-${token}=\"off\"] #aff-route-badge {\n display: none !important;\n}\n`);\n }\n\n return \"\\n\" + chunks.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * CSS-only hiding for disabled flags. The Astro integration no longer injects this into\n * production builds — static HTML is culled instead. Kept for custom tooling or tests.\n */\nexport function createProductionGateStyles(\n runtime: ResolvedFeatureRuntime,\n): string {\n const nsAttr = `data-${toToken(runtime.namespace) || \"ff\"}`;\n const chunks: string[] = [];\n for (const [flag, enabled] of Object.entries(runtime.flags)) {\n if (enabled) continue;\n const token = toToken(flag);\n const valueSelectors = [`[${nsAttr}~=\"${token}\"]`];\n if (flag !== token) valueSelectors.push(`[${nsAttr}~=\"${flag}\"]`);\n chunks.push(\n `${[...valueSelectors, `[${nsAttr}-${token}]`].join(\", \")} { display: none !important; }`,\n );\n }\n return chunks.length ? `\\n${chunks.join(\"\\n\")}\\n` : \"\";\n}\n\nexport function buildAffDevBootstrapScript(\n flagTokens: string[],\n colors: Record<string, string>,\n outlineDefaults: Record<string, boolean>,\n badgeDefaults: Record<string, boolean>,\n routeFlags: Record<string, string[]>,\n flagNameToToken: Record<string, string>,\n namespace: string,\n): string {\n return inlineInvoke(affDevBootstrapRuntime, {\n flagTokens,\n colors,\n outlineDefaults,\n badgeDefaults,\n routeFlags,\n flagNameToToken,\n namespace: toToken(namespace) || \"ff\",\n });\n}\n","import { readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parse, type HTMLElement } from \"node-html-parser\";\nimport type { ResolvedFeatureRuntime } from \"./runtime\";\nimport { toToken } from \"./runtime\";\n\nfunction walkHtmlFiles(dir: string): string[] {\n const out: string[] = [];\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const ent of entries) {\n const p = join(dir, ent.name);\n if (ent.isDirectory()) out.push(...walkHtmlFiles(p));\n else if (ent.isFile() && ent.name.endsWith(\".html\")) out.push(p);\n }\n return out;\n}\n\nfunction namespaceAttrName(namespace: string): string {\n return `data-${toToken(namespace) || \"ff\"}`;\n}\n\nfunction elementFlagSlugs(\n el: HTMLElement,\n nsAttr: string,\n knownTokens: readonly string[],\n): string[] {\n const slugSet = new Set<string>();\n const combined = el.getAttribute(nsAttr)?.trim();\n if (combined) {\n for (const part of combined.split(/\\s+/).filter(Boolean)) {\n slugSet.add(part);\n }\n }\n for (const tk of knownTokens) {\n if (el.hasAttribute(`${nsAttr}-${tk}`)) slugSet.add(tk);\n }\n return [...slugSet];\n}\n\nfunction slugToFlagNames(slug: string, flagNames: readonly string[]): string[] {\n const out: string[] = [];\n for (const name of flagNames) {\n if (slug === name || slug === toToken(name)) out.push(name);\n }\n return out;\n}\n\nfunction shouldCullElement(\n el: HTMLElement,\n runtime: ResolvedFeatureRuntime,\n nsAttr: string,\n knownTokens: readonly string[],\n flagNames: readonly string[],\n): boolean {\n const slugs = elementFlagSlugs(el, nsAttr, knownTokens);\n if (slugs.length === 0) return false;\n for (const slug of slugs) {\n const names = slugToFlagNames(slug, flagNames);\n if (names.length === 0) return false;\n }\n for (const slug of slugs) {\n const names = slugToFlagNames(slug, flagNames);\n for (const name of names) {\n if (!runtime.flags[name]) return true;\n }\n }\n return false;\n}\n\nfunction elementDepth(el: HTMLElement): number {\n let d = 0;\n let n: HTMLElement | null = el.parentNode as HTMLElement | null;\n while (n) {\n d++;\n n = n.parentNode as HTMLElement | null;\n }\n return d;\n}\n\n/**\n * Production static HTML: remove nodes gated by disabled flags (same rules as dev\n * `data-*` / `data-*-<token>`), strip dev-only route attributes on `<html>`, and drop\n * empty `<style>` tags left after `featureFlagStyles` is empty.\n */\nexport function cullProductionHtml(\n html: string,\n runtime: ResolvedFeatureRuntime,\n): string {\n const root = parse(html) as HTMLElement;\n const nsAttr = namespaceAttrName(runtime.namespace);\n const flagNames = Object.keys(runtime.flags);\n const knownTokens = flagNames.map((n) => toToken(n));\n\n const candidates = root.querySelectorAll(\"*\") as unknown as HTMLElement[];\n const toRemove: HTMLElement[] = [];\n for (const el of candidates) {\n if (shouldCullElement(el, runtime, nsAttr, knownTokens, flagNames)) {\n toRemove.push(el);\n }\n }\n toRemove.sort((a, b) => elementDepth(b) - elementDepth(a));\n for (const el of toRemove) {\n el.remove();\n }\n\n const htmlEl = root.querySelector(\"html\") as HTMLElement | null;\n if (htmlEl) {\n htmlEl.removeAttribute(\"data-ff-route\");\n htmlEl.removeAttribute(\"data-ff-route-label\");\n }\n\n const styles = root.querySelectorAll(\"style\") as unknown as HTMLElement[];\n for (const st of styles) {\n const text = st.textContent ?? \"\";\n if (!text.trim()) st.remove();\n }\n\n return root.outerHTML;\n}\n\n/**\n * Walk `outDir` (e.g. Astro `dist/`) and apply {@link cullProductionHtml} to every `.html` file.\n */\nexport function applyProductionHtmlCullToDist(\n outDir: string,\n runtime: ResolvedFeatureRuntime,\n): void {\n for (const file of walkHtmlFiles(outDir)) {\n const before = readFileSync(file, \"utf8\");\n const after = cullProductionHtml(before, runtime);\n if (after !== before) writeFileSync(file, after, \"utf8\");\n }\n}\n","import type { ResolvedFeatureRuntime } from \"./runtime\";\nimport { toToken } from \"./runtime\";\nimport { inlineInvoke } from \"./inline-script\";\nimport { affHeadInlineRuntime } from \"./dev-inline-runtimes\";\n\n/**\n * Single `injectScript('head-inline', …)` payload for `astro dev`: dev-only outline CSS,\n * `data-ff-route` on `<html>` (pathname + {@link ResolvedFeatureRuntime.routeFlags}), then\n * the feature-flag dev bootstrap (toolbar state, combo badges, route chrome).\n */\nexport function buildAffDevHeadInline(args: {\n runtime: ResolvedFeatureRuntime;\n featureFlagStyles: string;\n affDevBootstrap: string;\n}): string {\n const { runtime, featureFlagStyles, affDevBootstrap } = args;\n const flagNameToToken = Object.fromEntries(\n Object.keys(runtime.flags).map((name) => [name, toToken(name)]),\n );\n const setup = inlineInvoke(affHeadInlineRuntime, {\n featureFlagStyles,\n routeFlags: runtime.routeFlags,\n flagNameToToken,\n });\n return `${setup}\\n${affDevBootstrap}`;\n}\n","/**\n * Shared JS helper source used by generated browser scripts.\n * Keep this in sync with runtime.routePatternToPrefix semantics.\n */\nexport function routePrefixJsHelper(functionName: string): string {\n return `function ${functionName}(pattern){var p=String(pattern||'').trim();if(p.endsWith('/**'))p=p.slice(0,-3);else if(p.endsWith('/*'))p=p.slice(0,-2);else if(p.length>1&&p.endsWith('*'))p=p.slice(0,-1);return p.endsWith('/')?p:p+'/';}`;\n}\n","import { rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n elementBadgePositionBlock,\n normalizeElementBadgeLayout,\n} from \"./badge-layout\";\nimport { DEV_TOOLBAR_FLAG_ICON_SVG } from \"./dev-toolbar-flag-icon\";\nimport type {\n ElementBadgeHorizontalAlign,\n ElementBadgeLayoutOptions,\n ElementBadgeVerticalAnchor,\n NormalizedElementBadgeLayout,\n} from \"./badge-layout\";\nimport {\n type FeatureFlagMap,\n type ResolveFeatureRuntimeOptions,\n type ResolvedFeatureRuntime,\n resolveFeatureFlagsByEnvironment,\n resolveFeatureRuntime,\n routePathsToPrune,\n shouldIncludeRoute,\n toEnumKey,\n toToken,\n} from \"./runtime\";\n\nexport type {\n ElementBadgeHorizontalAlign,\n ElementBadgeLayoutOptions,\n ElementBadgeVerticalAnchor,\n NormalizedElementBadgeLayout,\n};\nexport { elementBadgePositionBlock, normalizeElementBadgeLayout };\n\nexport type {\n DevOutlineCssOptions,\n DevOutlineHiddenStrategy,\n} from \"./dev-outline-css\";\n\nimport type { DevOutlineCssOptions } from \"./dev-outline-css\";\nimport {\n buildAffDevBootstrapScript,\n createFeatureFlagStyles,\n createProductionGateStyles,\n} from \"./dev-outline-css\";\nimport { applyProductionHtmlCullToDist } from \"./production-html-cull\";\nimport { buildAffDevHeadInline } from \"./dev-head-inject\";\nimport { routePrefixJsHelper } from \"./route-prefix-js\";\n\nexport { createFeatureFlagStyles, createProductionGateStyles };\nexport {\n cullProductionHtml,\n applyProductionHtmlCullToDist,\n} from \"./production-html-cull\";\n\nexport interface AstroFeatureFlagsOptions extends ResolveFeatureRuntimeOptions {\n css?: DevOutlineCssOptions;\n /** When false, keeps static build output untouched (no route pruning / HTML cull). */\n staticMinify?: boolean;\n}\n\n/** Prefer `prod` if present; else first non-`dev` key (sorted); else `\"prod\"`. */\nexport function primaryNonDevEnvironmentKey(\n flagsByEnvironment: Record<string, FeatureFlagMap>,\n): string {\n const keys = Object.keys(flagsByEnvironment);\n if (keys.includes(\"prod\")) return \"prod\";\n const nonDev = keys.filter((k) => k !== \"dev\").sort();\n return nonDev[0] ?? \"prod\";\n}\n\nfunction withDefaultEnvironments(\n options: ResolveFeatureRuntimeOptions = {},\n): ResolveFeatureRuntimeOptions {\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const raw =\n options.environments &&\n typeof options.environments === \"object\" &&\n !Array.isArray(options.environments)\n ? { ...options.environments }\n : {};\n delete raw.dev;\n const environments: NonNullable<ResolveFeatureRuntimeOptions[\"environments\"]> =\n {\n dev: {\n when: mode !== \"production\",\n },\n ...raw,\n };\n if (Object.keys(environments).length < 2) {\n environments.prod = environments.prod ?? {\n when: mode === \"production\",\n flags: {},\n };\n }\n return { ...options, environments };\n}\n\nexport function createVirtualModuleSource(\n runtime: ResolvedFeatureRuntime,\n css?: DevOutlineCssOptions,\n flagsByEnvironment: Record<string, FeatureFlagMap> = {},\n devBootstrap?: string,\n): string {\n const flagNames = Object.keys(runtime.flags);\n const flagTokens = flagNames.map((name) => toToken(name));\n const enumEntries = flagNames\n .map((name) => ` ${toEnumKey(name)}: ${JSON.stringify(name)}`)\n .join(\",\\n\");\n const tokenEntries = flagNames\n .map((name) => ` ${toEnumKey(name)}: ${JSON.stringify(toToken(name))}`)\n .join(\",\\n\");\n const styles = createFeatureFlagStyles(runtime, css);\n const colorsJson = JSON.stringify(runtime.flagColorsByToken, null, 2);\n const flagNameToToken = JSON.stringify(\n Object.fromEntries(flagNames.map((name) => [name, toToken(name)])),\n null,\n 2,\n );\n const defaultNonDevEnvironment =\n primaryNonDevEnvironmentKey(flagsByEnvironment);\n const bootstrap =\n devBootstrap ??\n buildAffDevBootstrapScript(\n flagTokens,\n { ...runtime.flagColorsByToken },\n { ...runtime.flagOutlineDefaultsByToken },\n { ...runtime.flagBadgeDefaultsByToken },\n { ...runtime.routeFlags },\n Object.fromEntries(flagNames.map((name) => [name, toToken(name)])),\n runtime.namespace,\n );\n const affRoutePatternToPrefix = routePrefixJsHelper(\"affRoutePatternToPrefix\");\n\n return `${affRoutePatternToPrefix}\n\nexport const FeatureFlag = Object.freeze({\n${enumEntries}\n});\n\nexport const FeatureToken = Object.freeze({\n${tokenEntries}\n});\n\nexport const featureFlagTokens = Object.freeze(${JSON.stringify(flagTokens)});\nexport const featureFlagColors = Object.freeze(${colorsJson});\nexport const featureFlags = Object.freeze(${JSON.stringify(runtime.flags, null, 2)});\nexport const featureFlagsByEnvironment = Object.freeze(${JSON.stringify(flagsByEnvironment, null, 2)});\nexport const defaultNonDevEnvironment = ${JSON.stringify(defaultNonDevEnvironment)};\nexport const featureRouteFlags = Object.freeze(${JSON.stringify(runtime.routeFlags, null, 2)});\nexport const featureNamespace = ${JSON.stringify(runtime.namespace)};\n/** True when Astro is running the dev server or dev build (import.meta.env.DEV). Not the same as the reserved \\`dev\\` environment layer — see \\`activeEnvironmentKey\\`. */\nexport const isAstroDev = import.meta.env.DEV;\nexport const activeEnvironmentKey = ${JSON.stringify(runtime.activeEnvironment)};\n\nexport const affDevBootstrap = import.meta.env.DEV ? ${JSON.stringify(bootstrap)} : '';\n\nexport function isFeatureEnabled(flag) {\n return Boolean(featureFlags[flag]);\n}\n\nexport function shouldRenderFeature(flag) {\n return isFeatureEnabled(flag);\n}\n\nexport function isFeatureRoute(pathname) {\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n return Object.keys(featureRouteFlags).some((route) => {\n const candidate = affRoutePatternToPrefix(route);\n return normalized === candidate || normalized.startsWith(candidate);\n });\n}\n\nexport function shouldIncludePath(pathname) {\n if (import.meta.env.DEV) return true;\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n for (const [route, flags] of Object.entries(featureRouteFlags)) {\n const candidate = affRoutePatternToPrefix(route);\n if (normalized === candidate || normalized.startsWith(candidate)) {\n return flags.every((flag) => isFeatureEnabled(flag));\n }\n }\n return true;\n}\n\nexport function flagsForEnvironment(envName) {\n var F = featureFlagsByEnvironment[envName];\n return F != null ? F : null;\n}\n\nexport function isFeatureEnabledForEnvironment(flag, envName) {\n var F = featureFlagsByEnvironment[envName];\n return !!(F && F[flag]);\n}\n\nexport function shouldIncludePathForEnvironment(pathname, envName) {\n var F = featureFlagsByEnvironment[envName];\n if (!F) return true;\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n for (const [route, flagList] of Object.entries(featureRouteFlags)) {\n const candidate = affRoutePatternToPrefix(route);\n if (normalized === candidate || normalized.startsWith(candidate)) {\n return flagList.every((flag) => Boolean(F[flag]));\n }\n }\n return true;\n}\n\nconst flagNameToToken = Object.freeze(${flagNameToToken});\n\nexport function matchedFeatureRoutePrefix(pathname) {\n if (!pathname) return null;\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n let best = null;\n let bestLen = -1;\n for (const routePrefix of Object.keys(featureRouteFlags)) {\n const route = affRoutePatternToPrefix(routePrefix);\n if (normalized === route || normalized.startsWith(route)) {\n if (route.length > bestLen) {\n bestLen = route.length;\n best = routePrefix;\n }\n }\n }\n return best;\n}\n\nexport function routeFeatureTokenForPath(pathname) {\n const prefix = matchedFeatureRoutePrefix(pathname);\n if (!prefix) return undefined;\n const flagNames = featureRouteFlags[prefix] || [];\n const first = flagNames[0];\n return first != null ? flagNameToToken[first] : undefined;\n}\n\nexport function routeFeatureTokensForPath(pathname) {\n if (!pathname) return [];\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n const out = [];\n const seen = new Set();\n for (const [routePrefix, flagNames] of Object.entries(featureRouteFlags)) {\n const route = affRoutePatternToPrefix(routePrefix);\n if (!(normalized === route || normalized.startsWith(route))) continue;\n for (const name of flagNames || []) {\n const token = flagNameToToken[name];\n if (!token || seen.has(token)) continue;\n seen.add(token);\n out.push(token);\n }\n }\n return out;\n}\n\nexport function routeFeatureMatchesForPath(pathname) {\n if (!pathname) return [];\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n var byFlag = {};\n for (const [routePattern, flagNames] of Object.entries(featureRouteFlags)) {\n const candidate = affRoutePatternToPrefix(routePattern);\n if (!(normalized === candidate || normalized.startsWith(candidate))) continue;\n for (const flagName of flagNames || []) {\n const token = flagNameToToken[flagName];\n if (!token) continue;\n if (!byFlag[flagName]) byFlag[flagName] = { flag: flagName, token, routes: [] };\n byFlag[flagName].routes.push(routePattern);\n }\n }\n return Object.values(byFlag);\n}\n\nexport const featureFlagStyles = import.meta.env.DEV ? ${JSON.stringify(styles)} : \"\";\n`;\n}\n\nexport function getResolvedFeatures(\n options: ResolveFeatureRuntimeOptions = {},\n): ResolvedFeatureRuntime {\n return resolveFeatureRuntime(withDefaultEnvironments(options));\n}\n\nexport function featureRouteIncluded(\n pathname: string,\n runtime: ResolvedFeatureRuntime,\n): boolean {\n return shouldIncludeRoute({\n pathname,\n routeFlags: runtime.routeFlags,\n flags: runtime.flags,\n isDev: runtime.isDev,\n });\n}\n\nexport type { FeatureFlagMap } from \"./runtime\";\nexport {\n longestMatchingRoutePrefix,\n mergeFlagsWithProcessEnvOverrides,\n resolveFeatureFlagsByEnvironment,\n routePatternToPrefix,\n} from \"./runtime\";\n\nexport default function astroFeatureFlags(\n options: AstroFeatureFlagsOptions = {},\n): any {\n const { css, staticMinify = true, ...flagOpts } = options;\n const opts = withDefaultEnvironments(flagOpts);\n const mode = opts.mode ?? process.env.NODE_ENV ?? \"development\";\n\n const runtime = resolveFeatureRuntime({\n ...opts,\n mode,\n });\n\n return {\n name: \"astro-feature-flags\",\n hooks: {\n \"astro:config:setup\": ({\n updateConfig,\n addDevToolbarApp,\n command,\n injectScript,\n }: {\n updateConfig: (config: unknown) => void;\n addDevToolbarApp?: (opts: {\n id: string;\n name: string;\n icon: string;\n entrypoint: string;\n }) => void;\n command?: string;\n injectScript?: (stage: string, content: string) => void;\n }) => {\n const flagNames = Object.keys(runtime.flags);\n const flagTokens = flagNames.map((name) => toToken(name));\n const flagsByEnvironment = resolveFeatureFlagsByEnvironment(opts);\n const flagNameToToken = Object.fromEntries(\n flagNames.map((name) => [name, toToken(name)]),\n );\n const bootstrap = buildAffDevBootstrapScript(\n flagTokens,\n { ...runtime.flagColorsByToken },\n { ...runtime.flagOutlineDefaultsByToken },\n { ...runtime.flagBadgeDefaultsByToken },\n { ...runtime.routeFlags },\n flagNameToToken,\n runtime.namespace,\n );\n\n if (\n command === \"dev\" &&\n runtime.isDev &&\n typeof addDevToolbarApp === \"function\"\n ) {\n addDevToolbarApp({\n id: \"astro-feature-flags\",\n name: \"Feature flags\",\n icon: DEV_TOOLBAR_FLAG_ICON_SVG,\n entrypoint: fileURLToPath(\n new URL(\"./dev-toolbar-app.mjs\", import.meta.url),\n ),\n });\n }\n if (\n command === \"dev\" &&\n runtime.isDev &&\n typeof injectScript === \"function\"\n ) {\n const styles = createFeatureFlagStyles(runtime, css);\n injectScript(\n \"head-inline\",\n buildAffDevHeadInline({\n runtime,\n featureFlagStyles: styles,\n affDevBootstrap: bootstrap,\n }),\n );\n }\n updateConfig({\n vite: {\n plugins: [\n {\n name: \"astro-feature-flags:virtual-module\",\n resolveId(id: string) {\n if (id === \"virtual:astro-feature-flags\")\n return \"\\0virtual:astro-feature-flags\";\n return null;\n },\n load(id: string) {\n if (id === \"\\0virtual:astro-feature-flags\") {\n return createVirtualModuleSource(\n runtime,\n css,\n flagsByEnvironment,\n bootstrap,\n );\n }\n return null;\n },\n },\n ],\n },\n });\n },\n \"astro:build:done\": ({ dir }: { dir: URL }) => {\n if (runtime.isDev || !staticMinify) return;\n const outDir = fileURLToPath(dir);\n const prunePaths = routePathsToPrune({\n routeFlags: runtime.routeFlags,\n flags: runtime.flags,\n });\n for (const routePath of prunePaths) {\n rmSync(join(outDir, routePath), { recursive: true, force: true });\n }\n applyProductionHtmlCullToDist(outDir, runtime);\n },\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/badge-layout.ts","../src/inline-script.ts","../src/dev-inline-runtimes.ts","../src/dev-outline-css.ts","../src/production-html-cull.ts","../src/dev-head-inject.ts","../src/route-prefix-js.ts","../src/index.ts"],"sourcesContent":["export type ElementBadgeVerticalAnchor = \"top\" | \"bottom\";\n\n/** Horizontal placement of the element pill: `end` = top-right (LTR), `start` = top-left, `center` = centred. */\nexport type ElementBadgeHorizontalAlign = \"start\" | \"center\" | \"end\";\n\n/** Subset of dev CSS options used for element-badge geometry (also on `DevOutlineCssOptions`). */\nexport interface ElementBadgeLayoutOptions {\n /**\n * Horizontal alignment along the element’s top or bottom edge. Default `end` (top-right in LTR).\n * Ignored when `elementBadgeHorizontalPercent` is set.\n */\n elementBadgeHorizontalAlign?: ElementBadgeHorizontalAlign;\n /**\n * Optional: anchor at a percentage along the element width (0–100), with the pill centred on that point (`translateX(-50%)`).\n * When set, overrides `elementBadgeHorizontalAlign`.\n */\n elementBadgeHorizontalPercent?: number;\n /**\n * Vertical shift as a percentage of the **badge’s own height** (CSS transform %).\n * With anchor `top`, moves the badge upward. Default `80` (~20% of the pill overlaps the element top edge).\n */\n elementBadgeVerticalShiftPercent?: number;\n /** Anchor the badge to the top or bottom edge of the element. Default `top`. */\n elementBadgeVerticalAnchor?: ElementBadgeVerticalAnchor;\n}\n\nexport type NormalizedElementBadgeLayout =\n | {\n mode: \"align\";\n horizontalAlign: ElementBadgeHorizontalAlign;\n verticalShiftPercent: number;\n verticalAnchor: ElementBadgeVerticalAnchor;\n }\n | {\n mode: \"percent\";\n horizontalPercent: number;\n verticalShiftPercent: number;\n verticalAnchor: ElementBadgeVerticalAnchor;\n };\n\nfunction clampPercent(n: number, fallback: number): number {\n if (typeof n !== \"number\" || Number.isNaN(n)) return fallback;\n return Math.min(100, Math.max(0, n));\n}\n\nexport function normalizeElementBadgeLayout(\n input: ElementBadgeLayoutOptions | undefined,\n): NormalizedElementBadgeLayout {\n const v = clampPercent(input?.elementBadgeVerticalShiftPercent ?? 80, 80);\n const anchor =\n input?.elementBadgeVerticalAnchor === \"bottom\" ? \"bottom\" : \"top\";\n const hp = input?.elementBadgeHorizontalPercent;\n if (hp !== undefined && hp !== null && typeof hp === \"number\") {\n return {\n mode: \"percent\",\n horizontalPercent: clampPercent(hp, 50),\n verticalShiftPercent: v,\n verticalAnchor: anchor,\n };\n }\n const align: ElementBadgeHorizontalAlign =\n input?.elementBadgeHorizontalAlign === \"start\" ||\n input?.elementBadgeHorizontalAlign === \"center\"\n ? input.elementBadgeHorizontalAlign\n : \"end\";\n return {\n mode: \"align\",\n horizontalAlign: align,\n verticalShiftPercent: v,\n verticalAnchor: anchor,\n };\n}\n\nconst INSET = \"0.35rem\";\n\n/**\n * `left` / `right` / `top` | `bottom` / `transform` for the element `::before` badge (no trailing newline).\n */\nexport function elementBadgePositionBlock(\n layout: NormalizedElementBadgeLayout,\n): string {\n const { verticalShiftPercent: v, verticalAnchor } = layout;\n const y =\n verticalAnchor === \"top\"\n ? `translateY(calc(-1 * ${v}%))`\n : `translateY(${v}%)`;\n\n if (layout.mode === \"percent\") {\n const h = layout.horizontalPercent;\n if (verticalAnchor === \"top\") {\n return ` left: ${h}%;\n right: auto;\n top: 0;\n bottom: auto;\n transform: translateX(-50%) ${y};`;\n }\n return ` left: ${h}%;\n right: auto;\n bottom: 0;\n top: auto;\n transform: translateX(-50%) ${y};`;\n }\n\n const { horizontalAlign } = layout;\n if (horizontalAlign === \"center\") {\n if (verticalAnchor === \"top\") {\n return ` left: 50%;\n right: auto;\n top: 0;\n bottom: auto;\n transform: translateX(-50%) ${y};`;\n }\n return ` left: 50%;\n right: auto;\n bottom: 0;\n top: auto;\n transform: translateX(-50%) ${y};`;\n }\n if (horizontalAlign === \"start\") {\n if (verticalAnchor === \"top\") {\n return ` left: ${INSET};\n right: auto;\n top: 0;\n bottom: auto;\n transform: ${y};`;\n }\n return ` left: ${INSET};\n right: auto;\n bottom: 0;\n top: auto;\n transform: ${y};`;\n }\n /* end — top-right / bottom-right */\n if (verticalAnchor === \"top\") {\n return ` left: auto;\n right: ${INSET};\n top: 0;\n bottom: auto;\n transform: ${y};`;\n }\n return ` left: auto;\n right: ${INSET};\n bottom: 0;\n top: auto;\n transform: ${y};`;\n}\n","export function compactInlineScript(source: string): string {\n const lines = source\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(\n (line, idx, arr) => line.length > 0 || (idx > 0 && idx < arr.length - 1),\n );\n return lines.join(\"\\n\").trim();\n}\n\nexport function inlineInvoke<Payload>(\n fn: (payload: Payload) => void,\n payload: Payload,\n): string {\n return compactInlineScript(`(${fn.toString()})(${JSON.stringify(payload)});`);\n}\n","type HeadInlinePayload = {\n featureFlagStyles: string;\n routeFlags: Record<string, string[]>;\n flagNameToToken: Record<string, string>;\n};\n\ntype BootstrapPayload = {\n flagTokens: string[];\n colors: Record<string, string>;\n outlineDefaults: Record<string, boolean>;\n badgeDefaults: Record<string, boolean>;\n routeFlags: Record<string, string[]>;\n flagNameToToken: Record<string, string>;\n namespace: string;\n};\n\nexport function affHeadInlineRuntime(payload: HeadInlinePayload): void {\n const toPrefix = (pattern: string): string => {\n let p = String(pattern || \"\").trim();\n if (p.endsWith(\"/**\")) p = p.slice(0, -3);\n else if (p.endsWith(\"/*\")) p = p.slice(0, -2);\n else if (p.length > 1 && p.endsWith(\"*\")) p = p.slice(0, -1);\n return p.endsWith(\"/\") ? p : `${p}/`;\n };\n try {\n const { featureFlagStyles, routeFlags: RF, flagNameToToken: M } = payload;\n\n // Inject the dev-chrome stylesheet. Astro's ClientRouter swaps <head> on a\n // view-transition navigation, and a runtime-injected <style> is dropped on\n // the first swap unless marked persistent — which is why the element\n // outline/badge chrome vanished after navigating. Mark it\n // data-astro-transition-persist so ClientRouter keeps a single copy, and\n // keep the injector idempotent + re-run it on every nav so the styles stay\n // constant across pages even where a swap removes them.\n const ensureFeatureFlagStyles = () => {\n if (document.querySelector(\"style[data-astro-feature-flags]\")) return;\n const s = document.createElement(\"style\");\n s.setAttribute(\"data-astro-feature-flags\", \"\");\n s.setAttribute(\"data-astro-transition-persist\", \"astro-feature-flags\");\n s.textContent = featureFlagStyles;\n (document.head || document.documentElement).appendChild(s);\n };\n ensureFeatureFlagStyles();\n\n const affPath = () => {\n let p =\n typeof location !== \"undefined\" && location.pathname\n ? location.pathname\n : \"/\";\n if (!p.endsWith(\"/\")) p += \"/\";\n return p;\n };\n\n const affFlagNames = (pathname: string) => {\n let p = pathname || \"/\";\n if (!p.endsWith(\"/\")) p += \"/\";\n const out: string[] = [];\n const seen = new Set<string>();\n for (const rp in RF) {\n if (!Object.prototype.hasOwnProperty.call(RF, rp)) continue;\n const route = toPrefix(rp);\n if (!(p === route || p.indexOf(route) === 0)) continue;\n const fns = RF[rp] || [];\n for (let i = 0; i < fns.length; i++) {\n const fn = fns[i];\n if (fn && !seen.has(fn)) {\n seen.add(fn);\n out.push(fn);\n }\n }\n }\n return out;\n };\n\n const affTokens = (pathname: string) =>\n affFlagNames(pathname)\n .map((name) => M[name])\n .filter(Boolean);\n\n const affSyncDisabledOverlay = () => {\n const root = document.documentElement;\n if (!document.body) return;\n const names = affFlagNames(affPath());\n const disabled: string[] = [];\n for (let i = 0; i < names.length; i++) {\n const tk = M[names[i]];\n if (!tk) continue;\n if (root.getAttribute(`data-ff-enabled-${tk}`) === \"off\")\n disabled.push(tk);\n }\n const id = \"aff-route-disabled-overlay\";\n let el = document.getElementById(id);\n if (!disabled.length) {\n if (el) el.remove();\n root.removeAttribute(\"data-aff-route-disabled\");\n return;\n }\n root.setAttribute(\"data-aff-route-disabled\", \"\");\n if (!el) {\n el = document.createElement(\"div\");\n el.id = id;\n el.className = \"aff-route-disabled-overlay\";\n const p = document.createElement(\"p\");\n el.appendChild(p);\n document.body.appendChild(el);\n }\n const pEl = el.querySelector(\"p\") || el;\n const flagsText = disabled.join(\", \");\n const line1 =\n disabled.length === 1\n ? `Page disabled: ${flagsText} flag is disabled.`\n : `Page disabled: ${flagsText} flags are disabled.`;\n const line2 =\n \"In production builds, pages with disabled flags like this will not be emitted\";\n pEl.textContent = `${line1}\\n${line2}`;\n };\n\n const affApply = () => {\n ensureFeatureFlagStyles();\n document.documentElement.setAttribute(\n \"data-ff-route\",\n affTokens(affPath()).join(\" \"),\n );\n affSyncDisabledOverlay();\n };\n\n affApply();\n if (typeof MutationObserver === \"function\") {\n const obs = new MutationObserver((muts) => {\n for (let i = 0; i < muts.length; i++) {\n const a = muts[i] && muts[i].attributeName;\n if (\n a === \"data-ff-route\" ||\n (a && a.indexOf(\"data-ff-enabled-\") === 0)\n ) {\n affSyncDisabledOverlay();\n break;\n }\n }\n });\n obs.observe(document.documentElement, { attributes: true });\n }\n document.addEventListener(\"astro:page-load\", affApply);\n document.addEventListener(\"astro:after-swap\", affApply);\n } catch {\n // no-op in injected runtime\n }\n}\n\nexport function affDevBootstrapRuntime(payload: BootstrapPayload): void {\n const toPrefix = (pattern: string): string => {\n let p = String(pattern || \"\").trim();\n if (p.endsWith(\"/**\")) p = p.slice(0, -3);\n else if (p.endsWith(\"/*\")) p = p.slice(0, -2);\n else if (p.length > 1 && p.endsWith(\"*\")) p = p.slice(0, -1);\n return p.endsWith(\"/\") ? p : `${p}/`;\n };\n const T = payload.flagTokens;\n const C = payload.colors;\n const OD = payload.outlineDefaults;\n const BD = payload.badgeDefaults;\n const RF = payload.routeFlags;\n const F2T = payload.flagNameToToken;\n const N = payload.namespace;\n const K = `${N}.dev.v1`;\n\n const root = document.documentElement;\n const isEnabled = (tk: string) =>\n root.getAttribute(`data-ff-enabled-${tk}`) !== \"off\";\n const currentTokenColor = (\n tk: string,\n cols: Record<string, string>,\n ): string => {\n const cssVar = root.style.getPropertyValue(`--${N}-c-${tk}`).trim();\n return cssVar || cols[tk] || C[tk] || \"#94a3b8\";\n };\n const unique = (a: string[]) => [...new Set(a.filter(Boolean))];\n\n const comboTokens = (el: Element): string[] => {\n let out: string[] = [];\n const raw = (el.getAttribute(`data-${N}`) || \"\").trim();\n if (raw) out = out.concat(raw.split(/\\s+/).filter(Boolean));\n for (let i = 0; i < T.length; i++) {\n const tk = T[i];\n if (el.hasAttribute(`data-${N}-${tk}`)) out.push(tk);\n }\n return unique(out);\n };\n\n const stripBooleanFlagAttrs = (el: Element) => {\n for (let i = 0; i < T.length; i++) {\n el.removeAttribute(`data-${N}-${T[i]}`);\n }\n };\n const clearComboVisualState = (el: HTMLElement) => {\n el.removeAttribute(\"data-ff-label\");\n el.style.removeProperty(\"--ff-combo-gradient\");\n el.style.removeProperty(\"--ff-combo-gradient-soft\");\n el.style.removeProperty(\"--ff-combo-outline\");\n el.style.removeProperty(\"--ff-combo-text\");\n el.style.removeProperty(\"--ff-combo-badge-border\");\n el.style.removeProperty(\"--ff-combo-badge-gradient\");\n };\n\n const applyCombo = (el: HTMLElement, cols: Record<string, string>) => {\n const allTokens = comboTokens(el);\n const hasCombo = allTokens.length >= 2;\n const hasDisabledInCombo =\n hasCombo && allTokens.some((tk) => !isEnabled(tk));\n const visual = allTokens.filter((tk) => isEnabled(tk));\n if (hasDisabledInCombo) {\n // Fail-closed for combos: if any member token is disabled, hide the whole element.\n // Keep all combo tokens mirrored in data-<ns> so enabled-off CSS selectors can hide it.\n stripBooleanFlagAttrs(el);\n el.setAttribute(`data-${N}`, allTokens.join(\" \"));\n clearComboVisualState(el);\n return;\n }\n if (visual.length < 2) {\n clearComboVisualState(el);\n if (hasCombo) {\n // Only normalize attrs for true combos. Single-flag shorthand markers\n // (e.g. data-ff-wip) must stay intact so re-enabling can recover styling.\n stripBooleanFlagAttrs(el);\n if (visual.length === 1) {\n el.setAttribute(`data-${N}`, visual[0]!);\n } else {\n el.removeAttribute(`data-${N}`);\n }\n }\n return;\n }\n stripBooleanFlagAttrs(el);\n // Mirror all enabled tokens into the primary namespace attribute so `[data-<ns>*=\" \"]`\n // matches (required for boolean-only combos like data-ff-a + data-ff-b).\n el.setAttribute(`data-${N}`, visual.join(\" \"));\n el.setAttribute(\"data-ff-label\", visual.join(\" | \"));\n const strong = visual.map((tk) => currentTokenColor(tk, cols));\n const soft = strong.map((c) => `color-mix(in oklab, white 86%, ${c} 14%)`);\n el.style.setProperty(\n \"--ff-combo-gradient\",\n `linear-gradient(90deg, ${strong.join(\", \")})`,\n );\n el.style.setProperty(\n \"--ff-combo-gradient-soft\",\n `linear-gradient(90deg, ${soft.join(\", \")})`,\n );\n el.style.setProperty(\"--ff-combo-outline\", strong[0] || \"#64748b\");\n el.style.setProperty(\"--ff-combo-text\", strong[0] || \"#111827\");\n el.style.setProperty(\n \"--ff-combo-badge-border\",\n `color-mix(in oklab, ${strong[0] || \"#64748b\"} 35%, transparent)`,\n );\n el.style.setProperty(\n \"--ff-combo-badge-gradient\",\n `linear-gradient(90deg, ${soft.join(\", \")})`,\n );\n };\n\n const routeTokensForPath = (path: string): string[] => {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const rp in RF) {\n if (!Object.prototype.hasOwnProperty.call(RF, rp)) continue;\n const cnd = toPrefix(rp);\n if (!(path === cnd || path.indexOf(cnd) === 0)) continue;\n const fns = RF[rp] || [];\n for (let i = 0; i < fns.length; i++) {\n const tk = F2T[fns[i]];\n if (tk && !seen.has(tk)) {\n seen.add(tk);\n out.push(tk);\n }\n }\n }\n return out;\n };\n\n const routeLabelFor = (path: string, toks: string[]): string => {\n if (!toks.length) return \"\";\n const byFlag: Record<string, string[]> = {};\n for (const rp in RF) {\n if (!Object.prototype.hasOwnProperty.call(RF, rp)) continue;\n const cnd = toPrefix(rp);\n if (!(path === cnd || path.indexOf(cnd) === 0)) continue;\n const fns = RF[rp] || [];\n for (let i = 0; i < fns.length; i++) {\n const tk = F2T[fns[i]];\n if (!tk) continue;\n if (!byFlag[tk]) byFlag[tk] = [];\n byFlag[tk].push(rp);\n }\n }\n return `Page: ${toks\n .map((tk) => `${tk} - ${(byFlag[tk] || []).join(\", \") || \"matched\"}`)\n .join(\" | \")}`;\n };\n\n const affSyncRouteChrome = (path: string) => {\n if (!document.body) return;\n // Keep every matched route token on <html> so per-token toolbar rules\n // (`[data-ff-route~=\"tk\"]`) still apply; gradients use enabled-only below.\n const routeAll = routeTokensForPath(path);\n if (!routeAll.length) {\n document.getElementById(\"aff-route-frame\")?.remove();\n document.getElementById(\"aff-route-badge\")?.remove();\n root.removeAttribute(\"data-ff-route\");\n root.removeAttribute(\"data-ff-route-label\");\n return;\n }\n root.setAttribute(\"data-ff-route\", routeAll.join(\" \"));\n root.setAttribute(\"data-ff-route-label\", routeLabelFor(path, routeAll));\n if (!document.getElementById(\"aff-route-frame\")) {\n const frame = document.createElement(\"div\");\n frame.id = \"aff-route-frame\";\n frame.className = \"aff-route-frame\";\n frame.setAttribute(\"aria-hidden\", \"true\");\n document.body.appendChild(frame);\n }\n let badge = document.getElementById(\"aff-route-badge\");\n if (!badge) {\n badge = document.createElement(\"div\");\n badge.id = \"aff-route-badge\";\n badge.className = \"aff-route-badge\";\n badge.setAttribute(\"role\", \"status\");\n document.body.appendChild(badge);\n }\n badge.textContent = root.getAttribute(\"data-ff-route-label\") || \"\";\n badge.setAttribute(\"aria-label\", badge.textContent || \"\");\n };\n\n try {\n (window as Window & { __AFF__?: unknown }).__AFF__ = {\n tokens: T,\n colors: C,\n namespace: N,\n };\n const raw = localStorage.getItem(K) || localStorage.getItem(\"aff.dev.v1\");\n const st = raw ? JSON.parse(raw) : {};\n const o = st.outline || st.chrome || {};\n const e = st.enabled || st.render || {};\n const b = st.badge || {};\n const cols = st.colors || {};\n\n for (let i = 0; i < T.length; i++) {\n const t = T[i];\n const od = OD[t] !== false;\n const bd = BD[t] !== false;\n if (o[t] === false || (!od && o[t] !== true))\n root.setAttribute(`data-ff-outline-${t}`, \"off\");\n else root.removeAttribute(`data-ff-outline-${t}`);\n if (e[t] === false) root.setAttribute(`data-ff-enabled-${t}`, \"off\");\n else root.removeAttribute(`data-ff-enabled-${t}`);\n if (b[t] === false || (!bd && b[t] !== true))\n root.setAttribute(`data-ff-badge-${t}`, \"off\");\n else root.removeAttribute(`data-ff-badge-${t}`);\n const col = cols[t] || C[t];\n const vn = `--${N}-c-${t}`;\n if (col) root.style.setProperty(vn, col);\n else root.style.removeProperty(vn);\n }\n\n const applyAll = () => {\n const map = new Set<HTMLElement>();\n document\n .querySelectorAll<HTMLElement>(`[data-${N}]`)\n .forEach((el) => map.add(el));\n for (let i = 0; i < T.length; i++) {\n document\n .querySelectorAll<HTMLElement>(`[data-${N}-${T[i]}]`)\n .forEach((el) => map.add(el));\n }\n map.forEach((el) => applyCombo(el, cols));\n };\n\n const affAfterNav = () => {\n if (!document.body) return;\n let p = window.location?.pathname || \"/\";\n if (!p.endsWith(\"/\")) p += \"/\";\n const toks = routeTokensForPath(p).filter((tk) => isEnabled(tk));\n if (toks.length) {\n const strong = toks.map((tk) => currentTokenColor(tk, cols));\n const soft = strong.map(\n (c) => `color-mix(in oklab, white 86%, ${c} 14%)`,\n );\n root.style.setProperty(\n `--${N}-route-gradient`,\n `linear-gradient(90deg, ${soft.join(\", \")})`,\n );\n root.style.setProperty(\n \"--ff-route-outline-gradient\",\n `linear-gradient(90deg, ${strong.join(\", \")})`,\n );\n root.style.setProperty(\n \"--ff-route-badge-gradient\",\n `linear-gradient(90deg, ${soft.join(\", \")})`,\n );\n root.style.setProperty(\n \"--ff-route-badge-border\",\n `color-mix(in oklab, ${strong[0] || \"#64748b\"} 35%, transparent)`,\n );\n root.style.setProperty(\"--ff-route-outline\", strong[0] || \"#64748b\");\n root.style.setProperty(\"--ff-route-text\", strong[0] || \"#111827\");\n } else {\n root.style.removeProperty(`--${N}-route-gradient`);\n root.style.removeProperty(\"--ff-route-outline-gradient\");\n root.style.removeProperty(\"--ff-route-badge-gradient\");\n root.style.removeProperty(\"--ff-route-badge-border\");\n root.style.removeProperty(\"--ff-route-outline\");\n root.style.removeProperty(\"--ff-route-text\");\n }\n applyAll();\n affSyncRouteChrome(p);\n };\n\n affAfterNav();\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", affAfterNav, {\n once: true,\n });\n }\n document.addEventListener(\"astro:page-load\", affAfterNav);\n document.addEventListener(\"astro:after-swap\", affAfterNav);\n if (typeof MutationObserver === \"function\") {\n const obs = new MutationObserver((muts) => {\n for (let i = 0; i < muts.length; i++) {\n const a = muts[i]?.attributeName;\n if (!a) continue;\n if (\n a === \"style\" ||\n a.indexOf(\"data-ff-enabled-\") === 0 ||\n a.indexOf(\"data-ff-outline-\") === 0 ||\n a.indexOf(\"data-ff-badge-\") === 0\n ) {\n affAfterNav();\n break;\n }\n }\n });\n obs.observe(root, { attributes: true });\n }\n } catch {\n // no-op in injected runtime\n }\n}\n","import {\n elementBadgePositionBlock,\n normalizeElementBadgeLayout,\n} from \"./badge-layout\";\nimport type { ElementBadgeLayoutOptions } from \"./badge-layout\";\nimport { inlineInvoke } from \"./inline-script\";\nimport { affDevBootstrapRuntime } from \"./dev-inline-runtimes\";\nimport type { ResolvedFeatureRuntime } from \"./runtime\";\nimport { toToken } from \"./runtime\";\n\nexport type DevOutlineHiddenStrategy = \"visibility\" | \"display\";\n\nexport interface DevOutlineCssOptions extends ElementBadgeLayoutOptions {\n outlineWidth?: string;\n /** Fallback when no per-token colour is set. */\n outlineColor?: string;\n /** Per-flag-token outline / badge / route-badge colour (overrides JSON `colors`). */\n outlineColorByToken?: Record<string, string>;\n outlineOffset?: string;\n borderRadius?: string;\n\n /** Default pill text for the `wip` flag token in the dev toolbar. */\n badgeLabelWip?: string;\n /** @deprecated Use {@link badgeLabelWip}. */\n badgeLabelDev?: string;\n badgeLabelByToken?: Record<string, string>;\n\n hiddenStrategy?: DevOutlineHiddenStrategy;\n\n /**\n * @deprecated Unused: badge does not use container queries.\n */\n badgeMinInlineSize?: string;\n}\ntype NormalizedDevOutlineCssOptions = {\n outlineWidth: string;\n outlineColor: string;\n outlineColorByToken: Record<string, string>;\n outlineOffset: string;\n borderRadius: string;\n badgeLabelWip: string;\n badgeLabelByToken: Record<string, string>;\n hiddenStrategy: DevOutlineHiddenStrategy;\n badgeMinInlineSize: string;\n};\n\nconst defaultDevOutlineCssOptions: Omit<\n NormalizedDevOutlineCssOptions,\n \"outlineColorByToken\"\n> = {\n outlineWidth: \"2px\",\n outlineColor: \"rgb(220 38 38)\",\n outlineOffset: \"-2px\",\n borderRadius: \"0.5rem\",\n badgeLabelWip: \"wip\",\n badgeLabelByToken: {},\n hiddenStrategy: \"visibility\",\n badgeMinInlineSize: \"8rem\",\n};\n\nfunction normalizeCssOptions(\n css: DevOutlineCssOptions | undefined,\n runtime: ResolvedFeatureRuntime,\n): NormalizedDevOutlineCssOptions {\n const byToken = {\n ...runtime.flagColorsByToken,\n ...(css?.outlineColorByToken ?? {}),\n };\n const badgeLabelWip =\n css?.badgeLabelWip ??\n css?.badgeLabelDev ??\n defaultDevOutlineCssOptions.badgeLabelWip;\n return {\n ...defaultDevOutlineCssOptions,\n ...(css ?? {}),\n outlineColorByToken: byToken,\n badgeLabelWip,\n badgeLabelByToken: {\n ...defaultDevOutlineCssOptions.badgeLabelByToken,\n ...(css?.badgeLabelByToken ?? {}),\n },\n };\n}\n\nfunction colorForToken(\n token: string,\n opts: NormalizedDevOutlineCssOptions,\n): string {\n return opts.outlineColorByToken[token] ?? opts.outlineColor;\n}\n\n/** CSS variable per token, set on &lt;html&gt; from ff.json + dev-toolbar overrides. */\nfunction featureColorVar(token: string, namespace: string): string {\n const ns = toToken(namespace) || \"ff\";\n return `--${ns}-c-${token}`;\n}\n\n/**\n * Dev-only styles: `data-ff=\"token\"` (or space-separated tokens) gates outlines/badges.\n * `html[data-ff-route=\"<token>\"]` (dev) adds a fixed top-right route badge (label only).\n * Toolbar toggles: `data-ff-enabled-*`, `data-ff-outline-*`, `data-ff-badge-*`, `--<namespace>-c-*`.\n */\nexport function createFeatureFlagStyles(\n runtime: ResolvedFeatureRuntime,\n css?: DevOutlineCssOptions,\n): string {\n const nsAttr = `data-${toToken(runtime.namespace) || \"ff\"}`;\n const selectorsForFlag = (flag: string) => {\n const token = toToken(flag);\n const valueSelectors = [`[${nsAttr}~=\"${token}\"]`];\n if (flag !== token) valueSelectors.push(`[${nsAttr}~=\"${flag}\"]`);\n const baseSelectors = [...valueSelectors, `[${nsAttr}-${token}]`];\n return {\n token,\n baseSelectors,\n selOutline: baseSelectors\n .map((s) => `${s}:not([${nsAttr}*=\" \"])`)\n .join(\", \"),\n selIs: `:is(${baseSelectors.join(\", \")})`,\n };\n };\n const opts = normalizeCssOptions(css, runtime);\n const badgeLayout = normalizeElementBadgeLayout(css);\n const badgePos = elementBadgePositionBlock(badgeLayout);\n const chunks: string[] = [];\n\n for (const flag of Object.keys(runtime.flags)) {\n const { token, selOutline, selIs } = selectorsForFlag(flag);\n /** Combo hosts use `[${nsAttr}*=\" \"]` + `data-ff-label`; skip per-token ::before so combo rules win. */\n const selIsSingleBadge = `${selIs}:not([${nsAttr}*=\" \"])`;\n const col = colorForToken(token, opts);\n const v = featureColorVar(token, runtime.namespace);\n const label =\n opts.badgeLabelByToken[token] ??\n (token === \"wip\" ? opts.badgeLabelWip : token);\n const labelEscaped = String(label).replace(/'/g, \"\\\\'\");\n\n chunks.push(`\nhtml {\n --aff-outline-c-${token}: transparent;\n}\nhtml:not([data-ff-outline-${token}=\"off\"]) {\n --aff-outline-c-${token}: var(${v}, ${col});\n}\n${selOutline} {\n position: relative;\n outline: ${opts.outlineWidth} solid var(--aff-outline-c-${token});\n outline-offset: ${opts.outlineOffset};\n border-radius: ${opts.borderRadius};\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}::before {\n box-sizing: border-box;\n position: absolute;\n inset: auto;\n margin: 0;\n width: max-content;\n max-width: min(18rem, calc(100% - 0.75rem));\n pointer-events: auto;\n z-index: 20;\n${badgePos}\n display: block;\n content: '${labelEscaped}';\n border: 1px solid color-mix(in oklab, var(${v}, ${col}) 60%, transparent);\n border-radius: 9999px;\n padding: 0.125rem 0.45rem;\n font-size: 0.625rem;\n line-height: 1.2;\n letter-spacing: 0.02em;\n font-weight: 600;\n color: var(${v}, ${col});\n background: color-mix(in oklab, white 85%, var(${v}, ${col}) 15%);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n transition: opacity 0.14s ease, background 0.14s ease, border-color 0.14s ease;\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}:hover::before {\n opacity: 0.16;\n background: color-mix(in oklab, white 94%, var(${v}, ${col}) 6%);\n border-color: color-mix(in oklab, var(${v}, ${col}) 35%, transparent);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-align=\"start\"]::before {\n left: 0.35rem;\n right: auto;\n transform: translateY(calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-align=\"center\"]::before {\n left: 50%;\n right: auto;\n transform: translate(-50%, calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-align=\"end\"]::before {\n left: auto;\n right: 0.35rem;\n transform: translateY(calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-horizontal]::before {\n left: calc(attr(data-ff-horizontal number, 50) * 1%);\n right: auto;\n transform: translate(-50%, calc(-1 * 80%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-horizontal][data-ff-anchor=\"bottom\"]::before {\n transform: translate(-50%, 80%);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"]::before {\n top: auto;\n bottom: 0;\n transform: translateY(80%);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"][data-ff-align=\"center\"]::before {\n transform: translate(-50%, 80%);\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-vertical]::before {\n transform: translateY(calc(attr(data-ff-vertical number, 80) * -1%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-horizontal][data-ff-vertical]::before {\n transform: translate(-50%, calc(attr(data-ff-vertical number, 80) * -1%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"][data-ff-vertical]::before {\n transform: translateY(calc(attr(data-ff-vertical number, 80) * 1%));\n}\nhtml:not([data-ff-badge-${token}=\"off\"]) ${selIsSingleBadge}[data-ff-anchor=\"bottom\"][data-ff-horizontal][data-ff-vertical]::before {\n transform: translate(-50%, calc(attr(data-ff-vertical number, 80) * 1%));\n}\nhtml[data-ff-enabled-${token}=\"off\"] ${selIs} {\n display: none !important;\n}\n`);\n }\n\n // Multi-token value on a single element: show combined badge text and a gradient outline.\n chunks.push(`\n[${nsAttr}*=\" \"] {\n position: relative;\n outline: none !important;\n outline-offset: 0 !important;\n border-radius: ${opts.borderRadius};\n}\nhtml [${nsAttr}*=\" \"]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 10;\n box-sizing: border-box;\n padding: ${opts.outlineWidth};\n background: var(--ff-combo-gradient, linear-gradient(90deg, #fecaca, #bfdbfe, #bbf7d0));\n -webkit-mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\nhtml [${nsAttr}*=\" \"]::before {\n box-sizing: border-box;\n position: absolute;\n inset: auto;\n margin: 0;\n width: max-content;\n max-width: min(18rem, calc(100% - 0.75rem));\n pointer-events: auto;\n z-index: 20;\n${badgePos}\n display: block;\n content: attr(${nsAttr});\n background: var(--ff-combo-badge-gradient, var(--ff-combo-gradient-soft, linear-gradient(90deg, #fff1f2, #eff6ff, #f0fdf4))) !important;\n color: var(--ff-combo-text, #111827) !important;\n border: 1px solid var(--ff-combo-badge-border, color-mix(in oklab, #94a3b8 50%, transparent)) !important;\n border-radius: 9999px;\n padding: 0.125rem 0.45rem;\n font-size: 0.625rem;\n line-height: 1.2;\n letter-spacing: 0.02em;\n font-weight: 600;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n transition: opacity 0.14s ease, background 0.14s ease, border-color 0.14s ease;\n}\nhtml [${nsAttr}*=\" \"][data-ff-label]::before {\n content: attr(data-ff-label) !important;\n}\nhtml [${nsAttr}*=\" \"]:hover::before {\n opacity: 0.2;\n background: linear-gradient(90deg, #fff8f9, #f8fbff, #f8fff9);\n border-color: color-mix(in oklab, #94a3b8 35%, transparent);\n}\n`);\n\n // Combo chrome must be suppressed *after* generic combo rules so `!important` / order cannot be\n // overridden by `html [...][data-ff-label]::before { content: ... !important }`.\n for (const flag of Object.keys(runtime.flags)) {\n const { token, selIs } = selectorsForFlag(flag);\n chunks.push(`\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"]::before,\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"][data-ff-label]::before {\n display: none !important;\n content: none !important;\n}\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"]:hover::before,\nhtml[data-ff-badge-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"][data-ff-label]:hover::before {\n display: none !important;\n opacity: 1 !important;\n background: none !important;\n border-color: transparent !important;\n}\nhtml[data-ff-outline-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"] {\n outline: none !important;\n outline-offset: 0 !important;\n}\nhtml[data-ff-outline-${token}=\"off\"] ${selIs}[${nsAttr}*=\" \"]::after {\n display: none !important;\n}\n`);\n }\n\n chunks.push(`\n.aff-route-frame {\n position: fixed;\n inset: 0.6rem;\n pointer-events: none;\n z-index: 10040;\n box-sizing: border-box;\n border-radius: 0.5rem;\n overflow: hidden;\n}\n.aff-route-frame::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n padding: 2px;\n background: var(--ff-route-outline-gradient, linear-gradient(90deg, #ef4444, #3b82f6, #22c55e));\n -webkit-mask:\n linear-gradient(#000 0 0) content-box,\n linear-gradient(#000 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\n.aff-route-badge {\n position: fixed;\n top: 0.75rem;\n right: 0.75rem;\n z-index: 10060;\n pointer-events: auto;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n max-width: min(34rem, calc(100vw - 1.5rem));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border: 1px solid var(--ff-route-badge-border, color-mix(in oklab, #94a3b8 55%, transparent));\n border-radius: 9999px;\n padding: 0.15rem 0.5rem;\n font-size: 0.625rem;\n line-height: 1.2;\n letter-spacing: 0.02em;\n font-weight: 600;\n color: var(--ff-route-text, #111827);\n background: var(--ff-route-badge-gradient, linear-gradient(90deg, #fff1f2));\n opacity: 1;\n transition: opacity 0.14s ease, border-color 0.14s ease, background 0.14s ease;\n}\n.aff-route-badge:hover {\n opacity: 0.2;\n border-color: color-mix(in oklab, #94a3b8 35%, transparent);\n}\n.aff-route-disabled-overlay {\n position: fixed;\n inset: 0;\n z-index: 10050;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: clamp(1rem, 4vw, 2.5rem);\n text-align: center;\n font: 600 0.95rem/1.45 system-ui, -apple-system, Segoe UI, sans-serif;\n color: #f8fafc;\n background: rgba(15, 23, 42, 0.52);\n backdrop-filter: blur(2px);\n pointer-events: auto;\n}\n.aff-route-disabled-overlay > p {\n margin: 0;\n max-width: min(44rem, calc(100vw - 2rem));\n white-space: pre-line;\n}\n`);\n\n for (const flag of Object.keys(runtime.flags)) {\n const token = toToken(flag);\n chunks.push(`\n[data-ff-route~=\"${token}\"][data-ff-outline-${token}=\"off\"] #aff-route-frame {\n display: none !important;\n}\n[data-ff-route~=\"${token}\"][data-ff-badge-${token}=\"off\"] #aff-route-badge {\n display: none !important;\n}\n[data-ff-route~=\"${token}\"][data-ff-enabled-${token}=\"off\"] #aff-route-frame {\n display: none !important;\n}\n[data-ff-route~=\"${token}\"][data-ff-enabled-${token}=\"off\"] #aff-route-badge {\n display: none !important;\n}\n`);\n }\n\n return \"\\n\" + chunks.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * CSS-only hiding for disabled flags. The Astro integration no longer injects this into\n * production builds — static HTML is culled instead. Kept for custom tooling or tests.\n */\nexport function createProductionGateStyles(\n runtime: ResolvedFeatureRuntime,\n): string {\n const nsAttr = `data-${toToken(runtime.namespace) || \"ff\"}`;\n const chunks: string[] = [];\n for (const [flag, enabled] of Object.entries(runtime.flags)) {\n if (enabled) continue;\n const token = toToken(flag);\n const valueSelectors = [`[${nsAttr}~=\"${token}\"]`];\n if (flag !== token) valueSelectors.push(`[${nsAttr}~=\"${flag}\"]`);\n chunks.push(\n `${[...valueSelectors, `[${nsAttr}-${token}]`].join(\", \")} { display: none !important; }`,\n );\n }\n return chunks.length ? `\\n${chunks.join(\"\\n\")}\\n` : \"\";\n}\n\nexport function buildAffDevBootstrapScript(\n flagTokens: string[],\n colors: Record<string, string>,\n outlineDefaults: Record<string, boolean>,\n badgeDefaults: Record<string, boolean>,\n routeFlags: Record<string, string[]>,\n flagNameToToken: Record<string, string>,\n namespace: string,\n): string {\n return inlineInvoke(affDevBootstrapRuntime, {\n flagTokens,\n colors,\n outlineDefaults,\n badgeDefaults,\n routeFlags,\n flagNameToToken,\n namespace: toToken(namespace) || \"ff\",\n });\n}\n","import { readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { parse, type HTMLElement } from \"node-html-parser\";\nimport type { ResolvedFeatureRuntime } from \"./runtime\";\nimport { toToken } from \"./runtime\";\n\nfunction walkHtmlFiles(dir: string): string[] {\n const out: string[] = [];\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const ent of entries) {\n const p = join(dir, ent.name);\n if (ent.isDirectory()) out.push(...walkHtmlFiles(p));\n else if (ent.isFile() && ent.name.endsWith(\".html\")) out.push(p);\n }\n return out;\n}\n\nfunction namespaceAttrName(namespace: string): string {\n return `data-${toToken(namespace) || \"ff\"}`;\n}\n\nfunction elementFlagSlugs(\n el: HTMLElement,\n nsAttr: string,\n knownTokens: readonly string[],\n): string[] {\n const slugSet = new Set<string>();\n const combined = el.getAttribute(nsAttr)?.trim();\n if (combined) {\n for (const part of combined.split(/\\s+/).filter(Boolean)) {\n slugSet.add(part);\n }\n }\n for (const tk of knownTokens) {\n if (el.hasAttribute(`${nsAttr}-${tk}`)) slugSet.add(tk);\n }\n return [...slugSet];\n}\n\nfunction slugToFlagNames(slug: string, flagNames: readonly string[]): string[] {\n const out: string[] = [];\n for (const name of flagNames) {\n if (slug === name || slug === toToken(name)) out.push(name);\n }\n return out;\n}\n\nfunction shouldCullElement(\n el: HTMLElement,\n runtime: ResolvedFeatureRuntime,\n nsAttr: string,\n knownTokens: readonly string[],\n flagNames: readonly string[],\n): boolean {\n const slugs = elementFlagSlugs(el, nsAttr, knownTokens);\n if (slugs.length === 0) return false;\n for (const slug of slugs) {\n const names = slugToFlagNames(slug, flagNames);\n if (names.length === 0) return false;\n }\n for (const slug of slugs) {\n const names = slugToFlagNames(slug, flagNames);\n for (const name of names) {\n if (!runtime.flags[name]) return true;\n }\n }\n return false;\n}\n\nfunction elementDepth(el: HTMLElement): number {\n let d = 0;\n let n: HTMLElement | null = el.parentNode as HTMLElement | null;\n while (n) {\n d++;\n n = n.parentNode as HTMLElement | null;\n }\n return d;\n}\n\n/**\n * Production static HTML: remove nodes gated by disabled flags (same rules as dev\n * `data-*` / `data-*-<token>`), strip dev-only route attributes on `<html>`, and drop\n * empty `<style>` tags left after `featureFlagStyles` is empty.\n */\nexport function cullProductionHtml(\n html: string,\n runtime: ResolvedFeatureRuntime,\n): string {\n const root = parse(html) as HTMLElement;\n const nsAttr = namespaceAttrName(runtime.namespace);\n const flagNames = Object.keys(runtime.flags);\n const knownTokens = flagNames.map((n) => toToken(n));\n\n const candidates = root.querySelectorAll(\"*\") as unknown as HTMLElement[];\n const toRemove: HTMLElement[] = [];\n for (const el of candidates) {\n if (shouldCullElement(el, runtime, nsAttr, knownTokens, flagNames)) {\n toRemove.push(el);\n }\n }\n toRemove.sort((a, b) => elementDepth(b) - elementDepth(a));\n for (const el of toRemove) {\n el.remove();\n }\n\n const htmlEl = root.querySelector(\"html\") as HTMLElement | null;\n if (htmlEl) {\n htmlEl.removeAttribute(\"data-ff-route\");\n htmlEl.removeAttribute(\"data-ff-route-label\");\n }\n\n const styles = root.querySelectorAll(\"style\") as unknown as HTMLElement[];\n for (const st of styles) {\n const text = st.textContent ?? \"\";\n if (!text.trim()) st.remove();\n }\n\n return root.outerHTML;\n}\n\n/**\n * Walk `outDir` (e.g. Astro `dist/`) and apply {@link cullProductionHtml} to every `.html` file.\n */\nexport function applyProductionHtmlCullToDist(\n outDir: string,\n runtime: ResolvedFeatureRuntime,\n): void {\n for (const file of walkHtmlFiles(outDir)) {\n const before = readFileSync(file, \"utf8\");\n const after = cullProductionHtml(before, runtime);\n if (after !== before) writeFileSync(file, after, \"utf8\");\n }\n}\n","import type { ResolvedFeatureRuntime } from \"./runtime\";\nimport { toToken } from \"./runtime\";\nimport { inlineInvoke } from \"./inline-script\";\nimport { affHeadInlineRuntime } from \"./dev-inline-runtimes\";\n\n/**\n * Single `injectScript('head-inline', …)` payload for `astro dev`: dev-only outline CSS,\n * `data-ff-route` on `<html>` (pathname + {@link ResolvedFeatureRuntime.routeFlags}), then\n * the feature-flag dev bootstrap (toolbar state, combo badges, route chrome).\n */\nexport function buildAffDevHeadInline(args: {\n runtime: ResolvedFeatureRuntime;\n featureFlagStyles: string;\n affDevBootstrap: string;\n}): string {\n const { runtime, featureFlagStyles, affDevBootstrap } = args;\n const flagNameToToken = Object.fromEntries(\n Object.keys(runtime.flags).map((name) => [name, toToken(name)]),\n );\n const setup = inlineInvoke(affHeadInlineRuntime, {\n featureFlagStyles,\n routeFlags: runtime.routeFlags,\n flagNameToToken,\n });\n return `${setup}\\n${affDevBootstrap}`;\n}\n","/**\n * Shared JS helper source used by generated browser scripts.\n * Keep this in sync with runtime.routePatternToPrefix semantics.\n */\nexport function routePrefixJsHelper(functionName: string): string {\n return `function ${functionName}(pattern){var p=String(pattern||'').trim();if(p.endsWith('/**'))p=p.slice(0,-3);else if(p.endsWith('/*'))p=p.slice(0,-2);else if(p.length>1&&p.endsWith('*'))p=p.slice(0,-1);return p.endsWith('/')?p:p+'/';}`;\n}\n","import { rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n elementBadgePositionBlock,\n normalizeElementBadgeLayout,\n} from \"./badge-layout\";\nimport { DEV_TOOLBAR_FLAG_ICON_SVG } from \"./dev-toolbar-flag-icon\";\nimport type {\n ElementBadgeHorizontalAlign,\n ElementBadgeLayoutOptions,\n ElementBadgeVerticalAnchor,\n NormalizedElementBadgeLayout,\n} from \"./badge-layout\";\nimport {\n type FeatureFlagMap,\n type ResolveFeatureRuntimeOptions,\n type ResolvedFeatureRuntime,\n resolveFeatureFlagsByEnvironment,\n resolveFeatureRuntime,\n routePathsToPrune,\n shouldIncludeRoute,\n toEnumKey,\n toToken,\n} from \"./runtime\";\n\nexport type {\n ElementBadgeHorizontalAlign,\n ElementBadgeLayoutOptions,\n ElementBadgeVerticalAnchor,\n NormalizedElementBadgeLayout,\n};\nexport { elementBadgePositionBlock, normalizeElementBadgeLayout };\n\nexport type {\n DevOutlineCssOptions,\n DevOutlineHiddenStrategy,\n} from \"./dev-outline-css\";\n\nimport type { DevOutlineCssOptions } from \"./dev-outline-css\";\nimport {\n buildAffDevBootstrapScript,\n createFeatureFlagStyles,\n createProductionGateStyles,\n} from \"./dev-outline-css\";\nimport { applyProductionHtmlCullToDist } from \"./production-html-cull\";\nimport { buildAffDevHeadInline } from \"./dev-head-inject\";\nimport { routePrefixJsHelper } from \"./route-prefix-js\";\n\nexport { createFeatureFlagStyles, createProductionGateStyles };\nexport {\n cullProductionHtml,\n applyProductionHtmlCullToDist,\n} from \"./production-html-cull\";\n\nexport interface AstroFeatureFlagsOptions extends ResolveFeatureRuntimeOptions {\n css?: DevOutlineCssOptions;\n /** When false, keeps static build output untouched (no route pruning / HTML cull). */\n staticMinify?: boolean;\n}\n\n/** Prefer `prod` if present; else first non-`dev` key (sorted); else `\"prod\"`. */\nexport function primaryNonDevEnvironmentKey(\n flagsByEnvironment: Record<string, FeatureFlagMap>,\n): string {\n const keys = Object.keys(flagsByEnvironment);\n if (keys.includes(\"prod\")) return \"prod\";\n const nonDev = keys.filter((k) => k !== \"dev\").sort();\n return nonDev[0] ?? \"prod\";\n}\n\nfunction withDefaultEnvironments(\n options: ResolveFeatureRuntimeOptions = {},\n): ResolveFeatureRuntimeOptions {\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const raw =\n options.environments &&\n typeof options.environments === \"object\" &&\n !Array.isArray(options.environments)\n ? { ...options.environments }\n : {};\n delete raw.dev;\n const environments: NonNullable<\n ResolveFeatureRuntimeOptions[\"environments\"]\n > = {\n dev: {\n when: mode !== \"production\",\n },\n ...raw,\n };\n if (Object.keys(environments).length < 2) {\n environments.prod = environments.prod ?? {\n when: mode === \"production\",\n flags: {},\n };\n }\n return { ...options, environments };\n}\n\nexport function createVirtualModuleSource(\n runtime: ResolvedFeatureRuntime,\n css?: DevOutlineCssOptions,\n flagsByEnvironment: Record<string, FeatureFlagMap> = {},\n devBootstrap?: string,\n): string {\n const flagNames = Object.keys(runtime.flags);\n const flagTokens = flagNames.map((name) => toToken(name));\n const enumEntries = flagNames\n .map((name) => ` ${toEnumKey(name)}: ${JSON.stringify(name)}`)\n .join(\",\\n\");\n const tokenEntries = flagNames\n .map((name) => ` ${toEnumKey(name)}: ${JSON.stringify(toToken(name))}`)\n .join(\",\\n\");\n const styles = createFeatureFlagStyles(runtime, css);\n const colorsJson = JSON.stringify(runtime.flagColorsByToken, null, 2);\n const flagNameToToken = JSON.stringify(\n Object.fromEntries(flagNames.map((name) => [name, toToken(name)])),\n null,\n 2,\n );\n const defaultNonDevEnvironment =\n primaryNonDevEnvironmentKey(flagsByEnvironment);\n const bootstrap =\n devBootstrap ??\n buildAffDevBootstrapScript(\n flagTokens,\n { ...runtime.flagColorsByToken },\n { ...runtime.flagOutlineDefaultsByToken },\n { ...runtime.flagBadgeDefaultsByToken },\n { ...runtime.routeFlags },\n Object.fromEntries(flagNames.map((name) => [name, toToken(name)])),\n runtime.namespace,\n );\n const affRoutePatternToPrefix = routePrefixJsHelper(\n \"affRoutePatternToPrefix\",\n );\n\n return `${affRoutePatternToPrefix}\n\nexport const FeatureFlag = Object.freeze({\n${enumEntries}\n});\n\nexport const FeatureToken = Object.freeze({\n${tokenEntries}\n});\n\nexport const featureFlagTokens = Object.freeze(${JSON.stringify(flagTokens)});\nexport const featureFlagColors = Object.freeze(${colorsJson});\nexport const featureFlags = Object.freeze(${JSON.stringify(runtime.flags, null, 2)});\nexport const featureFlagsByEnvironment = Object.freeze(${JSON.stringify(flagsByEnvironment, null, 2)});\nexport const defaultNonDevEnvironment = ${JSON.stringify(defaultNonDevEnvironment)};\nexport const featureRouteFlags = Object.freeze(${JSON.stringify(runtime.routeFlags, null, 2)});\nexport const featureNamespace = ${JSON.stringify(runtime.namespace)};\n/** True when Astro is running the dev server or dev build (import.meta.env.DEV). Not the same as the reserved \\`dev\\` environment layer — see \\`activeEnvironmentKey\\`. */\nexport const isAstroDev = import.meta.env.DEV;\nexport const activeEnvironmentKey = ${JSON.stringify(runtime.activeEnvironment)};\n\nexport const affDevBootstrap = import.meta.env.DEV ? ${JSON.stringify(bootstrap)} : '';\n\nexport function isFeatureEnabled(flag) {\n return Boolean(featureFlags[flag]);\n}\n\nexport function shouldRenderFeature(flag) {\n return isFeatureEnabled(flag);\n}\n\nexport function isFeatureRoute(pathname) {\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n return Object.keys(featureRouteFlags).some((route) => {\n const candidate = affRoutePatternToPrefix(route);\n return normalized === candidate || normalized.startsWith(candidate);\n });\n}\n\nexport function shouldIncludePath(pathname) {\n if (import.meta.env.DEV) return true;\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n for (const [route, flags] of Object.entries(featureRouteFlags)) {\n const candidate = affRoutePatternToPrefix(route);\n if (normalized === candidate || normalized.startsWith(candidate)) {\n return flags.every((flag) => isFeatureEnabled(flag));\n }\n }\n return true;\n}\n\nexport function flagsForEnvironment(envName) {\n var F = featureFlagsByEnvironment[envName];\n return F != null ? F : null;\n}\n\nexport function isFeatureEnabledForEnvironment(flag, envName) {\n var F = featureFlagsByEnvironment[envName];\n return !!(F && F[flag]);\n}\n\nexport function shouldIncludePathForEnvironment(pathname, envName) {\n var F = featureFlagsByEnvironment[envName];\n if (!F) return true;\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n for (const [route, flagList] of Object.entries(featureRouteFlags)) {\n const candidate = affRoutePatternToPrefix(route);\n if (normalized === candidate || normalized.startsWith(candidate)) {\n return flagList.every((flag) => Boolean(F[flag]));\n }\n }\n return true;\n}\n\nconst flagNameToToken = Object.freeze(${flagNameToToken});\n\nexport function matchedFeatureRoutePrefix(pathname) {\n if (!pathname) return null;\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n let best = null;\n let bestLen = -1;\n for (const routePrefix of Object.keys(featureRouteFlags)) {\n const route = affRoutePatternToPrefix(routePrefix);\n if (normalized === route || normalized.startsWith(route)) {\n if (route.length > bestLen) {\n bestLen = route.length;\n best = routePrefix;\n }\n }\n }\n return best;\n}\n\nexport function routeFeatureTokenForPath(pathname) {\n const prefix = matchedFeatureRoutePrefix(pathname);\n if (!prefix) return undefined;\n const flagNames = featureRouteFlags[prefix] || [];\n const first = flagNames[0];\n return first != null ? flagNameToToken[first] : undefined;\n}\n\nexport function routeFeatureTokensForPath(pathname) {\n if (!pathname) return [];\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n const out = [];\n const seen = new Set();\n for (const [routePrefix, flagNames] of Object.entries(featureRouteFlags)) {\n const route = affRoutePatternToPrefix(routePrefix);\n if (!(normalized === route || normalized.startsWith(route))) continue;\n for (const name of flagNames || []) {\n const token = flagNameToToken[name];\n if (!token || seen.has(token)) continue;\n seen.add(token);\n out.push(token);\n }\n }\n return out;\n}\n\nexport function routeFeatureMatchesForPath(pathname) {\n if (!pathname) return [];\n const normalized = pathname.endsWith('/') ? pathname : pathname + '/';\n var byFlag = {};\n for (const [routePattern, flagNames] of Object.entries(featureRouteFlags)) {\n const candidate = affRoutePatternToPrefix(routePattern);\n if (!(normalized === candidate || normalized.startsWith(candidate))) continue;\n for (const flagName of flagNames || []) {\n const token = flagNameToToken[flagName];\n if (!token) continue;\n if (!byFlag[flagName]) byFlag[flagName] = { flag: flagName, token, routes: [] };\n byFlag[flagName].routes.push(routePattern);\n }\n }\n return Object.values(byFlag);\n}\n\nexport const featureFlagStyles = import.meta.env.DEV ? ${JSON.stringify(styles)} : \"\";\n`;\n}\n\nexport function getResolvedFeatures(\n options: ResolveFeatureRuntimeOptions = {},\n): ResolvedFeatureRuntime {\n return resolveFeatureRuntime(withDefaultEnvironments(options));\n}\n\nexport function featureRouteIncluded(\n pathname: string,\n runtime: ResolvedFeatureRuntime,\n): boolean {\n return shouldIncludeRoute({\n pathname,\n routeFlags: runtime.routeFlags,\n flags: runtime.flags,\n isDev: runtime.isDev,\n });\n}\n\nexport type { FeatureFlagMap } from \"./runtime\";\nexport {\n longestMatchingRoutePrefix,\n mergeFlagsWithProcessEnvOverrides,\n resolveFeatureFlagsByEnvironment,\n routePatternToPrefix,\n} from \"./runtime\";\n\nexport default function astroFeatureFlags(\n options: AstroFeatureFlagsOptions = {},\n): any {\n const { css, staticMinify = true, ...flagOpts } = options;\n const opts = withDefaultEnvironments(flagOpts);\n const mode = opts.mode ?? process.env.NODE_ENV ?? \"development\";\n\n const runtime = resolveFeatureRuntime({\n ...opts,\n mode,\n });\n\n return {\n name: \"astro-feature-flags\",\n hooks: {\n \"astro:config:setup\": ({\n updateConfig,\n addDevToolbarApp,\n command,\n injectScript,\n }: {\n updateConfig: (config: unknown) => void;\n addDevToolbarApp?: (opts: {\n id: string;\n name: string;\n icon: string;\n entrypoint: string;\n }) => void;\n command?: string;\n injectScript?: (stage: string, content: string) => void;\n }) => {\n const flagNames = Object.keys(runtime.flags);\n const flagTokens = flagNames.map((name) => toToken(name));\n const flagsByEnvironment = resolveFeatureFlagsByEnvironment(opts);\n const flagNameToToken = Object.fromEntries(\n flagNames.map((name) => [name, toToken(name)]),\n );\n const bootstrap = buildAffDevBootstrapScript(\n flagTokens,\n { ...runtime.flagColorsByToken },\n { ...runtime.flagOutlineDefaultsByToken },\n { ...runtime.flagBadgeDefaultsByToken },\n { ...runtime.routeFlags },\n flagNameToToken,\n runtime.namespace,\n );\n\n if (\n command === \"dev\" &&\n runtime.isDev &&\n typeof addDevToolbarApp === \"function\"\n ) {\n addDevToolbarApp({\n id: \"astro-feature-flags\",\n name: \"Feature flags\",\n icon: DEV_TOOLBAR_FLAG_ICON_SVG,\n entrypoint: fileURLToPath(\n new URL(\"./dev-toolbar-app.mjs\", import.meta.url),\n ),\n });\n }\n if (\n command === \"dev\" &&\n runtime.isDev &&\n typeof injectScript === \"function\"\n ) {\n const styles = createFeatureFlagStyles(runtime, css);\n injectScript(\n \"head-inline\",\n buildAffDevHeadInline({\n runtime,\n featureFlagStyles: styles,\n affDevBootstrap: bootstrap,\n }),\n );\n }\n updateConfig({\n vite: {\n plugins: [\n {\n name: \"astro-feature-flags:virtual-module\",\n resolveId(id: string) {\n if (id === \"virtual:astro-feature-flags\")\n return \"\\0virtual:astro-feature-flags\";\n return null;\n },\n load(id: string) {\n if (id === \"\\0virtual:astro-feature-flags\") {\n return createVirtualModuleSource(\n runtime,\n css,\n flagsByEnvironment,\n bootstrap,\n );\n }\n return null;\n },\n },\n ],\n },\n });\n },\n \"astro:build:done\": ({ dir }: { dir: URL }) => {\n if (runtime.isDev || !staticMinify) return;\n const outDir = fileURLToPath(dir);\n const prunePaths = routePathsToPrune({\n routeFlags: runtime.routeFlags,\n flags: runtime.flags,\n });\n for (const routePath of prunePaths) {\n rmSync(join(outDir, routePath), { recursive: true, force: true });\n }\n applyProductionHtmlCullToDist(outDir, runtime);\n },\n },\n };\n}\n"],"mappings":"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"}
@@ -49,7 +49,8 @@ interface ResolveFeatureRuntimeOptions {
49
49
  }>;
50
50
  environments?: Record<string, {
51
51
  when?: boolean;
52
- flags?: Record<string, boolean>; /** Optional JSON merged after the root file when this environment is active. */
52
+ flags?: Record<string, boolean>;
53
+ /** Optional JSON merged after the root file when this environment is active. */
53
54
  jsonConfigPath?: string;
54
55
  }>;
55
56
  }
@@ -88,21 +89,13 @@ interface ResolvedFeatureRuntime {
88
89
  declare function resolveFeatureRuntime(options?: ResolveFeatureRuntimeOptions): ResolvedFeatureRuntime;
89
90
  declare function isFlagEnabled(flags: FeatureFlagMap, flag: string): boolean;
90
91
  declare function isRouteFlagged(pathname: string, routeFlags: FeatureRouteMap): boolean;
91
- declare function shouldIncludeRoute({
92
- pathname,
93
- routeFlags,
94
- flags,
95
- isDev
96
- }: {
92
+ declare function shouldIncludeRoute({ pathname, routeFlags, flags, isDev }: {
97
93
  pathname: string;
98
94
  routeFlags: FeatureRouteMap;
99
95
  flags: FeatureFlagMap;
100
96
  isDev: boolean;
101
97
  }): boolean;
102
- declare function routePathsToPrune({
103
- routeFlags,
104
- flags
105
- }: {
98
+ declare function routePathsToPrune({ routeFlags, flags }: {
106
99
  routeFlags: FeatureRouteMap;
107
100
  flags: FeatureFlagMap;
108
101
  }): string[];
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/runtime.ts"],"mappings":";KAGY,cAAA,GAAiB,MAAA;AAAA,KACjB,eAAA,GAAkB,MAAA;AAAA,KAClB,eAAA,GAAkB,MAAA;AAAA,KAClB,qBAAA,GAAwB,MAAA;AAAA,UAEnB,aAAA;EACf,SAAA;EACA,KAAA,EAAO,cAAA;EACP,UAAA,EAAY,eAAA;EACZ,MAAA,EAAQ,eAAA;EACR,sBAAA,EAAwB,qBAAA;EACxB,oBAAA,EAAsB,qBAAA;EACtB,IAAA;EAVyB;EAYzB,iBAAA;AAAA;;AAXF;;;;;AAEA;;;UAqBiB,4BAAA;EAlBH;;;;EAuBZ,UAAA;EApB2C;EAsB3C,cAAA;EA1BA;EA4BA,IAAA;EA3BA;EA6BA,GAAA,GAAM,MAAA;EA5BN;;;EAgCA,gBAAA;EACA,cAAA;EACA,KAAA,GAAQ,MAAA;IAGJ,KAAA;IACA,MAAA;IACA,OAAA;IACA,KAAA;IACA,MAAA;EAAA;EAGJ,YAAA,GAAe,MAAA;IAGX,IAAA;IACA,KAAA,GAAQ,MAAA;IAER,cAAA;EAAA;AAAA;AAAA,iBAmBU,aAAA,CAAc,QAAA;;;;;iBASd,oBAAA,CAAqB,OAAA;AAAA,iBAYrB,SAAA,CAAU,QAAA;AAAA,iBASV,OAAA,CAAQ,QAAA;AAAA,iBAiPR,iBAAA,CACd,OAAA,GAAS,4BAAA,GACR,aAAA;;iBA2Ca,iCAAA,CACd,KAAA,EAAO,cAAA,EACP,GAAA,GAAK,MAAA,+BAIJ,cAAA;;;;;iBAyBa,gCAAA,CACd,OAAA,GAAS,4BAAA,GACR,MAAA,SAAe,cAAA;;iBAkBF,gBAAA,CACd,MAAA,EAAQ,eAAA,GACP,MAAA;AAAA,UAQc,sBAAA;EACf,SAAA;EACA,IAAA;EA9YkB;EAgZlB,KAAA;EACA,iBAAA;EACA,KAAA,EAAO,cAAA;EACP,UAAA,EAAY,eAAA;EAhYgC;EAkY5C,iBAAA,EAAmB,MAAA;EAzXe;EA2XlC,0BAAA,EAA4B,MAAA;EAC5B,wBAAA,EAA0B,MAAA;AAAA;AAAA,iBAGZ,qBAAA,CACd,OAAA,GAAS,4BAAA,GACR,sBAAA;AAAA,iBAuBa,aAAA,CAAc,KAAA,EAAO,cAAA,EAAgB,IAAA;AAAA,iBAIrC,cAAA,CACd,QAAA,UACA,UAAA,EAAY,eAAA;AAAA,iBASE,kBAAA,CAAA;EACd,QAAA;EACA,UAAA;EACA,KAAA;EACA;AAAA;EAEA,QAAA;EACA,UAAA,EAAY,eAAA;EACZ,KAAA,EAAO,cAAA;EACP,KAAA;AAAA;AAAA,iBAec,iBAAA,CAAA;EACd,UAAA;EACA;AAAA;EAEA,UAAA,EAAY,eAAA;EACZ,KAAA,EAAO,cAAA;AAAA;;;;iBAeO,0BAAA,CACd,QAAA,UACA,UAAA,EAAY,eAAA"}
1
+ {"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/runtime.ts"],"mappings":";KAGY,iBAAiB;KACjB,kBAAkB;KAClB,kBAAkB;KAClB,wBAAwB;UAEnB;EACf;EACA,OAAO;EACP,YAAY;EACZ,QAAQ;EACR,wBAAwB;EACxB,sBAAsB;EACtB;;EAEA;;;;;;;;;;;UAYe;;;;;EAKf;;EAEA;;EAEA;;EAEA,MAAM;;;;EAIN;EACA;EACA,QAAQ;IAGJ;IACA;IACA;IACA;IACA;;EAGJ,eAAe;IAGX;IACA,QAAQ;;IAER;;;iBAmBU,cAAc;;;;;iBASd,qBAAqB;iBAYrB,UAAU;iBASV,QAAQ;iBAsPR,kBACd,UAAS,+BACR;;iBA2Ca,kCACd,OAAO,gBACP,MAAK,qCAIJ;;;;;iBAyBa,iCACd,UAAS,+BACR,eAAe;;iBAmBF,iBACd,QAAQ,kBACP;UAQc;EACf;EACA;;EAEA;EACA;EACA,OAAO;EACP,YAAY;;EAEZ,mBAAmB;;EAEnB,4BAA4B;EAC5B,0BAA0B;;iBAGZ,sBACd,UAAS,+BACR;iBAwBa,cAAc,OAAO,gBAAgB;iBAIrC,eACd,kBACA,YAAY;iBASE,qBACd,UACA,YACA,OACA;EAEA;EACA,YAAY;EACZ,OAAO;EACP;;iBAec,oBACd,YACA;EAEA,YAAY;EACZ,OAAO;;;;;iBAeO,2BACd,kBACA,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.mjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\n\nexport type FeatureFlagMap = Record<string, boolean>;\nexport type FeatureRouteMap = Record<string, string[]>;\nexport type FeatureColorMap = Record<string, string>;\nexport type FeatureBoolByTokenMap = Record<string, boolean>;\n\nexport interface FeatureConfig {\n namespace: string;\n flags: FeatureFlagMap;\n routeFlags: FeatureRouteMap;\n colors: FeatureColorMap;\n outlineDefaultsByToken: FeatureBoolByTokenMap;\n badgeDefaultsByToken: FeatureBoolByTokenMap;\n mode: string;\n /** Which `environments` entry was used (reserved `dev` = all flags on, toolbar layer). */\n activeEnvironment: string;\n}\n\n/**\n * Declarative feature flags for Astro. Merge order: inline options → optional root\n * {@link ResolveFeatureRuntimeOptions.jsonConfigPath} → optional per-environment\n * `environments.<name>.jsonConfigPath` (merged when that layer is active).\n *\n * Exactly one `when: true` across environments unless `forceEnvironment` or `AFF_ENVIRONMENT`\n * selects the layer. A reserved **`dev`** environment is required (all flags on at resolve time;\n * toggles are dev-toolbar only) plus at least one other environment (e.g. `prod`).\n */\nexport interface ResolveFeatureRuntimeOptions {\n /**\n * Directory used to resolve relative {@link jsonConfigPath} values (root and per-environment).\n * Defaults to `process.cwd()`.\n */\n configRoot?: string;\n /** Optional main JSON file merged after inline `flags` / `environments`. */\n jsonConfigPath?: string;\n /** Passed through to `ResolvedFeatureRuntime.mode` (e.g. `process.env.NODE_ENV`). */\n mode?: string;\n /** Process env for `AFF_FEATURE_*` and `ASTRO_FEATURE_FLAGS` (skipped when active env is `dev`). */\n env?: Record<string, string | undefined>;\n /**\n * Use this `environments` entry regardless of `when` / `AFF_ENVIRONMENT` (e.g. sitemaps, tests).\n */\n forceEnvironment?: string;\n tokenNamespace?: string;\n flags?: Record<\n string,\n {\n color?: string;\n colour?: string;\n outline?: boolean;\n badge?: boolean;\n routes?: string[];\n }\n >;\n environments?: Record<\n string,\n {\n when?: boolean;\n flags?: Record<string, boolean>;\n /** Optional JSON merged after the root file when this environment is active. */\n jsonConfigPath?: string;\n }\n >;\n}\n\nfunction toBoolean(value: unknown, fallback = false): boolean {\n if (typeof value === \"boolean\") return value;\n if (typeof value !== \"string\") return fallback;\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"0\", \"false\", \"no\", \"off\"].includes(normalized)) return false;\n return fallback;\n}\n\nfunction readJsonIfExists(pathname: string): Record<string, unknown> {\n if (!existsSync(pathname)) return {};\n return JSON.parse(readFileSync(pathname, \"utf8\")) as Record<string, unknown>;\n}\n\nexport function normalizePath(pathname: string): string {\n if (!pathname) return \"/\";\n return pathname.endsWith(\"/\") ? pathname : `${pathname}/`;\n}\n\n/**\n * Normalizes a route key from `ff.json` for prefix matching.\n * Supports wildcards: `/blog/*`, `/docs/**` → prefix `/blog/`, `/docs/`.\n */\nexport function routePatternToPrefix(pattern: string): string {\n let p = pattern.trim();\n if (p.endsWith(\"/**\")) {\n p = p.slice(0, -3);\n } else if (p.endsWith(\"/*\")) {\n p = p.slice(0, -2);\n } else if (p.endsWith(\"*\") && p.length > 1) {\n p = p.slice(0, -1);\n }\n return normalizePath(p);\n}\n\nexport function toEnumKey(flagName: string): string {\n return flagName\n .replace(/[^a-zA-Z0-9]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n}\n\nexport function toToken(flagName: string): string {\n return flagName\n .replace(/[^a-zA-Z0-9]+/g, \"-\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/([a-zA-Z])([0-9])/g, \"$1-$2\")\n .replace(/([0-9])([a-zA-Z])/g, \"$1-$2\")\n .toLowerCase()\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nfunction mergeRecords<T extends Record<string, unknown>>(\n base: T,\n ...layers: Partial<T>[]\n): T {\n const out = { ...base };\n for (const layer of layers) {\n for (const [k, v] of Object.entries(layer)) {\n if (v === undefined) continue;\n const cur = out[k as keyof T];\n if (\n v &&\n typeof v === \"object\" &&\n !Array.isArray(v) &&\n cur &&\n typeof cur === \"object\" &&\n !Array.isArray(cur)\n ) {\n (out as Record<string, unknown>)[k] = mergeRecords(\n cur as Record<string, unknown>,\n v as Record<string, unknown>,\n );\n } else {\n (out as Record<string, unknown>)[k] = v;\n }\n }\n }\n return out;\n}\n\nfunction resolvePath(relativeOrAbsolute: string, configRoot: string): string {\n return isAbsolute(relativeOrAbsolute)\n ? relativeOrAbsolute\n : join(configRoot, relativeOrAbsolute);\n}\n\ntype NormalizedFlagDef = {\n color?: string;\n outline: boolean;\n badge: boolean;\n routes: string[];\n};\n\ntype NormalizedEnvEntry = {\n when?: boolean;\n flags: Record<string, boolean>;\n /** Per-environment JSON merged after root `jsonConfigPath` when this layer is active. */\n jsonConfigPath?: string;\n};\n\ntype DeclarativeFeatureConfig = {\n tokenNamespace: string;\n flags: Record<string, NormalizedFlagDef>;\n environments: Record<string, NormalizedEnvEntry>;\n};\n\nfunction normalizeDeclarativeConfig(\n raw: Record<string, unknown>,\n mode: string = process.env.NODE_ENV ?? \"development\",\n): DeclarativeFeatureConfig {\n const tokenNamespaceRaw =\n (typeof raw.tokenNamespace === \"string\" ? raw.tokenNamespace : undefined) ??\n (typeof raw.namespace === \"string\" ? raw.namespace : undefined) ??\n \"ff\";\n\n const flagsRaw =\n raw.flags && typeof raw.flags === \"object\" && !Array.isArray(raw.flags)\n ? (raw.flags as Record<string, unknown>)\n : {};\n const flags: Record<string, NormalizedFlagDef> = {};\n for (const [flagName, maybeDef] of Object.entries(flagsRaw)) {\n if (!maybeDef || typeof maybeDef !== \"object\" || Array.isArray(maybeDef))\n continue;\n const def = maybeDef as Record<string, unknown>;\n const color =\n (typeof def.colour === \"string\" ? def.colour : undefined) ??\n (typeof def.color === \"string\" ? def.color : undefined);\n const outline = typeof def.outline === \"boolean\" ? def.outline : true;\n const badge = typeof def.badge === \"boolean\" ? def.badge : true;\n const routes = Array.isArray(def.routes)\n ? def.routes.filter((v): v is string => typeof v === \"string\")\n : [];\n flags[flagName] = { color, outline, badge, routes };\n }\n\n const envRaw =\n raw.environments &&\n typeof raw.environments === \"object\" &&\n !Array.isArray(raw.environments)\n ? (raw.environments as Record<string, unknown>)\n : {};\n const environments: Record<string, NormalizedEnvEntry> = {};\n for (const [envName, maybeEnv] of Object.entries(envRaw)) {\n if (envName === \"dev\") continue;\n if (!maybeEnv || typeof maybeEnv !== \"object\" || Array.isArray(maybeEnv))\n continue;\n const env = maybeEnv as Record<string, unknown>;\n const envFlagsRaw =\n env.flags && typeof env.flags === \"object\" && !Array.isArray(env.flags)\n ? (env.flags as Record<string, unknown>)\n : {};\n const envFlags: Record<string, boolean> = {};\n for (const [flagName, value] of Object.entries(envFlagsRaw)) {\n envFlags[flagName] = Boolean(value);\n }\n const when = typeof env.when === \"boolean\" ? env.when : undefined;\n const layerJson =\n typeof env.jsonConfigPath === \"string\" ? env.jsonConfigPath : undefined;\n environments[envName] = {\n ...(when !== undefined ? { when } : {}),\n ...(layerJson ? { jsonConfigPath: layerJson } : {}),\n flags: envFlags,\n };\n }\n\n environments.dev = {\n when: mode !== \"production\",\n flags: {},\n };\n\n return {\n tokenNamespace: tokenNamespaceRaw,\n flags,\n environments,\n };\n}\n\nfunction assertEnvironmentShape(environments: Record<string, NormalizedEnvEntry>) {\n const keys = Object.keys(environments);\n if (!environments.dev) {\n throw new Error(\n 'astro-feature-flags: environments must include a reserved \"dev\" entry.',\n );\n }\n if (keys.length < 2) {\n throw new Error(\n \"astro-feature-flags: environments must include `dev` plus at least one other layer (e.g. `prod`).\",\n );\n }\n}\n\nfunction countActiveWhen(environments: Record<string, NormalizedEnvEntry>): number {\n return Object.values(environments).filter((e) => e.when === true).length;\n}\n\nfunction resolveAffEnvironment(\n options: ResolveFeatureRuntimeOptions,\n): string | undefined {\n const proc =\n options.env ?? (process.env as Record<string, string | undefined>);\n return proc.AFF_ENVIRONMENT?.trim();\n}\n\nfunction resolveActiveEnvironmentName(\n normalized: DeclarativeFeatureConfig,\n options: ResolveFeatureRuntimeOptions,\n): string {\n const { environments } = normalized;\n assertEnvironmentShape(environments);\n\n const forced = options.forceEnvironment?.trim();\n if (forced && environments[forced]) return forced;\n\n const aff = resolveAffEnvironment(options);\n if (aff && environments[aff]) return aff;\n\n const n = countActiveWhen(environments);\n if (n !== 1) {\n const activeNames = Object.entries(environments)\n .filter(([, e]) => e.when === true)\n .map(([k]) => k);\n const devWhen = environments.dev?.when;\n const hint =\n n > 1 && environments.dev && devWhen === true\n ? \" The reserved `dev` environment is active for this `mode` while another layer also has `when: true`. Pin one layer with `forceEnvironment` or `AFF_ENVIRONMENT`, or adjust non-dev `when` predicates.\"\n : \"\";\n throw new Error(\n `astro-feature-flags: exactly one environment must have when: true (found ${n}${activeNames.length ? `: ${activeNames.join(\", \")}` : \"\"}).${hint} Set forceEnvironment or AFF_ENVIRONMENT to pick a layer explicitly.`,\n );\n }\n for (const [name, cfg] of Object.entries(environments)) {\n if (cfg.when === true) return name;\n }\n throw new Error(\"astro-feature-flags: internal error resolving environment.\");\n}\n\nfunction readBaseMergedRaw(options: ResolveFeatureRuntimeOptions): Record<string, unknown> {\n const configRoot = options.configRoot ?? process.cwd();\n const {\n tokenNamespace = \"ff\",\n flags = {},\n environments = {},\n } = options;\n const inlineRaw: Record<string, unknown> = {\n tokenNamespace,\n flags,\n environments,\n };\n let merged = { ...inlineRaw };\n if (options.jsonConfigPath) {\n const p = resolvePath(options.jsonConfigPath, configRoot);\n merged = mergeRecords(merged as Record<string, unknown>, readJsonIfExists(p));\n }\n return merged;\n}\n\nfunction mergePerEnvironmentJson(\n baseRaw: Record<string, unknown>,\n envName: string,\n configRoot: string,\n mode: string,\n): Record<string, unknown> {\n if (envName === \"dev\") return baseRaw;\n const normalized = normalizeDeclarativeConfig(baseRaw, mode);\n const entry = normalized.environments[envName];\n const rel = entry?.jsonConfigPath;\n if (!rel) return baseRaw;\n const p = resolvePath(rel, configRoot);\n return mergeRecords(baseRaw, readJsonIfExists(p));\n}\n\nfunction readMergedRawForActiveEnv(\n options: ResolveFeatureRuntimeOptions,\n envName: string,\n): Record<string, unknown> {\n const configRoot = options.configRoot ?? process.cwd();\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const base = readBaseMergedRaw(options);\n return mergePerEnvironmentJson(base, envName, configRoot, mode);\n}\n\nexport function loadFeatureConfig(\n options: ResolveFeatureRuntimeOptions = {},\n): FeatureConfig {\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const baseRaw = readBaseMergedRaw(options);\n const baseNorm = normalizeDeclarativeConfig(baseRaw, mode);\n const envName = resolveActiveEnvironmentName(baseNorm, options);\n const fullRaw = readMergedRawForActiveEnv(options, envName);\n const normalized = normalizeDeclarativeConfig(fullRaw, mode);\n\n const envFlags = normalized.environments[envName]?.flags ?? {};\n const routeFlags: FeatureRouteMap = {};\n const colors: FeatureColorMap = {};\n const outlineDefaultsByToken: FeatureBoolByTokenMap = {};\n const badgeDefaultsByToken: FeatureBoolByTokenMap = {};\n const resolvedFlags: FeatureFlagMap = {};\n\n for (const [flagName, flagDef] of Object.entries(normalized.flags)) {\n if (envName === \"dev\") {\n resolvedFlags[flagName] = true;\n } else {\n resolvedFlags[flagName] = envFlags[flagName] === true;\n }\n if (flagDef.color) colors[flagName] = flagDef.color;\n const token = toToken(flagName);\n outlineDefaultsByToken[token] = flagDef.outline;\n badgeDefaultsByToken[token] = flagDef.badge;\n for (const route of flagDef.routes) {\n routeFlags[route] = [...(routeFlags[route] ?? []), flagName];\n }\n }\n\n return {\n namespace: normalized.tokenNamespace || \"ff\",\n flags: resolvedFlags,\n routeFlags,\n colors,\n outlineDefaultsByToken,\n badgeDefaultsByToken,\n mode,\n activeEnvironment: envName,\n };\n}\n\n/** Applies `AFF_FEATURE_*` and `ASTRO_FEATURE_FLAGS` on top of a resolved flag map. */\nexport function mergeFlagsWithProcessEnvOverrides(\n flags: FeatureFlagMap,\n env: Record<string, string | undefined> = process.env as Record<\n string,\n string | undefined\n >,\n): FeatureFlagMap {\n const resolvedFlags: FeatureFlagMap = { ...flags };\n for (const [key, value] of Object.entries(resolvedFlags)) {\n const slug = toToken(key).replace(/-/g, \"_\").toUpperCase();\n const envKey = `AFF_FEATURE_${slug}`;\n resolvedFlags[key] = toBoolean(env[envKey], Boolean(value));\n }\n const envMapRaw = env.ASTRO_FEATURE_FLAGS;\n if (envMapRaw) {\n try {\n const envMap = JSON.parse(envMapRaw) as Record<string, unknown>;\n for (const [flag, value] of Object.entries(envMap)) {\n resolvedFlags[flag] = Boolean(value);\n }\n } catch {\n // ignore invalid JSON override\n }\n }\n return resolvedFlags;\n}\n\n/**\n * Resolved flag booleans for each `environments` key, after the same process-env overrides\n * as {@link resolveFeatureRuntime} (overrides skipped for the reserved `dev` layer).\n */\nexport function resolveFeatureFlagsByEnvironment(\n options: ResolveFeatureRuntimeOptions = {},\n): Record<string, FeatureFlagMap> {\n const baseRaw = readBaseMergedRaw(options);\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const normalized = normalizeDeclarativeConfig(baseRaw, mode);\n const envKeys = Object.keys(normalized.environments);\n const proc = options.env ?? (process.env as Record<string, string | undefined>);\n const out: Record<string, FeatureFlagMap> = {};\n for (const envName of envKeys) {\n const cfg = loadFeatureConfig({ ...options, forceEnvironment: envName });\n out[envName] =\n envName === \"dev\"\n ? { ...cfg.flags }\n : mergeFlagsWithProcessEnvOverrides({ ...cfg.flags }, proc);\n }\n return out;\n}\n\n/** Normalize colour map keys (flag names or tokens) to CSS tokens. */\nexport function colorsToTokenMap(\n colors: FeatureColorMap,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(colors)) {\n out[toToken(key)] = value;\n }\n return out;\n}\n\nexport interface ResolvedFeatureRuntime {\n namespace: string;\n mode: string;\n /** True when the active environment is the reserved `dev` layer (toolbar + all flags on). */\n isDev: boolean;\n activeEnvironment: string;\n flags: FeatureFlagMap;\n routeFlags: FeatureRouteMap;\n /** Outline/badge/route-frame colour per flag token (CSS colour strings). */\n flagColorsByToken: Record<string, string>;\n /** Default dev-toolbar outline/badge state per flag token. */\n flagOutlineDefaultsByToken: Record<string, boolean>;\n flagBadgeDefaultsByToken: Record<string, boolean>;\n}\n\nexport function resolveFeatureRuntime(\n options: ResolveFeatureRuntimeOptions = {},\n): ResolvedFeatureRuntime {\n const env = options.env ?? (process.env as Record<string, string | undefined>);\n const config = loadFeatureConfig(options);\n const isDevLayer = config.activeEnvironment === \"dev\";\n const resolvedFlags = isDevLayer\n ? { ...config.flags }\n : mergeFlagsWithProcessEnvOverrides(config.flags, env);\n\n const colorByToken = colorsToTokenMap(config.colors);\n\n return {\n namespace: config.namespace,\n mode: config.mode,\n isDev: isDevLayer,\n activeEnvironment: config.activeEnvironment,\n flags: resolvedFlags,\n routeFlags: config.routeFlags,\n flagColorsByToken: colorByToken,\n flagOutlineDefaultsByToken: config.outlineDefaultsByToken,\n flagBadgeDefaultsByToken: config.badgeDefaultsByToken,\n };\n}\n\nexport function isFlagEnabled(flags: FeatureFlagMap, flag: string): boolean {\n return Boolean(flags?.[flag]);\n}\n\nexport function isRouteFlagged(\n pathname: string,\n routeFlags: FeatureRouteMap,\n): boolean {\n const normalized = normalizePath(pathname);\n return Object.keys(routeFlags || {}).some((routePrefix) => {\n const route = routePatternToPrefix(routePrefix);\n return normalized === route || normalized.startsWith(route);\n });\n}\n\nexport function shouldIncludeRoute({\n pathname,\n routeFlags,\n flags,\n isDev,\n}: {\n pathname: string;\n routeFlags: FeatureRouteMap;\n flags: FeatureFlagMap;\n isDev: boolean;\n}): boolean {\n if (isDev) return true;\n const normalized = normalizePath(pathname);\n for (const [routePrefix, flagNames] of Object.entries(routeFlags || {})) {\n const route = routePatternToPrefix(routePrefix);\n if (normalized === route || normalized.startsWith(route)) {\n return (flagNames || []).every((flagName) =>\n isFlagEnabled(flags, flagName),\n );\n }\n }\n return true;\n}\n\nexport function routePathsToPrune({\n routeFlags,\n flags,\n}: {\n routeFlags: FeatureRouteMap;\n flags: FeatureFlagMap;\n}): string[] {\n return Object.entries(routeFlags || {})\n .filter(([, flagNames]) =>\n (flagNames || []).some((flagName) => !isFlagEnabled(flags, flagName)),\n )\n .map(([routePath]) =>\n routePatternToPrefix(routePath).replace(/^\\/+|\\/+$/g, \"\"),\n )\n .filter(Boolean);\n}\n\n/**\n * Longest `routeFlags` key that matches `pathname` (prefix match, trailing slashes normalized).\n */\nexport function longestMatchingRoutePrefix(\n pathname: string,\n routeFlags: FeatureRouteMap,\n): string | null {\n const normalized = normalizePath(pathname);\n let best: string | null = null;\n let bestLen = -1;\n for (const routePrefix of Object.keys(routeFlags || {})) {\n const route = routePatternToPrefix(routePrefix);\n if (normalized === route || normalized.startsWith(route)) {\n if (route.length > bestLen) {\n bestLen = route.length;\n best = routePrefix;\n }\n }\n }\n return best;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.mjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\n\nexport type FeatureFlagMap = Record<string, boolean>;\nexport type FeatureRouteMap = Record<string, string[]>;\nexport type FeatureColorMap = Record<string, string>;\nexport type FeatureBoolByTokenMap = Record<string, boolean>;\n\nexport interface FeatureConfig {\n namespace: string;\n flags: FeatureFlagMap;\n routeFlags: FeatureRouteMap;\n colors: FeatureColorMap;\n outlineDefaultsByToken: FeatureBoolByTokenMap;\n badgeDefaultsByToken: FeatureBoolByTokenMap;\n mode: string;\n /** Which `environments` entry was used (reserved `dev` = all flags on, toolbar layer). */\n activeEnvironment: string;\n}\n\n/**\n * Declarative feature flags for Astro. Merge order: inline options → optional root\n * {@link ResolveFeatureRuntimeOptions.jsonConfigPath} → optional per-environment\n * `environments.<name>.jsonConfigPath` (merged when that layer is active).\n *\n * Exactly one `when: true` across environments unless `forceEnvironment` or `AFF_ENVIRONMENT`\n * selects the layer. A reserved **`dev`** environment is required (all flags on at resolve time;\n * toggles are dev-toolbar only) plus at least one other environment (e.g. `prod`).\n */\nexport interface ResolveFeatureRuntimeOptions {\n /**\n * Directory used to resolve relative {@link jsonConfigPath} values (root and per-environment).\n * Defaults to `process.cwd()`.\n */\n configRoot?: string;\n /** Optional main JSON file merged after inline `flags` / `environments`. */\n jsonConfigPath?: string;\n /** Passed through to `ResolvedFeatureRuntime.mode` (e.g. `process.env.NODE_ENV`). */\n mode?: string;\n /** Process env for `AFF_FEATURE_*` and `ASTRO_FEATURE_FLAGS` (skipped when active env is `dev`). */\n env?: Record<string, string | undefined>;\n /**\n * Use this `environments` entry regardless of `when` / `AFF_ENVIRONMENT` (e.g. sitemaps, tests).\n */\n forceEnvironment?: string;\n tokenNamespace?: string;\n flags?: Record<\n string,\n {\n color?: string;\n colour?: string;\n outline?: boolean;\n badge?: boolean;\n routes?: string[];\n }\n >;\n environments?: Record<\n string,\n {\n when?: boolean;\n flags?: Record<string, boolean>;\n /** Optional JSON merged after the root file when this environment is active. */\n jsonConfigPath?: string;\n }\n >;\n}\n\nfunction toBoolean(value: unknown, fallback = false): boolean {\n if (typeof value === \"boolean\") return value;\n if (typeof value !== \"string\") return fallback;\n const normalized = value.trim().toLowerCase();\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"0\", \"false\", \"no\", \"off\"].includes(normalized)) return false;\n return fallback;\n}\n\nfunction readJsonIfExists(pathname: string): Record<string, unknown> {\n if (!existsSync(pathname)) return {};\n return JSON.parse(readFileSync(pathname, \"utf8\")) as Record<string, unknown>;\n}\n\nexport function normalizePath(pathname: string): string {\n if (!pathname) return \"/\";\n return pathname.endsWith(\"/\") ? pathname : `${pathname}/`;\n}\n\n/**\n * Normalizes a route key from `ff.json` for prefix matching.\n * Supports wildcards: `/blog/*`, `/docs/**` → prefix `/blog/`, `/docs/`.\n */\nexport function routePatternToPrefix(pattern: string): string {\n let p = pattern.trim();\n if (p.endsWith(\"/**\")) {\n p = p.slice(0, -3);\n } else if (p.endsWith(\"/*\")) {\n p = p.slice(0, -2);\n } else if (p.endsWith(\"*\") && p.length > 1) {\n p = p.slice(0, -1);\n }\n return normalizePath(p);\n}\n\nexport function toEnumKey(flagName: string): string {\n return flagName\n .replace(/[^a-zA-Z0-9]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n}\n\nexport function toToken(flagName: string): string {\n return flagName\n .replace(/[^a-zA-Z0-9]+/g, \"-\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/([a-zA-Z])([0-9])/g, \"$1-$2\")\n .replace(/([0-9])([a-zA-Z])/g, \"$1-$2\")\n .toLowerCase()\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nfunction mergeRecords<T extends Record<string, unknown>>(\n base: T,\n ...layers: Partial<T>[]\n): T {\n const out = { ...base };\n for (const layer of layers) {\n for (const [k, v] of Object.entries(layer)) {\n if (v === undefined) continue;\n const cur = out[k as keyof T];\n if (\n v &&\n typeof v === \"object\" &&\n !Array.isArray(v) &&\n cur &&\n typeof cur === \"object\" &&\n !Array.isArray(cur)\n ) {\n (out as Record<string, unknown>)[k] = mergeRecords(\n cur as Record<string, unknown>,\n v as Record<string, unknown>,\n );\n } else {\n (out as Record<string, unknown>)[k] = v;\n }\n }\n }\n return out;\n}\n\nfunction resolvePath(relativeOrAbsolute: string, configRoot: string): string {\n return isAbsolute(relativeOrAbsolute)\n ? relativeOrAbsolute\n : join(configRoot, relativeOrAbsolute);\n}\n\ntype NormalizedFlagDef = {\n color?: string;\n outline: boolean;\n badge: boolean;\n routes: string[];\n};\n\ntype NormalizedEnvEntry = {\n when?: boolean;\n flags: Record<string, boolean>;\n /** Per-environment JSON merged after root `jsonConfigPath` when this layer is active. */\n jsonConfigPath?: string;\n};\n\ntype DeclarativeFeatureConfig = {\n tokenNamespace: string;\n flags: Record<string, NormalizedFlagDef>;\n environments: Record<string, NormalizedEnvEntry>;\n};\n\nfunction normalizeDeclarativeConfig(\n raw: Record<string, unknown>,\n mode: string = process.env.NODE_ENV ?? \"development\",\n): DeclarativeFeatureConfig {\n const tokenNamespaceRaw =\n (typeof raw.tokenNamespace === \"string\" ? raw.tokenNamespace : undefined) ??\n (typeof raw.namespace === \"string\" ? raw.namespace : undefined) ??\n \"ff\";\n\n const flagsRaw =\n raw.flags && typeof raw.flags === \"object\" && !Array.isArray(raw.flags)\n ? (raw.flags as Record<string, unknown>)\n : {};\n const flags: Record<string, NormalizedFlagDef> = {};\n for (const [flagName, maybeDef] of Object.entries(flagsRaw)) {\n if (!maybeDef || typeof maybeDef !== \"object\" || Array.isArray(maybeDef))\n continue;\n const def = maybeDef as Record<string, unknown>;\n const color =\n (typeof def.colour === \"string\" ? def.colour : undefined) ??\n (typeof def.color === \"string\" ? def.color : undefined);\n const outline = typeof def.outline === \"boolean\" ? def.outline : true;\n const badge = typeof def.badge === \"boolean\" ? def.badge : true;\n const routes = Array.isArray(def.routes)\n ? def.routes.filter((v): v is string => typeof v === \"string\")\n : [];\n flags[flagName] = { color, outline, badge, routes };\n }\n\n const envRaw =\n raw.environments &&\n typeof raw.environments === \"object\" &&\n !Array.isArray(raw.environments)\n ? (raw.environments as Record<string, unknown>)\n : {};\n const environments: Record<string, NormalizedEnvEntry> = {};\n for (const [envName, maybeEnv] of Object.entries(envRaw)) {\n if (envName === \"dev\") continue;\n if (!maybeEnv || typeof maybeEnv !== \"object\" || Array.isArray(maybeEnv))\n continue;\n const env = maybeEnv as Record<string, unknown>;\n const envFlagsRaw =\n env.flags && typeof env.flags === \"object\" && !Array.isArray(env.flags)\n ? (env.flags as Record<string, unknown>)\n : {};\n const envFlags: Record<string, boolean> = {};\n for (const [flagName, value] of Object.entries(envFlagsRaw)) {\n envFlags[flagName] = Boolean(value);\n }\n const when = typeof env.when === \"boolean\" ? env.when : undefined;\n const layerJson =\n typeof env.jsonConfigPath === \"string\" ? env.jsonConfigPath : undefined;\n environments[envName] = {\n ...(when !== undefined ? { when } : {}),\n ...(layerJson ? { jsonConfigPath: layerJson } : {}),\n flags: envFlags,\n };\n }\n\n environments.dev = {\n when: mode !== \"production\",\n flags: {},\n };\n\n return {\n tokenNamespace: tokenNamespaceRaw,\n flags,\n environments,\n };\n}\n\nfunction assertEnvironmentShape(\n environments: Record<string, NormalizedEnvEntry>,\n) {\n const keys = Object.keys(environments);\n if (!environments.dev) {\n throw new Error(\n 'astro-feature-flags: environments must include a reserved \"dev\" entry.',\n );\n }\n if (keys.length < 2) {\n throw new Error(\n \"astro-feature-flags: environments must include `dev` plus at least one other layer (e.g. `prod`).\",\n );\n }\n}\n\nfunction countActiveWhen(\n environments: Record<string, NormalizedEnvEntry>,\n): number {\n return Object.values(environments).filter((e) => e.when === true).length;\n}\n\nfunction resolveAffEnvironment(\n options: ResolveFeatureRuntimeOptions,\n): string | undefined {\n const proc =\n options.env ?? (process.env as Record<string, string | undefined>);\n return proc.AFF_ENVIRONMENT?.trim();\n}\n\nfunction resolveActiveEnvironmentName(\n normalized: DeclarativeFeatureConfig,\n options: ResolveFeatureRuntimeOptions,\n): string {\n const { environments } = normalized;\n assertEnvironmentShape(environments);\n\n const forced = options.forceEnvironment?.trim();\n if (forced && environments[forced]) return forced;\n\n const aff = resolveAffEnvironment(options);\n if (aff && environments[aff]) return aff;\n\n const n = countActiveWhen(environments);\n if (n !== 1) {\n const activeNames = Object.entries(environments)\n .filter(([, e]) => e.when === true)\n .map(([k]) => k);\n const devWhen = environments.dev?.when;\n const hint =\n n > 1 && environments.dev && devWhen === true\n ? \" The reserved `dev` environment is active for this `mode` while another layer also has `when: true`. Pin one layer with `forceEnvironment` or `AFF_ENVIRONMENT`, or adjust non-dev `when` predicates.\"\n : \"\";\n throw new Error(\n `astro-feature-flags: exactly one environment must have when: true (found ${n}${activeNames.length ? `: ${activeNames.join(\", \")}` : \"\"}).${hint} Set forceEnvironment or AFF_ENVIRONMENT to pick a layer explicitly.`,\n );\n }\n for (const [name, cfg] of Object.entries(environments)) {\n if (cfg.when === true) return name;\n }\n throw new Error(\"astro-feature-flags: internal error resolving environment.\");\n}\n\nfunction readBaseMergedRaw(\n options: ResolveFeatureRuntimeOptions,\n): Record<string, unknown> {\n const configRoot = options.configRoot ?? process.cwd();\n const { tokenNamespace = \"ff\", flags = {}, environments = {} } = options;\n const inlineRaw: Record<string, unknown> = {\n tokenNamespace,\n flags,\n environments,\n };\n let merged = { ...inlineRaw };\n if (options.jsonConfigPath) {\n const p = resolvePath(options.jsonConfigPath, configRoot);\n merged = mergeRecords(\n merged as Record<string, unknown>,\n readJsonIfExists(p),\n );\n }\n return merged;\n}\n\nfunction mergePerEnvironmentJson(\n baseRaw: Record<string, unknown>,\n envName: string,\n configRoot: string,\n mode: string,\n): Record<string, unknown> {\n if (envName === \"dev\") return baseRaw;\n const normalized = normalizeDeclarativeConfig(baseRaw, mode);\n const entry = normalized.environments[envName];\n const rel = entry?.jsonConfigPath;\n if (!rel) return baseRaw;\n const p = resolvePath(rel, configRoot);\n return mergeRecords(baseRaw, readJsonIfExists(p));\n}\n\nfunction readMergedRawForActiveEnv(\n options: ResolveFeatureRuntimeOptions,\n envName: string,\n): Record<string, unknown> {\n const configRoot = options.configRoot ?? process.cwd();\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const base = readBaseMergedRaw(options);\n return mergePerEnvironmentJson(base, envName, configRoot, mode);\n}\n\nexport function loadFeatureConfig(\n options: ResolveFeatureRuntimeOptions = {},\n): FeatureConfig {\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const baseRaw = readBaseMergedRaw(options);\n const baseNorm = normalizeDeclarativeConfig(baseRaw, mode);\n const envName = resolveActiveEnvironmentName(baseNorm, options);\n const fullRaw = readMergedRawForActiveEnv(options, envName);\n const normalized = normalizeDeclarativeConfig(fullRaw, mode);\n\n const envFlags = normalized.environments[envName]?.flags ?? {};\n const routeFlags: FeatureRouteMap = {};\n const colors: FeatureColorMap = {};\n const outlineDefaultsByToken: FeatureBoolByTokenMap = {};\n const badgeDefaultsByToken: FeatureBoolByTokenMap = {};\n const resolvedFlags: FeatureFlagMap = {};\n\n for (const [flagName, flagDef] of Object.entries(normalized.flags)) {\n if (envName === \"dev\") {\n resolvedFlags[flagName] = true;\n } else {\n resolvedFlags[flagName] = envFlags[flagName] === true;\n }\n if (flagDef.color) colors[flagName] = flagDef.color;\n const token = toToken(flagName);\n outlineDefaultsByToken[token] = flagDef.outline;\n badgeDefaultsByToken[token] = flagDef.badge;\n for (const route of flagDef.routes) {\n routeFlags[route] = [...(routeFlags[route] ?? []), flagName];\n }\n }\n\n return {\n namespace: normalized.tokenNamespace || \"ff\",\n flags: resolvedFlags,\n routeFlags,\n colors,\n outlineDefaultsByToken,\n badgeDefaultsByToken,\n mode,\n activeEnvironment: envName,\n };\n}\n\n/** Applies `AFF_FEATURE_*` and `ASTRO_FEATURE_FLAGS` on top of a resolved flag map. */\nexport function mergeFlagsWithProcessEnvOverrides(\n flags: FeatureFlagMap,\n env: Record<string, string | undefined> = process.env as Record<\n string,\n string | undefined\n >,\n): FeatureFlagMap {\n const resolvedFlags: FeatureFlagMap = { ...flags };\n for (const [key, value] of Object.entries(resolvedFlags)) {\n const slug = toToken(key).replace(/-/g, \"_\").toUpperCase();\n const envKey = `AFF_FEATURE_${slug}`;\n resolvedFlags[key] = toBoolean(env[envKey], Boolean(value));\n }\n const envMapRaw = env.ASTRO_FEATURE_FLAGS;\n if (envMapRaw) {\n try {\n const envMap = JSON.parse(envMapRaw) as Record<string, unknown>;\n for (const [flag, value] of Object.entries(envMap)) {\n resolvedFlags[flag] = Boolean(value);\n }\n } catch {\n // ignore invalid JSON override\n }\n }\n return resolvedFlags;\n}\n\n/**\n * Resolved flag booleans for each `environments` key, after the same process-env overrides\n * as {@link resolveFeatureRuntime} (overrides skipped for the reserved `dev` layer).\n */\nexport function resolveFeatureFlagsByEnvironment(\n options: ResolveFeatureRuntimeOptions = {},\n): Record<string, FeatureFlagMap> {\n const baseRaw = readBaseMergedRaw(options);\n const mode = options.mode ?? process.env.NODE_ENV ?? \"development\";\n const normalized = normalizeDeclarativeConfig(baseRaw, mode);\n const envKeys = Object.keys(normalized.environments);\n const proc =\n options.env ?? (process.env as Record<string, string | undefined>);\n const out: Record<string, FeatureFlagMap> = {};\n for (const envName of envKeys) {\n const cfg = loadFeatureConfig({ ...options, forceEnvironment: envName });\n out[envName] =\n envName === \"dev\"\n ? { ...cfg.flags }\n : mergeFlagsWithProcessEnvOverrides({ ...cfg.flags }, proc);\n }\n return out;\n}\n\n/** Normalize colour map keys (flag names or tokens) to CSS tokens. */\nexport function colorsToTokenMap(\n colors: FeatureColorMap,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(colors)) {\n out[toToken(key)] = value;\n }\n return out;\n}\n\nexport interface ResolvedFeatureRuntime {\n namespace: string;\n mode: string;\n /** True when the active environment is the reserved `dev` layer (toolbar + all flags on). */\n isDev: boolean;\n activeEnvironment: string;\n flags: FeatureFlagMap;\n routeFlags: FeatureRouteMap;\n /** Outline/badge/route-frame colour per flag token (CSS colour strings). */\n flagColorsByToken: Record<string, string>;\n /** Default dev-toolbar outline/badge state per flag token. */\n flagOutlineDefaultsByToken: Record<string, boolean>;\n flagBadgeDefaultsByToken: Record<string, boolean>;\n}\n\nexport function resolveFeatureRuntime(\n options: ResolveFeatureRuntimeOptions = {},\n): ResolvedFeatureRuntime {\n const env =\n options.env ?? (process.env as Record<string, string | undefined>);\n const config = loadFeatureConfig(options);\n const isDevLayer = config.activeEnvironment === \"dev\";\n const resolvedFlags = isDevLayer\n ? { ...config.flags }\n : mergeFlagsWithProcessEnvOverrides(config.flags, env);\n\n const colorByToken = colorsToTokenMap(config.colors);\n\n return {\n namespace: config.namespace,\n mode: config.mode,\n isDev: isDevLayer,\n activeEnvironment: config.activeEnvironment,\n flags: resolvedFlags,\n routeFlags: config.routeFlags,\n flagColorsByToken: colorByToken,\n flagOutlineDefaultsByToken: config.outlineDefaultsByToken,\n flagBadgeDefaultsByToken: config.badgeDefaultsByToken,\n };\n}\n\nexport function isFlagEnabled(flags: FeatureFlagMap, flag: string): boolean {\n return Boolean(flags?.[flag]);\n}\n\nexport function isRouteFlagged(\n pathname: string,\n routeFlags: FeatureRouteMap,\n): boolean {\n const normalized = normalizePath(pathname);\n return Object.keys(routeFlags || {}).some((routePrefix) => {\n const route = routePatternToPrefix(routePrefix);\n return normalized === route || normalized.startsWith(route);\n });\n}\n\nexport function shouldIncludeRoute({\n pathname,\n routeFlags,\n flags,\n isDev,\n}: {\n pathname: string;\n routeFlags: FeatureRouteMap;\n flags: FeatureFlagMap;\n isDev: boolean;\n}): boolean {\n if (isDev) return true;\n const normalized = normalizePath(pathname);\n for (const [routePrefix, flagNames] of Object.entries(routeFlags || {})) {\n const route = routePatternToPrefix(routePrefix);\n if (normalized === route || normalized.startsWith(route)) {\n return (flagNames || []).every((flagName) =>\n isFlagEnabled(flags, flagName),\n );\n }\n }\n return true;\n}\n\nexport function routePathsToPrune({\n routeFlags,\n flags,\n}: {\n routeFlags: FeatureRouteMap;\n flags: FeatureFlagMap;\n}): string[] {\n return Object.entries(routeFlags || {})\n .filter(([, flagNames]) =>\n (flagNames || []).some((flagName) => !isFlagEnabled(flags, flagName)),\n )\n .map(([routePath]) =>\n routePatternToPrefix(routePath).replace(/^\\/+|\\/+$/g, \"\"),\n )\n .filter(Boolean);\n}\n\n/**\n * Longest `routeFlags` key that matches `pathname` (prefix match, trailing slashes normalized).\n */\nexport function longestMatchingRoutePrefix(\n pathname: string,\n routeFlags: FeatureRouteMap,\n): string | null {\n const normalized = normalizePath(pathname);\n let best: string | null = null;\n let bestLen = -1;\n for (const routePrefix of Object.keys(routeFlags || {})) {\n const route = routePatternToPrefix(routePrefix);\n if (normalized === route || normalized.startsWith(route)) {\n if (route.length > bestLen) {\n bestLen = route.length;\n best = routePrefix;\n }\n }\n }\n return best;\n}\n"],"mappings":"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"}
@@ -11,12 +11,12 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@at-flux/astro-feature-flags": "link:..",
14
- "astro": "^5.18.0"
14
+ "astro": "5.18.0"
15
15
  },
16
16
  "devDependencies": {
17
- "@astrojs/check": "^0.9.8",
18
- "@tailwindcss/vite": "^4.2.2",
19
- "tailwindcss": "^4.2.2",
20
- "typescript": "^5.9.3"
17
+ "@astrojs/check": "0.9.8",
18
+ "@tailwindcss/vite": "4.2.2",
19
+ "tailwindcss": "4.2.2",
20
+ "typescript": "5.9.3"
21
21
  }
22
22
  }