@wippy-fe/vite-plugin 0.0.53 → 0.0.55

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../@wippy-fe--shared/src/visibility.ts","../../@wippy-fe--shared/src/index.ts","../src/page-plugin.ts","../src/shared.ts","../src/component-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * Host-owned logical activity for a retained web component.\n *\n * This is deliberately independent from CSS visibility, viewport\n * intersection, and document visibility. Hosts set it before connection and\n * update it without replacing the element when a retained surface changes\n * ownership.\n */\nexport const WIPPY_VISIBILITY_ATTRIBUTE = 'data-wippy-visible'\n\n/** Parse the public attribute. Absent or invalid values are unmanaged. */\nexport function readWippyVisibility(element: Element): boolean | null {\n const value = element.getAttribute(WIPPY_VISIBILITY_ATTRIBUTE)\n if (value === 'true')\n return true\n if (value === 'false')\n return false\n return null\n}\n\n/**\n * Reflect logical activity onto an element without a redundant attribute\n * reaction. Call before appending for the initial value and on ownership\n * changes thereafter; neither path remounts the element.\n */\nexport function setWippyVisibility(element: Element, visible: boolean): void {\n const next = String(visible)\n if (element.getAttribute(WIPPY_VISIBILITY_ATTRIBUTE) !== next)\n element.setAttribute(WIPPY_VISIBILITY_ATTRIBUTE, next)\n}\n","/**\n * Cross-boundary contracts shared between the gen-2-chat host and the\n * `@wippy-fe/*` consumer packages.\n *\n * **Pure contracts and dependency-free DOM helpers.** No framework runtime or\n * `@wippy-fe/proxy` dependency. Importing from this module never loads\n * the proxy globals checker — it is safe to import from anywhere in the\n * host source tree without tripping the `host-import-guard` Vite plugin\n * (this package is on the allowlist).\n *\n * **Status: Draft 1 (preview).** Field names and shapes may change\n * between minor releases until a production consumer drives the corner\n * cases out.\n */\n\n// ─── Layout bus envelopes ────────────────────────────────────────────\n\n/**\n * In-tab broadcast envelope. Same shape on both sides of the bus —\n * iframe panels, host-mounted web components, and headless services\n * all see this object.\n */\nexport interface BroadcastEnvelope {\n channel: string\n payload: unknown\n sourcePanelId: string | null\n targetPanelId: string | null\n}\n\n/**\n * Panel-bound layout bus exposed on `el.__wippyHostBus` for web\n * components mounted as `kind: 'component'` panels. Source / target\n * attribution is set by the host — publishers cannot spoof it.\n */\nexport interface LayoutBusBound {\n /** 1:N broadcast — every other panel receives, sender excluded. */\n broadcast: (channel: string, payload: unknown) => void\n /** 1:1 send — only `target` receives. Unknown targets are no-ops. */\n send: (target: string, channel: string, payload: unknown) => void\n /** Subscribe; returns an `off()` for cleanup. */\n subscribe: (handler: (env: BroadcastEnvelope) => void) => () => void\n}\n\n// ─── Layout mutation targets ─────────────────────────────────────────\n\n/**\n * Drop target positions (relative to a slot rect). Reserved for the\n * future panelDrag capability; declared in v1 for forward compat.\n */\nexport type DropPosition = 'left' | 'right' | 'top' | 'bottom' | 'center' | 'none'\n\n/**\n * Slot size grammar (mirrors `@wippy-fe/layout` `SizeValue`). Tight\n * whitelist — `clamp()`, `minmax()`, `min-content`, `calc()`, em/rem/\n * vh/vw are rejected at validateLayout time. See `@wippy-fe/layout`\n * `helpers.ts` \"Size grammar\" for rationale.\n */\nexport type SizeValue\n = | 'auto'\n | `${number}fr`\n | `${number}px`\n | `${number}%`\n\n/** Pixel-only size, used for min/max and drawer dimensions. */\nexport type PixelSize = `${number}px`\n\n/**\n * Target for addPanel / movePanel. `relativeTo` names a panel already in\n * the tree; `position` picks the drop relative to that panel's rect.\n * Omit `relativeTo` to attach to the root tree (position becomes\n * direction-aware).\n */\nexport interface PanelTarget {\n relativeTo?: string\n position: DropPosition\n size?: SizeValue\n}\n\n// ─── Global-name constants ───────────────────────────────────────────\n//\n// These literal strings name the four `window.*` globals that the host\n// writes and consumer code reads. Both sides MUST agree on the spelling\n// — moving a typo here would silently break communication across the\n// host/proxy boundary. No `Window` augmentation is declared in this\n// package because the augmentation references host-side types\n// (`AppConfig`, `ProxyApiInstance`); host-side `src/shared/constants/global.ts`\n// keeps the `declare global` block.\n\nexport const GLOBAL_CONFIG_VAR = '__WIPPY_APP_CONFIG__' as const\nexport const GLOBAL_PROXY_CONFIG_VAR = '__WIPPY_PROXY_CONFIG__' as const\nexport const GLOBAL_API_PROVIDER = '__WIPPY_APP_API__' as const\nexport const GLOBAL_WEB_COMPONENT_CACHE = '__WIPPY_WEB_COMPONENT_CACHE__' as const\n\n// ─── HTML data-role markers ─────────────────────────────────────────\n//\n// `data-role` attributes that the host and dev-proxy use to find anchor\n// elements in the consuming app's `app.html`. The host removes / inserts\n// scripts at the `@wippy/scripts` element; dev-proxy reads the consuming\n// app's package.json from the `@wippy/package` JSON script (injected at\n// build time by `@wippy-fe/vite-plugin`'s `wippyPackagePlugin()`).\n\nexport const WIPPY_SCRIPTS_DATA_ROLE = '@wippy/scripts' as const\nexport const WIPPY_PACKAGE_DATA_ROLE = '@wippy/package' as const\n\n// ─── Retained web-component visibility ─────────────────────────────\n\nexport { readWippyVisibility, setWippyVisibility, WIPPY_VISIBILITY_ATTRIBUTE } from './visibility.ts'\n","/**\n * `wippyPagePlugin` — for `view.page` packages (those with `wippy.type === 'page'`).\n *\n * Two outputs from a single resolved JSON source:\n * 1. An inline `<script type=\"application/json\" data-role=\"@wippy/package\">`\n * injected at the top of `app.html`'s `<head>`. Read at boot by\n * host-less dev-proxy.\n * 2. `wippy-meta.json` emitted into Vite's `outDir`. Read at request time\n * by `wippy/views` in wippy-hosted mode.\n *\n * Both contain the consumer's `package.json` with every `file://<relative>`\n * reference replaced by its file contents. Single source = identical render\n * in either mode.\n */\n\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { LoadedPackage } from './shared'\nimport { resolve } from 'node:path'\nimport { WIPPY_PACKAGE_DATA_ROLE } from '@wippy-fe/shared'\nimport { defangScriptClose, loadPackage, resolveFileRefs, validatePagePackage } from './shared'\n\nexport interface WippyPagePluginOptions {\n /** Override the `package.json` path. Defaults to `<viteRoot>/package.json`. */\n packageJsonPath?: string\n /**\n * If `true`, fail the build when `package.json` is missing. If `false`\n * (default), the plugin silently no-ops — useful for shared configs\n * where some target apps don't need the injection.\n */\n required?: boolean\n}\n\nexport function wippyPagePlugin(options: WippyPagePluginOptions = {}): Plugin {\n let root: string\n // Cache so transformIndexHtml + generateBundle don't re-read package.json\n // and don't double-resolve file:// refs within the same build.\n let resolvedSerialized: string | null = null\n\n function compute(): string | null {\n if (resolvedSerialized !== null)\n return resolvedSerialized\n const pkgPath = options.packageJsonPath ?? resolve(root, 'package.json')\n let loaded: LoadedPackage\n try {\n loaded = loadPackage(pkgPath)\n }\n catch (err) {\n if (options.required)\n throw new Error(`[@wippy-fe/vite-plugin] failed to read ${pkgPath}: ${(err as Error).message}`)\n return null\n }\n // Strict spec validation — throws on any wippy-block shape violation\n // (wrong `wippy.type`, missing `wippy.path`, forbidden `wippy.tagName`,\n // etc.). We throw rather than warn so misconfigurations fail the build\n // instead of silently shipping broken metadata. See shared.ts for the\n // full rule set.\n validatePagePackage(loaded.pkg, pkgPath)\n\n // `file://` basename convention violations also throw: the\n // `.do-not-link.` infix is the AI-readable directive that prevents\n // agents from `<link>`-ing the file directly. A consumer using\n // `file://theme.css` defeats that signal even though the resolved\n // content is correct, so we fail the build to force the rename.\n const resolvedPkg = resolveFileRefs(loaded.pkg, loaded.baseDir, (msg) => {\n throw new Error(msg)\n })\n resolvedSerialized = JSON.stringify(resolvedPkg)\n return resolvedSerialized\n }\n\n // Build-time reframed-incompatibility scan (EE2-2313). Warn once per hostile\n // API so a fragment-incompatible page is caught at BUILD, not in prod. Skipped\n // when the page already opts out (wippy.renderEngine: 'iframe').\n const warnedApis = new Set<string>()\n let optedOut: boolean | null = null\n const isOptedOut = (): boolean => {\n if (optedOut === null) {\n try {\n optedOut = (JSON.parse(compute() ?? '{}')?.wippy?.renderEngine) === 'iframe'\n }\n catch {\n optedOut = false\n }\n }\n return optedOut\n }\n\n return {\n name: '@wippy-fe/vite-plugin:wippy-page',\n enforce: 'pre',\n configResolved(config: ResolvedConfig) {\n root = config.root\n resolvedSerialized = null\n },\n transform(code: string, id: string) {\n if (/node_modules/.test(id) || !/\\.(?:vue|m?[jt]sx?)$/.test(id) || isOptedOut())\n return null\n const hostile: Array<[RegExp, string]> = [\n [/\\belementFromPoint\\b/, 'elementFromPoint (hit-testing returns null in a reframed realm)'],\n [/\\bwindow\\.scroll(?:X|Y|To|By)?\\b/, 'window scroll geometry (always 0 in a reframed realm)'],\n [/\\bmatchMedia\\s*\\(/, 'matchMedia (resolves against the HOST viewport, not the fragment panel)'],\n [/\\b\\d+(?:\\.\\d+)?v[hw]\\b/, 'vh/vw units (resolve against the HOST viewport)'],\n [/position\\s*:\\s*fixed/, 'position:fixed (pins to the HOST viewport, not the fragment panel)'],\n ]\n for (const [re, msg] of hostile) {\n if (re.test(code) && !warnedApis.has(msg)) {\n warnedApis.add(msg)\n this.warn(`[@wippy-fe/vite-plugin] this view.page uses ${msg}. Such APIs misbehave inside a Web Fragment. If it will run under the fragment engine, set \\`wippy.renderEngine: \"iframe\"\\` in package.json to render it as a legacy iframe. [EE2-2313]`)\n }\n }\n return null\n },\n transformIndexHtml: {\n order: 'pre',\n handler(html) {\n const json = compute()\n if (json === null)\n return html\n const safeJson = defangScriptClose(json)\n const tag = `<script type=\"application/json\" data-role=\"${WIPPY_PACKAGE_DATA_ROLE}\">${safeJson}</script>`\n if (html.includes('<head>'))\n return html.replace('<head>', `<head>\\n ${tag}`)\n return tag + html\n },\n },\n generateBundle() {\n const json = compute()\n if (json === null)\n return\n this.emitFile({\n type: 'asset',\n fileName: 'wippy-meta.json',\n source: json,\n })\n },\n }\n}\n","/**\n * Shared helpers for `wippyPagePlugin` and `wippyComponentPlugin`.\n *\n * Both plugins produce `dist/wippy-meta.json` — a resolved copy of the\n * consumer's `package.json` with every `file://<relative-path>` reference\n * replaced by the referenced file's UTF-8 contents. The page plugin\n * additionally injects the same resolved JSON into `app.html` as an\n * `<script type=\"application/json\" data-role=\"@wippy/package\">` so host-less\n * mode (gen-2-chat dev-proxy) can read it synchronously at boot.\n *\n * `wippy-meta.json` is the MANDATORY contract between consumers and\n * `wippy/views`. See `web_components.spec.md` § \"Package metadata: source of\n * truth\" for the full spec.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { basename, dirname, resolve } from 'node:path'\n\nexport interface LoadedPackage {\n /** The parsed `package.json` as a JS object. */\n pkg: Record<string, unknown>\n /**\n * Absolute path to the directory containing `package.json` — used as the\n * base for `file://` reference resolution.\n */\n baseDir: string\n}\n\n/**\n * Read + parse `package.json` from disk. Throws if the file is missing or\n * not valid JSON — the build is expected to fail loud rather than silently\n * skip the package.\n */\nexport function loadPackage(packageJsonPath: string): LoadedPackage {\n const raw = readFileSync(packageJsonPath, 'utf-8')\n const pkg = JSON.parse(raw) as Record<string, unknown>\n return { pkg, baseDir: dirname(packageJsonPath) }\n}\n\n/**\n * camelCase → kebab-case conversion used by the `*.do-not-link.<ext>`\n * naming convention. Treats consecutive capitals as a single word so\n * `customCSS` → `custom-css` (not `custom-c-s-s`). Matches lodash's\n * kebabCase semantics for these specific input shapes.\n *\n * Examples codified in tests:\n * - `customCSS` → `custom-css`\n * - `customCss` → `custom-css`\n * - `cssVariables` → `css-variables`\n * - `tailwindConfig` → `tailwind-config`\n * - `description` → `description`\n * - `URLPath` → `url-path`\n */\nexport function kebabize(camel: string): string {\n return camel\n // Insert a hyphen between a run of capitals and a following Capital+lowercase:\n // \"URLPath\" → \"URL-Path\"\n // \"customCSS\" stays \"customCSS\" here (no following lowercase)\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n // Insert a hyphen between a lowercase/digit and a following capital:\n // \"customCSS\" → \"custom-CSS\"\n // \"URL-Path\" → \"URL-Path\" (unchanged — already split)\n .replace(/([a-z\\d])([A-Z])/g, '$1-$2')\n .toLowerCase()\n}\n\n/**\n * Validator used by `resolveFileRefs` to surface mismatches between a\n * `file://` reference's basename and the canonical `<field-kebab>.do-not-link.<ext>`\n * convention. Returns the expected basename (for use in the warning\n * message) or `null` if the actual basename already conforms.\n *\n * Convention: basename without extension MUST end with `.do-not-link` and\n * its prefix MUST equal `kebabize(fieldName)`. Examples:\n * - field `customCSS`, file `custom-css.do-not-link.css` → null (ok)\n * - field `customCSS`, file `my-theme.css` → \"custom-css.do-not-link.css\"\n * - field `customCSS`, file `custom-css.css` → \"custom-css.do-not-link.css\"\n *\n * `null` field name (top-level / array index) skips the check.\n */\nexport function expectedDoNotLinkBasename(fieldName: string | null, actualBasename: string): string | null {\n if (!fieldName)\n return null\n const dot = actualBasename.lastIndexOf('.')\n if (dot <= 0)\n return `${kebabize(fieldName)}.do-not-link.<ext>`\n const ext = actualBasename.slice(dot + 1)\n const expected = `${kebabize(fieldName)}.do-not-link.${ext}`\n if (actualBasename === expected)\n return null\n return expected\n}\n\n/**\n * Recursively replace every string value of shape `file://<relative-path>`\n * with the referenced file's UTF-8 contents. Paths are resolved against\n * `baseDir` (typically the directory containing `package.json`).\n *\n * Non-string, non-array, non-object values pass through unchanged. Missing\n * files throw — the convention is that `file://` refs are load-bearing.\n *\n * `onWarn` (optional) is called when a `file://` basename doesn't match the\n * canonical `<field-kebab>.do-not-link.<ext>` convention. The warning is\n * advisory — resolution still succeeds — so consumers can opt out by not\n * passing the callback.\n */\nexport function resolveFileRefs<T>(\n node: T,\n baseDir: string,\n onWarn?: (msg: string) => void,\n fieldName: string | null = null,\n): T {\n if (typeof node === 'string' && node.startsWith('file://')) {\n const rel = node.slice('file://'.length)\n const abs = resolve(baseDir, rel)\n if (onWarn) {\n const expected = expectedDoNotLinkBasename(fieldName, basename(rel))\n if (expected) {\n onWarn(`[@wippy-fe/vite-plugin] file:// basename \"${basename(rel)}\" for field \"${fieldName}\" does not match the *.do-not-link.<ext> convention. Expected: \"${expected}\". See web_components.spec.md § \"Package metadata: source of truth\".`)\n }\n }\n return readFileSync(abs, 'utf-8') as unknown as T\n }\n if (Array.isArray(node))\n return node.map(v => resolveFileRefs(v, baseDir, onWarn, fieldName)) as unknown as T\n if (node && typeof node === 'object') {\n return Object.fromEntries(\n Object.entries(node as Record<string, unknown>)\n .map(([k, v]) => [k, resolveFileRefs(v, baseDir, onWarn, k)]),\n ) as unknown as T\n }\n return node\n}\n\n/**\n * Defang `</script>` sequences inside a JSON string so it's safe to embed\n * verbatim inside an inline `<script type=\"application/json\">` tag. Case\n * insensitive (`</SCRIPT`, `</Script`, etc. all need escaping).\n */\nexport function defangScriptClose(json: string): string {\n return json.replace(/<\\/script/gi, '<\\\\/script')\n}\n\n/**\n * Validate a consumer's `package.json` against the `wippy-component-1.0`\n * spec FOR A PAGE PACKAGE. Throws with a clear, actionable message on any\n * violation. Called by `wippyPagePlugin` at build time so misconfigurations\n * fail the build instead of silently shipping broken metadata.\n *\n * We throw rather than warn because nobody reads build warnings — they\n * scroll past in CI output and get filtered out of IDE diagnostics. A\n * field-shape mistake that warns today is a real bug tomorrow.\n *\n * Rules enforced (must all hold for a page):\n * - Top-level `name` and `version` must be strings.\n * - `wippy` must be a plain object.\n * - `wippy.type`, when set, MUST equal `'page'` (not `'component'`,\n * `'widget'`, or anything else).\n * - `wippy.path` is REQUIRED for pages (HTML entry path).\n * - `wippy.tagName` is FORBIDDEN for pages (custom-element-tag is a\n * component-only concept).\n * - `specification`, when set, MUST equal `'wippy-component-1.0'`.\n */\nexport function validatePagePackage(pkg: Record<string, unknown>, packageJsonPath: string): void {\n const prefix = `[@wippy-fe/vite-plugin] ${packageJsonPath}:`\n\n if (typeof pkg.name !== 'string' || pkg.name.length === 0)\n throw new Error(`${prefix} \\`name\\` is required and must be a non-empty string`)\n if (typeof pkg.version !== 'string' || pkg.version.length === 0)\n throw new Error(`${prefix} \\`version\\` is required and must be a non-empty string`)\n if (pkg.specification !== undefined && pkg.specification !== 'wippy-component-1.0')\n throw new Error(`${prefix} \\`specification\\` must be \"wippy-component-1.0\" (got ${JSON.stringify(pkg.specification)})`)\n\n const wippy = pkg.wippy\n if (wippy === undefined || wippy === null)\n throw new Error(`${prefix} top-level \\`wippy\\` block is required for a page package using wippyPagePlugin()`)\n if (typeof wippy !== 'object' || Array.isArray(wippy))\n throw new Error(`${prefix} \\`wippy\\` must be a JSON object (got ${Array.isArray(wippy) ? 'array' : typeof wippy})`)\n\n const w = wippy as Record<string, unknown>\n\n if (w.type !== undefined && w.type !== 'page')\n throw new Error(`${prefix} \\`wippy.type\\` is \"${String(w.type)}\" but wippyPagePlugin() was used. Either set \\`wippy.type: \"page\"\\` or switch to wippyComponentPlugin() for components/widgets.`)\n\n if (w.path === undefined)\n throw new Error(`${prefix} \\`wippy.path\\` is required for a page package (the relative path to the HTML entry, e.g. \"dist/app.html\")`)\n if (typeof w.path !== 'string' || w.path.length === 0)\n throw new Error(`${prefix} \\`wippy.path\\` must be a non-empty string (got ${JSON.stringify(w.path)})`)\n\n if (w.tagName !== undefined)\n throw new Error(`${prefix} \\`wippy.tagName\\` is set on a page package but the field is component-only. Either remove it or switch to wippyComponentPlugin().`)\n\n // EE2-2313: per-page render engine. The string form must be a known value; the\n // reserved object form ({ route?, artifact? }) is permitted but not read yet.\n if (w.renderEngine !== undefined && typeof w.renderEngine === 'string'\n && w.renderEngine !== 'auto' && w.renderEngine !== 'iframe' && w.renderEngine !== 'fragment') {\n throw new Error(`${prefix} \\`wippy.renderEngine\\` must be \"auto\", \"iframe\", or \"fragment\" (got ${JSON.stringify(w.renderEngine)}). Absent = \"auto\" (follow the deployment's global engine); use \"iframe\" to opt a fragment-incompatible page out.`)\n }\n}\n\n/**\n * Validate a consumer's `package.json` for a component/widget package using\n * `wippyComponentPlugin`. Throws on any violation. Same rationale as\n * `validatePagePackage` — fail loud at build time.\n *\n * Rules enforced (must all hold for a component):\n * - Top-level `name` and `version` must be strings.\n * - `wippy` must be a plain object.\n * - `wippy.type`, when set, MUST be one of `'component'` or `'widget'` (the\n * spec uses both interchangeably for ESM-shipped custom elements).\n * - `wippy.tagName` is REQUIRED for components — without it the host has\n * no element name to register against.\n * - `wippy.path` is FORBIDDEN for components (HTML-entry is a page-only\n * concept; components use top-level `browser` for the ESM entry).\n * - `specification`, when set, MUST equal `'wippy-component-1.0'`.\n * - `browser` SHOULD be set (the ESM entry path); only warn-by-throw if\n * absent because the plugin still emits useful meta without it.\n */\nexport function validateComponentPackage(pkg: Record<string, unknown>, packageJsonPath: string): void {\n const prefix = `[@wippy-fe/vite-plugin] ${packageJsonPath}:`\n\n if (typeof pkg.name !== 'string' || pkg.name.length === 0)\n throw new Error(`${prefix} \\`name\\` is required and must be a non-empty string`)\n if (typeof pkg.version !== 'string' || pkg.version.length === 0)\n throw new Error(`${prefix} \\`version\\` is required and must be a non-empty string`)\n if (pkg.specification !== undefined && pkg.specification !== 'wippy-component-1.0')\n throw new Error(`${prefix} \\`specification\\` must be \"wippy-component-1.0\" (got ${JSON.stringify(pkg.specification)})`)\n\n const wippy = pkg.wippy\n if (wippy === undefined || wippy === null)\n throw new Error(`${prefix} top-level \\`wippy\\` block is required for a component package using wippyComponentPlugin()`)\n if (typeof wippy !== 'object' || Array.isArray(wippy))\n throw new Error(`${prefix} \\`wippy\\` must be a JSON object (got ${Array.isArray(wippy) ? 'array' : typeof wippy})`)\n\n const w = wippy as Record<string, unknown>\n\n if (w.type !== undefined && w.type !== 'component' && w.type !== 'widget')\n throw new Error(`${prefix} \\`wippy.type\\` is \"${String(w.type)}\" but wippyComponentPlugin() was used. Either set \\`wippy.type: \"component\"\\` (or \"widget\") or switch to wippyPagePlugin() for pages.`)\n\n if (w.tagName === undefined)\n throw new Error(`${prefix} \\`wippy.tagName\\` is required for a component package (the custom-element tag name, e.g. \"example-mermaid\"). Without it the host cannot register the element.`)\n if (typeof w.tagName !== 'string' || w.tagName.length === 0)\n throw new Error(`${prefix} \\`wippy.tagName\\` must be a non-empty string (got ${JSON.stringify(w.tagName)})`)\n // Custom Elements spec (PotentialCustomElementName):\n // - MUST start with an ASCII lowercase letter [a-z]\n // - MUST contain a hyphen\n // - MAY contain ASCII lowercase letters, digits, or hyphens\n // (The full spec also allows ., _, and some Unicode ranges, but in practice\n // Wippy tag names only ever use [a-z0-9-]. We keep the check tight rather\n // than full-spec because a \"FOO-BAR\" or \"-leading\" passing validation today\n // would silently break tomorrow when `customElements.define()` rejects it.)\n //\n // Mirror twin: `@wippy-fe/proxy`'s `vue-warn-suppressor.ts` uses an\n // equivalent regex (`/^[a-z][a-z0-9]*-[a-z0-9-]*$/`) to decide whether\n // an unresolved Vue tag \"looks like a pending-registration custom\n // element\". The two patterns match exactly the same name shape — keep\n // them in sync. Functionally identical; differ only in character-class\n // notation (`[\\da-z]` vs `[a-z0-9]`).\n if (!/^[a-z][\\da-z]*-[-\\da-z]*$/.test(w.tagName))\n throw new Error(`${prefix} \\`wippy.tagName\\` \"${w.tagName}\" is not a valid Custom Elements name. Must start with an ASCII lowercase letter, contain a hyphen, and use only lowercase letters, digits, and hyphens. Examples: \"example-mermaid\", \"my-widget-v2\".`)\n // Reserved names that browsers refuse to register (HTML5 spec):\n const reserved = new Set([\n 'annotation-xml',\n 'color-profile',\n 'font-face',\n 'font-face-src',\n 'font-face-uri',\n 'font-face-format',\n 'font-face-name',\n 'missing-glyph',\n ])\n if (reserved.has(w.tagName))\n throw new Error(`${prefix} \\`wippy.tagName\\` \"${w.tagName}\" is a reserved HTML name; browsers will refuse to register it.`)\n\n if (w.path !== undefined)\n throw new Error(`${prefix} \\`wippy.path\\` is set on a component package but the field is page-only. Components use top-level \\`browser\\` for the ESM entry path. Either remove \\`wippy.path\\` or switch to wippyPagePlugin().`)\n\n // EE2-2313: render engine applies to view.page only — a view.component's render\n // path is fixed, so the flag is meaningless (and would silently do nothing) here.\n if (w.renderEngine !== undefined)\n throw new Error(`${prefix} \\`wippy.renderEngine\\` is set on a component package but the field is page-only (a view.component's render path is fixed). Remove it.`)\n}\n","/**\n * `wippyComponentPlugin` — for `view.component` packages (those with\n * `wippy.type === 'component'`).\n *\n * Components ship a JS module, not an HTML entry — there's nothing to inject\n * an inline `<script>` into. The plugin's only job is to emit `wippy-meta.json`\n * into Vite's `outDir` for `wippy/views` to read at request time.\n *\n * The `wippy-meta.json` file is the MANDATORY contract between components and\n * `wippy/views`. See `web_components.spec.md` § \"Package metadata: source of\n * truth\". Without it, `views` falls back to its legacy YAML-synthesis path,\n * which is deprecated and exists only for migration.\n */\n\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { LoadedPackage } from './shared'\nimport { resolve } from 'node:path'\nimport { loadPackage, resolveFileRefs, validateComponentPackage } from './shared'\n\nexport interface WippyComponentPluginOptions {\n /** Override the `package.json` path. Defaults to `<viteRoot>/package.json`. */\n packageJsonPath?: string\n /**\n * If `true`, fail the build when `package.json` is missing. If `false`\n * (default), the plugin silently no-ops.\n */\n required?: boolean\n}\n\nexport function wippyComponentPlugin(options: WippyComponentPluginOptions = {}): Plugin {\n let root: string\n\n return {\n name: '@wippy-fe/vite-plugin:wippy-component',\n enforce: 'pre',\n configResolved(config: ResolvedConfig) {\n root = config.root\n },\n generateBundle() {\n const pkgPath = options.packageJsonPath ?? resolve(root, 'package.json')\n let loaded: LoadedPackage\n try {\n loaded = loadPackage(pkgPath)\n }\n catch (err) {\n if (options.required)\n throw new Error(`[@wippy-fe/vite-plugin] failed to read ${pkgPath}: ${(err as Error).message}`)\n return\n }\n // Strict spec validation — throws on any wippy-block shape violation\n // (wrong `wippy.type`, missing `wippy.tagName`, forbidden `wippy.path`,\n // tagName without hyphen, etc.). We throw rather than warn so\n // misconfigurations fail the build instead of silently shipping broken\n // metadata. See shared.ts for the full rule set.\n validateComponentPackage(loaded.pkg, pkgPath)\n\n // `file://` basename convention violations throw — see page-plugin's\n // identical comment for the rationale.\n const resolvedPkg = resolveFileRefs(loaded.pkg, loaded.baseDir, (msg) => {\n throw new Error(msg)\n })\n this.emitFile({\n type: 'asset',\n fileName: 'wippy-meta.json',\n source: JSON.stringify(resolvedPkg),\n })\n },\n }\n}\n","/**\n * Vite plugins for Wippy view.page and view.component packages.\n *\n * Both plugins emit `dist/wippy-meta.json` — the consumer's `package.json`\n * with every `file://<relative-path>` reference replaced by the referenced\n * file's UTF-8 contents. `wippy-meta.json` is the MANDATORY contract between\n * consumers and `wippy/views` ≥ 1.0.31. See `web_components.spec.md` §\n * \"Package metadata: source of truth\" for the full spec.\n *\n * - `wippyPagePlugin()` — for `view.page` packages. Emits `wippy-meta.json`\n * AND injects an inline `<script data-role=\"@wippy/package\">` into the\n * built `app.html` (for host-less mode).\n * - `wippyComponentPlugin()` — for `view.component` packages. Emits\n * `wippy-meta.json` only; components have no HTML entry.\n *\n * Convention: bulky string fields (`customCSS`, `description`, etc.) should\n * be moved into separate files referenced via `file://` and named\n * `<field-name-kebab>.do-not-link.<ext>` — basename matches the kebab-case\n * wippy block field name (e.g. `customCSS` → `custom-css.do-not-link.css`,\n * `description` → `description.do-not-link.md`). The `.do-not-link.` infix\n * is what stops AI agents from `<link>`-ing the file directly into app.html.\n * The proxy injects the content at runtime from the resolved package metadata.\n *\n * **Status: Draft 1 (preview).** API may change between minor releases.\n */\n\nimport type { Plugin } from 'vite'\nimport { WIPPY_PACKAGE_DATA_ROLE } from '@wippy-fe/shared'\nimport { wippyPagePlugin } from './page-plugin'\n\nexport { WIPPY_PACKAGE_DATA_ROLE }\nexport { wippyComponentPlugin } from './component-plugin'\nexport type { WippyComponentPluginOptions } from './component-plugin'\nexport { wippyPagePlugin } from './page-plugin'\nexport type { WippyPagePluginOptions } from './page-plugin'\nexport type { WippyPagePluginOptions as WippyPackagePluginOptions } from './page-plugin'\n\n/**\n * @deprecated Use `wippyPagePlugin()` instead. The new name disambiguates\n * the page-side plugin from `wippyComponentPlugin()` introduced alongside it.\n * This alias preserves backwards compatibility for existing `vite.config.ts`\n * files and will be removed in a future major.\n */\nexport function wippyPackagePlugin(...args: Parameters<typeof wippyPagePlugin>): Plugin {\n return wippyPagePlugin(...args)\n}\n// Re-export the strict validators so CI tooling / external linters can\n// reuse the same rules the plugins enforce at build time.\nexport { validateComponentPackage, validatePagePackage } from './shared'\n"],"mappings":";ACsGO,IAAM,0BAA0B;;;ACrFvC,SAAS,WAAAA,gBAAe;;;ACFxB,SAAS,oBAAoB;AAC7B,SAAS,UAAU,SAAS,eAAe;AAiBpC,SAAS,YAAY,iBAAwC;AAClE,QAAM,MAAM,aAAa,iBAAiB,OAAO;AACjD,QAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,SAAO,EAAE,KAAK,SAAS,QAAQ,eAAe,EAAE;AAClD;AAgBO,SAAS,SAAS,OAAuB;AAC9C,SAAO,MAIJ,QAAQ,yBAAyB,OAAO,EAIxC,QAAQ,qBAAqB,OAAO,EACpC,YAAY;AACjB;AAgBO,SAAS,0BAA0B,WAA0B,gBAAuC;AACzG,MAAI,CAAC;AACH,WAAO;AACT,QAAM,MAAM,eAAe,YAAY,GAAG;AAC1C,MAAI,OAAO;AACT,WAAO,GAAG,SAAS,SAAS,CAAC;AAC/B,QAAM,MAAM,eAAe,MAAM,MAAM,CAAC;AACxC,QAAM,WAAW,GAAG,SAAS,SAAS,CAAC,gBAAgB,GAAG;AAC1D,MAAI,mBAAmB;AACrB,WAAO;AACT,SAAO;AACT;AAeO,SAAS,gBACd,MACA,SACA,QACA,YAA2B,MACxB;AACH,MAAI,OAAO,SAAS,YAAY,KAAK,WAAW,SAAS,GAAG;AAC1D,UAAM,MAAM,KAAK,MAAM,UAAU,MAAM;AACvC,UAAM,MAAM,QAAQ,SAAS,GAAG;AAChC,QAAI,QAAQ;AACV,YAAM,WAAW,0BAA0B,WAAW,SAAS,GAAG,CAAC;AACnE,UAAI,UAAU;AACZ,eAAO,6CAA6C,SAAS,GAAG,CAAC,gBAAgB,SAAS,mEAAmE,QAAQ,yEAAsE;AAAA,MAC7O;AAAA,IACF;AACA,WAAO,aAAa,KAAK,OAAO;AAAA,EAClC;AACA,MAAI,MAAM,QAAQ,IAAI;AACpB,WAAO,KAAK,IAAI,OAAK,gBAAgB,GAAG,SAAS,QAAQ,SAAS,CAAC;AACrE,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,WAAO,OAAO;AAAA,MACZ,OAAO,QAAQ,IAA+B,EAC3C,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,gBAAgB,GAAG,SAAS,QAAQ,CAAC,CAAC,CAAC;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,kBAAkB,MAAsB;AACtD,SAAO,KAAK,QAAQ,eAAe,YAAY;AACjD;AAsBO,SAAS,oBAAoB,KAA8B,iBAA+B;AAC/F,QAAM,SAAS,2BAA2B,eAAe;AAEzD,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW;AACtD,UAAM,IAAI,MAAM,GAAG,MAAM,sDAAsD;AACjF,MAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,WAAW;AAC5D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD;AACpF,MAAI,IAAI,kBAAkB,UAAa,IAAI,kBAAkB;AAC3D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD,KAAK,UAAU,IAAI,aAAa,CAAC,GAAG;AAExH,QAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,UAAa,UAAU;AACnC,UAAM,IAAI,MAAM,GAAG,MAAM,mFAAmF;AAC9G,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAClD,UAAM,IAAI,MAAM,GAAG,MAAM,yCAAyC,MAAM,QAAQ,KAAK,IAAI,UAAU,OAAO,KAAK,GAAG;AAEpH,QAAM,IAAI;AAEV,MAAI,EAAE,SAAS,UAAa,EAAE,SAAS;AACrC,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,OAAO,EAAE,IAAI,CAAC,iIAAiI;AAEjM,MAAI,EAAE,SAAS;AACb,UAAM,IAAI,MAAM,GAAG,MAAM,4GAA4G;AACvI,MAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,WAAW;AAClD,UAAM,IAAI,MAAM,GAAG,MAAM,mDAAmD,KAAK,UAAU,EAAE,IAAI,CAAC,GAAG;AAEvG,MAAI,EAAE,YAAY;AAChB,UAAM,IAAI,MAAM,GAAG,MAAM,oIAAoI;AAI/J,MAAI,EAAE,iBAAiB,UAAa,OAAO,EAAE,iBAAiB,YACzD,EAAE,iBAAiB,UAAU,EAAE,iBAAiB,YAAY,EAAE,iBAAiB,YAAY;AAC9F,UAAM,IAAI,MAAM,GAAG,MAAM,wEAAwE,KAAK,UAAU,EAAE,YAAY,CAAC,mHAAmH;AAAA,EACpP;AACF;AAoBO,SAAS,yBAAyB,KAA8B,iBAA+B;AACpG,QAAM,SAAS,2BAA2B,eAAe;AAEzD,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW;AACtD,UAAM,IAAI,MAAM,GAAG,MAAM,sDAAsD;AACjF,MAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,WAAW;AAC5D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD;AACpF,MAAI,IAAI,kBAAkB,UAAa,IAAI,kBAAkB;AAC3D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD,KAAK,UAAU,IAAI,aAAa,CAAC,GAAG;AAExH,QAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,UAAa,UAAU;AACnC,UAAM,IAAI,MAAM,GAAG,MAAM,6FAA6F;AACxH,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAClD,UAAM,IAAI,MAAM,GAAG,MAAM,yCAAyC,MAAM,QAAQ,KAAK,IAAI,UAAU,OAAO,KAAK,GAAG;AAEpH,QAAM,IAAI;AAEV,MAAI,EAAE,SAAS,UAAa,EAAE,SAAS,eAAe,EAAE,SAAS;AAC/D,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,OAAO,EAAE,IAAI,CAAC,uIAAuI;AAEvM,MAAI,EAAE,YAAY;AAChB,UAAM,IAAI,MAAM,GAAG,MAAM,gKAAgK;AAC3L,MAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW;AACxD,UAAM,IAAI,MAAM,GAAG,MAAM,sDAAsD,KAAK,UAAU,EAAE,OAAO,CAAC,GAAG;AAgB7G,MAAI,CAAC,4BAA4B,KAAK,EAAE,OAAO;AAC7C,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,EAAE,OAAO,uMAAuM;AAElQ,QAAM,WAAW,oBAAI,IAAI;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,SAAS,IAAI,EAAE,OAAO;AACxB,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,EAAE,OAAO,iEAAiE;AAE5H,MAAI,EAAE,SAAS;AACb,UAAM,IAAI,MAAM,GAAG,MAAM,qMAAqM;AAIhO,MAAI,EAAE,iBAAiB;AACrB,UAAM,IAAI,MAAM,GAAG,MAAM,wIAAwI;AACrK;;;ADzPO,SAAS,gBAAgB,UAAkC,CAAC,GAAW;AAC5E,MAAI;AAGJ,MAAI,qBAAoC;AAExC,WAAS,UAAyB;AAChC,QAAI,uBAAuB;AACzB,aAAO;AACT,UAAM,UAAU,QAAQ,mBAAmBC,SAAQ,MAAM,cAAc;AACvE,QAAI;AACJ,QAAI;AACF,eAAS,YAAY,OAAO;AAAA,IAC9B,SACO,KAAK;AACV,UAAI,QAAQ;AACV,cAAM,IAAI,MAAM,0CAA0C,OAAO,KAAM,IAAc,OAAO,EAAE;AAChG,aAAO;AAAA,IACT;AAMA,wBAAoB,OAAO,KAAK,OAAO;AAOvC,UAAM,cAAc,gBAAgB,OAAO,KAAK,OAAO,SAAS,CAAC,QAAQ;AACvE,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB,CAAC;AACD,yBAAqB,KAAK,UAAU,WAAW;AAC/C,WAAO;AAAA,EACT;AAKA,QAAM,aAAa,oBAAI,IAAY;AACnC,MAAI,WAA2B;AAC/B,QAAM,aAAa,MAAe;AAChC,QAAI,aAAa,MAAM;AACrB,UAAI;AACF,mBAAY,KAAK,MAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,iBAAkB;AAAA,MACtE,QACM;AACJ,mBAAW;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAwB;AACrC,aAAO,OAAO;AACd,2BAAqB;AAAA,IACvB;AAAA,IACA,UAAU,MAAc,IAAY;AAClC,UAAI,eAAe,KAAK,EAAE,KAAK,CAAC,uBAAuB,KAAK,EAAE,KAAK,WAAW;AAC5E,eAAO;AACT,YAAM,UAAmC;AAAA,QACvC,CAAC,wBAAwB,iEAAiE;AAAA,QAC1F,CAAC,oCAAoC,uDAAuD;AAAA,QAC5F,CAAC,qBAAqB,yEAAyE;AAAA,QAC/F,CAAC,0BAA0B,iDAAiD;AAAA,QAC5E,CAAC,wBAAwB,oEAAoE;AAAA,MAC/F;AACA,iBAAW,CAAC,IAAI,GAAG,KAAK,SAAS;AAC/B,YAAI,GAAG,KAAK,IAAI,KAAK,CAAC,WAAW,IAAI,GAAG,GAAG;AACzC,qBAAW,IAAI,GAAG;AAClB,eAAK,KAAK,+CAA+C,GAAG,yLAAyL;AAAA,QACvP;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB;AAAA,MAClB,OAAO;AAAA,MACP,QAAQ,MAAM;AACZ,cAAM,OAAO,QAAQ;AACrB,YAAI,SAAS;AACX,iBAAO;AACT,cAAM,WAAW,kBAAkB,IAAI;AACvC,cAAM,MAAM,8CAA8C,uBAAuB,KAAK,QAAQ;AAC9F,YAAI,KAAK,SAAS,QAAQ;AACxB,iBAAO,KAAK,QAAQ,UAAU;AAAA,MAAe,GAAG,EAAE;AACpD,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,IACA,iBAAiB;AACf,YAAM,OAAO,QAAQ;AACrB,UAAI,SAAS;AACX;AACF,WAAK,SAAS;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AExHA,SAAS,WAAAC,gBAAe;AAajB,SAAS,qBAAqB,UAAuC,CAAC,GAAW;AACtF,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAwB;AACrC,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,iBAAiB;AACf,YAAM,UAAU,QAAQ,mBAAmBC,SAAQ,MAAM,cAAc;AACvE,UAAI;AACJ,UAAI;AACF,iBAAS,YAAY,OAAO;AAAA,MAC9B,SACO,KAAK;AACV,YAAI,QAAQ;AACV,gBAAM,IAAI,MAAM,0CAA0C,OAAO,KAAM,IAAc,OAAO,EAAE;AAChG;AAAA,MACF;AAMA,+BAAyB,OAAO,KAAK,OAAO;AAI5C,YAAM,cAAc,gBAAgB,OAAO,KAAK,OAAO,SAAS,CAAC,QAAQ;AACvE,cAAM,IAAI,MAAM,GAAG;AAAA,MACrB,CAAC;AACD,WAAK,SAAS;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ,KAAK,UAAU,WAAW;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ACzBO,SAAS,sBAAsB,MAAkD;AACtF,SAAO,gBAAgB,GAAG,IAAI;AAChC;","names":["resolve","resolve","resolve","resolve"]}
1
+ {"version":3,"sources":["../../@wippy-fe--shared/src/surface.ts","../../@wippy-fe--shared/src/visibility.ts","../../@wippy-fe--shared/src/index.ts","../src/page-plugin.ts","../src/shared.ts","../src/component-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * Surface portability contract, version 1 (EE2-2339).\n *\n * A **surface** is the page-owned rectangular rendering area the host\n * allocates. The same page package must lay out correctly whether the host\n * renders it as a srcdoc iframe or as a Web Fragment, so the contract names\n * one observable structure both engines materialize:\n *\n * - a query container named `wippy-surface` whose content box IS the\n * allocated surface, and which is a flat-tree ancestor of all page content;\n * - four reserved custom properties pinned to that container.\n *\n * The two engines place that container in different documents — the iframe\n * engine injects it into the srcdoc, the fragment engine uses a host-document\n * wrapper above the reframed shadow roots — but authors see one contract.\n *\n * **Why a wrapper and not `html` / `body`** (measured, Chrome 148):\n * `container-type: size` on the document root yields no block axis at all\n * (`min-height` queries never match, `cqh` resolves to `0px`), and `body`\n * redefines the inline axis through its own margin/padding/border. Only a\n * dedicated element carries both axes faithfully.\n */\n\n/**\n * How the host sizes the surface.\n *\n * - `container` — the host imposes both dimensions. Both axes are queryable.\n * - `content` — the host imposes the inline axis and the page's intrinsic\n * content determines the block axis. Only the inline axis is queryable;\n * exposing a measured block size here would create a resize feedback loop.\n *\n * `auto-height` on a page/artifact is the compatibility spelling of `content`.\n */\nexport type PageSizing = 'container' | 'content'\n\n/**\n * Which engine materialized this surface.\n *\n * `host` is not a page engine: it is a component mounted directly into the\n * host document (or the standalone dev proxy), where no surface is allocated\n * and no query box exists. Such a context reports zero width and `content`\n * sizing — deliberately, rather than borrowing the host viewport, which would\n * be the false viewport equivalence the contract exists to avoid.\n */\nexport type SurfaceEngine = 'iframe' | 'fragment' | 'host'\n\n/**\n * Capabilities a page can require via `wippy.surface.requirements`, or test at\n * runtime via `host.surface.supports()`.\n *\n * The inline axis is the contract baseline and deliberately has no token — it\n * is available on every surface, so requiring it would say nothing.\n *\n * - `block-size` — block-axis queries, `cqb`, aspect-ratio and orientation.\n * Container sizing only.\n * - `surface-scroll` — a page-owned scrollport. Container sizing only.\n * - `registered-hit-testing` / `native-document-hit-testing` — deep hit\n * testing through shadow roots.\n * - `owner-visibility` — the owner-visible field on intersection records.\n *\n * The last three are declared so the vocabulary is stable, but are not\n * implemented in this release: `supports()` reports them false and a package\n * requiring one is rejected before startup rather than rendering degraded.\n */\nexport type SurfaceCapability\n = | 'block-size'\n | 'surface-scroll'\n | 'registered-hit-testing'\n | 'native-document-hit-testing'\n | 'owner-visibility'\n\n/** Every capability token, in declaration order. */\nexport const SURFACE_CAPABILITIES: readonly SurfaceCapability[] = [\n 'block-size',\n 'surface-scroll',\n 'registered-hit-testing',\n 'native-document-hit-testing',\n 'owner-visibility',\n]\n\n/**\n * Capabilities this release can actually deliver, and the sizing each needs.\n *\n * A capability absent from this map is part of the vocabulary but unshipped.\n */\nexport const SURFACE_SUPPORTED_CAPABILITIES: Partial<Record<SurfaceCapability, PageSizing>> = {\n 'block-size': 'container',\n 'surface-scroll': 'container',\n}\n\n/** The only contract version this host implements. */\nexport const SURFACE_CONTRACT_VERSION = 1 as const\n\n/** Reserved query-container name. Applications must not override it. */\nexport const SURFACE_CONTAINER_NAME = 'wippy-surface' as const\n\n/**\n * The four reserved custom properties, pinned to the surface container.\n *\n * Applications and their bundled dependencies must not declare, register\n * (`@property` / `CSS.registerProperty()`), or assign these anywhere — a\n * descendant declaration shadows inheritance and silently unpins the value\n * from the surface.\n *\n * Values are literal CSS-pixel lengths, never `cq*` token streams: native\n * container units can retarget to a nearer eligible container, and a missing\n * axis can fall back to the small viewport.\n */\nexport const SURFACE_WIDTH_PROPERTY = '--wippy-surface-width' as const\nexport const SURFACE_WIDTH_UNIT_PROPERTY = '--wippy-surface-width-unit' as const\nexport const SURFACE_HEIGHT_PROPERTY = '--wippy-surface-height' as const\nexport const SURFACE_HEIGHT_UNIT_PROPERTY = '--wippy-surface-height-unit' as const\n\n/**\n * Immutable geometry snapshot.\n *\n * `height` and `heightUnit` are `null` in content sizing — the block axis is\n * genuinely unavailable there, and a number would imply a viewport\n * equivalence that does not exist.\n */\nexport interface SurfaceSnapshot {\n /** Contract version that produced this snapshot. */\n readonly contract: typeof SURFACE_CONTRACT_VERSION\n /** Monotonic, bumped once per coalesced measurement. */\n readonly revision: number\n readonly engine: SurfaceEngine\n readonly sizing: PageSizing\n /** Physical content-box width in CSS pixels. */\n readonly width: number\n /** 1% of `width`, in CSS pixels. */\n readonly widthUnit: number\n /** Physical content-box height in CSS pixels; `null` in content sizing. */\n readonly height: number | null\n /** 1% of `height`, in CSS pixels; `null` in content sizing. */\n readonly heightUnit: number | null\n}\n\n/** Read API exposed to pages as `host.surface`. */\nexport interface SurfaceApi {\n readonly contract: typeof SURFACE_CONTRACT_VERSION\n /** Which engine rendered this page. Prefer `supports()` for behavior decisions. */\n readonly engine: SurfaceEngine\n readonly sizing: PageSizing\n /**\n * Current geometry, re-read from computed style on **every** access — never\n * memoized, so a value read after a layout change is never frame-stale.\n *\n * That also means it forces a style read each time. Cheap for the occasional\n * read; do not poll it in your own animation frame. Use `onChange` to be told\n * when it moves, and read once per notification.\n */\n readonly snapshot: SurfaceSnapshot\n /** Subscribe to geometry changes. Returns an idempotent unsubscribe. */\n onChange: (listener: (snapshot: SurfaceSnapshot) => void) => () => void\n /** Is a capability available for this surface? */\n supports: (capability: SurfaceCapability) => boolean\n}\n\n/**\n * `wippy.surface` in a page package's `package.json`.\n *\n * Absent means the package predates the contract: it still renders, but the\n * host does not advertise portability for it and declares no requirements.\n */\nexport interface SurfaceManifest {\n contract: typeof SURFACE_CONTRACT_VERSION\n /**\n * Capabilities the page cannot render without. The spelling is\n * `requirements` — matching the normative manifest format. An empty or\n * absent list means the page needs only the baseline inline axis.\n */\n requirements?: SurfaceCapability[]\n}\n\n/**\n * Can this surface deliver `capability`?\n *\n * False for tokens that are part of the vocabulary but unshipped, so a page\n * branching on `supports()` degrades instead of assuming a behavior that is\n * not there.\n */\nexport function sizingSupports(sizing: PageSizing, capability: SurfaceCapability): boolean {\n const required = SURFACE_SUPPORTED_CAPABILITIES[capability]\n return required !== undefined && required === sizing\n}\n","/**\n * Host-owned logical activity for a retained web component.\n *\n * This is deliberately independent from CSS visibility, viewport\n * intersection, and document visibility. Hosts set it before connection and\n * update it without replacing the element when a retained surface changes\n * ownership.\n */\nexport const WIPPY_VISIBILITY_ATTRIBUTE = 'data-wippy-visible'\n\n/** Parse the public attribute. Absent or invalid values are unmanaged. */\nexport function readWippyVisibility(element: Element): boolean | null {\n const value = element.getAttribute(WIPPY_VISIBILITY_ATTRIBUTE)\n if (value === 'true')\n return true\n if (value === 'false')\n return false\n return null\n}\n\n/**\n * Reflect logical activity onto an element without a redundant attribute\n * reaction. Call before appending for the initial value and on ownership\n * changes thereafter; neither path remounts the element.\n */\nexport function setWippyVisibility(element: Element, visible: boolean): void {\n const next = String(visible)\n if (element.getAttribute(WIPPY_VISIBILITY_ATTRIBUTE) !== next)\n element.setAttribute(WIPPY_VISIBILITY_ATTRIBUTE, next)\n}\n","/**\n * Cross-boundary contracts shared between the gen-2-chat host and the\n * `@wippy-fe/*` consumer packages.\n *\n * **Pure contracts and dependency-free DOM helpers.** No framework runtime or\n * `@wippy-fe/proxy` dependency. Importing from this module never loads\n * the proxy globals checker — it is safe to import from anywhere in the\n * host source tree without tripping the `host-import-guard` Vite plugin\n * (this package is on the allowlist).\n *\n * **Status: Draft 1 (preview).** Field names and shapes may change\n * between minor releases until a production consumer drives the corner\n * cases out.\n */\n\n// ─── Layout bus envelopes ────────────────────────────────────────────\n\n/**\n * In-tab broadcast envelope. Same shape on both sides of the bus —\n * iframe panels, host-mounted web components, and headless services\n * all see this object.\n */\nexport interface BroadcastEnvelope {\n channel: string\n payload: unknown\n sourcePanelId: string | null\n targetPanelId: string | null\n}\n\n/**\n * Panel-bound layout bus exposed on `el.__wippyHostBus` for web\n * components mounted as `kind: 'component'` panels. Source / target\n * attribution is set by the host — publishers cannot spoof it.\n */\nexport interface LayoutBusBound {\n /** 1:N broadcast — every other panel receives, sender excluded. */\n broadcast: (channel: string, payload: unknown) => void\n /** 1:1 send — only `target` receives. Unknown targets are no-ops. */\n send: (target: string, channel: string, payload: unknown) => void\n /** Subscribe; returns an `off()` for cleanup. */\n subscribe: (handler: (env: BroadcastEnvelope) => void) => () => void\n}\n\n// ─── Layout mutation targets ─────────────────────────────────────────\n\n/**\n * Drop target positions (relative to a slot rect). Reserved for the\n * future panelDrag capability; declared in v1 for forward compat.\n */\nexport type DropPosition = 'left' | 'right' | 'top' | 'bottom' | 'center' | 'none'\n\n/**\n * Slot size grammar (mirrors `@wippy-fe/layout` `SizeValue`). Tight\n * whitelist — `clamp()`, `minmax()`, `min-content`, `calc()`, em/rem/\n * vh/vw are rejected at validateLayout time. See `@wippy-fe/layout`\n * `helpers.ts` \"Size grammar\" for rationale.\n */\nexport type SizeValue\n = | 'auto'\n | `${number}fr`\n | `${number}px`\n | `${number}%`\n\n/** Pixel-only size, used for min/max and drawer dimensions. */\nexport type PixelSize = `${number}px`\n\n/**\n * Target for addPanel / movePanel. `relativeTo` names a panel already in\n * the tree; `position` picks the drop relative to that panel's rect.\n * Omit `relativeTo` to attach to the root tree (position becomes\n * direction-aware).\n */\nexport interface PanelTarget {\n relativeTo?: string\n position: DropPosition\n size?: SizeValue\n}\n\n// ─── Global-name constants ───────────────────────────────────────────\n//\n// These literal strings name the four `window.*` globals that the host\n// writes and consumer code reads. Both sides MUST agree on the spelling\n// — moving a typo here would silently break communication across the\n// host/proxy boundary. No `Window` augmentation is declared in this\n// package because the augmentation references host-side types\n// (`AppConfig`, `ProxyApiInstance`); host-side `src/shared/constants/global.ts`\n// keeps the `declare global` block.\n\nexport const GLOBAL_CONFIG_VAR = '__WIPPY_APP_CONFIG__' as const\nexport const GLOBAL_PROXY_CONFIG_VAR = '__WIPPY_PROXY_CONFIG__' as const\nexport const GLOBAL_API_PROVIDER = '__WIPPY_APP_API__' as const\nexport const GLOBAL_WEB_COMPONENT_CACHE = '__WIPPY_WEB_COMPONENT_CACHE__' as const\n\n// ─── HTML data-role markers ─────────────────────────────────────────\n//\n// `data-role` attributes that the host and dev-proxy use to find anchor\n// elements in the consuming app's `app.html`. The host removes / inserts\n// scripts at the `@wippy/scripts` element; dev-proxy reads the consuming\n// app's package.json from the `@wippy/package` JSON script (injected at\n// build time by `@wippy-fe/vite-plugin`'s `wippyPackagePlugin()`).\n\nexport const WIPPY_SCRIPTS_DATA_ROLE = '@wippy/scripts' as const\nexport const WIPPY_PACKAGE_DATA_ROLE = '@wippy/package' as const\n\n// ─── Surface portability contract (EE2-2339) ───────────────────────\n\nexport type {\n PageSizing,\n SurfaceApi,\n SurfaceCapability,\n SurfaceEngine,\n SurfaceManifest,\n SurfaceSnapshot,\n} from './surface.ts'\n\nexport {\n sizingSupports,\n SURFACE_CAPABILITIES,\n SURFACE_CONTAINER_NAME,\n SURFACE_CONTRACT_VERSION,\n SURFACE_HEIGHT_PROPERTY,\n SURFACE_HEIGHT_UNIT_PROPERTY,\n SURFACE_SUPPORTED_CAPABILITIES,\n SURFACE_WIDTH_PROPERTY,\n SURFACE_WIDTH_UNIT_PROPERTY,\n} from './surface.ts'\n\n// ─── Retained web-component visibility ─────────────────────────────\n\nexport { readWippyVisibility, setWippyVisibility, WIPPY_VISIBILITY_ATTRIBUTE } from './visibility.ts'\n","/**\n * `wippyPagePlugin` — for `view.page` packages (those with `wippy.type === 'page'`).\n *\n * Two outputs from a single resolved JSON source:\n * 1. An inline `<script type=\"application/json\" data-role=\"@wippy/package\">`\n * injected at the top of `app.html`'s `<head>`. Read at boot by\n * host-less dev-proxy.\n * 2. `wippy-meta.json` emitted into Vite's `outDir`. Read at request time\n * by `wippy/views` in wippy-hosted mode.\n *\n * Both contain the consumer's `package.json` with every `file://<relative>`\n * reference replaced by its file contents. Single source = identical render\n * in either mode.\n */\n\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { LoadedPackage } from './shared'\nimport { resolve } from 'node:path'\nimport { WIPPY_PACKAGE_DATA_ROLE } from '@wippy-fe/shared'\nimport { defangScriptClose, loadPackage, resolveFileRefs, validatePagePackage } from './shared'\n\nexport interface WippyPagePluginOptions {\n /** Override the `package.json` path. Defaults to `<viteRoot>/package.json`. */\n packageJsonPath?: string\n /**\n * If `true`, fail the build when `package.json` is missing. If `false`\n * (default), the plugin silently no-ops — useful for shared configs\n * where some target apps don't need the injection.\n */\n required?: boolean\n}\n\nexport function wippyPagePlugin(options: WippyPagePluginOptions = {}): Plugin {\n let root: string\n // Cache so transformIndexHtml + generateBundle don't re-read package.json\n // and don't double-resolve file:// refs within the same build.\n let resolvedSerialized: string | null = null\n\n function compute(): string | null {\n if (resolvedSerialized !== null)\n return resolvedSerialized\n const pkgPath = options.packageJsonPath ?? resolve(root, 'package.json')\n let loaded: LoadedPackage\n try {\n loaded = loadPackage(pkgPath)\n }\n catch (err) {\n if (options.required)\n throw new Error(`[@wippy-fe/vite-plugin] failed to read ${pkgPath}: ${(err as Error).message}`)\n return null\n }\n // Strict spec validation — throws on any wippy-block shape violation\n // (wrong `wippy.type`, missing `wippy.path`, forbidden `wippy.tagName`,\n // etc.). We throw rather than warn so misconfigurations fail the build\n // instead of silently shipping broken metadata. See shared.ts for the\n // full rule set.\n validatePagePackage(loaded.pkg, pkgPath)\n\n // `file://` basename convention violations also throw: the\n // `.do-not-link.` infix is the AI-readable directive that prevents\n // agents from `<link>`-ing the file directly. A consumer using\n // `file://theme.css` defeats that signal even though the resolved\n // content is correct, so we fail the build to force the rename.\n const resolvedPkg = resolveFileRefs(loaded.pkg, loaded.baseDir, (msg) => {\n throw new Error(msg)\n })\n resolvedSerialized = JSON.stringify(resolvedPkg)\n return resolvedSerialized\n }\n\n // Build-time reframed-incompatibility scan (EE2-2313). Warn once per hostile\n // API so a fragment-incompatible page is caught at BUILD, not in prod. Skipped\n // when the page already opts out (wippy.renderEngine: 'iframe').\n const warnedApis = new Set<string>()\n let optedOut: boolean | null = null\n const isOptedOut = (): boolean => {\n if (optedOut === null) {\n try {\n optedOut = (JSON.parse(compute() ?? '{}')?.wippy?.renderEngine) === 'iframe'\n }\n catch {\n optedOut = false\n }\n }\n return optedOut\n }\n\n return {\n name: '@wippy-fe/vite-plugin:wippy-page',\n enforce: 'pre',\n configResolved(config: ResolvedConfig) {\n root = config.root\n resolvedSerialized = null\n },\n transform(code: string, id: string) {\n if (/node_modules/.test(id) || !/\\.(?:vue|m?[jt]sx?)$/.test(id) || isOptedOut())\n return null\n const hostile: Array<[RegExp, string]> = [\n [/\\belementFromPoint\\b/, 'elementFromPoint (hit-testing returns null in a reframed realm)'],\n [/\\bwindow\\.scroll(?:X|Y|To|By)?\\b/, 'window scroll geometry (always 0 in a reframed realm)'],\n [/\\bmatchMedia\\s*\\(/, 'matchMedia (resolves against the HOST viewport, not the fragment panel)'],\n [/\\b\\d+(?:\\.\\d+)?v[hw]\\b/, 'vh/vw units (resolve against the HOST viewport)'],\n [/position\\s*:\\s*fixed/, 'position:fixed (pins to the HOST viewport, not the fragment panel)'],\n ]\n for (const [re, msg] of hostile) {\n if (re.test(code) && !warnedApis.has(msg)) {\n warnedApis.add(msg)\n this.warn(`[@wippy-fe/vite-plugin] this view.page uses ${msg}. Such APIs misbehave inside a Web Fragment. If it will run under the fragment engine, set \\`wippy.renderEngine: \"iframe\"\\` in package.json to render it as a legacy iframe. [EE2-2313]`)\n }\n }\n return null\n },\n transformIndexHtml: {\n order: 'pre',\n handler(html) {\n const json = compute()\n if (json === null)\n return html\n const safeJson = defangScriptClose(json)\n const tag = `<script type=\"application/json\" data-role=\"${WIPPY_PACKAGE_DATA_ROLE}\">${safeJson}</script>`\n if (html.includes('<head>'))\n return html.replace('<head>', `<head>\\n ${tag}`)\n return tag + html\n },\n },\n generateBundle() {\n const json = compute()\n if (json === null)\n return\n this.emitFile({\n type: 'asset',\n fileName: 'wippy-meta.json',\n source: json,\n })\n },\n }\n}\n","/**\n * Shared helpers for `wippyPagePlugin` and `wippyComponentPlugin`.\n *\n * Both plugins produce `dist/wippy-meta.json` — a resolved copy of the\n * consumer's `package.json` with every `file://<relative-path>` reference\n * replaced by the referenced file's UTF-8 contents. The page plugin\n * additionally injects the same resolved JSON into `app.html` as an\n * `<script type=\"application/json\" data-role=\"@wippy/package\">` so host-less\n * mode (gen-2-chat dev-proxy) can read it synchronously at boot.\n *\n * `wippy-meta.json` is the MANDATORY contract between consumers and\n * `wippy/views`. See `web_components.spec.md` § \"Package metadata: source of\n * truth\" for the full spec.\n */\n\nimport { readFileSync } from 'node:fs'\nimport { basename, dirname, resolve } from 'node:path'\n\nexport interface LoadedPackage {\n /** The parsed `package.json` as a JS object. */\n pkg: Record<string, unknown>\n /**\n * Absolute path to the directory containing `package.json` — used as the\n * base for `file://` reference resolution.\n */\n baseDir: string\n}\n\n/**\n * Read + parse `package.json` from disk. Throws if the file is missing or\n * not valid JSON — the build is expected to fail loud rather than silently\n * skip the package.\n */\nexport function loadPackage(packageJsonPath: string): LoadedPackage {\n const raw = readFileSync(packageJsonPath, 'utf-8')\n const pkg = JSON.parse(raw) as Record<string, unknown>\n return { pkg, baseDir: dirname(packageJsonPath) }\n}\n\n/**\n * camelCase → kebab-case conversion used by the `*.do-not-link.<ext>`\n * naming convention. Treats consecutive capitals as a single word so\n * `customCSS` → `custom-css` (not `custom-c-s-s`). Matches lodash's\n * kebabCase semantics for these specific input shapes.\n *\n * Examples codified in tests:\n * - `customCSS` → `custom-css`\n * - `customCss` → `custom-css`\n * - `cssVariables` → `css-variables`\n * - `tailwindConfig` → `tailwind-config`\n * - `description` → `description`\n * - `URLPath` → `url-path`\n */\nexport function kebabize(camel: string): string {\n return camel\n // Insert a hyphen between a run of capitals and a following Capital+lowercase:\n // \"URLPath\" → \"URL-Path\"\n // \"customCSS\" stays \"customCSS\" here (no following lowercase)\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n // Insert a hyphen between a lowercase/digit and a following capital:\n // \"customCSS\" → \"custom-CSS\"\n // \"URL-Path\" → \"URL-Path\" (unchanged — already split)\n .replace(/([a-z\\d])([A-Z])/g, '$1-$2')\n .toLowerCase()\n}\n\n/**\n * Validator used by `resolveFileRefs` to surface mismatches between a\n * `file://` reference's basename and the canonical `<field-kebab>.do-not-link.<ext>`\n * convention. Returns the expected basename (for use in the warning\n * message) or `null` if the actual basename already conforms.\n *\n * Convention: basename without extension MUST end with `.do-not-link` and\n * its prefix MUST equal `kebabize(fieldName)`. Examples:\n * - field `customCSS`, file `custom-css.do-not-link.css` → null (ok)\n * - field `customCSS`, file `my-theme.css` → \"custom-css.do-not-link.css\"\n * - field `customCSS`, file `custom-css.css` → \"custom-css.do-not-link.css\"\n *\n * `null` field name (top-level / array index) skips the check.\n */\nexport function expectedDoNotLinkBasename(fieldName: string | null, actualBasename: string): string | null {\n if (!fieldName)\n return null\n const dot = actualBasename.lastIndexOf('.')\n if (dot <= 0)\n return `${kebabize(fieldName)}.do-not-link.<ext>`\n const ext = actualBasename.slice(dot + 1)\n const expected = `${kebabize(fieldName)}.do-not-link.${ext}`\n if (actualBasename === expected)\n return null\n return expected\n}\n\n/**\n * Recursively replace every string value of shape `file://<relative-path>`\n * with the referenced file's UTF-8 contents. Paths are resolved against\n * `baseDir` (typically the directory containing `package.json`).\n *\n * Non-string, non-array, non-object values pass through unchanged. Missing\n * files throw — the convention is that `file://` refs are load-bearing.\n *\n * `onWarn` (optional) is called when a `file://` basename doesn't match the\n * canonical `<field-kebab>.do-not-link.<ext>` convention. The warning is\n * advisory — resolution still succeeds — so consumers can opt out by not\n * passing the callback.\n */\nexport function resolveFileRefs<T>(\n node: T,\n baseDir: string,\n onWarn?: (msg: string) => void,\n fieldName: string | null = null,\n): T {\n if (typeof node === 'string' && node.startsWith('file://')) {\n const rel = node.slice('file://'.length)\n const abs = resolve(baseDir, rel)\n if (onWarn) {\n const expected = expectedDoNotLinkBasename(fieldName, basename(rel))\n if (expected) {\n onWarn(`[@wippy-fe/vite-plugin] file:// basename \"${basename(rel)}\" for field \"${fieldName}\" does not match the *.do-not-link.<ext> convention. Expected: \"${expected}\". See web_components.spec.md § \"Package metadata: source of truth\".`)\n }\n }\n return readFileSync(abs, 'utf-8') as unknown as T\n }\n if (Array.isArray(node))\n return node.map(v => resolveFileRefs(v, baseDir, onWarn, fieldName)) as unknown as T\n if (node && typeof node === 'object') {\n return Object.fromEntries(\n Object.entries(node as Record<string, unknown>)\n .map(([k, v]) => [k, resolveFileRefs(v, baseDir, onWarn, k)]),\n ) as unknown as T\n }\n return node\n}\n\n/**\n * Defang `</script>` sequences inside a JSON string so it's safe to embed\n * verbatim inside an inline `<script type=\"application/json\">` tag. Case\n * insensitive (`</SCRIPT`, `</Script`, etc. all need escaping).\n */\nexport function defangScriptClose(json: string): string {\n return json.replace(/<\\/script/gi, '<\\\\/script')\n}\n\n/**\n * Validate a consumer's `package.json` against the `wippy-component-1.0`\n * spec FOR A PAGE PACKAGE. Throws with a clear, actionable message on any\n * violation. Called by `wippyPagePlugin` at build time so misconfigurations\n * fail the build instead of silently shipping broken metadata.\n *\n * We throw rather than warn because nobody reads build warnings — they\n * scroll past in CI output and get filtered out of IDE diagnostics. A\n * field-shape mistake that warns today is a real bug tomorrow.\n *\n * Rules enforced (must all hold for a page):\n * - Top-level `name` and `version` must be strings.\n * - `wippy` must be a plain object.\n * - `wippy.type`, when set, MUST equal `'page'` (not `'component'`,\n * `'widget'`, or anything else).\n * - `wippy.path` is REQUIRED for pages (HTML entry path).\n * - `wippy.tagName` is FORBIDDEN for pages (custom-element-tag is a\n * component-only concept).\n * - `specification`, when set, MUST equal `'wippy-component-1.0'`.\n */\nexport function validatePagePackage(pkg: Record<string, unknown>, packageJsonPath: string): void {\n const prefix = `[@wippy-fe/vite-plugin] ${packageJsonPath}:`\n\n if (typeof pkg.name !== 'string' || pkg.name.length === 0)\n throw new Error(`${prefix} \\`name\\` is required and must be a non-empty string`)\n if (typeof pkg.version !== 'string' || pkg.version.length === 0)\n throw new Error(`${prefix} \\`version\\` is required and must be a non-empty string`)\n if (pkg.specification !== undefined && pkg.specification !== 'wippy-component-1.0')\n throw new Error(`${prefix} \\`specification\\` must be \"wippy-component-1.0\" (got ${JSON.stringify(pkg.specification)})`)\n\n const wippy = pkg.wippy\n if (wippy === undefined || wippy === null)\n throw new Error(`${prefix} top-level \\`wippy\\` block is required for a page package using wippyPagePlugin()`)\n if (typeof wippy !== 'object' || Array.isArray(wippy))\n throw new Error(`${prefix} \\`wippy\\` must be a JSON object (got ${Array.isArray(wippy) ? 'array' : typeof wippy})`)\n\n const w = wippy as Record<string, unknown>\n\n if (w.type !== undefined && w.type !== 'page')\n throw new Error(`${prefix} \\`wippy.type\\` is \"${String(w.type)}\" but wippyPagePlugin() was used. Either set \\`wippy.type: \"page\"\\` or switch to wippyComponentPlugin() for components/widgets.`)\n\n if (w.path === undefined)\n throw new Error(`${prefix} \\`wippy.path\\` is required for a page package (the relative path to the HTML entry, e.g. \"dist/app.html\")`)\n if (typeof w.path !== 'string' || w.path.length === 0)\n throw new Error(`${prefix} \\`wippy.path\\` must be a non-empty string (got ${JSON.stringify(w.path)})`)\n\n if (w.tagName !== undefined)\n throw new Error(`${prefix} \\`wippy.tagName\\` is set on a page package but the field is component-only. Either remove it or switch to wippyComponentPlugin().`)\n\n // EE2-2313: per-page render engine. The string form must be a known value; the\n // reserved object form ({ route?, artifact? }) is permitted but not read yet.\n if (w.renderEngine !== undefined && typeof w.renderEngine === 'string'\n && w.renderEngine !== 'auto' && w.renderEngine !== 'iframe' && w.renderEngine !== 'fragment') {\n throw new Error(`${prefix} \\`wippy.renderEngine\\` must be \"auto\", \"iframe\", or \"fragment\" (got ${JSON.stringify(w.renderEngine)}). Absent = \"auto\" (follow the deployment's global engine); use \"iframe\" to opt a fragment-incompatible page out.`)\n }\n}\n\n/**\n * Validate a consumer's `package.json` for a component/widget package using\n * `wippyComponentPlugin`. Throws on any violation. Same rationale as\n * `validatePagePackage` — fail loud at build time.\n *\n * Rules enforced (must all hold for a component):\n * - Top-level `name` and `version` must be strings.\n * - `wippy` must be a plain object.\n * - `wippy.type`, when set, MUST be one of `'component'` or `'widget'` (the\n * spec uses both interchangeably for ESM-shipped custom elements).\n * - `wippy.tagName` is REQUIRED for components — without it the host has\n * no element name to register against.\n * - `wippy.path` is FORBIDDEN for components (HTML-entry is a page-only\n * concept; components use top-level `browser` for the ESM entry).\n * - `specification`, when set, MUST equal `'wippy-component-1.0'`.\n * - `browser` SHOULD be set (the ESM entry path); only warn-by-throw if\n * absent because the plugin still emits useful meta without it.\n */\nexport function validateComponentPackage(pkg: Record<string, unknown>, packageJsonPath: string): void {\n const prefix = `[@wippy-fe/vite-plugin] ${packageJsonPath}:`\n\n if (typeof pkg.name !== 'string' || pkg.name.length === 0)\n throw new Error(`${prefix} \\`name\\` is required and must be a non-empty string`)\n if (typeof pkg.version !== 'string' || pkg.version.length === 0)\n throw new Error(`${prefix} \\`version\\` is required and must be a non-empty string`)\n if (pkg.specification !== undefined && pkg.specification !== 'wippy-component-1.0')\n throw new Error(`${prefix} \\`specification\\` must be \"wippy-component-1.0\" (got ${JSON.stringify(pkg.specification)})`)\n\n const wippy = pkg.wippy\n if (wippy === undefined || wippy === null)\n throw new Error(`${prefix} top-level \\`wippy\\` block is required for a component package using wippyComponentPlugin()`)\n if (typeof wippy !== 'object' || Array.isArray(wippy))\n throw new Error(`${prefix} \\`wippy\\` must be a JSON object (got ${Array.isArray(wippy) ? 'array' : typeof wippy})`)\n\n const w = wippy as Record<string, unknown>\n\n if (w.type !== undefined && w.type !== 'component' && w.type !== 'widget')\n throw new Error(`${prefix} \\`wippy.type\\` is \"${String(w.type)}\" but wippyComponentPlugin() was used. Either set \\`wippy.type: \"component\"\\` (or \"widget\") or switch to wippyPagePlugin() for pages.`)\n\n if (w.tagName === undefined)\n throw new Error(`${prefix} \\`wippy.tagName\\` is required for a component package (the custom-element tag name, e.g. \"example-mermaid\"). Without it the host cannot register the element.`)\n if (typeof w.tagName !== 'string' || w.tagName.length === 0)\n throw new Error(`${prefix} \\`wippy.tagName\\` must be a non-empty string (got ${JSON.stringify(w.tagName)})`)\n // Custom Elements spec (PotentialCustomElementName):\n // - MUST start with an ASCII lowercase letter [a-z]\n // - MUST contain a hyphen\n // - MAY contain ASCII lowercase letters, digits, or hyphens\n // (The full spec also allows ., _, and some Unicode ranges, but in practice\n // Wippy tag names only ever use [a-z0-9-]. We keep the check tight rather\n // than full-spec because a \"FOO-BAR\" or \"-leading\" passing validation today\n // would silently break tomorrow when `customElements.define()` rejects it.)\n //\n // Mirror twin: `@wippy-fe/proxy`'s `vue-warn-suppressor.ts` uses an\n // equivalent regex (`/^[a-z][a-z0-9]*-[a-z0-9-]*$/`) to decide whether\n // an unresolved Vue tag \"looks like a pending-registration custom\n // element\". The two patterns match exactly the same name shape — keep\n // them in sync. Functionally identical; differ only in character-class\n // notation (`[\\da-z]` vs `[a-z0-9]`).\n if (!/^[a-z][\\da-z]*-[-\\da-z]*$/.test(w.tagName))\n throw new Error(`${prefix} \\`wippy.tagName\\` \"${w.tagName}\" is not a valid Custom Elements name. Must start with an ASCII lowercase letter, contain a hyphen, and use only lowercase letters, digits, and hyphens. Examples: \"example-mermaid\", \"my-widget-v2\".`)\n // Reserved names that browsers refuse to register (HTML5 spec):\n const reserved = new Set([\n 'annotation-xml',\n 'color-profile',\n 'font-face',\n 'font-face-src',\n 'font-face-uri',\n 'font-face-format',\n 'font-face-name',\n 'missing-glyph',\n ])\n if (reserved.has(w.tagName))\n throw new Error(`${prefix} \\`wippy.tagName\\` \"${w.tagName}\" is a reserved HTML name; browsers will refuse to register it.`)\n\n if (w.path !== undefined)\n throw new Error(`${prefix} \\`wippy.path\\` is set on a component package but the field is page-only. Components use top-level \\`browser\\` for the ESM entry path. Either remove \\`wippy.path\\` or switch to wippyPagePlugin().`)\n\n // EE2-2313: render engine applies to view.page only — a view.component's render\n // path is fixed, so the flag is meaningless (and would silently do nothing) here.\n if (w.renderEngine !== undefined)\n throw new Error(`${prefix} \\`wippy.renderEngine\\` is set on a component package but the field is page-only (a view.component's render path is fixed). Remove it.`)\n}\n","/**\n * `wippyComponentPlugin` — for `view.component` packages (those with\n * `wippy.type === 'component'`).\n *\n * Components ship a JS module, not an HTML entry — there's nothing to inject\n * an inline `<script>` into. The plugin's only job is to emit `wippy-meta.json`\n * into Vite's `outDir` for `wippy/views` to read at request time.\n *\n * The `wippy-meta.json` file is the MANDATORY contract between components and\n * `wippy/views`. See `web_components.spec.md` § \"Package metadata: source of\n * truth\". Without it, `views` falls back to its legacy YAML-synthesis path,\n * which is deprecated and exists only for migration.\n */\n\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport type { LoadedPackage } from './shared'\nimport { resolve } from 'node:path'\nimport { loadPackage, resolveFileRefs, validateComponentPackage } from './shared'\n\nexport interface WippyComponentPluginOptions {\n /** Override the `package.json` path. Defaults to `<viteRoot>/package.json`. */\n packageJsonPath?: string\n /**\n * If `true`, fail the build when `package.json` is missing. If `false`\n * (default), the plugin silently no-ops.\n */\n required?: boolean\n}\n\nexport function wippyComponentPlugin(options: WippyComponentPluginOptions = {}): Plugin {\n let root: string\n\n return {\n name: '@wippy-fe/vite-plugin:wippy-component',\n enforce: 'pre',\n configResolved(config: ResolvedConfig) {\n root = config.root\n },\n generateBundle() {\n const pkgPath = options.packageJsonPath ?? resolve(root, 'package.json')\n let loaded: LoadedPackage\n try {\n loaded = loadPackage(pkgPath)\n }\n catch (err) {\n if (options.required)\n throw new Error(`[@wippy-fe/vite-plugin] failed to read ${pkgPath}: ${(err as Error).message}`)\n return\n }\n // Strict spec validation — throws on any wippy-block shape violation\n // (wrong `wippy.type`, missing `wippy.tagName`, forbidden `wippy.path`,\n // tagName without hyphen, etc.). We throw rather than warn so\n // misconfigurations fail the build instead of silently shipping broken\n // metadata. See shared.ts for the full rule set.\n validateComponentPackage(loaded.pkg, pkgPath)\n\n // `file://` basename convention violations throw — see page-plugin's\n // identical comment for the rationale.\n const resolvedPkg = resolveFileRefs(loaded.pkg, loaded.baseDir, (msg) => {\n throw new Error(msg)\n })\n this.emitFile({\n type: 'asset',\n fileName: 'wippy-meta.json',\n source: JSON.stringify(resolvedPkg),\n })\n },\n }\n}\n","/**\n * Vite plugins for Wippy view.page and view.component packages.\n *\n * Both plugins emit `dist/wippy-meta.json` — the consumer's `package.json`\n * with every `file://<relative-path>` reference replaced by the referenced\n * file's UTF-8 contents. `wippy-meta.json` is the MANDATORY contract between\n * consumers and `wippy/views` ≥ 1.0.31. See `web_components.spec.md` §\n * \"Package metadata: source of truth\" for the full spec.\n *\n * - `wippyPagePlugin()` — for `view.page` packages. Emits `wippy-meta.json`\n * AND injects an inline `<script data-role=\"@wippy/package\">` into the\n * built `app.html` (for host-less mode).\n * - `wippyComponentPlugin()` — for `view.component` packages. Emits\n * `wippy-meta.json` only; components have no HTML entry.\n *\n * Convention: bulky string fields (`customCSS`, `description`, etc.) should\n * be moved into separate files referenced via `file://` and named\n * `<field-name-kebab>.do-not-link.<ext>` — basename matches the kebab-case\n * wippy block field name (e.g. `customCSS` → `custom-css.do-not-link.css`,\n * `description` → `description.do-not-link.md`). The `.do-not-link.` infix\n * is what stops AI agents from `<link>`-ing the file directly into app.html.\n * The proxy injects the content at runtime from the resolved package metadata.\n *\n * **Status: Draft 1 (preview).** API may change between minor releases.\n */\n\nimport type { Plugin } from 'vite'\nimport { WIPPY_PACKAGE_DATA_ROLE } from '@wippy-fe/shared'\nimport { wippyPagePlugin } from './page-plugin'\n\nexport { WIPPY_PACKAGE_DATA_ROLE }\nexport { wippyComponentPlugin } from './component-plugin'\nexport type { WippyComponentPluginOptions } from './component-plugin'\nexport { wippyPagePlugin } from './page-plugin'\nexport type { WippyPagePluginOptions } from './page-plugin'\nexport type { WippyPagePluginOptions as WippyPackagePluginOptions } from './page-plugin'\n\n/**\n * @deprecated Use `wippyPagePlugin()` instead. The new name disambiguates\n * the page-side plugin from `wippyComponentPlugin()` introduced alongside it.\n * This alias preserves backwards compatibility for existing `vite.config.ts`\n * files and will be removed in a future major.\n */\nexport function wippyPackagePlugin(...args: Parameters<typeof wippyPagePlugin>): Plugin {\n return wippyPagePlugin(...args)\n}\n// Re-export the strict validators so CI tooling / external linters can\n// reuse the same rules the plugins enforce at build time.\nexport { validateComponentPackage, validatePagePackage } from './shared'\n"],"mappings":";AEsGO,IAAM,0BAA0B;;;ACrFvC,SAAS,WAAAA,gBAAe;;;ACFxB,SAAS,oBAAoB;AAC7B,SAAS,UAAU,SAAS,eAAe;AAiBpC,SAAS,YAAY,iBAAwC;AAClE,QAAM,MAAM,aAAa,iBAAiB,OAAO;AACjD,QAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,SAAO,EAAE,KAAK,SAAS,QAAQ,eAAe,EAAE;AAClD;AAgBO,SAAS,SAAS,OAAuB;AAC9C,SAAO,MAIJ,QAAQ,yBAAyB,OAAO,EAIxC,QAAQ,qBAAqB,OAAO,EACpC,YAAY;AACjB;AAgBO,SAAS,0BAA0B,WAA0B,gBAAuC;AACzG,MAAI,CAAC;AACH,WAAO;AACT,QAAM,MAAM,eAAe,YAAY,GAAG;AAC1C,MAAI,OAAO;AACT,WAAO,GAAG,SAAS,SAAS,CAAC;AAC/B,QAAM,MAAM,eAAe,MAAM,MAAM,CAAC;AACxC,QAAM,WAAW,GAAG,SAAS,SAAS,CAAC,gBAAgB,GAAG;AAC1D,MAAI,mBAAmB;AACrB,WAAO;AACT,SAAO;AACT;AAeO,SAAS,gBACd,MACA,SACA,QACA,YAA2B,MACxB;AACH,MAAI,OAAO,SAAS,YAAY,KAAK,WAAW,SAAS,GAAG;AAC1D,UAAM,MAAM,KAAK,MAAM,UAAU,MAAM;AACvC,UAAM,MAAM,QAAQ,SAAS,GAAG;AAChC,QAAI,QAAQ;AACV,YAAM,WAAW,0BAA0B,WAAW,SAAS,GAAG,CAAC;AACnE,UAAI,UAAU;AACZ,eAAO,6CAA6C,SAAS,GAAG,CAAC,gBAAgB,SAAS,mEAAmE,QAAQ,yEAAsE;AAAA,MAC7O;AAAA,IACF;AACA,WAAO,aAAa,KAAK,OAAO;AAAA,EAClC;AACA,MAAI,MAAM,QAAQ,IAAI;AACpB,WAAO,KAAK,IAAI,OAAK,gBAAgB,GAAG,SAAS,QAAQ,SAAS,CAAC;AACrE,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,WAAO,OAAO;AAAA,MACZ,OAAO,QAAQ,IAA+B,EAC3C,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,gBAAgB,GAAG,SAAS,QAAQ,CAAC,CAAC,CAAC;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,kBAAkB,MAAsB;AACtD,SAAO,KAAK,QAAQ,eAAe,YAAY;AACjD;AAsBO,SAAS,oBAAoB,KAA8B,iBAA+B;AAC/F,QAAM,SAAS,2BAA2B,eAAe;AAEzD,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW;AACtD,UAAM,IAAI,MAAM,GAAG,MAAM,sDAAsD;AACjF,MAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,WAAW;AAC5D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD;AACpF,MAAI,IAAI,kBAAkB,UAAa,IAAI,kBAAkB;AAC3D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD,KAAK,UAAU,IAAI,aAAa,CAAC,GAAG;AAExH,QAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,UAAa,UAAU;AACnC,UAAM,IAAI,MAAM,GAAG,MAAM,mFAAmF;AAC9G,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAClD,UAAM,IAAI,MAAM,GAAG,MAAM,yCAAyC,MAAM,QAAQ,KAAK,IAAI,UAAU,OAAO,KAAK,GAAG;AAEpH,QAAM,IAAI;AAEV,MAAI,EAAE,SAAS,UAAa,EAAE,SAAS;AACrC,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,OAAO,EAAE,IAAI,CAAC,iIAAiI;AAEjM,MAAI,EAAE,SAAS;AACb,UAAM,IAAI,MAAM,GAAG,MAAM,4GAA4G;AACvI,MAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,WAAW;AAClD,UAAM,IAAI,MAAM,GAAG,MAAM,mDAAmD,KAAK,UAAU,EAAE,IAAI,CAAC,GAAG;AAEvG,MAAI,EAAE,YAAY;AAChB,UAAM,IAAI,MAAM,GAAG,MAAM,oIAAoI;AAI/J,MAAI,EAAE,iBAAiB,UAAa,OAAO,EAAE,iBAAiB,YACzD,EAAE,iBAAiB,UAAU,EAAE,iBAAiB,YAAY,EAAE,iBAAiB,YAAY;AAC9F,UAAM,IAAI,MAAM,GAAG,MAAM,wEAAwE,KAAK,UAAU,EAAE,YAAY,CAAC,mHAAmH;AAAA,EACpP;AACF;AAoBO,SAAS,yBAAyB,KAA8B,iBAA+B;AACpG,QAAM,SAAS,2BAA2B,eAAe;AAEzD,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW;AACtD,UAAM,IAAI,MAAM,GAAG,MAAM,sDAAsD;AACjF,MAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,WAAW;AAC5D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD;AACpF,MAAI,IAAI,kBAAkB,UAAa,IAAI,kBAAkB;AAC3D,UAAM,IAAI,MAAM,GAAG,MAAM,yDAAyD,KAAK,UAAU,IAAI,aAAa,CAAC,GAAG;AAExH,QAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,UAAa,UAAU;AACnC,UAAM,IAAI,MAAM,GAAG,MAAM,6FAA6F;AACxH,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAClD,UAAM,IAAI,MAAM,GAAG,MAAM,yCAAyC,MAAM,QAAQ,KAAK,IAAI,UAAU,OAAO,KAAK,GAAG;AAEpH,QAAM,IAAI;AAEV,MAAI,EAAE,SAAS,UAAa,EAAE,SAAS,eAAe,EAAE,SAAS;AAC/D,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,OAAO,EAAE,IAAI,CAAC,uIAAuI;AAEvM,MAAI,EAAE,YAAY;AAChB,UAAM,IAAI,MAAM,GAAG,MAAM,gKAAgK;AAC3L,MAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW;AACxD,UAAM,IAAI,MAAM,GAAG,MAAM,sDAAsD,KAAK,UAAU,EAAE,OAAO,CAAC,GAAG;AAgB7G,MAAI,CAAC,4BAA4B,KAAK,EAAE,OAAO;AAC7C,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,EAAE,OAAO,uMAAuM;AAElQ,QAAM,WAAW,oBAAI,IAAI;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,MAAI,SAAS,IAAI,EAAE,OAAO;AACxB,UAAM,IAAI,MAAM,GAAG,MAAM,uBAAuB,EAAE,OAAO,iEAAiE;AAE5H,MAAI,EAAE,SAAS;AACb,UAAM,IAAI,MAAM,GAAG,MAAM,qMAAqM;AAIhO,MAAI,EAAE,iBAAiB;AACrB,UAAM,IAAI,MAAM,GAAG,MAAM,wIAAwI;AACrK;;;ADzPO,SAAS,gBAAgB,UAAkC,CAAC,GAAW;AAC5E,MAAI;AAGJ,MAAI,qBAAoC;AAExC,WAAS,UAAyB;AAChC,QAAI,uBAAuB;AACzB,aAAO;AACT,UAAM,UAAU,QAAQ,mBAAmBC,SAAQ,MAAM,cAAc;AACvE,QAAI;AACJ,QAAI;AACF,eAAS,YAAY,OAAO;AAAA,IAC9B,SACO,KAAK;AACV,UAAI,QAAQ;AACV,cAAM,IAAI,MAAM,0CAA0C,OAAO,KAAM,IAAc,OAAO,EAAE;AAChG,aAAO;AAAA,IACT;AAMA,wBAAoB,OAAO,KAAK,OAAO;AAOvC,UAAM,cAAc,gBAAgB,OAAO,KAAK,OAAO,SAAS,CAAC,QAAQ;AACvE,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB,CAAC;AACD,yBAAqB,KAAK,UAAU,WAAW;AAC/C,WAAO;AAAA,EACT;AAKA,QAAM,aAAa,oBAAI,IAAY;AACnC,MAAI,WAA2B;AAC/B,QAAM,aAAa,MAAe;AAChC,QAAI,aAAa,MAAM;AACrB,UAAI;AACF,mBAAY,KAAK,MAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,iBAAkB;AAAA,MACtE,QACM;AACJ,mBAAW;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAwB;AACrC,aAAO,OAAO;AACd,2BAAqB;AAAA,IACvB;AAAA,IACA,UAAU,MAAc,IAAY;AAClC,UAAI,eAAe,KAAK,EAAE,KAAK,CAAC,uBAAuB,KAAK,EAAE,KAAK,WAAW;AAC5E,eAAO;AACT,YAAM,UAAmC;AAAA,QACvC,CAAC,wBAAwB,iEAAiE;AAAA,QAC1F,CAAC,oCAAoC,uDAAuD;AAAA,QAC5F,CAAC,qBAAqB,yEAAyE;AAAA,QAC/F,CAAC,0BAA0B,iDAAiD;AAAA,QAC5E,CAAC,wBAAwB,oEAAoE;AAAA,MAC/F;AACA,iBAAW,CAAC,IAAI,GAAG,KAAK,SAAS;AAC/B,YAAI,GAAG,KAAK,IAAI,KAAK,CAAC,WAAW,IAAI,GAAG,GAAG;AACzC,qBAAW,IAAI,GAAG;AAClB,eAAK,KAAK,+CAA+C,GAAG,yLAAyL;AAAA,QACvP;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB;AAAA,MAClB,OAAO;AAAA,MACP,QAAQ,MAAM;AACZ,cAAM,OAAO,QAAQ;AACrB,YAAI,SAAS;AACX,iBAAO;AACT,cAAM,WAAW,kBAAkB,IAAI;AACvC,cAAM,MAAM,8CAA8C,uBAAuB,KAAK,QAAQ;AAC9F,YAAI,KAAK,SAAS,QAAQ;AACxB,iBAAO,KAAK,QAAQ,UAAU;AAAA,MAAe,GAAG,EAAE;AACpD,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,IACA,iBAAiB;AACf,YAAM,OAAO,QAAQ;AACrB,UAAI,SAAS;AACX;AACF,WAAK,SAAS;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AExHA,SAAS,WAAAC,gBAAe;AAajB,SAAS,qBAAqB,UAAuC,CAAC,GAAW;AACtF,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAwB;AACrC,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,iBAAiB;AACf,YAAM,UAAU,QAAQ,mBAAmBC,SAAQ,MAAM,cAAc;AACvE,UAAI;AACJ,UAAI;AACF,iBAAS,YAAY,OAAO;AAAA,MAC9B,SACO,KAAK;AACV,YAAI,QAAQ;AACV,gBAAM,IAAI,MAAM,0CAA0C,OAAO,KAAM,IAAc,OAAO,EAAE;AAChG;AAAA,MACF;AAMA,+BAAyB,OAAO,KAAK,OAAO;AAI5C,YAAM,cAAc,gBAAgB,OAAO,KAAK,OAAO,SAAS,CAAC,QAAQ;AACvE,cAAM,IAAI,MAAM,GAAG;AAAA,MACrB,CAAC;AACD,WAAK,SAAS;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ,KAAK,UAAU,WAAW;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ACzBO,SAAS,sBAAsB,MAAkD;AACtF,SAAO,gBAAgB,GAAG,IAAI;AAChC;","names":["resolve","resolve","resolve","resolve"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wippy-fe/vite-plugin",
3
3
  "type": "module",
4
- "version": "0.0.53",
4
+ "version": "0.0.55",
5
5
  "description": "Vite plugins for Wippy apps and web components — package metadata injection, future build-time helpers.",
6
6
  "license": "UNLICENSED",
7
7
  "sideEffects": false,
@@ -16,7 +16,7 @@
16
16
  "vite": "^5 || ^6 || ^7"
17
17
  },
18
18
  "devDependencies": {
19
- "@wippy-fe/shared": "0.0.53"
19
+ "@wippy-fe/shared": "0.0.55"
20
20
  },
21
21
  "scripts": {
22
22
  "build": "tsup",