vitral 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/dist/angular.d.ts +3 -2
  3. package/dist/angular.js +7 -6
  4. package/dist/auto.js +7 -6
  5. package/dist/capture-TT5WBLJ6.js +42 -0
  6. package/dist/channel-2YPYGX3J.js +95 -0
  7. package/dist/chunk-463H6B56.js +50 -0
  8. package/dist/chunk-54CBIZES.js +105 -0
  9. package/dist/chunk-6EX5KYT5.js +64 -0
  10. package/dist/{chunk-6Y3VMWHH.js → chunk-BCC25ANK.js} +11 -5
  11. package/dist/{chunk-2XF5BKV3.js → chunk-EMSB2NVX.js} +26 -13
  12. package/dist/{chunk-HP6QWU6K.js → chunk-IH3ZT3QU.js} +2 -2
  13. package/dist/{chunk-PX7PBCCT.js → chunk-TW7KYJQ6.js} +7 -17
  14. package/dist/{chunk-S5MZT5IT.js → chunk-UYOPJ4XQ.js} +1 -1
  15. package/dist/{chunk-UTYAX6MU.js → chunk-W6322KGP.js} +2 -2
  16. package/dist/{chunk-NCONW6WS.js → chunk-WD4CDGDZ.js} +73 -44
  17. package/dist/cli.js +1196 -31
  18. package/dist/contract-46EZFQPQ.js +17 -0
  19. package/dist/{dedupe-IWFIXRWG.js → dedupe-S7BHQMOZ.js} +4 -3
  20. package/dist/devtools.d.ts +32 -2
  21. package/dist/devtools.js +27 -12
  22. package/dist/element.d.ts +13 -4
  23. package/dist/element.js +7 -6
  24. package/dist/embed.js +2 -0
  25. package/dist/{errors-KKB8FGCz.d.ts → errors-kjBv6IH_.d.ts} +7 -1
  26. package/dist/{events-DUdjhfps.d.ts → events-Dkpkw_Sv.d.ts} +1 -1
  27. package/dist/expose-OVWTPHH5.js +15 -0
  28. package/dist/federation.d.ts +89 -0
  29. package/dist/federation.js +101 -0
  30. package/dist/iframe.d.ts +1 -1
  31. package/dist/iframe.js +13 -10
  32. package/dist/index.d.ts +23 -21
  33. package/dist/index.js +5 -4
  34. package/dist/otel.d.ts +44 -0
  35. package/dist/otel.js +27 -0
  36. package/dist/overrides-NP754HY7.js +27 -0
  37. package/dist/preact.d.ts +5 -5
  38. package/dist/preact.js +6 -5
  39. package/dist/react.d.ts +12 -4
  40. package/dist/react.js +11 -6
  41. package/dist/routes.d.ts +3 -3
  42. package/dist/routes.js +5 -4
  43. package/dist/sentry.d.ts +25 -0
  44. package/dist/sentry.js +11 -0
  45. package/dist/shadow-PVSETNMZ.js +159 -0
  46. package/dist/single-spa.d.ts +40 -0
  47. package/dist/single-spa.js +52 -0
  48. package/dist/{slot-pB276oPt.d.ts → slot-UPg6ob9v.d.ts} +2 -2
  49. package/dist/solid.d.ts +4 -4
  50. package/dist/solid.js +6 -5
  51. package/dist/{sri-BVKZNX5Q.js → sri-M7ZRU57G.js} +43 -11
  52. package/dist/svelte.d.ts +5 -5
  53. package/dist/svelte.js +6 -5
  54. package/dist/testing.d.ts +2 -1
  55. package/dist/testing.js +5 -4
  56. package/dist/{types-BV-hUrms.d.ts → types-CA2p9KHC.d.ts} +174 -4
  57. package/dist/vite.d.ts +26 -0
  58. package/dist/vite.js +686 -51
  59. package/dist/vue.d.ts +11 -4
  60. package/dist/vue.js +10 -5
  61. package/package.json +115 -23
  62. package/dist/chunk-DXORSF4X.js +0 -42
  63. package/dist/chunk-SFL6LTP3.js +0 -56
  64. package/dist/expose-53BEJB34.js +0 -14
  65. package/dist/overrides-NZAIUGK5.js +0 -15
  66. package/dist/shadow-MYRJQLLY.js +0 -72
package/dist/vite.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/vite.ts
2
- import { createHash as createHash2 } from "crypto";
3
- import { readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
4
- import { join as join4, resolve as resolve4 } from "path";
2
+ import { createHash as createHash3 } from "crypto";
3
+ import { readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
4
+ import { join as join6, resolve as resolve5 } from "path";
5
5
 
6
6
  // src/vite-exposes.ts
7
7
  import { resolve } from "path";
@@ -16,6 +16,7 @@ function exposeKeys(exposes) {
16
16
  }
17
17
  return out;
18
18
  }
19
+ var EXPOSES_IDS = /(^|[\\/])__vitral_exposes__\.js$/;
19
20
  function resolveExposesId(id) {
20
21
  return id === EXPOSES_ENTRY || id.endsWith("/" + EXPOSES_ENTRY) || id.endsWith("\\" + EXPOSES_ENTRY) ? ID : null;
21
22
  }
@@ -99,14 +100,154 @@ ${helper()}${code.slice(at)}`;
99
100
  }
100
101
  function withSplit(m, outDir, s, groups2 = []) {
101
102
  const files = {};
102
- for (const f of [m.entry, ...m.css ?? [], ...s?.files ?? []]) files[f] = sri(join(outDir, f));
103
+ for (const f of [m.entry, ...m.css ?? [], ...m.shadow?.css ?? [], ...m.shadow?.global ?? [], ...s?.files ?? []]) files[f] = sri(join(outDir, f));
103
104
  const dedupe = groups2.filter((g) => s?.own[g.name]).map(({ name, range, version }) => ({ name, range, version, ...s.own[name] }));
104
105
  return { ...m, files, ...s && { split: { entry: s.entry, chunks: s.chunks } }, ...dedupe.length && { dedupe } };
105
106
  }
106
107
 
108
+ // src/vite/sbom.ts
109
+ import { createHash as createHash2 } from "crypto";
110
+ import { existsSync, readFileSync as readFileSync2, realpathSync } from "fs";
111
+ import { dirname, isAbsolute, join as join2, sep } from "path";
112
+ var SBOM_FILE = "sbom.cdx.json";
113
+ var readPkg = (dir) => {
114
+ try {
115
+ return JSON.parse(readFileSync2(join2(dir, "package.json"), "utf8"));
116
+ } catch {
117
+ return void 0;
118
+ }
119
+ };
120
+ function bundledFiles(bundle, into = /* @__PURE__ */ new Set()) {
121
+ for (const f of Object.values(bundle)) {
122
+ if (f.type !== "chunk" || !f.modules) continue;
123
+ for (const [id, m] of Object.entries(f.modules)) {
124
+ const file = id.split("?")[0];
125
+ if (m.renderedLength > 0 && isAbsolute(file)) into.add(file);
126
+ }
127
+ }
128
+ return into;
129
+ }
130
+ function packageDirs(files) {
131
+ const dirs = /* @__PURE__ */ new Set();
132
+ const near = /* @__PURE__ */ new Map();
133
+ const nearest = (dir) => {
134
+ if (near.has(dir)) return near.get(dir);
135
+ const parent = dirname(dir);
136
+ const found = readPkg(dir)?.name ? dir : parent === dir ? null : nearest(parent);
137
+ near.set(dir, found);
138
+ return found;
139
+ };
140
+ const nm = `${sep}node_modules${sep}`;
141
+ for (const file of files) {
142
+ const at = file.lastIndexOf(nm);
143
+ if (at >= 0) {
144
+ const parts = file.slice(at + nm.length).split(sep);
145
+ const name = parts[0].startsWith("@") ? parts.slice(0, 2).join(sep) : parts[0];
146
+ if (parts.length > (parts[0].startsWith("@") ? 2 : 1)) dirs.add(file.slice(0, at + nm.length) + name);
147
+ } else {
148
+ const dir = nearest(dirname(file));
149
+ if (dir) dirs.add(dir);
150
+ }
151
+ }
152
+ return dirs;
153
+ }
154
+ function purl(name, version) {
155
+ const path = name.split("/").map(encodeURIComponent).join("/");
156
+ return `pkg:npm/${path}${version ? `@${encodeURIComponent(version)}` : ""}`;
157
+ }
158
+ function licenses(pkg) {
159
+ const raw = typeof pkg.license === "string" ? pkg.license : pkg.license?.type ?? pkg.licenses?.map((l) => l.type).filter(Boolean).join(" OR ");
160
+ if (!raw) return void 0;
161
+ const spdx = /^\(?[A-Za-z0-9.+-]+( (AND|OR|WITH) \(?[A-Za-z0-9.+-]+\)?)*\)?$/.test(raw) && raw !== "UNLICENSED";
162
+ return spdx ? [{ expression: raw }] : [{ license: { name: raw } }];
163
+ }
164
+ function component(pkg, type) {
165
+ const scoped = pkg.name.startsWith("@") && pkg.name.includes("/");
166
+ const ref = purl(pkg.name, pkg.version);
167
+ const license = licenses(pkg);
168
+ return {
169
+ type,
170
+ "bom-ref": ref,
171
+ ...scoped && { group: pkg.name.slice(0, pkg.name.indexOf("/")) },
172
+ name: scoped ? pkg.name.slice(pkg.name.indexOf("/") + 1) : pkg.name,
173
+ ...pkg.version && { version: pkg.version },
174
+ ...pkg.description && { description: pkg.description },
175
+ ...license && { licenses: license },
176
+ purl: ref
177
+ };
178
+ }
179
+ function resolveDir(from, name) {
180
+ for (let dir = from; ; dir = dirname(dir)) {
181
+ const candidate = join2(dir, "node_modules", name);
182
+ if (existsSync(join2(candidate, "package.json"))) {
183
+ try {
184
+ return realpathSync(candidate);
185
+ } catch {
186
+ return candidate;
187
+ }
188
+ }
189
+ if (dirname(dir) === dir) return void 0;
190
+ }
191
+ }
192
+ function createSbom(input) {
193
+ const rootDir = realpathSync(input.root);
194
+ const rootPkg = readPkg(rootDir) ?? {};
195
+ const main = component({ ...rootPkg, name: input.name, version: input.version }, "application");
196
+ const hashes = input.entry && [{ alg: "SHA-512", content: createHash2("sha512").update(input.entry).digest("hex") }];
197
+ const byDir = /* @__PURE__ */ new Map();
198
+ for (const dir of packageDirs(input.files)) {
199
+ let real = dir;
200
+ try {
201
+ real = realpathSync(dir);
202
+ } catch {
203
+ }
204
+ const pkg = readPkg(real);
205
+ if (real === rootDir || !pkg?.name || byDir.has(real)) continue;
206
+ byDir.set(real, { pkg, ref: purl(pkg.name, pkg.version) });
207
+ }
208
+ const deps = (dir, pkg) => {
209
+ const names = Object.keys({ ...pkg.peerDependencies, ...pkg.optionalDependencies, ...pkg.dependencies });
210
+ const refs = /* @__PURE__ */ new Set();
211
+ for (const n of names) {
212
+ const hit = byDir.get(resolveDir(dir, n) ?? "");
213
+ if (hit) refs.add(hit.ref);
214
+ }
215
+ return [...refs].sort();
216
+ };
217
+ const components = /* @__PURE__ */ new Map();
218
+ const graph = /* @__PURE__ */ new Map([[main["bom-ref"], new Set(deps(rootDir, rootPkg))]]);
219
+ for (const [dir, { pkg, ref }] of byDir) {
220
+ if (!components.has(ref)) components.set(ref, component(pkg, "library"));
221
+ const set = graph.get(ref) ?? /* @__PURE__ */ new Set();
222
+ for (const d of deps(dir, pkg)) if (d !== ref) set.add(d);
223
+ graph.set(ref, set);
224
+ }
225
+ const epoch = Number(process.env.SOURCE_DATE_EPOCH);
226
+ const timestamp = input.timestamp ?? (Number.isFinite(epoch) && process.env.SOURCE_DATE_EPOCH ? new Date(epoch * 1e3) : /* @__PURE__ */ new Date());
227
+ const body = {
228
+ metadata: {
229
+ timestamp: timestamp.toISOString().replace(/\.\d{3}Z$/, "Z"),
230
+ tools: { components: [{ type: "application", name: "vitral", ...input.tool && { version: input.tool }, purl: purl("vitral", input.tool) }] },
231
+ component: { ...main, ...hashes && { hashes } }
232
+ },
233
+ components: [...components.values()].sort((a, b) => a["bom-ref"].localeCompare(b["bom-ref"])),
234
+ dependencies: [...graph].map(([ref, set]) => ({ ref, dependsOn: [...set].sort() }))
235
+ };
236
+ const h = createHash2("sha1").update(JSON.stringify(body)).digest("hex");
237
+ const serial = `urn:uuid:${h.slice(0, 8)}-${h.slice(8, 12)}-5${h.slice(13, 16)}-${(parseInt(h[16], 16) & 3 | 8).toString(16)}${h.slice(17, 20)}-${h.slice(20, 32)}`;
238
+ return {
239
+ $schema: "http://cyclonedx.org/schema/bom-1.6.schema.json",
240
+ bomFormat: "CycloneDX",
241
+ specVersion: "1.6",
242
+ serialNumber: serial,
243
+ version: 1,
244
+ ...body
245
+ };
246
+ }
247
+
107
248
  // src/vite/dedupe.ts
108
- import { existsSync, readFileSync as readFileSync2 } from "fs";
109
- import { dirname, join as join2, resolve as resolve2 } from "path";
249
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
250
+ import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
110
251
  import { pathToFileURL } from "url";
111
252
  var REACT = ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime", "react/compiler-runtime"];
112
253
  var BOOT = "virtual:vitral-boot";
@@ -117,10 +258,10 @@ var pkgOf = (spec) => spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).joi
117
258
  var groupOf = (spec) => REACT.includes(spec) || pkgOf(spec) === "scheduler" ? "react" : pkgOf(spec);
118
259
  var ident = /^[A-Za-z_$][\w$]*$/;
119
260
  function versionOf(file, pkg) {
120
- for (let dir = dirname(file); dir !== dirname(dir); dir = dirname(dir)) {
121
- const json = join2(dir, "package.json");
122
- if (!existsSync(json)) continue;
123
- const data = JSON.parse(readFileSync2(json, "utf8"));
261
+ for (let dir = dirname2(file); dir !== dirname2(dir); dir = dirname2(dir)) {
262
+ const json = join3(dir, "package.json");
263
+ if (!existsSync2(json)) continue;
264
+ const data = JSON.parse(readFileSync3(json, "utf8"));
124
265
  if (data.name === pkg) return data.version;
125
266
  }
126
267
  throw new Error(`vitral: vers\xE3o de ${pkg} n\xE3o encontrada`);
@@ -152,6 +293,11 @@ async function groups(list, root, entry, resolveId) {
152
293
  }
153
294
  return out;
154
295
  }
296
+ var escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\0/g, "\\x00");
297
+ function dedupeIds(list) {
298
+ const specs = new Set(list.flatMap((s) => groupOf(s) === "react" ? REACT : [s]));
299
+ return new RegExp(`${escape(BOOT)}$|^(${[DEPS, ...specs].map(escape).join("|")})$|^(${escape(OWN)}|${escape(SHIM)})`);
300
+ }
155
301
  function dedupeHooks(entry, getGroups) {
156
302
  const keyOf = (id) => getGroups().find((g) => g.keys.includes(id));
157
303
  return {
@@ -389,9 +535,29 @@ function transformCss(css, options, scope) {
389
535
  if (options.scopeCss !== false) scopeRoot(root, scope);
390
536
  return root.toString();
391
537
  }
538
+ var RELATIVE_URL = /url\(\s*(['"]?)(?![a-z]+:|\/\/|#)([^'")]+)\1\s*\)/i;
539
+ var IMPORT_URL = /^\s*(?:url\(\s*(['"]?)([^'")]+)\1\s*\)|(['"])(.*?)\3)/i;
540
+ function splitShadowCss(text) {
541
+ const root = postcss2.parse(text);
542
+ const global = [];
543
+ const imports = [];
544
+ root.walkAtRules((rule) => {
545
+ const name = rule.name.toLowerCase();
546
+ if (name === "import" && rule.parent === root) {
547
+ const m = IMPORT_URL.exec(rule.params);
548
+ if (m) imports.push(m[2] ?? m[4]);
549
+ rule.remove();
550
+ } else if (name === "property" || name === "font-face") {
551
+ global.push(rule.toString());
552
+ rule.remove();
553
+ }
554
+ });
555
+ const css = global.length || imports.length ? root.toString() : text;
556
+ return { css, global: global.join("\n"), imports, rebase: RELATIVE_URL.test(css) };
557
+ }
392
558
 
393
559
  // src/vite/adapter.ts
394
- import { existsSync as existsSync2 } from "fs";
560
+ import { existsSync as existsSync3 } from "fs";
395
561
  import { resolve as resolve3 } from "path";
396
562
  var PLUGINS = [
397
563
  [/^(preact:|prefresh$)/, "preact"],
@@ -430,10 +596,14 @@ import { component } from 'vitral'
430
596
  function wrap(c) {
431
597
  if (typeof c === 'function' && typeof HTMLElement !== 'undefined' && c.prototype instanceof HTMLElement) {
432
598
  const base = ${JSON.stringify(`${scope}-remote`.toLowerCase().replace(/^[^a-z]+/, "x-"))}
433
- let tag = customElements.getName?.(c) || base
434
- // Uma tag n\xE3o aceita outra classe: no HMR, a classe nova ganha tag nova.
435
- for (let n = 2; customElements.get(tag) && customElements.get(tag) !== c; n++) tag = base + '-' + n
436
- return elementRemote(tag, () => customElements.get(tag) || customElements.define(tag, c))
599
+ // No registro do remote (ctx.customElements). Uma tag n\xE3o aceita outra
600
+ // classe: no HMR, a classe nova ganha tag nova.
601
+ return elementRemote(base, (r) => {
602
+ let tag = r.getName?.(c) || base
603
+ for (let n = 2; r.get(tag) && r.get(tag) !== c; n++) tag = base + '-' + n
604
+ r.get(tag) || r.define(tag, c)
605
+ return tag
606
+ })
437
607
  }
438
608
  if (typeof c === 'function') return component(c)
439
609
  throw new Error('[vitral] o export default n\xE3o \xE9 um remote: exporte um componente, uma fun\xE7\xE3o ou um objeto com mount()')
@@ -445,33 +615,306 @@ var CANDIDATES = ["src/remote", "src/App", "src/app"];
445
615
  var EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".vue", ".svelte"];
446
616
  function findEntry(root) {
447
617
  for (const base of CANDIDATES) {
448
- for (const ext of EXTENSIONS) if (existsSync2(resolve3(root, base + ext))) return base + ext;
618
+ for (const ext of EXTENSIONS) if (existsSync3(resolve3(root, base + ext))) return base + ext;
449
619
  }
450
620
  }
451
621
 
452
622
  // src/vite/types.ts
623
+ import { createRequire as createRequire2 } from "module";
624
+ import { join as join5 } from "path";
625
+
626
+ // src/vite/oxc.ts
627
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
453
628
  import { createRequire } from "module";
454
- import { join as join3 } from "path";
629
+ import { dirname as dirname3, join as join4, resolve as resolve4 } from "path";
630
+ import { pathToFileURL as pathToFileURL2 } from "url";
631
+ async function loadOxc(root) {
632
+ const req = createRequire(join4(root, "package.json"));
633
+ const ids = [() => req.resolve("oxc-transform"), () => createRequire(req.resolve("vite/package.json")).resolve("rolldown/experimental")];
634
+ for (const id of ids) {
635
+ try {
636
+ const mod = await import(pathToFileURL2(id()).href);
637
+ if (typeof mod.isolatedDeclarationSync === "function") return mod;
638
+ } catch {
639
+ }
640
+ }
641
+ return null;
642
+ }
643
+ var GLOBAL3 = /^(Date|RegExp|Error|Map|Set|WeakMap|WeakSet|Promise|PromiseLike|Record|Partial|Required|Readonly|Pick|Omit|URL|URLSearchParams|Blob|File|FormData|Headers|AbortSignal|EventTarget|Node|Element|Document|DocumentFragment|ShadowRoot|Window|(HTML|SVG)\w*Element|\w*Event)$/;
644
+ var IDENT = /^[A-Za-z_$][\w$]*$/;
645
+ var Unsupported = class extends Error {
646
+ };
647
+ var unsupported = () => {
648
+ throw new Unsupported();
649
+ };
650
+ function propsFromOxc(ts, oxc, file) {
651
+ try {
652
+ const reader = new Reader(ts, oxc);
653
+ const scope = reader.scope(file);
654
+ const props = reader.defaultProps(scope);
655
+ return props ? reader.print(props.node, props.scope, 0, { top: true }) : "Record<string, unknown>";
656
+ } catch {
657
+ return null;
658
+ }
659
+ }
660
+ var Reader = class {
661
+ constructor(ts, oxc) {
662
+ this.ts = ts;
663
+ this.oxc = oxc;
664
+ this.scopes = /* @__PURE__ */ new Map();
665
+ this.seen = /* @__PURE__ */ new Set();
666
+ }
667
+ /** Declarações de um arquivo: `.d.ts` como está, o resto pelo Oxc. */
668
+ scope(file) {
669
+ const cached = this.scopes.get(file);
670
+ if (cached) return cached;
671
+ const { ts } = this;
672
+ let code = readFileSync4(file, "utf8");
673
+ if (!/\.d\.[cm]?ts$/.test(file)) {
674
+ const out = this.oxc.isolatedDeclarationSync(file, code, {});
675
+ if (out.errors.length) unsupported();
676
+ code = out.code;
677
+ }
678
+ const source = ts.createSourceFile(file + ".d.ts", code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
679
+ const scope = { file, types: /* @__PURE__ */ new Map(), values: /* @__PURE__ */ new Map(), imports: /* @__PURE__ */ new Map() };
680
+ const isDefault = (n) => ts.canHaveModifiers(n) && !!ts.getModifiers(n)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword);
681
+ let defaultName;
682
+ for (const st of source.statements) {
683
+ if (ts.isInterfaceDeclaration(st) || ts.isTypeAliasDeclaration(st)) {
684
+ if (scope.types.has(st.name.text)) unsupported();
685
+ scope.types.set(st.name.text, st);
686
+ } else if (ts.isImportDeclaration(st) && ts.isStringLiteral(st.moduleSpecifier)) {
687
+ const from = st.moduleSpecifier.text;
688
+ const clause = st.importClause;
689
+ if (clause?.name) scope.imports.set(clause.name.text, { from, name: "default" });
690
+ const bindings = clause?.namedBindings;
691
+ if (bindings && ts.isNamespaceImport(bindings)) scope.imports.set(bindings.name.text, { from, name: "*" });
692
+ if (bindings && ts.isNamedImports(bindings)) for (const el of bindings.elements) scope.imports.set(el.name.text, { from, name: (el.propertyName ?? el.name).text });
693
+ } else if (ts.isFunctionDeclaration(st) || ts.isClassDeclaration(st)) {
694
+ if (isDefault(st)) scope.default ??= st;
695
+ else if (st.name && !scope.values.has(st.name.text)) scope.values.set(st.name.text, st);
696
+ } else if (ts.isVariableStatement(st)) {
697
+ for (const d of st.declarationList.declarations) if (ts.isIdentifier(d.name)) scope.values.set(d.name.text, d);
698
+ } else if (ts.isExportAssignment(st) && !st.isExportEquals) {
699
+ defaultName = ts.isIdentifier(st.expression) ? st.expression.text : unsupported();
700
+ } else if (ts.isExportDeclaration(st) && !st.moduleSpecifier && st.exportClause && ts.isNamedExports(st.exportClause)) {
701
+ const el = st.exportClause.elements.find((e) => e.name.text === "default");
702
+ if (el) defaultName = (el.propertyName ?? el.name).text;
703
+ }
704
+ }
705
+ if (defaultName) scope.default = scope.values.get(defaultName);
706
+ this.scopes.set(file, scope);
707
+ return scope;
708
+ }
709
+ /** `mount(el, props)`, componente-função `(props)` ou classe com `props`. `undefined`: sem props. */
710
+ defaultProps(scope) {
711
+ const { ts } = this;
712
+ const node = scope.default ?? unsupported();
713
+ const param = (params, i) => {
714
+ const p = params[i];
715
+ return p && { node: p.type ?? unsupported(), scope };
716
+ };
717
+ if (ts.isFunctionDeclaration(node)) return param(node.parameters, 0);
718
+ if (ts.isClassDeclaration(node)) {
719
+ if (node.heritageClauses?.length) unsupported();
720
+ const props = node.members.find((m) => ts.isPropertyDeclaration(m) && m.name.getText() === "props");
721
+ return props && { node: props.type ?? unsupported(), scope };
722
+ }
723
+ if (ts.isVariableDeclaration(node)) return this.propsOfType(node.type ?? unsupported(), scope);
724
+ return unsupported();
725
+ }
726
+ propsOfType(node, scope) {
727
+ const { ts } = this;
728
+ const param = (params, i, at2) => {
729
+ const p = params[i];
730
+ return p && { node: p.type ?? unsupported(), scope: at2 };
731
+ };
732
+ if (ts.isParenthesizedTypeNode(node)) return this.propsOfType(node.type, scope);
733
+ if (ts.isFunctionTypeNode(node)) return param(node.parameters, 0, scope);
734
+ let members;
735
+ let at = scope;
736
+ if (ts.isTypeLiteralNode(node)) members = node.members;
737
+ else if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && !node.typeArguments) {
738
+ const found = this.lookup(node.typeName.text, scope);
739
+ if (!found || found === "package" || found.decl.typeParameters) return unsupported();
740
+ if (ts.isTypeAliasDeclaration(found.decl)) return this.propsOfType(found.decl.type, found.scope);
741
+ if (found.decl.heritageClauses?.length) unsupported();
742
+ members = found.decl.members;
743
+ at = found.scope;
744
+ } else return unsupported();
745
+ const mount = members.find((m) => m.name?.getText() === "mount");
746
+ if (mount) {
747
+ if (ts.isMethodSignature(mount)) return param(mount.parameters, 1, at);
748
+ if (ts.isPropertySignature(mount) && mount.type) return this.mountProps(mount.type, at);
749
+ return unsupported();
750
+ }
751
+ const call = members.find(ts.isCallSignatureDeclaration);
752
+ if (call) return param(call.parameters, 0, at);
753
+ if (members.some(ts.isConstructSignatureDeclaration)) unsupported();
754
+ return void 0;
755
+ }
756
+ mountProps(node, scope) {
757
+ const { ts } = this;
758
+ if (ts.isParenthesizedTypeNode(node)) return this.mountProps(node.type, scope);
759
+ if (!ts.isFunctionTypeNode(node)) return unsupported();
760
+ const p = node.parameters[1];
761
+ return p && { node: p.type ?? unsupported(), scope };
762
+ }
763
+ /** Acha um tipo pelo nome: no arquivo, num import relativo ou num pacote. */
764
+ lookup(name, scope) {
765
+ const decl = scope.types.get(name);
766
+ if (decl) return { decl, scope };
767
+ const imp = scope.imports.get(name);
768
+ if (!imp) return void 0;
769
+ if (!imp.from.startsWith(".")) return "package";
770
+ if (imp.name === "default" || imp.name === "*") return unsupported();
771
+ const found = this.lookup(imp.name, this.scope(resolveFile(scope.file, imp.from)));
772
+ return found ?? unsupported();
773
+ }
774
+ print(node, scope, depth, opts = {}) {
775
+ const { ts } = this;
776
+ const K = ts.SyntaxKind;
777
+ switch (node.kind) {
778
+ case K.AnyKeyword:
779
+ case K.UnknownKeyword:
780
+ return "unknown";
781
+ case K.StringKeyword:
782
+ case K.NumberKeyword:
783
+ case K.BooleanKeyword:
784
+ case K.BigIntKeyword:
785
+ case K.SymbolKeyword:
786
+ case K.UndefinedKeyword:
787
+ case K.VoidKeyword:
788
+ case K.NeverKeyword:
789
+ return node.getText();
790
+ }
791
+ if (ts.isLiteralTypeNode(node)) {
792
+ const lit = node.literal;
793
+ if (ts.isStringLiteral(lit)) return JSON.stringify(lit.text);
794
+ if (lit.kind === K.NullKeyword || lit.kind === K.TrueKeyword || lit.kind === K.FalseKeyword || ts.isNumericLiteral(lit) || ts.isPrefixUnaryExpression(lit)) return lit.getText();
795
+ return unsupported();
796
+ }
797
+ if (ts.isParenthesizedTypeNode(node)) return this.print(node.type, scope, depth, opts);
798
+ if (ts.isUnionTypeNode(node)) {
799
+ const types = opts.nonNull ? node.types.filter((t) => t.kind !== K.UndefinedKeyword && !(ts.isLiteralTypeNode(t) && t.literal.kind === K.NullKeyword)) : node.types;
800
+ const parts = [...new Set(types.map((t) => this.print(t, scope, depth)))];
801
+ if (parts.includes("true") && parts.includes("false")) parts.splice(parts.indexOf("true"), 1, "boolean"), parts.splice(parts.indexOf("false"), 1);
802
+ return parts.join(" | ");
803
+ }
804
+ if (ts.isIntersectionTypeNode(node)) {
805
+ return node.types.map((t) => {
806
+ const s = this.print(t, scope, depth);
807
+ return ts.isUnionTypeNode(t) ? `(${s})` : s;
808
+ }).join(" & ");
809
+ }
810
+ if (depth > 6) return "unknown";
811
+ if (ts.isArrayTypeNode(node)) return `Array<${this.print(node.elementType, scope, depth + 1)}>`;
812
+ if (ts.isTypeOperatorNode(node) && node.operator === K.ReadonlyKeyword && (ts.isArrayTypeNode(node.type) || ts.isTupleTypeNode(node.type))) return this.print(node.type, scope, depth);
813
+ if (ts.isTupleTypeNode(node)) {
814
+ if (node.elements.some((e) => ts.isNamedTupleMember(e) || ts.isOptionalTypeNode(e) || ts.isRestTypeNode(e))) unsupported();
815
+ return `[${node.elements.map((e) => this.print(e, scope, depth + 1)).join(", ")}]`;
816
+ }
817
+ if (ts.isTypeLiteralNode(node)) return this.object(node.members, scope, depth, !!opts.top);
818
+ if (ts.isFunctionTypeNode(node)) return this.signature(node, scope, depth);
819
+ if (ts.isTypeReferenceNode(node)) return this.reference(node, scope, depth, opts);
820
+ return unsupported();
821
+ }
822
+ reference(node, scope, depth, opts) {
823
+ const { ts } = this;
824
+ if (!ts.isIdentifier(node.typeName)) return unsupported();
825
+ const name = node.typeName.text;
826
+ const args = node.typeArguments ?? [];
827
+ const found = this.lookup(name, scope);
828
+ if (found === "package") return "unknown";
829
+ if (found) {
830
+ if (args.length || found.decl.typeParameters) unsupported();
831
+ if (this.seen.has(found.decl)) return "unknown";
832
+ this.seen.add(found.decl);
833
+ try {
834
+ const decl = found.decl;
835
+ if (ts.isTypeAliasDeclaration(decl)) return this.print(decl.type, found.scope, depth, opts);
836
+ if (decl.heritageClauses?.length) unsupported();
837
+ return this.object(decl.members, found.scope, depth, !!opts.top);
838
+ } finally {
839
+ this.seen.delete(found.decl);
840
+ }
841
+ }
842
+ if ((name === "Array" || name === "ReadonlyArray") && args.length === 1) return `Array<${this.print(args[0], scope, depth + 1)}>`;
843
+ if (!GLOBAL3.test(name)) return unsupported();
844
+ return args.length ? `${name}<${args.map((t) => this.print(t, scope, depth + 1)).join(", ")}>` : name;
845
+ }
846
+ object(members, scope, depth, top) {
847
+ const { ts } = this;
848
+ const fields = [];
849
+ const calls = [];
850
+ let index;
851
+ for (const m of members) {
852
+ if (ts.isPropertySignature(m) || ts.isMethodSignature(m)) {
853
+ const name = ts.isIdentifier(m.name) || ts.isStringLiteral(m.name) || ts.isNumericLiteral(m.name) ? m.name.text : unsupported();
854
+ if (top && name === "vitral") continue;
855
+ const optional = m.questionToken ? "?" : "";
856
+ const key = IDENT.test(name) ? name : JSON.stringify(name);
857
+ const type = ts.isMethodSignature(m) ? this.signature(m, scope, depth + 1) : m.type ? this.print(m.type, scope, depth + 1, { nonNull: !!optional }) : "unknown";
858
+ fields.push(`${key}${optional}: ${type}`);
859
+ } else if (ts.isIndexSignatureDeclaration(m)) {
860
+ const key = m.parameters[0]?.type;
861
+ if (!key || key.kind !== ts.SyntaxKind.StringKeyword) unsupported();
862
+ index = `[key: string]: ${this.print(m.type, scope, depth + 1)}`;
863
+ } else if (ts.isCallSignatureDeclaration(m)) {
864
+ calls.push(this.signature(m, scope, depth));
865
+ } else unsupported();
866
+ }
867
+ if (calls.length && !fields.length) return calls[0];
868
+ if (index) fields.push(index);
869
+ for (const c of calls) fields.push(c.replace(" =>", ":"));
870
+ return fields.length ? `{ ${fields.join("; ")} }` : "{}";
871
+ }
872
+ signature(sig, scope, depth) {
873
+ const { ts } = this;
874
+ if (sig.typeParameters?.length || !sig.type) unsupported();
875
+ const params = sig.parameters.map((p, i) => {
876
+ if (p.dotDotDotToken || ts.isIdentifier(p.name) && p.name.text === "this") unsupported();
877
+ const name = ts.isIdentifier(p.name) && IDENT.test(p.name.text) ? p.name.text : `a${i}`;
878
+ const type = p.type ? this.print(p.type, scope, depth + 1) : "unknown";
879
+ return `${name}: ${p.questionToken || p.initializer ? `${type} | undefined` : type}`;
880
+ });
881
+ return `(${params.join(", ")}) => ${this.print(sig.type, scope, depth + 1)}`;
882
+ }
883
+ };
884
+ function resolveFile(from, spec) {
885
+ const base = resolve4(dirname3(from), spec);
886
+ const stem = base.replace(/\.[cm]?jsx?$/, "");
887
+ const candidates = [base, ...[".ts", ".tsx", ".mts", ".cts", ".d.ts"].map((ext) => stem + ext), ...["index.ts", "index.tsx", "index.d.ts"].map((f) => join4(base, f))];
888
+ const file = candidates.find((f) => /\.[cm]?tsx?$/.test(f) && existsSync4(f));
889
+ return file ?? unsupported();
890
+ }
891
+
892
+ // src/vite/types.ts
455
893
  function typesFile(name, props) {
456
894
  return `// Props do remote ${JSON.stringify(name)}, geradas pelo vitral. N\xE3o edite.
457
895
  export type Props = ${props}
458
896
  `;
459
897
  }
460
898
  async function loadTs(root) {
899
+ const api = (ts) => typeof ts?.createProgram === "function" ? ts : null;
461
900
  try {
462
- return createRequire(join3(root, "package.json"))("typescript");
901
+ const ts = api(createRequire2(join5(root, "package.json"))("typescript"));
902
+ if (ts) return ts;
463
903
  } catch {
464
- try {
465
- return (await import("typescript")).default;
466
- } catch {
467
- return null;
468
- }
904
+ }
905
+ try {
906
+ return api((await import("typescript")).default);
907
+ } catch {
908
+ return null;
469
909
  }
470
910
  }
471
911
  async function extractProps(root, file) {
472
912
  if (!/\.[cm]?[jt]sx?$/.test(file)) return null;
473
913
  const ts = await loadTs(root);
474
914
  if (!ts) return null;
915
+ const oxc = /\.[cm]?tsx?$/.test(file) ? await loadOxc(root) : null;
916
+ const fast = oxc && propsFromOxc(ts, oxc, file);
917
+ if (fast) return fast;
475
918
  const configPath = ts.findConfigFile(root, ts.sys.fileExists);
476
919
  const base = configPath ? ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, ts.sys.readFile).config, ts.sys, root).options : {};
477
920
  const options = {
@@ -575,6 +1018,116 @@ var Printer = class {
575
1018
  }
576
1019
  };
577
1020
 
1021
+ // src/vite/mcp-app.ts
1022
+ var MCP_APP_PROTOCOL = "2026-01-26";
1023
+ var MCP_APP_GLOBAL = "__vitral_remote__";
1024
+ var MCP_RUNTIME = `function (w, mod, info) {
1025
+ var parent = w.parent, doc = w.document, seq = 0, pending = {}, handlers = {}, last = {}, context = {}
1026
+ var props = {}, mounted = null, ready = false, dirty = false
1027
+ function send(m) { m.jsonrpc = '2.0'; parent.postMessage(m, '*') }
1028
+ function request(method, params) {
1029
+ var id = ++seq
1030
+ return new Promise(function (ok, fail) {
1031
+ pending[id] = [ok, fail]
1032
+ send({ id: id, method: method, params: params || {} })
1033
+ })
1034
+ }
1035
+ function notify(method, params) { send({ method: method, params: params || {} }) }
1036
+ function report(e) { notify('notifications/message', { level: 'error', logger: info.name, data: String((e && e.message) || e) }) }
1037
+ function text(p, key) { return typeof p === 'string' ? p : p && p[key] }
1038
+ function push() { if (mounted && mounted.update) { try { mounted.update(Object.assign({}, props)) } catch (e) { report(e) } } }
1039
+ // Antes do mount terminar, s\xF3 guarda: o update sai uma vez, logo depois.
1040
+ function set(key, value) { props[key] = value; if (ready) push(); else dirty = true }
1041
+ function theme(c) {
1042
+ if (!c) return
1043
+ var root = doc.documentElement, vars = c.styles && c.styles.variables
1044
+ if (c.theme) { root.setAttribute('data-theme', c.theme); root.style.colorScheme = c.theme }
1045
+ for (var k in vars) if (vars[k] != null) root.style.setProperty(k, vars[k])
1046
+ }
1047
+ var events = {
1048
+ emit: function (type, payload) {
1049
+ last[type] = payload
1050
+ ;(handlers[type] || []).slice().forEach(function (h) { try { h(payload) } catch (e) { w.console.error(e) } })
1051
+ if (type === 'mcp:message') request('ui/message', { role: 'user', content: [{ type: 'text', text: String(text(payload, 'text')) }] }).catch(report)
1052
+ else if (type === 'mcp:open-link') request('ui/open-link', { url: String(text(payload, 'url')) }).catch(report)
1053
+ else {
1054
+ context[type] = payload
1055
+ request('ui/update-model-context', { structuredContent: context, content: [{ type: 'text', text: JSON.stringify(context) }] }).catch(report)
1056
+ }
1057
+ },
1058
+ on: function (type, fn) {
1059
+ ;(handlers[type] = handlers[type] || []).push(fn)
1060
+ return function () { handlers[type] = handlers[type].filter(function (h) { return h !== fn }) }
1061
+ },
1062
+ last: function (type) { return last[type] }
1063
+ }
1064
+ var root = doc.createElement('div')
1065
+ root.setAttribute('data-vitral-root', info.name)
1066
+ if (info.scope) root.setAttribute('data-vitral-scope', info.scope)
1067
+ var ctx = {
1068
+ name: info.name, baseUrl: w.location.href, events: events, shadowRoot: null, portalContainer: doc.body, protocol: 1,
1069
+ reportError: report,
1070
+ navigate: function (url) { request('ui/open-link', { url: String(url) }).catch(report) },
1071
+ mcp: { request: request, notify: notify, hostContext: function () { return props.hostContext } }
1072
+ }
1073
+ function size() {
1074
+ var h = doc.documentElement, old = h.style.height
1075
+ h.style.height = 'max-content'
1076
+ var height = Math.ceil(h.getBoundingClientRect().height)
1077
+ h.style.height = old
1078
+ notify('ui/notifications/size-changed', { width: Math.ceil(w.innerWidth), height: height })
1079
+ }
1080
+ var on = {
1081
+ 'ui/notifications/tool-input': function (p) { set('toolInput', p.arguments) },
1082
+ 'ui/notifications/tool-input-partial': function (p) { set('toolInputPartial', p.arguments) },
1083
+ 'ui/notifications/tool-result': function (p) { set('toolResult', p) },
1084
+ 'ui/notifications/tool-cancelled': function (p) { set('toolCancelled', p.reason || true) },
1085
+ 'ui/notifications/host-context-changed': function (p) { theme(p); set('hostContext', Object.assign({}, props.hostContext, p)) },
1086
+ 'ui/resource-teardown': function () { if (mounted) mounted.unmount(); mounted = null; return {} },
1087
+ ping: function () { return {} }
1088
+ }
1089
+ w.addEventListener('message', function (e) {
1090
+ var m = e.data
1091
+ if (e.source !== parent || !m || m.jsonrpc !== '2.0') return
1092
+ if (m.method === undefined) {
1093
+ var p = pending[m.id]
1094
+ if (!p) return
1095
+ delete pending[m.id]
1096
+ return m.error ? p[1](new Error(m.error.message)) : p[0](m.result)
1097
+ }
1098
+ var fn = on[m.method], result
1099
+ if (m.id === undefined) return void (fn && fn(m.params || {}))
1100
+ if (!fn) return send({ id: m.id, error: { code: -32601, message: 'm\xE9todo desconhecido: ' + m.method } })
1101
+ try { result = fn(m.params || {}) } catch (err) { return send({ id: m.id, error: { code: -32603, message: String(err && err.message || err) } }) }
1102
+ send({ id: m.id, result: result })
1103
+ })
1104
+ request('ui/initialize', {
1105
+ appInfo: { name: info.name, version: info.version || '0.0.0' }, appCapabilities: {}, protocolVersion: '${MCP_APP_PROTOCOL}'
1106
+ }).then(function (r) {
1107
+ props.hostContext = r && r.hostContext
1108
+ theme(props.hostContext)
1109
+ notify('ui/notifications/initialized')
1110
+ doc.body.appendChild(root)
1111
+ var remote = (mod && mod.default) || mod
1112
+ if (!remote || typeof remote.mount !== 'function') throw new Error('o m\xF3dulo n\xE3o exporta mount()')
1113
+ dirty = false
1114
+ return remote.mount(root, Object.assign({}, props), ctx)
1115
+ }).then(function (handle) {
1116
+ mounted = handle
1117
+ ready = true
1118
+ if (dirty) push()
1119
+ size()
1120
+ if (w.ResizeObserver) { var ro = new w.ResizeObserver(size); ro.observe(doc.documentElement); ro.observe(doc.body) }
1121
+ }).catch(report)
1122
+ }`;
1123
+ var inline = (text, tag) => text.replace(new RegExp(`</(${tag})`, "gi"), "<\\/$1").replace(/<!--/g, "<\\!--");
1124
+ function mcpAppHtml(page) {
1125
+ const info = JSON.stringify({ name: page.name, version: page.version, scope: page.scope });
1126
+ const styles = page.css.map((css) => `<style>${inline(css, "style")}</style>`).join("");
1127
+ return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${page.name.replace(/[<&]/g, (c) => c === "<" ? "&lt;" : "&amp;")}</title><style>html,body{margin:0}body{display:flow-root}</style>${styles}</head><body><script>${inline(page.code, "script")}</script><script>(${MCP_RUNTIME})(window, ${MCP_APP_GLOBAL}, ${inline(info, "script")})</script></body></html>
1128
+ `;
1129
+ }
1130
+
578
1131
  // src/vite/dev.ts
579
1132
  var DEV_ENTRY = "@vitral/entry.js";
580
1133
  var VIRTUAL_DEV_ENTRY = "\0vitral:dev-entry";
@@ -623,6 +1176,7 @@ if (import.meta.hot) {
623
1176
  }
624
1177
  `;
625
1178
  }
1179
+ var DEV_IDS = /^virtual:vitral-react-preamble$|\/@vitral\/entry\.js$/;
626
1180
  function resolveDevId(id) {
627
1181
  if (id === PREAMBLE_ID) return "\0" + PREAMBLE_ID;
628
1182
  if (id.endsWith("/" + DEV_ENTRY)) return VIRTUAL_DEV_ENTRY;
@@ -633,8 +1187,9 @@ function loadPreamble(id) {
633
1187
  function devManifest(name, scope) {
634
1188
  return { name, entry: DEV_ENTRY, css: [], ...scope ? { scope } : {} };
635
1189
  }
1190
+ var DEV_CSS = { include: /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(\?|$)/, exclude: /[?&](raw|url|inline)\b/ };
636
1191
  function scopeDevCss(code, id, scope) {
637
- if (!/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(\?|$)/.test(id) || /[?&](raw|url|inline)\b/.test(id)) return;
1192
+ if (!DEV_CSS.include.test(id) || DEV_CSS.exclude.test(id)) return;
638
1193
  return scopeCss(code, scope);
639
1194
  }
640
1195
  function serveDevManifest(server, manifest) {
@@ -670,21 +1225,44 @@ function vitral(options = {}) {
670
1225
  let pkg = {};
671
1226
  let manifest;
672
1227
  let split;
1228
+ let modules = /* @__PURE__ */ new Set();
673
1229
  let entry = options.entry;
674
1230
  let adapter = "element";
675
1231
  let framework = "element";
676
- const entryFile = () => resolve4(root, entry);
1232
+ const entryFile = () => resolve5(root, entry);
677
1233
  let serve = false;
678
1234
  let shared = [];
679
1235
  const dedupe = !!options.dedupe?.length;
680
1236
  const hooks = dedupeHooks(() => options.exposes ? EXPOSES_ENTRY : options.adapter === false ? entryFile() : ENTRY_ID, () => shared);
1237
+ const mcp = options.target === "mcp-app";
1238
+ if (mcp && (options.exposes || dedupe || options.shared?.length)) {
1239
+ throw new Error("[vitral] target: 'mcp-app' gera um HTML \xFAnico: n\xE3o combina com exposes, dedupe nem shared.");
1240
+ }
681
1241
  const scopeName = () => (options.name ?? pkg.name ?? "remote").replace(/[^a-zA-Z0-9_-]/g, "-");
1242
+ const mcpApp = (files, js) => {
1243
+ const css = files.filter((f) => f.type === "asset" && f.fileName.endsWith(".css")).map((f) => f.fileName);
1244
+ const read = (file) => {
1245
+ const text = readFileSync5(join6(outDir, file), "utf8");
1246
+ rmSync2(join6(outDir, file));
1247
+ return text;
1248
+ };
1249
+ const scope = options.scopeCss === false ? void 0 : scopeName();
1250
+ const html = mcpAppHtml({
1251
+ name: options.name ?? pkg.name ?? "remote",
1252
+ version: options.version ?? pkg.version,
1253
+ scope,
1254
+ code: read(js),
1255
+ css: css.map((f) => transformCss(read(f), options, scopeName()))
1256
+ });
1257
+ writeFileSync2(join6(outDir, "mcp-app.html"), html);
1258
+ };
682
1259
  return {
683
1260
  name: "vitral",
684
1261
  config(user, { mode, command }) {
685
- entry ??= findEntry(resolve4(user.root ?? process.cwd()));
1262
+ entry ??= findEntry(resolve5(user.root ?? process.cwd()));
686
1263
  if (!entry) throw new Error("[vitral] n\xE3o achei a entrada do remote (src/remote.* ou src/App.*). Use vitral({ entry }).");
687
1264
  const rolldown = "rolldownVersion" in this.meta;
1265
+ const dir = options.versionDir ? versionDir(user.root ?? process.cwd(), user.build?.outDir, options.version) : void 0;
688
1266
  return {
689
1267
  // Código de biblioteca não tem process.env; React e Vue precisam disso.
690
1268
  define: { "process.env.NODE_ENV": JSON.stringify(mode === "development" ? "development" : "production") },
@@ -694,12 +1272,18 @@ function vitral(options = {}) {
694
1272
  // O remote não tem index.html: sem isso o Vite só descobre as
695
1273
  // dependências no primeiro request e recarrega a página do host.
696
1274
  optimizeDeps: user.optimizeDeps?.entries ? void 0 : { entries: [entry] },
697
- build: {
1275
+ build: mcp ? {
1276
+ // Um IIFE só, sem chunks: o HTML do MCP App não pode buscar arquivos.
1277
+ lib: { entry: options.adapter === false ? entry : ENTRY_ID, formats: ["iife"], name: MCP_APP_GLOBAL, fileName: () => "mcp-app.js", cssFileName: "remote" },
1278
+ rollupOptions: { output: rolldown ? { codeSplitting: false } : { inlineDynamicImports: true } },
1279
+ cssCodeSplit: false
1280
+ } : {
698
1281
  // Nomes com hash: cache eterno no CDN. Só o vitral.json muda a cada deploy.
699
1282
  lib: { entry: dedupe ? BOOT : options.exposes ? EXPOSES_ENTRY : options.adapter === false ? entry : ENTRY_ID, fileName: () => "remote-[hash].js", cssFileName: "remote" },
700
1283
  // Arquivo único (hosts antigos e caminho com blob:) e build dividido (manifesto v2).
701
1284
  rollupOptions: { external: options.shared ?? [], output: outputs(rolldown) },
702
- cssCodeSplit: false
1285
+ cssCodeSplit: false,
1286
+ ...dir && { outDir: dir }
703
1287
  }
704
1288
  };
705
1289
  },
@@ -708,9 +1292,9 @@ function vitral(options = {}) {
708
1292
  framework = detectAdapter(c.plugins);
709
1293
  adapter = options.adapter || framework;
710
1294
  serve = c.command === "serve";
711
- outDir = resolve4(c.root, c.build.outDir);
1295
+ outDir = resolve5(c.root, c.build.outDir);
712
1296
  try {
713
- pkg = JSON.parse(readFileSync3(join4(root, "package.json"), "utf8"));
1297
+ pkg = JSON.parse(readFileSync5(join6(root, "package.json"), "utf8"));
714
1298
  } catch {
715
1299
  }
716
1300
  },
@@ -722,8 +1306,11 @@ function vitral(options = {}) {
722
1306
  const scope = options.scopeCss === false ? void 0 : scopeName();
723
1307
  serveDevManifest(server, () => devManifest(options.name ?? pkg.name ?? "remote", scope));
724
1308
  },
1309
+ // Filtros de hook (Rolldown, Vite 6.3+): os módulos que não são do vitral
1310
+ // nem chegam ao JS. As checagens nos handlers continuam para Vite 5 e 6.0-6.2.
725
1311
  resolveId: {
726
1312
  order: "pre",
1313
+ filter: { id: [...dedupe ? [dedupeIds(options.dedupe)] : [], ...options.exposes ? [EXPOSES_IDS] : [], /__vitral_entry__\.js$/, DEV_IDS] },
727
1314
  handler(id, importer) {
728
1315
  const own = dedupe && !serve ? hooks.resolveId.handler(id, importer) : null;
729
1316
  if (own) return own;
@@ -732,54 +1319,102 @@ function vitral(options = {}) {
732
1319
  return resolveDevId(id);
733
1320
  }
734
1321
  },
735
- load(id) {
736
- const own = dedupe && !serve ? hooks.load(id) : null;
737
- if (own != null) return own;
738
- const exposed = options.exposes ? loadExposes(id, root, entry, options.exposes, options.adapter === false ? void 0 : ENTRY_ID) : null;
739
- if (exposed != null) return exposed;
740
- if (id === VIRTUAL_ENTRY) return entryCode(resolve4(root, entry), adapter, scopeName());
741
- if (id === VIRTUAL_DEV_ENTRY) return devEntryCode(framework, options.adapter === false ? resolve4(root, entry) : void 0);
742
- return loadPreamble(id);
1322
+ load: {
1323
+ // Todos os módulos virtuais do vitral: \0vitral... e \0virtual:vitral...
1324
+ filter: { id: /^\x00(virtual:)?vitral/ },
1325
+ handler(id) {
1326
+ const own = dedupe && !serve ? hooks.load(id) : null;
1327
+ if (own != null) return own;
1328
+ const exposed = options.exposes ? loadExposes(id, root, entry, options.exposes, options.adapter === false ? void 0 : ENTRY_ID) : null;
1329
+ if (exposed != null) return exposed;
1330
+ if (id === VIRTUAL_ENTRY) return entryCode(resolve5(root, entry), adapter, scopeName());
1331
+ if (id === VIRTUAL_DEV_ENTRY) return devEntryCode(framework, options.adapter === false ? resolve5(root, entry) : void 0);
1332
+ return loadPreamble(id);
1333
+ }
743
1334
  },
744
- transform(code, id) {
745
- if (serve && options.scopeCss !== false) return scopeDevCss(code, id, scopeName());
1335
+ transform: {
1336
+ filter: { id: DEV_CSS },
1337
+ handler(code, id) {
1338
+ if (serve && options.scopeCss !== false) return scopeDevCss(code, id, scopeName());
1339
+ }
746
1340
  },
747
1341
  writeBundle(_, bundle) {
1342
+ if (options.sbom) bundledFiles(bundle, modules);
748
1343
  if (isSplit(bundle)) return void (split = collect(outDir, bundle));
749
1344
  const files = Object.values(bundle);
750
1345
  const entry2 = files.find((f) => f.type === "chunk" && f.isEntry);
751
1346
  if (!entry2) return;
1347
+ if (mcp) return mcpApp(files, entry2.fileName);
1348
+ const emit = (file, text, kind = "") => {
1349
+ const hash = createHash3("sha256").update(text).digest("base64url").slice(0, 8);
1350
+ const name = file.replace(/\.css$/, `${kind}-${hash}.css`);
1351
+ writeFileSync2(join6(outDir, name), text);
1352
+ return name;
1353
+ };
1354
+ const shadow = { css: [] };
752
1355
  const css = files.filter((f) => f.type === "asset" && f.fileName.endsWith(".css")).map((f) => {
753
- const from = join4(outDir, f.fileName);
754
- let text = readFileSync3(from, "utf8");
755
- text = transformCss(text, options, scopeName());
756
- const hash = createHash2("sha256").update(text).digest("base64url").slice(0, 8);
757
- const name = f.fileName.replace(/\.css$/, `-${hash}.css`);
758
- writeFileSync2(join4(outDir, name), text);
1356
+ const from = join6(outDir, f.fileName);
1357
+ const text = transformCss(readFileSync5(from, "utf8"), options, scopeName());
1358
+ const name = emit(f.fileName, text);
759
1359
  if (name !== f.fileName) rmSync2(from);
1360
+ const split2 = splitShadowCss(text);
1361
+ shadow.css.push(split2.css === text ? name : emit(f.fileName, split2.css, "-shadow"));
1362
+ if (split2.global) (shadow.global ??= []).push(emit(f.fileName, split2.global, "-global"));
1363
+ if (split2.imports.length) (shadow.imports ??= []).push(...split2.imports);
1364
+ if (split2.rebase) shadow.rebase = true;
760
1365
  return name;
761
1366
  });
762
- const code = readFileSync3(join4(outDir, entry2.fileName));
1367
+ const code = readFileSync5(join6(outDir, entry2.fileName));
763
1368
  manifest = {
764
1369
  name: options.name ?? pkg.name ?? "remote",
765
1370
  version: options.version ?? pkg.version,
766
1371
  entry: entry2.fileName,
767
1372
  css,
768
- integrity: "sha384-" + createHash2("sha384").update(code).digest("base64"),
1373
+ ...css.length ? { shadow } : {},
1374
+ integrity: "sha384-" + createHash3("sha384").update(code).digest("base64"),
769
1375
  ...options.scopeCss === false ? {} : { scope: scopeName() },
770
- ...options.exposes ? { exposes: Object.keys(exposeKeys(options.exposes)) } : {}
1376
+ ...options.exposes ? { exposes: Object.keys(exposeKeys(options.exposes)) } : {},
1377
+ ...contractOf(options.contract?.version, shared)
771
1378
  };
772
1379
  },
773
1380
  async closeBundle() {
774
1381
  if (!manifest) return;
775
1382
  const done = withSplit(manifest, outDir, split, shared);
1383
+ if (options.sbom) {
1384
+ const bom = createSbom({ root, name: done.name, version: done.version, files: modules, entry: readFileSync5(join6(outDir, done.entry)), tool: ownVersion() });
1385
+ writeFileSync2(join6(outDir, SBOM_FILE), JSON.stringify(bom, null, 2) + "\n");
1386
+ done.sbom = { file: SBOM_FILE, integrity: sri(join6(outDir, SBOM_FILE)) };
1387
+ }
776
1388
  manifest = split = void 0;
777
- writeFileSync2(join4(outDir, "vitral.json"), JSON.stringify(done, null, 2) + "\n");
1389
+ modules = /* @__PURE__ */ new Set();
1390
+ writeFileSync2(join6(outDir, "vitral.json"), JSON.stringify(done, null, 2) + "\n");
778
1391
  const props = options.types === false ? null : await extractProps(root, entryFile());
779
- if (props) writeFileSync2(join4(outDir, "vitral.d.ts"), typesFile(done.name, props));
1392
+ if (props) writeFileSync2(join6(outDir, "vitral.d.ts"), typesFile(done.name, props));
780
1393
  }
781
1394
  };
782
1395
  }
1396
+ function ownVersion() {
1397
+ try {
1398
+ return JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf8")).version;
1399
+ } catch {
1400
+ return void 0;
1401
+ }
1402
+ }
1403
+ function versionDir(root, outDir = "dist", version) {
1404
+ try {
1405
+ version ??= JSON.parse(readFileSync5(join6(resolve5(root), "package.json"), "utf8")).version;
1406
+ } catch {
1407
+ }
1408
+ if (!version) throw new Error('[vitral] versionDir precisa de uma vers\xE3o: use vitral({ version }) ou "version" no package.json.');
1409
+ return join6(outDir, version);
1410
+ }
1411
+ function contractOf(version, groups2) {
1412
+ const contract = {
1413
+ ...version && { version },
1414
+ ...groups2.length && { peers: Object.fromEntries(groups2.map((g) => [g.name, g.range])) }
1415
+ };
1416
+ return Object.keys(contract).length ? { contract } : {};
1417
+ }
783
1418
  export {
784
1419
  vitral as default,
785
1420
  vitral