{"version":3,"sources":["../src/sheet.ts","../src/server.ts"],"names":[],"mappings":"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","file":"server.cjs","sourcesContent":["import {\n  namespacesFromTypestylesHmrPrefixes,\n  releaseReservedNamespacesForComponentOrClassNames,\n} from './registry';\n\nconst STYLE_ELEMENT_ID = 'typestyles';\n\n/**\n * Tracks which CSS rules have been inserted to avoid duplicates.\n */\nconst insertedRules = new Set<string>();\n\n/**\n * Last emitted CSS per dedupe key (see {@link warnIfDuplicateRuleKeyConflict}).\n * Cleared with {@link reset} and kept in sync when keys are invalidated.\n */\nconst ruleCssByKey = new Map<string, string>();\n\nfunction duplicateRuleKeyConflictWarningsEnabled(): boolean {\n  if (typeof process === 'undefined') return true;\n  return process.env.NODE_ENV !== 'production';\n}\n\n/**\n * When the same key is registered again with different CSS, the second rule is skipped\n * (idempotency / HMR). In non-production builds, surface that so overlapping globals\n * (e.g. reset `body` + app `body` in the same scope) are not silent failures.\n */\nfunction warnIfDuplicateRuleKeyConflict(\n  key: string,\n  previousCss: string,\n  ignoredCss: string,\n): void {\n  if (!duplicateRuleKeyConflictWarningsEnabled()) return;\n  const prevShort = previousCss.length > 220 ? `${previousCss.slice(0, 220)}…` : previousCss;\n  const nextShort = ignoredCss.length > 220 ? `${ignoredCss.slice(0, 220)}…` : ignoredCss;\n  console.warn(\n    `[typestyles] Skipped a rule: dedupe key \"${key}\" already exists with different CSS. ` +\n      `Only the first registration is kept. For globals, merge into one \\`global.style\\`, ` +\n      `or use a distinct selector (e.g. \\`html body\\` after reset’s \\`body\\`).\\n` +\n      `  Existing: ${prevShort}\\n` +\n      `  Skipped:  ${nextShort}`,\n  );\n}\n\n/**\n * Whether runtime DOM insertion is disabled (for build-time/zero-runtime mode).\n * The Vite plugin (mode: 'build') defines __TYPESTYLES_RUNTIME_DISABLED__ as the\n * string \"true\" at build time, so this is true in production and no <style> is created.\n *\n * `@typestyles/next/build` `withTypestylesExtract` sets `NEXT_PUBLIC_TYPESTYLES_RUNTIME_DISABLED`\n * via `next.config` `env` so Turbopack and webpack both inline the flag (DefinePlugin\n * alone does not run under Turbopack).\n */\ndeclare const __TYPESTYLES_RUNTIME_DISABLED__: string | undefined;\nfunction readNextPublicRuntimeDisabled(): boolean {\n  if (typeof process === 'undefined' || !process.env) return false;\n  return process.env.NEXT_PUBLIC_TYPESTYLES_RUNTIME_DISABLED === 'true';\n}\nconst RUNTIME_DISABLED =\n  (typeof __TYPESTYLES_RUNTIME_DISABLED__ !== 'undefined' &&\n    __TYPESTYLES_RUNTIME_DISABLED__ === 'true') ||\n  readNextPublicRuntimeDisabled();\n\n/**\n * Buffer of CSS rules waiting to be flushed.\n */\nlet pendingRules: string[] = [];\n\n/**\n * All CSS rules ever registered (for SSR extraction).\n * Unlike pendingRules (which is cleared on flush), this retains every rule\n * so getRegisteredCss() can return the full stylesheet at any point.\n */\nconst allRules: string[] = [];\n\n/**\n * Whether a flush is scheduled.\n */\nlet flushScheduled = false;\n\n/**\n * The managed <style> element, lazily created.\n */\nlet styleElement: HTMLStyleElement | null = null;\n\n/**\n * When in SSR collection mode, CSS is captured here instead of injected.\n */\nlet ssrBuffer: string[] | null = null;\n\n/**\n * Whether we're running in a browser environment.\n */\nconst isBrowser = typeof document !== 'undefined' && typeof window !== 'undefined';\n\n/**\n * Re-insert every registered rule into a (usually fresh) <style> element.\n * Used when the live element was detached (e.g. Astro view transitions replacing <head>).\n */\nfunction writeAllRulesToStyleElement(el: HTMLStyleElement): void {\n  if (RUNTIME_DISABLED || allRules.length === 0) return;\n  const sheet = el.sheet;\n  if (sheet) {\n    for (const css of allRules) {\n      try {\n        sheet.insertRule(css, sheet.cssRules.length);\n      } catch {\n        el.appendChild(document.createTextNode(css));\n      }\n    }\n  } else {\n    el.appendChild(document.createTextNode(allRules.join('\\n')));\n  }\n}\n\nfunction getStyleElement(): HTMLStyleElement {\n  let reconnectAfterDetach = false;\n  if (styleElement && !styleElement.isConnected) {\n    reconnectAfterDetach = true;\n    styleElement = null;\n  }\n  if (styleElement) return styleElement;\n\n  // Prefer an element actually in the document (SSR or another copy on the page).\n  const existing = document.getElementById(STYLE_ELEMENT_ID) as HTMLStyleElement | null;\n  if (existing?.isConnected) {\n    styleElement = existing;\n    return styleElement;\n  }\n\n  styleElement = document.createElement('style');\n  styleElement.id = STYLE_ELEMENT_ID;\n  document.head.appendChild(styleElement);\n\n  // After a doc swap, we have a new empty sheet but insertRule() won't re-queue (deduped keys).\n  if (reconnectAfterDetach && allRules.length > 0) {\n    writeAllRulesToStyleElement(styleElement);\n  }\n\n  return styleElement;\n}\n\n/**\n * Ensure the managed <style id=\"typestyles\"> is attached to the current document and populated.\n * Call after SPA-style navigation (e.g. Astro `astro:after-swap`) when runtime injection is enabled.\n */\nexport function ensureDocumentStylesAttached(): void {\n  if (!isBrowser || RUNTIME_DISABLED) return;\n  getStyleElement();\n}\n\nfunction flush(): void {\n  flushScheduled = false;\n  if (pendingRules.length === 0) return;\n\n  const rules = pendingRules;\n  pendingRules = [];\n\n  if (ssrBuffer) {\n    ssrBuffer.push(...rules);\n    return;\n  }\n\n  if (!isBrowser || RUNTIME_DISABLED) return;\n\n  const el = getStyleElement();\n  const sheet = el.sheet;\n\n  if (sheet) {\n    for (const rule of rules) {\n      try {\n        sheet.insertRule(rule, sheet.cssRules.length);\n      } catch {\n        // Fallback: append as text (handles edge cases with certain selectors)\n        el.appendChild(document.createTextNode(rule));\n      }\n    }\n  } else {\n    // Sheet not available yet, append as text\n    el.appendChild(document.createTextNode(rules.join('\\n')));\n  }\n}\n\nfunction scheduleFlush(): void {\n  if (flushScheduled) return;\n  flushScheduled = true;\n\n  if (ssrBuffer) {\n    // In SSR mode, flush synchronously\n    flush();\n    return;\n  }\n\n  if (isBrowser && !RUNTIME_DISABLED) {\n    // Use microtask for fast, batched insertion\n    queueMicrotask(flush);\n  }\n}\n\n/**\n * Register a single `@layer a, b, c;` preamble so layer **order** is defined before any\n * `@layer name { … }` blocks. Inserts at the front of the virtual sheet and at CSSOM index 0\n * when injecting into the document.\n */\nexport function registerCascadeLayerOrder(preambleKey: string, css: string): void {\n  const key = `typestyles:@layer-order:${preambleKey}`;\n  if (insertedRules.has(key)) return;\n  insertedRules.add(key);\n\n  allRules.unshift(css);\n\n  if (ssrBuffer) {\n    ssrBuffer.unshift(css);\n    return;\n  }\n\n  if (RUNTIME_DISABLED) return;\n\n  if (!isBrowser) return;\n\n  const el = getStyleElement();\n  const sheet = el.sheet;\n  if (sheet) {\n    try {\n      sheet.insertRule(css, 0);\n    } catch {\n      el.insertBefore(document.createTextNode(`${css}\\n`), el.firstChild);\n    }\n  } else {\n    el.insertBefore(document.createTextNode(`${css}\\n`), el.firstChild);\n  }\n}\n\n/**\n * Insert a CSS rule. Deduplicates by rule key.\n */\nexport function insertRule(key: string, css: string): void {\n  if (insertedRules.has(key)) {\n    const prev = ruleCssByKey.get(key);\n    if (prev != null && prev !== css) {\n      warnIfDuplicateRuleKeyConflict(key, prev, css);\n    }\n    return;\n  }\n  insertedRules.add(key);\n  ruleCssByKey.set(key, css);\n  allRules.push(css);\n  if (RUNTIME_DISABLED && !ssrBuffer) return;\n  pendingRules.push(css);\n  scheduleFlush();\n}\n\n/**\n * Insert multiple CSS rules at once.\n */\nexport function insertRules(rules: Array<{ key: string; css: string }>): void {\n  let added = false;\n  for (const { key, css } of rules) {\n    if (insertedRules.has(key)) {\n      const prev = ruleCssByKey.get(key);\n      if (prev != null && prev !== css) {\n        warnIfDuplicateRuleKeyConflict(key, prev, css);\n      }\n      continue;\n    }\n    insertedRules.add(key);\n    ruleCssByKey.set(key, css);\n    allRules.push(css);\n    if (!RUNTIME_DISABLED || ssrBuffer) {\n      pendingRules.push(css);\n      added = true;\n    }\n  }\n  if (added) scheduleFlush();\n}\n\n/**\n * Replace a CSS rule (used for HMR). Removes the old rule and inserts the new one.\n */\nexport function replaceRule(key: string, css: string): void {\n  if (!isBrowser || RUNTIME_DISABLED) return;\n\n  insertedRules.delete(key);\n  ruleCssByKey.delete(key);\n\n  // Remove existing rule from the sheet if possible\n  const el = getStyleElement();\n  const sheet = el.sheet;\n  if (sheet) {\n    for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n      // We can't reliably match by key in CSSOM, so for HMR we fall back to\n      // clearing and re-inserting. This is fine since HMR is dev-only.\n    }\n  }\n\n  insertRule(key, css);\n}\n\n/**\n * Start collecting CSS for SSR. Returns a function to stop collection and get the CSS.\n */\nexport function startCollection(): () => string {\n  ssrBuffer = [];\n  return () => {\n    const css = ssrBuffer ? ssrBuffer.join('\\n') : '';\n    ssrBuffer = null;\n    return css;\n  };\n}\n\n/**\n * Return all registered CSS as a string.\n *\n * Unlike `collectStyles`, this doesn't require wrapping a render function.\n * It simply returns every CSS rule that has been registered via\n * `styles.component`, `styles.class`, `tokens.create`, `keyframes.create`, etc.\n *\n * Ideal for SSR frameworks that need the CSS separately from the render\n * pass (e.g. TanStack Start's `head()`, Next.js metadata, Remix links).\n *\n * @example\n * ```ts\n * import { getRegisteredCss } from 'typestyles/server';\n *\n * // In a route's head/meta function:\n * export const head = () => ({\n *   styles: [{ id: 'typestyles', children: getRegisteredCss() }],\n * });\n * ```\n */\nexport function getRegisteredCss(): string {\n  return allRules.join('\\n');\n}\n\n/**\n * Reset all state (useful for testing).\n */\nexport function reset(): void {\n  insertedRules.clear();\n  ruleCssByKey.clear();\n  pendingRules = [];\n  allRules.length = 0;\n  flushScheduled = false;\n  ssrBuffer = null;\n  if (isBrowser && styleElement) {\n    styleElement.remove();\n    styleElement = null;\n  }\n}\n\n/**\n * Flush all pending rules synchronously. Used for SSR and testing.\n */\nexport function flushSync(): void {\n  flush();\n}\n\n/**\n * Invalidate all dedup keys that start with the given prefix.\n * Also removes matching rules from the live stylesheet.\n * Used for HMR — allows modules to re-register their styles after editing.\n */\nexport function invalidatePrefix(prefix: string): void {\n  for (const key of insertedRules) {\n    if (key.startsWith(prefix)) {\n      insertedRules.delete(key);\n      ruleCssByKey.delete(key);\n    }\n  }\n\n  releaseReservedNamespacesForComponentOrClassNames(namespacesFromTypestylesHmrPrefixes([prefix]));\n\n  if (!isBrowser) return;\n\n  const el = styleElement;\n  if (!el) return;\n  const sheet = el.sheet;\n  if (!sheet) return;\n\n  for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n    const rule = sheet.cssRules[i];\n    if (ruleMatchesPrefix(rule, prefix)) {\n      sheet.deleteRule(i);\n    }\n  }\n}\n\n/**\n * Invalidate a list of exact keys or prefixes.\n * Each entry in `keys` is treated as an exact key match.\n * Each entry in `prefixes` is treated as a prefix match.\n * Used for HMR to invalidate all styles from a module at once.\n */\nexport function invalidateKeys(keys: string[], prefixes: string[]): void {\n  for (const key of keys) {\n    insertedRules.delete(key);\n    ruleCssByKey.delete(key);\n  }\n  for (const prefix of prefixes) {\n    for (const key of insertedRules) {\n      if (key.startsWith(prefix)) {\n        insertedRules.delete(key);\n        ruleCssByKey.delete(key);\n      }\n    }\n  }\n\n  releaseReservedNamespacesForComponentOrClassNames(namespacesFromTypestylesHmrPrefixes(prefixes));\n\n  if (!isBrowser) return;\n\n  const el = styleElement;\n  if (!el) return;\n  const sheet = el.sheet;\n  if (!sheet) return;\n\n  const keySet = new Set(keys);\n  for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n    const rule = sheet.cssRules[i];\n    let shouldRemove = false;\n\n    for (const prefix of prefixes) {\n      if (ruleMatchesPrefix(rule, prefix)) {\n        shouldRemove = true;\n        break;\n      }\n    }\n\n    if (!shouldRemove) {\n      // Check exact key matches — for tokens/themes/keyframes,\n      // we match based on rule content patterns\n      const ruleText = rule.cssText;\n      for (const key of keySet) {\n        if (ruleMatchesKey(ruleText, key)) {\n          shouldRemove = true;\n          break;\n        }\n      }\n    }\n\n    if (shouldRemove) {\n      sheet.deleteRule(i);\n    }\n  }\n}\n\n/**\n * Drop every rule key tied to a `styles.component('namespace', …)` registration, including\n * `@layer`-wrapped keys (`layer:….:.namespace-…`), and release reserved namespace entries.\n * Used for Vite HMR and for dev recovery when a module re-runs before `hot.dispose`.\n */\nexport function invalidateComponentNamespaceForDev(namespace: string): void {\n  const selectorInfix = `.${namespace}-`;\n  const keysToDrop: string[] = [];\n  for (const k of insertedRules) {\n    if (k.includes(selectorInfix)) {\n      keysToDrop.push(k);\n    }\n  }\n  invalidateKeys(keysToDrop, [selectorInfix]);\n}\n\nfunction ruleMatchesPrefix(rule: CSSRule, prefix: string): boolean {\n  if (prefix.startsWith('font-face:')) {\n    const family = prefix.slice('font-face:'.length).split(':')[0];\n    // CSSFontFaceRule has type 5 and cssText contains @font-face\n    if (rule.cssText.includes('@font-face')) {\n      return rule.cssText.includes(`\"${family}\"`) || rule.cssText.includes(`'${family}'`);\n    }\n    return false;\n  }\n  if ('selectorText' in rule) {\n    return (rule as CSSStyleRule).selectorText.startsWith(prefix);\n  }\n  if ('name' in rule && prefix.startsWith('keyframes:')) {\n    return (rule as CSSKeyframesRule).name === prefix.slice('keyframes:'.length);\n  }\n  // For at-rules wrapping style rules, check inner rules\n  if ('cssRules' in rule) {\n    const innerRules = (rule as CSSGroupingRule).cssRules;\n    for (let i = 0; i < innerRules.length; i++) {\n      if (ruleMatchesPrefix(innerRules[i], prefix)) return true;\n    }\n  }\n  return false;\n}\n\nfunction ruleMatchesKey(cssText: string, key: string): boolean {\n  if (key.startsWith('tokens:')) {\n    // tokens:color or tokens:color@layerName -> :root rule with --color- custom properties\n    const rest = key.slice('tokens:'.length);\n    const at = rest.lastIndexOf('@');\n    const namespace = at === -1 ? rest : rest.slice(0, at);\n    return cssText.includes(`:root`) && cssText.includes(`--${namespace}-`);\n  }\n  if (key.startsWith('theme:')) {\n    // theme:dark -> .theme-dark selector\n    const name = key.slice('theme:'.length);\n    return cssText.includes(`.theme-${name}`);\n  }\n  if (key.startsWith('keyframes:')) {\n    const name = key.slice('keyframes:'.length);\n    return cssText.includes(`@keyframes ${name}`);\n  }\n  return false;\n}\n","import { startCollection, flushSync, getRegisteredCss } from './sheet';\n\nexport { getRegisteredCss };\n\n/**\n * Collect all CSS generated during a render pass (for SSR).\n *\n * Wraps a synchronous render function and captures all CSS that would\n * normally be injected into the DOM. Returns both the render result\n * and the collected CSS string.\n *\n * For frameworks where you need the CSS separately from the render pass\n * (e.g. TanStack Start's `head()`, Next.js metadata), use the simpler\n * `getRegisteredCss()` instead.\n *\n * @example\n * ```ts\n * import { collectStyles } from 'typestyles/server';\n * import { renderToString } from 'react-dom/server';\n *\n * const { html, css } = collectStyles(() => renderToString(<App />));\n *\n * const fullHtml = `\n *   <html>\n *     <head><style id=\"typestyles\">${css}</style></head>\n *     <body>${html}</body>\n *   </html>\n * `;\n * ```\n */\nexport function collectStyles<T>(renderFn: () => T): { html: T; css: string } {\n  const endCollection = startCollection();\n\n  const html = renderFn();\n  flushSync();\n  const css = endCollection();\n\n  return { html, css };\n}\n"]}