vitral 0.1.0 → 0.2.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 (56) hide show
  1. package/README.md +250 -217
  2. package/dist/angular.d.ts +15 -4
  3. package/dist/angular.js +25 -5
  4. package/dist/auto.d.ts +2 -0
  5. package/dist/auto.js +12 -0
  6. package/dist/chunk-2XF5BKV3.js +190 -0
  7. package/dist/chunk-6Y3VMWHH.js +181 -0
  8. package/dist/chunk-DXORSF4X.js +42 -0
  9. package/dist/chunk-GNPFWISJ.js +80 -0
  10. package/dist/chunk-HP6QWU6K.js +51 -0
  11. package/dist/chunk-NCONW6WS.js +606 -0
  12. package/dist/chunk-PX7PBCCT.js +89 -0
  13. package/dist/chunk-S5MZT5IT.js +20 -0
  14. package/dist/chunk-SFL6LTP3.js +56 -0
  15. package/dist/chunk-UTYAX6MU.js +152 -0
  16. package/dist/cli.d.ts +1 -0
  17. package/dist/cli.js +88 -0
  18. package/dist/dedupe-IWFIXRWG.js +81 -0
  19. package/dist/devtools.d.ts +12 -0
  20. package/dist/devtools.js +86 -0
  21. package/dist/element.d.ts +60 -2
  22. package/dist/element.js +9 -2
  23. package/dist/errors-KKB8FGCz.d.ts +11 -0
  24. package/dist/events-DUdjhfps.d.ts +6 -0
  25. package/dist/expose-53BEJB34.js +14 -0
  26. package/dist/host-slot-Cz6EiGsB.d.ts +6 -0
  27. package/dist/iframe.d.ts +28 -0
  28. package/dist/iframe.js +236 -0
  29. package/dist/index.d.ts +142 -147
  30. package/dist/index.js +39 -10
  31. package/dist/navigate-BRG1WJUM.d.ts +9 -0
  32. package/dist/overrides-NZAIUGK5.js +15 -0
  33. package/dist/preact.d.ts +30 -7
  34. package/dist/preact.js +37 -9
  35. package/dist/react.d.ts +38 -7
  36. package/dist/react.js +92 -42
  37. package/dist/routes.d.ts +56 -0
  38. package/dist/routes.js +143 -0
  39. package/dist/shadow-MYRJQLLY.js +72 -0
  40. package/dist/slot-pB276oPt.d.ts +36 -0
  41. package/dist/solid.d.ts +29 -6
  42. package/dist/solid.js +31 -8
  43. package/dist/sri-BVKZNX5Q.js +114 -0
  44. package/dist/state-BDdCwc21.d.ts +4 -0
  45. package/dist/svelte.d.ts +19 -3
  46. package/dist/svelte.js +10 -4
  47. package/dist/testing.d.ts +2 -2
  48. package/dist/testing.js +8 -3
  49. package/dist/types-BV-hUrms.d.ts +265 -0
  50. package/dist/vite.d.ts +58 -4
  51. package/dist/vite.js +714 -24
  52. package/dist/vue.d.ts +79 -7
  53. package/dist/vue.js +69 -46
  54. package/package.json +144 -8
  55. package/dist/chunk-IZK6ITIJ.js +0 -96
  56. package/dist/chunk-TTL52BF2.js +0 -547
@@ -0,0 +1,56 @@
1
+ import {
2
+ addLink
3
+ } from "./chunk-PX7PBCCT.js";
4
+ import {
5
+ protocol
6
+ } from "./chunk-GNPFWISJ.js";
7
+
8
+ // src/core/css.ts
9
+ var loadedCss = /* @__PURE__ */ new WeakMap();
10
+ var cssText = /* @__PURE__ */ new Map();
11
+ var noop = () => {
12
+ };
13
+ var adopts = () => typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype;
14
+ function fetchCssText(href, integrity, priority) {
15
+ let p = cssText.get(href);
16
+ if (!p) {
17
+ p = fetch(href, { credentials: "omit", integrity, priority }).then((r) => r.ok ? r.text() : "").catch(() => "");
18
+ cssText.set(href, p);
19
+ }
20
+ return p;
21
+ }
22
+ function prefetchCss(urls, shadow, sri = {}, priority = "auto") {
23
+ for (const href of urls) {
24
+ if (shadow && adopts()) void fetchCssText(href, sri[href], priority);
25
+ else if (!document.querySelector(`link[href="${href}"]`)) addLink("preload", href, { as: "style", integrity: sri[href] ?? "", fetchPriority: priority });
26
+ }
27
+ }
28
+ function injectStyles(urls, root, el, styles, sri = {}) {
29
+ return root ? import("./shadow-MYRJQLLY.js").then((m) => m.attachStyles(root, el, urls, protocol().settings().styles, styles, sri)) : injectCss(urls, null, sri).then(() => noop);
30
+ }
31
+ function injectCss(urls, root, sri = {}) {
32
+ const owner = root ?? document;
33
+ let seen = loadedCss.get(owner);
34
+ if (!seen) loadedCss.set(owner, seen = /* @__PURE__ */ new Map());
35
+ const parent = root ?? document.head;
36
+ return Promise.all(
37
+ urls.map((href) => {
38
+ let p = seen.get(href);
39
+ if (!p) {
40
+ p = new Promise((resolve) => {
41
+ const link = addLink("stylesheet", href, { integrity: sri[href] ?? "" }, parent);
42
+ link.onload = link.onerror = () => resolve();
43
+ });
44
+ seen.set(href, p);
45
+ }
46
+ return p;
47
+ })
48
+ );
49
+ }
50
+
51
+ export {
52
+ fetchCssText,
53
+ prefetchCss,
54
+ injectStyles,
55
+ injectCss
56
+ };
@@ -0,0 +1,152 @@
1
+ import {
2
+ createSlot
3
+ } from "./chunk-NCONW6WS.js";
4
+ import {
5
+ preload,
6
+ registerSrc
7
+ } from "./chunk-2XF5BKV3.js";
8
+
9
+ // src/core/host-slot.ts
10
+ var noop = () => {
11
+ };
12
+ function timings(name) {
13
+ const out = {};
14
+ if (typeof performance === "undefined" || !performance.getEntriesByName) return out;
15
+ for (const stage of ["manifest", "js", "css", "mount"]) {
16
+ const m = performance.getEntriesByName(`vitral:${name}:${stage}`, "measure").pop();
17
+ if (m) out[stage] = Math.round(m.duration * 10) / 10;
18
+ }
19
+ return out;
20
+ }
21
+ function when(el, mode, fn) {
22
+ if (mode === "lazy" || mode === "visible") {
23
+ if (typeof IntersectionObserver === "undefined") return fn(), noop;
24
+ const io = new IntersectionObserver(
25
+ (entries) => {
26
+ if (entries.some((e) => e.isIntersecting)) io.disconnect(), fn();
27
+ },
28
+ { rootMargin: "200px" }
29
+ );
30
+ io.observe(el);
31
+ return () => io.disconnect();
32
+ }
33
+ if (mode === "idle") {
34
+ if (typeof requestIdleCallback === "undefined") {
35
+ const t = setTimeout(fn, 1);
36
+ return () => clearTimeout(t);
37
+ }
38
+ const id = requestIdleCallback(fn, { timeout: 2e3 });
39
+ return () => cancelIdleCallback(id);
40
+ }
41
+ if (mode === "hover") {
42
+ const go = () => (off(), fn());
43
+ const off = () => {
44
+ el.removeEventListener("pointerenter", go);
45
+ el.removeEventListener("focusin", go);
46
+ };
47
+ el.addEventListener("pointerenter", go);
48
+ el.addEventListener("focusin", go);
49
+ return off;
50
+ }
51
+ fn();
52
+ return noop;
53
+ }
54
+ var kept = /* @__PURE__ */ new Map();
55
+ var shelf = null;
56
+ function move(parent, node) {
57
+ try {
58
+ ;
59
+ parent.moveBefore(node, null);
60
+ } catch {
61
+ parent.appendChild(node);
62
+ }
63
+ }
64
+ function signal(node, type) {
65
+ for (const el of node.querySelectorAll("*")) {
66
+ if (el.hasAttribute("data-vitral-root")) el.dispatchEvent(new Event(type));
67
+ if (el.shadowRoot) signal(el.shadowRoot, type);
68
+ }
69
+ }
70
+ function park(key, item, max) {
71
+ kept.get(key)?.slot.destroy();
72
+ kept.delete(key);
73
+ if (!shelf?.isConnected) {
74
+ shelf = document.createElement("div");
75
+ shelf.hidden = true;
76
+ shelf.setAttribute("data-vitral-keep-alive", "");
77
+ document.body.appendChild(shelf);
78
+ }
79
+ move(shelf, item.box);
80
+ signal(item.box, "vitral:deactivate");
81
+ kept.set(key, item);
82
+ for (const [k, old] of kept) {
83
+ if (kept.size <= max) break;
84
+ kept.delete(k);
85
+ old.slot.destroy();
86
+ old.box.remove();
87
+ }
88
+ }
89
+ function hostSlot(target, options) {
90
+ let { props = {}, keepAlive } = options;
91
+ const key = (o) => o.src ? registerSrc(o.src, o.name) : o.name ?? "";
92
+ let name = key(options);
93
+ let status = "loading";
94
+ let item = null;
95
+ const onStatus = (s, e) => {
96
+ status = s;
97
+ options.onStatus?.(s, e);
98
+ };
99
+ const cancelPrefetch = options.prefetch ? when(target, options.prefetch, () => preload(name)) : noop;
100
+ const cancel = when(target, options.loading, () => {
101
+ cancelPrefetch();
102
+ const found = keepAlive ? kept.get(name) : void 0;
103
+ if (found) {
104
+ kept.delete(name);
105
+ item = found;
106
+ item.on = onStatus;
107
+ move(target, item.box);
108
+ item.slot.update(props);
109
+ signal(item.box, "vitral:activate");
110
+ onStatus(item.slot.status, null);
111
+ return;
112
+ }
113
+ let box = target;
114
+ if (keepAlive) {
115
+ box = target.appendChild(document.createElement("div"));
116
+ box.style.display = "contents";
117
+ }
118
+ const it = { box, on: onStatus, slot: null };
119
+ it.slot = createSlot(box, { ...options, name, src: void 0, props, onStatus: (s, e) => it.on(s, e) });
120
+ item = it;
121
+ });
122
+ return {
123
+ update(next) {
124
+ props = next;
125
+ item?.slot.update(next);
126
+ },
127
+ set(next) {
128
+ if (next.src || next.name !== void 0) name = key(next);
129
+ item?.slot.set({ ...next, src: void 0, name });
130
+ },
131
+ retry: () => item?.slot.retry(),
132
+ destroy() {
133
+ cancel();
134
+ cancelPrefetch();
135
+ if (!item) return;
136
+ if (keepAlive && status === "ready") park(name, item, keepAlive === true ? 5 : keepAlive);
137
+ else {
138
+ item.slot.destroy();
139
+ if (item.box !== target) item.box.remove();
140
+ }
141
+ item = null;
142
+ },
143
+ get status() {
144
+ return status;
145
+ }
146
+ };
147
+ }
148
+
149
+ export {
150
+ timings,
151
+ hostSlot
152
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/types.ts
4
+ import { existsSync, readFileSync, writeFileSync } from "fs";
5
+ import { resolve } from "path";
6
+ var PROPS = /export type Props =\s*([\s\S]*?)\s*$/;
7
+ function parseProps(dts) {
8
+ return PROPS.exec(dts.replace(/^\s*\/\/.*$/gm, "").trim())?.[1]?.replace(/;$/, "") || null;
9
+ }
10
+ function envFile(props) {
11
+ const lines = Object.entries(props).map(([name, type]) => ` ${JSON.stringify(name)}: ${type}`);
12
+ return `// Gerado por \`npx vitral types\`. N\xE3o edite.
13
+ import 'vitral'
14
+
15
+ declare module 'vitral' {
16
+ interface Remotes {
17
+ ${lines.join("\n")}
18
+ }
19
+ }
20
+ `;
21
+ }
22
+ function readRemotes(cwd, args2, base) {
23
+ const pairs = args2.filter((a) => a.includes("="));
24
+ if (pairs.length) return Object.fromEntries(pairs.map((p) => [p.slice(0, p.indexOf("=")), p.slice(p.indexOf("=") + 1)]));
25
+ const file = [args2[0], "public/remotes.json", "remotes.json"].find((f) => f && existsSync(resolve(cwd, f)));
26
+ if (!file) throw new Error("[vitral] remotes.json n\xE3o encontrado. Passe o caminho ou pares nome=url.");
27
+ const map = JSON.parse(readFileSync(resolve(cwd, file), "utf8"));
28
+ return Object.fromEntries(
29
+ Object.entries(map).map(([name, v]) => {
30
+ const url = typeof v === "string" ? v : v.url;
31
+ return [name, base ? new URL(url, base).href : url];
32
+ })
33
+ );
34
+ }
35
+ async function types(options = {}) {
36
+ const cwd = options.cwd ?? process.cwd();
37
+ const get = options.fetch ?? fetch;
38
+ const log = options.log ?? console.log;
39
+ const remotes = readRemotes(cwd, options.args ?? [], options.base);
40
+ const props = {};
41
+ let falhas = 0;
42
+ for (const [name, url] of Object.entries(remotes)) {
43
+ let dts;
44
+ try {
45
+ const res = await get(new URL("vitral.d.ts", url).href);
46
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
47
+ dts = await res.text();
48
+ } catch (err) {
49
+ log(`[vitral] ${name}: sem tipos (${err.message}).`);
50
+ falhas++;
51
+ continue;
52
+ }
53
+ const type = parseProps(dts);
54
+ if (type) props[name] = type;
55
+ else log(`[vitral] ${name}: vitral.d.ts sem "export type Props".`);
56
+ }
57
+ const out = resolve(cwd, options.out ?? "vitral-env.d.ts");
58
+ writeFileSync(out, envFile(props));
59
+ log(`[vitral] ${Object.keys(props).length} remote(s) em ${out}`);
60
+ return falhas;
61
+ }
62
+
63
+ // src/cli.ts
64
+ var AJUDA = `Uso: vitral types [remotes.json | nome=url ...] [--base url] [--out arquivo]
65
+
66
+ Baixa o vitral.d.ts de cada remote e gera vitral-env.d.ts.`;
67
+ function flag(args2, name) {
68
+ const i = args2.indexOf(name);
69
+ if (i < 0) return void 0;
70
+ const value = args2[i + 1];
71
+ args2.splice(i, 2);
72
+ return value;
73
+ }
74
+ var [command, ...args] = process.argv.slice(2);
75
+ if (command === "types") {
76
+ const base = flag(args, "--base");
77
+ const out = flag(args, "--out");
78
+ types({ args, base, out }).then(
79
+ (falhas) => process.exitCode = falhas ? 1 : 0,
80
+ (err) => {
81
+ console.error(err.message);
82
+ process.exitCode = 1;
83
+ }
84
+ );
85
+ } else {
86
+ console.log(AJUDA);
87
+ process.exitCode = command && command !== "--help" ? 1 : 0;
88
+ }
@@ -0,0 +1,81 @@
1
+ // src/core/semver.ts
2
+ function satisfies(version, range) {
3
+ if (range === "*") return true;
4
+ const [, op = "", want = ""] = /^(\^|~|>=|=)?(.*)$/.exec(range.trim());
5
+ if (!op || op === "=" || version.includes("-")) return version === want;
6
+ const v = version.split(".").map(Number);
7
+ const w = want.split(".").map(Number);
8
+ for (let i = 0; i < 3; i++) if (v[i] !== w[i]) {
9
+ if (!(v[i] > w[i])) return false;
10
+ break;
11
+ }
12
+ if (op === ">=") return true;
13
+ const fixed = op === "~" ? 2 : w[0] ? 1 : w[1] ? 2 : 3;
14
+ return v.slice(0, fixed).join(".") === w.slice(0, fixed).join(".");
15
+ }
16
+
17
+ // src/core/dedupe.ts
18
+ var KEY = "vitral:dedupe:";
19
+ var remembered = (k) => {
20
+ try {
21
+ return localStorage.getItem(KEY + k);
22
+ } catch {
23
+ return null;
24
+ }
25
+ };
26
+ var remember = (k, url) => {
27
+ try {
28
+ localStorage.setItem(KEY + k, url);
29
+ } catch {
30
+ }
31
+ };
32
+ function shared(p) {
33
+ if (!p.dedupe) {
34
+ const offers = /* @__PURE__ */ new Map();
35
+ const waiting = /* @__PURE__ */ new Map();
36
+ const drop = (list, o) => list.includes(o) && list.splice(list.indexOf(o), 1);
37
+ const start = (name, list, o) => {
38
+ if (!o.p) {
39
+ ;
40
+ (o.p = o.load()).catch(() => drop(list, o));
41
+ if (o.url) o.p.then(() => remember(`${name}@${o.version}`, o.url), () => {
42
+ });
43
+ }
44
+ return o.p;
45
+ };
46
+ p.dedupe = (name, range, offer2) => {
47
+ const own = offer2;
48
+ const list = offers.get(name) ?? [];
49
+ offers.set(name, list);
50
+ if (own?.url) waiting.get(name + own.url)?.(own);
51
+ let hit = list.find((o) => satisfies(o.version, range));
52
+ if (!hit && own) {
53
+ hit = list[list.push(own) - 1];
54
+ const want = own.url && remembered(`${name}@${own.version}`);
55
+ if (want && want !== own.url) {
56
+ own.p = new Promise((resolve) => {
57
+ waiting.set(name + want, resolve);
58
+ setTimeout(resolve, 300, own);
59
+ }).then((o) => {
60
+ waiting.delete(name + want);
61
+ if (o === own) own.p = void 0;
62
+ return start(name, list, o);
63
+ });
64
+ own.p.catch(() => drop(list, own));
65
+ }
66
+ }
67
+ return hit && start(name, list, hit);
68
+ };
69
+ }
70
+ return p.dedupe;
71
+ }
72
+ function offer(p, groups) {
73
+ for (const name in groups) {
74
+ const { version, modules } = groups[name];
75
+ shared(p)(name, version, { version, load: async () => modules });
76
+ }
77
+ }
78
+ export {
79
+ offer,
80
+ shared
81
+ };
@@ -0,0 +1,12 @@
1
+ /** Overrides salvos neste navegador: `{ nome: url }`. */
2
+ declare function getOverrides(): Record<string, string>;
3
+ /** Salva (ou remove, com `null`) o override de um remote. Vale a partir do próximo carregamento. */
4
+ declare function setOverride(name: string, url: string | null): void;
5
+ interface DevtoolsOptions {
6
+ /** Recarrega a página depois de mudar um override. Padrão: true. */
7
+ reload?: boolean;
8
+ }
9
+ /** Mostra o painel no canto da página. Devolve uma função que o remove. */
10
+ declare function devtools(options?: DevtoolsOptions): () => void;
11
+
12
+ export { type DevtoolsOptions, devtools, getOverrides, setOverride };
@@ -0,0 +1,86 @@
1
+ import {
2
+ OVERRIDES_KEY,
3
+ manifestUrl,
4
+ overridesEnabled,
5
+ storedOverrides
6
+ } from "./chunk-DXORSF4X.js";
7
+ import "./chunk-GNPFWISJ.js";
8
+
9
+ // src/devtools.ts
10
+ function getOverrides() {
11
+ return storedOverrides();
12
+ }
13
+ function setOverride(name, url) {
14
+ const all = storedOverrides();
15
+ if (url) all[name] = manifestUrl(url);
16
+ else delete all[name];
17
+ if (Object.keys(all).length) localStorage.setItem(OVERRIDES_KEY, JSON.stringify(all));
18
+ else localStorage.removeItem(OVERRIDES_KEY);
19
+ }
20
+ var STYLE = `
21
+ :host { position: fixed; right: 12px; bottom: 12px; z-index: 2147483647; font: 13px/1.4 system-ui, sans-serif; color: #111 }
22
+ button { font: inherit; cursor: pointer }
23
+ .toggle { border: 1px solid #888; border-radius: 6px; background: #fff; padding: 4px 10px }
24
+ .panel { margin-bottom: 8px; padding: 10px; width: 320px; background: #fff; border: 1px solid #888; border-radius: 8px; box-shadow: 0 4px 16px #0003 }
25
+ ul { list-style: none; margin: 0 0 8px; padding: 0 }
26
+ li { display: flex; gap: 6px; align-items: center; margin-bottom: 4px; word-break: break-all }
27
+ form { display: grid; gap: 4px }
28
+ input { font: inherit; padding: 3px 6px }
29
+ .aviso { color: #a40000; margin: 0 0 8px }
30
+ `;
31
+ function devtools(options = {}) {
32
+ const host = document.createElement("div");
33
+ host.setAttribute("data-vitral-devtools", "");
34
+ const root = host.attachShadow({ mode: "open" });
35
+ const style = document.createElement("style");
36
+ style.textContent = STYLE;
37
+ const panel = document.createElement("div");
38
+ panel.className = "panel";
39
+ panel.hidden = true;
40
+ const toggle = document.createElement("button");
41
+ toggle.className = "toggle";
42
+ toggle.type = "button";
43
+ toggle.textContent = "vitral";
44
+ toggle.onclick = () => panel.hidden = !panel.hidden;
45
+ root.append(style, panel, toggle);
46
+ const changed = () => options.reload === false ? draw() : location.reload();
47
+ function draw() {
48
+ panel.replaceChildren();
49
+ if (!overridesEnabled()) {
50
+ const p = document.createElement("p");
51
+ p.className = "aviso";
52
+ p.textContent = "Overrides desligados: use configure({ devOverrides: true }) ou rode em localhost.";
53
+ panel.append(p);
54
+ }
55
+ const list = document.createElement("ul");
56
+ for (const [name2, url2] of Object.entries(storedOverrides())) {
57
+ const item = document.createElement("li");
58
+ const remove = document.createElement("button");
59
+ remove.type = "button";
60
+ remove.textContent = "remover";
61
+ remove.setAttribute("aria-label", `remover override de ${name2}`);
62
+ remove.onclick = () => (setOverride(name2, null), changed());
63
+ item.append(`${name2} \u2192 ${url2}`, remove);
64
+ list.append(item);
65
+ }
66
+ const form = document.createElement("form");
67
+ const name = Object.assign(document.createElement("input"), { placeholder: "nome (ex.: carrinho)", required: true, name: "name" });
68
+ const url = Object.assign(document.createElement("input"), { placeholder: "http://localhost:5174", required: true, name: "url" });
69
+ const save = Object.assign(document.createElement("button"), { type: "submit", textContent: "Salvar" });
70
+ form.append(name, url, save);
71
+ form.onsubmit = (e) => {
72
+ e.preventDefault();
73
+ setOverride(name.value.trim(), url.value.trim());
74
+ changed();
75
+ };
76
+ panel.append(list, form);
77
+ }
78
+ draw();
79
+ document.body.append(host);
80
+ return () => host.remove();
81
+ }
82
+ export {
83
+ devtools,
84
+ getOverrides,
85
+ setOverride
86
+ };
package/dist/element.d.ts CHANGED
@@ -1,4 +1,38 @@
1
- import { Props, SlotStatus, RemoteModule } from './index.js';
1
+ import { P as Props, S as Shared, a as RemoteModule } from './types-BV-hUrms.js';
2
+ import { S as SlotStatus } from './slot-pB276oPt.js';
3
+ import './errors-KKB8FGCz.js';
4
+
5
+ /**
6
+ * Host universal: `<vitral-remote>` funciona em qualquer lugar que renderize
7
+ * HTML (JS/TS puro, Angular, Svelte, Solid, Lit, Astro, Qwik, jQuery, server
8
+ * templates…).
9
+ *
10
+ * import { defineVitralElement } from 'vitral/element'
11
+ * defineVitralElement()
12
+ *
13
+ * <vitral-remote name="carrinho" props='{"userId": 42}' isolate="shadow"
14
+ * inherit-styles="/assets/base.css">
15
+ * <p slot="fallback">Carregando…</p>
16
+ * <p slot="error">Indisponível</p>
17
+ * </vitral-remote>
18
+ *
19
+ * <vitral-remote src="https://cdn.exemplo.com/carrinho/vitral.json"></vitral-remote>
20
+ *
21
+ * Sem os slots, mostra um carregando acessível e um erro com "Tentar de novo".
22
+ *
23
+ * el.props = { userId: 43 } // atualiza sem remontar
24
+ * el.addEventListener('vitral-error', (e) => e.detail.error)
25
+ * el.addEventListener('vitral-ready', (e) => e.detail.timings) // { manifest, js, css, mount } em ms
26
+ * el.retry()
27
+ *
28
+ * Atributos de performance: `loading="lazy|idle"` (monta perto de aparecer ou
29
+ * com o navegador ocioso; reserve o espaço com `min-height`),
30
+ * `prefetch="hover|visible|idle"` (baixa antes de montar), `priority="high"`
31
+ * e `keep-alive` (ou `keep-alive="3"`: máximo de remotes guardados).
32
+ *
33
+ * Também exporta `elementRemote()` para publicar um Web Component (Lit,
34
+ * Stencil, vanilla) como remote.
35
+ */
2
36
 
3
37
  declare const Base: typeof HTMLElement;
4
38
  declare class VitralRemoteElement extends Base {
@@ -21,10 +55,34 @@ declare function defineVitralElement(tag?: string): void;
21
55
  * export default elementRemote('meu-widget')
22
56
  */
23
57
  declare function elementRemote<P extends Props = Props>(tag: string, setup?: () => void): RemoteModule<P>;
58
+ /** O que o `SharedController` precisa do elemento (o `ReactiveControllerHost` do Lit). */
59
+ interface SharedControllerHost {
60
+ addController(controller: {
61
+ hostConnected?(): void;
62
+ hostDisconnected?(): void;
63
+ }): void;
64
+ requestUpdate(): void;
65
+ }
66
+ /**
67
+ * Controller do Lit para uma chave compartilhada (`provide`/`shared`). Assina
68
+ * enquanto o elemento está conectado e pede um novo render quando o valor
69
+ * (ou o resultado do seletor) muda.
70
+ *
71
+ * usuario = new SharedController(this, 'usuario')
72
+ * render() { return html`${this.usuario.value?.nome}` }
73
+ */
74
+ declare class SharedController<T = unknown, S = T | undefined> {
75
+ #private;
76
+ /** Valor atual (ou o resultado do seletor). */
77
+ value: S;
78
+ constructor(host: SharedControllerHost, key: keyof Shared | (string & {}), select?: (value: T | undefined) => S);
79
+ hostConnected(): void;
80
+ hostDisconnected(): void;
81
+ }
24
82
  declare global {
25
83
  interface HTMLElementTagNameMap {
26
84
  'vitral-remote': VitralRemoteElement;
27
85
  }
28
86
  }
29
87
 
30
- export { VitralRemoteElement, defineVitralElement, elementRemote };
88
+ export { SharedController, type SharedControllerHost, VitralRemoteElement, defineVitralElement, elementRemote };
package/dist/element.js CHANGED
@@ -1,10 +1,17 @@
1
1
  import {
2
+ SharedController,
2
3
  VitralRemoteElement,
3
4
  defineVitralElement,
4
5
  elementRemote
5
- } from "./chunk-IZK6ITIJ.js";
6
- import "./chunk-TTL52BF2.js";
6
+ } from "./chunk-6Y3VMWHH.js";
7
+ import "./chunk-UTYAX6MU.js";
8
+ import "./chunk-NCONW6WS.js";
9
+ import "./chunk-2XF5BKV3.js";
10
+ import "./chunk-SFL6LTP3.js";
11
+ import "./chunk-PX7PBCCT.js";
12
+ import "./chunk-GNPFWISJ.js";
7
13
  export {
14
+ SharedController,
8
15
  VitralRemoteElement,
9
16
  defineVitralElement,
10
17
  elementRemote
@@ -0,0 +1,11 @@
1
+ type RemoteErrorCode = 'NOT_REGISTERED' | 'NOT_EXPOSED' | 'ORIGIN_BLOCKED' | 'TIMEOUT' | 'INTEGRITY' | 'INVALID_MODULE' | 'LOAD_FAILED' | 'MOUNT_FAILED' | 'RENDER_FAILED' | 'SHARED_READONLY';
2
+ declare class RemoteError extends Error {
3
+ code: RemoteErrorCode;
4
+ remote: string;
5
+ cause?: unknown | undefined;
6
+ /** Link da página deste erro na documentação. */
7
+ docs: string;
8
+ constructor(code: RemoteErrorCode, remote: string, message: string, cause?: unknown | undefined);
9
+ }
10
+
11
+ export { RemoteError as R, type RemoteErrorCode as a };
@@ -0,0 +1,6 @@
1
+ import { E as EventBus } from './types-BV-hUrms.js';
2
+
3
+ /** Barramento global. É o mesmo objeto que os remotes recebem em `ctx.events`. */
4
+ declare const events: EventBus;
5
+
6
+ export { events as e };
@@ -0,0 +1,14 @@
1
+ import {
2
+ resolveModule,
3
+ resolveTarget,
4
+ splitName
5
+ } from "./chunk-HP6QWU6K.js";
6
+ import "./chunk-2XF5BKV3.js";
7
+ import "./chunk-SFL6LTP3.js";
8
+ import "./chunk-PX7PBCCT.js";
9
+ import "./chunk-GNPFWISJ.js";
10
+ export {
11
+ resolveModule,
12
+ resolveTarget,
13
+ splitName
14
+ };
@@ -0,0 +1,6 @@
1
+ /** Quando montar: já (`eager`, padrão), perto de aparecer na tela (`lazy`) ou com o navegador ocioso (`idle`). */
2
+ type Loading = 'eager' | 'lazy' | 'idle';
3
+ /** Quando baixar antes de montar: no hover ou foco (`hover`), perto de aparecer (`visible`) ou com o navegador ocioso (`idle`). */
4
+ type Prefetch = 'hover' | 'visible' | 'idle';
5
+
6
+ export type { Loading as L, Prefetch as P };
@@ -0,0 +1,28 @@
1
+ /** Script inline do iframe. Libere o hash dele no CSP (`script-src 'sha256-…'`). */
2
+ declare const FRAME_SCRIPT = "(function (w, load) {\n var parent = w.parent, doc = w.document, handlers = {}, last = {}, channel = {}, mounted = null, stage = 'LOAD_FAILED'\n function post(type, data) { parent.postMessage({ vitral: 1, type: type, data: data }, '*') }\n function call(fn, arg) { try { fn(arg) } catch (e) { w.console.error(e) } }\n var events = {\n emit: function (type, payload) { post('emit', { type: type, payload: payload }) },\n on: function (type, fn) {\n if (!handlers[type]) { handlers[type] = []; post('on', { type: type }) }\n handlers[type].push(fn)\n return function () { handlers[type] = handlers[type].filter(function (h) { return h !== fn }) }\n },\n last: function (type) { return last[type] }\n }\n function start(d) {\n var root = doc.createElement('div')\n root.setAttribute('data-vitral-root', d.name)\n if (d.scope) root.setAttribute('data-vitral-scope', d.scope)\n doc.body.appendChild(root)\n // Ponto de extens\u00E3o: uma ponte nova registra handlers em channel[tipo] e\n // acrescenta campos aqui (a Fase 2 acrescenta ctx.shared).\n var ctx = {\n name: d.name, baseUrl: d.baseUrl, events: events, shadowRoot: null, protocol: 1,\n reportError: function (e) { post('report', { message: String((e && e.message) || e) }) },\n navigate: function (url, o) { post('navigate', { url: String(url), replace: !!(o && o.replace) }) }\n }\n Promise.all(d.css.map(function (href) {\n return new Promise(function (done) {\n var link = doc.createElement('link')\n link.rel = 'stylesheet'; link.href = href; link.crossOrigin = 'anonymous'\n link.onload = link.onerror = done\n doc.head.appendChild(link)\n })\n })).then(function () {\n return load(d.code ? w.URL.createObjectURL(new w.Blob([d.code], { type: 'text/javascript' })) : d.url)\n }).then(function (ns) {\n if (!d.key) return ns\n var table = ns.exposes, part = table && table[d.key]\n if (!part) { stage = 'NOT_EXPOSED'; throw new Error(d.name + ' n\u00E3o exp\u00F5e ' + d.key) }\n return typeof part === 'function' ? part() : part\n }).then(function (ns) {\n var mod = (ns && ns.default) || ns\n if (!mod || typeof mod.mount !== 'function') { stage = 'INVALID_MODULE'; throw new Error('o m\u00F3dulo n\u00E3o exporta mount()') }\n stage = 'MOUNT_FAILED'\n return mod.mount(root, d.props, ctx)\n }).then(function (handle) {\n mounted = handle\n post('mounted')\n var size = function () { post('size', { height: Math.ceil(doc.body.getBoundingClientRect().height) }) }\n size()\n if (w.ResizeObserver) new w.ResizeObserver(size).observe(doc.body)\n }, function (e) {\n post('error', { code: stage, message: String((e && e.message) || e) })\n })\n }\n w.addEventListener('message', function (e) {\n var m = e.data\n if (e.source !== parent || !m || m.vitral !== 1) return\n var d = m.data\n if (m.type === 'mount') start(d)\n else if (m.type === 'update') { if (mounted && mounted.update) mounted.update(d) }\n else if (m.type === 'unmount') { if (mounted) mounted.unmount(); mounted = null }\n else if (m.type === 'last') last[d.type] = d.payload\n else if (m.type === 'event') {\n last[d.type] = d.payload\n ;(handlers[d.type] || []).slice().forEach(function (h) { call(h, d.payload) })\n } else (channel[m.type] || []).forEach(function (h) { call(h, d) })\n })\n post('ready')\n})(window, function (u) { return import(u) })";
3
+
4
+ /** Canal com um iframe montado, para pontes novas (ex.: estado compartilhado). */
5
+ interface FramePort {
6
+ /** Manda `data` (serializável) para o iframe com o tipo `type`. */
7
+ post(type: string, data?: unknown): void;
8
+ /** Recebe as mensagens do iframe com o tipo `type`. */
9
+ on(type: string, handler: (data: unknown) => void): () => void;
10
+ }
11
+ /** Chamada a cada iframe montado. Devolve a limpeza. */
12
+ type FrameBridge = (port: FramePort, info: {
13
+ name: string;
14
+ }) => void | (() => void);
15
+ interface IframeOptions {
16
+ /**
17
+ * Valor do atributo `sandbox`. Padrão `'allow-scripts'`. Acrescente o que o
18
+ * remote precisa (`'allow-scripts allow-forms allow-popups'`). Com
19
+ * `allow-same-origin` o iframe ganha a origem da página e deixa de isolar.
20
+ */
21
+ sandbox?: string;
22
+ /** Pontes extras, além de props e eventos. */
23
+ bridges?: FrameBridge[];
24
+ }
25
+ /** Liga `isolate="iframe"` em todos os componentes de host e em `mountRemote`. */
26
+ declare function enableIframe(options?: IframeOptions): void;
27
+
28
+ export { FRAME_SCRIPT, type FrameBridge, type FramePort, type IframeOptions, enableIframe };