@wippy-fe/vite-plugin 0.0.45 → 0.0.47

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 CHANGED
@@ -73,6 +73,9 @@ function validatePagePackage(pkg, packageJsonPath) {
73
73
  throw new Error(`${prefix} \`wippy.path\` must be a non-empty string (got ${JSON.stringify(w.path)})`);
74
74
  if (w.tagName !== void 0)
75
75
  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().`);
76
+ if (w.renderEngine !== void 0 && typeof w.renderEngine === "string" && w.renderEngine !== "auto" && w.renderEngine !== "iframe" && w.renderEngine !== "fragment") {
77
+ 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.`);
78
+ }
76
79
  }
77
80
  function validateComponentPackage(pkg, packageJsonPath) {
78
81
  const prefix = `[@wippy-fe/vite-plugin] ${packageJsonPath}:`;
@@ -110,6 +113,8 @@ function validateComponentPackage(pkg, packageJsonPath) {
110
113
  throw new Error(`${prefix} \`wippy.tagName\` "${w.tagName}" is a reserved HTML name; browsers will refuse to register it.`);
111
114
  if (w.path !== void 0)
112
115
  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().`);
116
+ if (w.renderEngine !== void 0)
117
+ 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.`);
113
118
  }
114
119
 
115
120
  // src/page-plugin.ts
@@ -135,6 +140,18 @@ function wippyPagePlugin(options = {}) {
135
140
  resolvedSerialized = JSON.stringify(resolvedPkg);
136
141
  return resolvedSerialized;
137
142
  }
143
+ const warnedApis = /* @__PURE__ */ new Set();
144
+ let optedOut = null;
145
+ const isOptedOut = () => {
146
+ if (optedOut === null) {
147
+ try {
148
+ optedOut = JSON.parse(compute() ?? "{}")?.wippy?.renderEngine === "iframe";
149
+ } catch {
150
+ optedOut = false;
151
+ }
152
+ }
153
+ return optedOut;
154
+ };
138
155
  return {
139
156
  name: "@wippy-fe/vite-plugin:wippy-page",
140
157
  enforce: "pre",
@@ -142,6 +159,24 @@ function wippyPagePlugin(options = {}) {
142
159
  root = config.root;
143
160
  resolvedSerialized = null;
144
161
  },
162
+ transform(code, id) {
163
+ if (/node_modules/.test(id) || !/\.(?:vue|m?[jt]sx?)$/.test(id) || isOptedOut())
164
+ return null;
165
+ const hostile = [
166
+ [/\belementFromPoint\b/, "elementFromPoint (hit-testing returns null in a reframed realm)"],
167
+ [/\bwindow\.scroll(?:X|Y|To|By)?\b/, "window scroll geometry (always 0 in a reframed realm)"],
168
+ [/\bmatchMedia\s*\(/, "matchMedia (resolves against the HOST viewport, not the fragment panel)"],
169
+ [/\b\d+(?:\.\d+)?v[hw]\b/, "vh/vw units (resolve against the HOST viewport)"],
170
+ [/position\s*:\s*fixed/, "position:fixed (pins to the HOST viewport, not the fragment panel)"]
171
+ ];
172
+ for (const [re, msg] of hostile) {
173
+ if (re.test(code) && !warnedApis.has(msg)) {
174
+ warnedApis.add(msg);
175
+ 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]`);
176
+ }
177
+ }
178
+ return null;
179
+ },
145
180
  transformIndexHtml: {
146
181
  order: "pre",
147
182
  handler(html) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../@wippy-fe--shared/src/index.ts","../src/page-plugin.ts","../src/shared.ts","../src/component-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * Cross-boundary contracts shared between the gen-2-chat host and the\n * `@wippy-fe/*` consumer packages.\n *\n * **Pure types and string-name constants.** No runtime code, no\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 * `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 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 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\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","/**\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":";AAsGO,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;AACjK;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;AAClO;;;AD7OO,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;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,eAAe,QAAwB;AACrC,aAAO,OAAO;AACd,2BAAqB;AAAA,IACvB;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;;;AErFA,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/index.ts","../src/page-plugin.ts","../src/shared.ts","../src/component-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * Cross-boundary contracts shared between the gen-2-chat host and the\n * `@wippy-fe/*` consumer packages.\n *\n * **Pure types and string-name constants.** No runtime code, no\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 * `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":";AAsGO,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.45",
4
+ "version": "0.0.47",
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.45"
19
+ "@wippy-fe/shared": "0.0.47"
20
20
  },
21
21
  "scripts": {
22
22
  "build": "tsup",