vitral 0.1.0 → 0.3.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 (63) hide show
  1. package/README.md +250 -217
  2. package/dist/angular.d.ts +16 -4
  3. package/dist/angular.js +26 -5
  4. package/dist/auto.d.ts +2 -0
  5. package/dist/auto.js +13 -0
  6. package/dist/capture-JYFERAPL.js +42 -0
  7. package/dist/chunk-3YXI3G34.js +181 -0
  8. package/dist/chunk-AH7KNMBW.js +20 -0
  9. package/dist/chunk-AKNNHQ2H.js +45 -0
  10. package/dist/chunk-DXORSF4X.js +42 -0
  11. package/dist/chunk-GNHCZRQP.js +79 -0
  12. package/dist/chunk-GNPFWISJ.js +80 -0
  13. package/dist/chunk-I3VSKSAZ.js +634 -0
  14. package/dist/chunk-IHTUM6LT.js +152 -0
  15. package/dist/chunk-SDB5AZEI.js +51 -0
  16. package/dist/chunk-TD4S3IHA.js +201 -0
  17. package/dist/chunk-ZAC6QQI6.js +64 -0
  18. package/dist/cli.d.ts +1 -0
  19. package/dist/cli.js +138 -0
  20. package/dist/contract-46EZFQPQ.js +17 -0
  21. package/dist/dedupe-S7BHQMOZ.js +82 -0
  22. package/dist/devtools.d.ts +12 -0
  23. package/dist/devtools.js +86 -0
  24. package/dist/element.d.ts +60 -2
  25. package/dist/element.js +10 -2
  26. package/dist/errors-kjBv6IH_.d.ts +17 -0
  27. package/dist/events-D5gs7rff.d.ts +6 -0
  28. package/dist/expose-JUOUN5N5.js +15 -0
  29. package/dist/host-slot-Cz6EiGsB.d.ts +6 -0
  30. package/dist/iframe.d.ts +28 -0
  31. package/dist/iframe.js +239 -0
  32. package/dist/index.d.ts +144 -147
  33. package/dist/index.js +40 -10
  34. package/dist/navigate-BRG1WJUM.d.ts +9 -0
  35. package/dist/otel.d.ts +44 -0
  36. package/dist/otel.js +27 -0
  37. package/dist/overrides-NZAIUGK5.js +15 -0
  38. package/dist/preact.d.ts +30 -7
  39. package/dist/preact.js +38 -9
  40. package/dist/react.d.ts +46 -7
  41. package/dist/react.js +97 -42
  42. package/dist/routes.d.ts +56 -0
  43. package/dist/routes.js +144 -0
  44. package/dist/sentry.d.ts +25 -0
  45. package/dist/sentry.js +11 -0
  46. package/dist/shadow-6HELCHCJ.js +98 -0
  47. package/dist/slot-DqXTwGbs.d.ts +36 -0
  48. package/dist/solid.d.ts +29 -6
  49. package/dist/solid.js +32 -8
  50. package/dist/sri-JMX6JLQP.js +116 -0
  51. package/dist/state-BDdCwc21.d.ts +4 -0
  52. package/dist/svelte.d.ts +19 -3
  53. package/dist/svelte.js +11 -4
  54. package/dist/testing.d.ts +3 -2
  55. package/dist/testing.js +9 -3
  56. package/dist/types-Czvm-siZ.d.ts +327 -0
  57. package/dist/vite.d.ts +66 -4
  58. package/dist/vite.js +1044 -25
  59. package/dist/vue.d.ts +86 -7
  60. package/dist/vue.js +74 -46
  61. package/package.json +181 -11
  62. package/dist/chunk-IZK6ITIJ.js +0 -96
  63. package/dist/chunk-TTL52BF2.js +0 -547
package/dist/react.d.ts CHANGED
@@ -1,19 +1,49 @@
1
- import * as react from 'react';
2
1
  import { ReactNode, ComponentType } from 'react';
3
- import { Props, Isolation, RemoteModule, RemoteContext } from './index.js';
4
- export { EventBus, events } from './index.js';
2
+ import { L as Loading, P as Prefetch } from './host-slot-Cz6EiGsB.js';
3
+ import * as JSXRuntime from 'react/jsx-runtime';
4
+ import { P as Props, I as Isolation, C as CheckedProps, a as RemoteModule, S as Shared, R as RemoteContext } from './types-Czvm-siZ.js';
5
+ export { E as EventBus } from './types-Czvm-siZ.js';
6
+ export { e as events } from './events-D5gs7rff.js';
7
+ import './errors-kjBv6IH_.js';
8
+
9
+ /**
10
+ * Adaptador React (funciona em Vite, CRA e Next.js App/Pages Router).
11
+ *
12
+ * Host: <Remote name="carrinho" props={{ userId }} />
13
+ * <Remote src="https://cdn.exemplo.com/carrinho/vitral.json" props={{ userId }} />
14
+ * Remote: export default reactRemote(App)
15
+ */
5
16
 
6
17
  /** Transforma um componente React em um remote. */
7
18
  declare function reactRemote<P extends Props>(Component: ComponentType<P>): RemoteModule<P>;
8
19
  /** Dentro de um remote: dá acesso ao contexto (nome, eventos, baseUrl). */
9
20
  declare function useVitral(): RemoteContext | null;
21
+ /**
22
+ * Dentro de um remote: onde renderizar portais. No Shadow DOM é um elemento
23
+ * dentro do shadow root (com os estilos do remote); fora de um remote,
24
+ * `undefined`, e a biblioteca usa o padrão dela (`document.body`). Use em
25
+ * `<Popover.Portal container={usePortalContainer()}>`.
26
+ */
27
+ declare function usePortalContainer(): HTMLElement | undefined;
10
28
  /** Assina um evento do barramento global enquanto o componente estiver montado. */
11
29
  declare function useEvent<T = unknown>(type: string, handler: (payload: T) => void): void;
12
30
  /** Estado derivado do último valor emitido em `type`. */
13
31
  declare function useEventValue<T = unknown>(type: string): T | undefined;
32
+ /**
33
+ * Lê uma chave compartilhada (`provide`/`shared`) e re-renderiza só quando
34
+ * ela muda. Com seletor, só quando o resultado do seletor muda (`Object.is`).
35
+ * No servidor e na hidratação o valor é `undefined`.
36
+ *
37
+ * const nome = useShared('usuario', (u) => u?.nome)
38
+ */
39
+ declare function useShared<K extends keyof Shared, S = Shared[K] | undefined>(key: K, select?: (value: Shared[K] | undefined) => S): S;
40
+ declare function useShared<T = unknown, S = T | undefined>(key: string, select?: (value: T | undefined) => S): S;
14
41
 
15
42
  interface RemoteProps<P extends Props = Props> {
16
- name: string;
43
+ /** Nome registrado com `configure()`. Com `src`, o nome sob o qual a URL é registrada. */
44
+ name?: string;
45
+ /** URL do `vitral.json`. Dispensa `configure()`. */
46
+ src?: string;
17
47
  props?: P;
18
48
  isolate?: Isolation;
19
49
  /** Mostrado enquanto o remote baixa. */
@@ -22,11 +52,20 @@ interface RemoteProps<P extends Props = Props> {
22
52
  error?: ReactNode | ((error: Error, retry: () => void) => ReactNode);
23
53
  onError?: (error: Error) => void;
24
54
  className?: string;
55
+ /** `'lazy'`: monta perto de aparecer na tela; `'idle'`: com o navegador ocioso. */
56
+ loading?: Loading;
57
+ /** Baixa antes de montar: `'hover'`, `'visible'` ou `'idle'`. */
58
+ prefetch?: Prefetch;
59
+ /** `'high'` para o remote que aparece logo ao abrir a página. */
60
+ priority?: RequestPriority;
61
+ /** Ao sair da página, guarda o remote montado (LRU, padrão 5) e na volta só atualiza as props. */
62
+ keepAlive?: boolean | number;
25
63
  }
26
64
  /**
27
65
  * Renderiza um remote. No servidor (Next SSR) renderiza só o fallback; o
28
- * remote monta no cliente, então não há erro de hidratação.
66
+ * remote monta no cliente, então não há erro de hidratação. Com o nome em
67
+ * `Remotes` (`npx vitral types`), as props são checadas.
29
68
  */
30
- declare function Remote<P extends Props = Props>({ name, props, isolate, fallback, error, onError, className, }: RemoteProps<P>): react.JSX.Element;
69
+ declare function Remote<P extends Props = Props, N extends string = string>({ name, src, props, isolate, fallback, error, onError, className, loading, prefetch, priority, keepAlive, }: RemoteProps<P> & CheckedProps<N>): JSXRuntime.JSX.Element;
31
70
 
32
- export { Remote, type RemoteProps, reactRemote, useEvent, useEventValue, useVitral };
71
+ export { Remote, type RemoteProps, reactRemote, useEvent, useEventValue, usePortalContainer, useShared, useVitral };
package/dist/react.js CHANGED
@@ -1,13 +1,39 @@
1
1
  "use client";
2
+ import {
3
+ hostSlot
4
+ } from "./chunk-IHTUM6LT.js";
2
5
  import {
3
6
  defineRemote,
4
7
  events,
5
- mountRemote
6
- } from "./chunk-TTL52BF2.js";
8
+ memoSelect,
9
+ same,
10
+ shared
11
+ } from "./chunk-I3VSKSAZ.js";
12
+ import "./chunk-TD4S3IHA.js";
13
+ import "./chunk-ZAC6QQI6.js";
14
+ import "./chunk-GNHCZRQP.js";
15
+ import "./chunk-AKNNHQ2H.js";
16
+ import {
17
+ protocol
18
+ } from "./chunk-GNPFWISJ.js";
7
19
 
8
20
  // src/react.tsx
9
- import { Component as ReactComponent, createContext, useContext, useEffect, useRef, useState } from "react";
21
+ import {
22
+ Component as ReactComponent,
23
+ createContext,
24
+ useContext,
25
+ useEffect,
26
+ useMemo,
27
+ useRef,
28
+ useState,
29
+ useSyncExternalStore
30
+ } from "react";
10
31
  import { createRoot } from "react-dom/client";
32
+ import * as ReactAll from "react";
33
+ import * as ReactDOM from "react-dom";
34
+ import * as ReactDOMClient from "react-dom/client";
35
+ import * as JSXRuntime from "react/jsx-runtime";
36
+ import * as JSXDevRuntime from "react/jsx-dev-runtime";
11
37
  import { jsx, jsxs } from "react/jsx-runtime";
12
38
  var VitralContext = createContext(null);
13
39
  var Boundary = class extends ReactComponent {
@@ -40,6 +66,9 @@ function reactRemote(Component) {
40
66
  function useVitral() {
41
67
  return useContext(VitralContext);
42
68
  }
69
+ function usePortalContainer() {
70
+ return useVitral()?.portalContainer;
71
+ }
43
72
  function useEvent(type, handler) {
44
73
  const ref = useRef(handler);
45
74
  ref.current = handler;
@@ -50,61 +79,85 @@ function useEventValue(type) {
50
79
  useEvent(type, setValue);
51
80
  return value;
52
81
  }
82
+ function useShared(key, select = same) {
83
+ const handle = useMemo(() => shared(key), [key]);
84
+ const [pick] = useState(memoSelect);
85
+ return useSyncExternalStore(
86
+ handle.subscribe,
87
+ () => pick(handle.get(), select),
88
+ () => pick(void 0, select)
89
+ );
90
+ }
91
+ var offeredTo;
92
+ function offerReact() {
93
+ const p = protocol();
94
+ if (offeredTo === p) return;
95
+ offeredTo = p;
96
+ const compiler = ReactAll.__COMPILER_RUNTIME;
97
+ const modules = {
98
+ react: ReactAll,
99
+ "react-dom": ReactDOM,
100
+ "react-dom/client": ReactDOMClient,
101
+ "react/jsx-runtime": JSXRuntime,
102
+ "react/jsx-dev-runtime": JSXDevRuntime,
103
+ // O React 19 expõe o react/compiler-runtime pelo próprio react.
104
+ ...compiler && { "react/compiler-runtime": compiler }
105
+ };
106
+ p.pending(import("./dedupe-S7BHQMOZ.js").then((m) => m.offer(p, { react: { version: ReactAll.version, modules } })).catch(() => {
107
+ }));
108
+ }
53
109
  function Remote({
54
110
  name,
111
+ src,
55
112
  props,
56
113
  isolate,
57
114
  fallback = null,
58
115
  error,
59
116
  onError,
60
- className
117
+ className,
118
+ loading,
119
+ prefetch,
120
+ priority,
121
+ keepAlive
61
122
  }) {
123
+ const target = useRef(null);
62
124
  const slot = useRef(null);
63
- const handle = useRef(null);
64
- const latestProps = useRef(props ?? {});
65
- latestProps.current = props ?? {};
66
- const [status, setStatus] = useState("loading");
67
- const [err, setErr] = useState(null);
68
- const [attempt, setAttempt] = useState(0);
125
+ const [state, setState] = useState({ status: "loading", error: null });
69
126
  const onErrorRef = useRef(onError);
70
127
  onErrorRef.current = onError;
71
128
  useEffect(() => {
72
- const el = slot.current;
73
- if (!el) return;
74
- let cancelled = false;
75
- setStatus("loading");
76
- const fail = (e) => {
77
- if (cancelled) return;
78
- setErr(e);
79
- setStatus("error");
80
- if (onErrorRef.current) onErrorRef.current(e);
81
- else console.error(e);
82
- };
83
- const initial = latestProps.current;
84
- mountRemote(el, name, initial, { isolate, onError: fail }).then(
85
- (h) => {
86
- if (cancelled) return h.unmount();
87
- handle.current = h;
88
- if (latestProps.current !== initial) h.update?.(latestProps.current);
89
- setStatus("ready");
90
- },
91
- fail
92
- );
129
+ offerReact();
130
+ const s = hostSlot(target.current, {
131
+ name,
132
+ src,
133
+ props: props ?? {},
134
+ isolate,
135
+ loading,
136
+ prefetch,
137
+ priority,
138
+ keepAlive,
139
+ onStatus(status2, e) {
140
+ setState({ status: status2, error: e });
141
+ if (e) {
142
+ if (onErrorRef.current) onErrorRef.current(e);
143
+ else console.error(e);
144
+ }
145
+ }
146
+ });
147
+ slot.current = s;
93
148
  return () => {
94
- cancelled = true;
95
- const h = handle.current;
96
- handle.current = null;
97
- if (h) queueMicrotask(() => h.unmount());
149
+ slot.current = null;
150
+ queueMicrotask(() => s.destroy());
98
151
  };
99
- }, [name, isolate, attempt]);
100
- useEffect(() => {
101
- handle.current?.update?.(latestProps.current);
102
- }, [props]);
103
- const retry = () => setAttempt((a) => a + 1);
104
- return /* @__PURE__ */ jsxs("div", { className, "data-vitral": name, "data-vitral-status": status, children: [
152
+ }, []);
153
+ useEffect(() => slot.current?.set({ name, src, isolate }), [name, src, isolate]);
154
+ useEffect(() => slot.current?.update(props ?? {}), [props]);
155
+ const retry = () => slot.current?.retry();
156
+ const { status, error: err } = state;
157
+ return /* @__PURE__ */ jsxs("div", { className, "data-vitral": name ?? src, "data-vitral-status": status, children: [
105
158
  status === "loading" && fallback,
106
159
  status === "error" && err && (typeof error === "function" ? error(err, retry) : error ?? null),
107
- /* @__PURE__ */ jsx("div", { ref: slot, style: status === "error" ? { display: "none" } : void 0 }, `${name}:${isolate}:${attempt}`)
160
+ /* @__PURE__ */ jsx("div", { ref: target })
108
161
  ] });
109
162
  }
110
163
  export {
@@ -113,5 +166,7 @@ export {
113
166
  reactRemote,
114
167
  useEvent,
115
168
  useEventValue,
169
+ usePortalContainer,
170
+ useShared,
116
171
  useVitral
117
172
  };
@@ -0,0 +1,56 @@
1
+ import { P as Props } from './types-Czvm-siZ.js';
2
+ import { S as SlotStatus } from './slot-DqXTwGbs.js';
3
+ import './errors-kjBv6IH_.js';
4
+
5
+ /** Padrão de URL → nome do remote. A primeira rota que bate vence. */
6
+ type Routes = Record<string, string>;
7
+ interface RoutesOptions {
8
+ /**
9
+ * Links `<a href>` da mesma origem que batem com uma rota navegam sem
10
+ * recarregar a página (via `navigate()`). Padrão: true.
11
+ */
12
+ links?: boolean;
13
+ }
14
+ interface RouteMatch {
15
+ /** Nome do remote. */
16
+ name: string;
17
+ /** Padrão que bateu. */
18
+ pattern: string;
19
+ /** Segmentos `:nome` do padrão. */
20
+ params: Record<string, string>;
21
+ }
22
+ /**
23
+ * Remote da rota que bate com `path`, ou `null`. Padrões: `/conta` (exato),
24
+ * `/checkout/*` (o prefixo e tudo abaixo dele), `/produto/:id` e `*` (qualquer).
25
+ */
26
+ declare function matchRoute(path: string, routes?: Routes): RouteMatch | null;
27
+ /**
28
+ * Define as rotas, registra `<vitral-outlet>` e, com `links` (padrão), faz os
29
+ * links internos navegarem sem recarregar. Devolve a função que desfaz tudo.
30
+ */
31
+ declare function routes(map: Routes, options?: RoutesOptions): () => void;
32
+ declare const Base: typeof HTMLElement;
33
+ declare class VitralOutletElement extends Base {
34
+ #private;
35
+ static observedAttributes: string[];
36
+ get props(): Props;
37
+ set props(value: Props);
38
+ /** Remote montado agora, ou `null`. */
39
+ get route(): string | null;
40
+ get status(): SlotStatus | "empty";
41
+ retry(): void;
42
+ connectedCallback(): void;
43
+ disconnectedCallback(): void;
44
+ attributeChangedCallback(attr: string, _old: string | null, value: string | null): void;
45
+ /** Confere a URL atual e troca de remote se a rota mudou. */
46
+ sync(): void;
47
+ }
48
+ /** Registra `<vitral-outlet>` (ou outro nome). `routes()` já chama. */
49
+ declare function defineVitralOutlet(tag?: string): void;
50
+ declare global {
51
+ interface HTMLElementTagNameMap {
52
+ 'vitral-outlet': VitralOutletElement;
53
+ }
54
+ }
55
+
56
+ export { type RouteMatch, type Routes, type RoutesOptions, VitralOutletElement, defineVitralOutlet, matchRoute, routes };
package/dist/routes.js ADDED
@@ -0,0 +1,144 @@
1
+ import {
2
+ createSlot,
3
+ navigate
4
+ } from "./chunk-I3VSKSAZ.js";
5
+ import "./chunk-TD4S3IHA.js";
6
+ import "./chunk-ZAC6QQI6.js";
7
+ import "./chunk-GNHCZRQP.js";
8
+ import "./chunk-AKNNHQ2H.js";
9
+ import "./chunk-GNPFWISJ.js";
10
+
11
+ // src/routes.ts
12
+ var table = {};
13
+ var outlets = /* @__PURE__ */ new Set();
14
+ var compiled = /* @__PURE__ */ new Map();
15
+ function compile(pattern) {
16
+ let re = compiled.get(pattern);
17
+ if (!re) {
18
+ const body = pattern.replace(/\/\*$|^\*$/, "\0").replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/:(\w+)/g, "(?<$1>[^/]+)").replace(/\/$/, "").replace("\0", "(?:/.*)?");
19
+ compiled.set(pattern, re = new RegExp(`^${body}/?$`));
20
+ }
21
+ return re;
22
+ }
23
+ function matchRoute(path, routes2 = table) {
24
+ for (const [pattern, name] of Object.entries(routes2)) {
25
+ const m = compile(pattern).exec(path);
26
+ if (m) return { name, pattern, params: { ...m.groups } };
27
+ }
28
+ return null;
29
+ }
30
+ function routes(map, options = {}) {
31
+ table = map;
32
+ defineVitralOutlet();
33
+ for (const o of outlets) o.sync();
34
+ const intercept = options.links !== false && typeof document !== "undefined";
35
+ if (intercept) document.addEventListener("click", onClick);
36
+ return () => {
37
+ if (intercept) document.removeEventListener("click", onClick);
38
+ if (table === map) table = {};
39
+ for (const o of outlets) o.sync();
40
+ };
41
+ }
42
+ function onClick(e) {
43
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
44
+ const a = e.composedPath().find((n) => n.localName === "a" && !!n.href);
45
+ if (!a || a.target && a.target !== "_self" || a.hasAttribute("download")) return;
46
+ const url = new URL(a.href);
47
+ if (url.origin !== location.origin || !matchRoute(url.pathname)) return;
48
+ e.preventDefault();
49
+ navigate(url.href);
50
+ }
51
+ var Base = typeof HTMLElement === "undefined" ? class {
52
+ } : HTMLElement;
53
+ var VitralOutletElement = class extends Base {
54
+ static {
55
+ this.observedAttributes = ["props", "isolate"];
56
+ }
57
+ #slot = null;
58
+ #props = {};
59
+ // `undefined` até a primeira checagem, para o estado `empty` aparecer já de início.
60
+ #route;
61
+ get props() {
62
+ return this.#props;
63
+ }
64
+ set props(value) {
65
+ this.#props = value ?? {};
66
+ this.#slot?.update(this.#props);
67
+ }
68
+ /** Remote montado agora, ou `null`. */
69
+ get route() {
70
+ return this.#route ?? null;
71
+ }
72
+ get status() {
73
+ return this.#slot?.status ?? (this.#route ? "loading" : "empty");
74
+ }
75
+ retry() {
76
+ this.#slot?.retry();
77
+ }
78
+ #onNavigate = () => this.sync();
79
+ connectedCallback() {
80
+ outlets.add(this);
81
+ addEventListener("popstate", this.#onNavigate);
82
+ globalThis.navigation?.addEventListener("navigatesuccess", this.#onNavigate);
83
+ this.sync();
84
+ }
85
+ disconnectedCallback() {
86
+ outlets.delete(this);
87
+ removeEventListener("popstate", this.#onNavigate);
88
+ globalThis.navigation?.removeEventListener("navigatesuccess", this.#onNavigate);
89
+ queueMicrotask(() => !this.isConnected && this.#show(null));
90
+ }
91
+ attributeChangedCallback(attr, _old, value) {
92
+ if (attr === "props") {
93
+ try {
94
+ this.props = value ? JSON.parse(value) : {};
95
+ } catch {
96
+ console.error("[vitral] atributo props n\xE3o \xE9 JSON v\xE1lido:", value);
97
+ }
98
+ } else this.#slot?.set({ isolate: value || void 0 });
99
+ }
100
+ /** Confere a URL atual e troca de remote se a rota mudou. */
101
+ sync() {
102
+ if (this.isConnected) this.#show(matchRoute(location.pathname)?.name ?? null);
103
+ }
104
+ #show(name) {
105
+ if (name === this.#route) return;
106
+ this.#route = name;
107
+ if (name) this.setAttribute("data-vitral-route", name);
108
+ else this.removeAttribute("data-vitral-route");
109
+ if (!name) {
110
+ this.#slot?.destroy();
111
+ this.#slot = null;
112
+ this.#status("empty", null);
113
+ } else if (this.#slot) {
114
+ this.#slot.set({ name });
115
+ } else {
116
+ this.#slot = createSlot(this, {
117
+ name,
118
+ props: this.#props,
119
+ isolate: this.getAttribute("isolate") || void 0,
120
+ onStatus: (s, e) => this.#status(s, e)
121
+ });
122
+ }
123
+ }
124
+ #status(status, error) {
125
+ this.setAttribute("data-vitral-status", status);
126
+ for (const [slot, on] of [["fallback", "loading"], ["error", "error"], ["empty", "empty"]]) {
127
+ for (const el of this.querySelectorAll(`:scope > [slot="${slot}"]`)) el.hidden = status !== on;
128
+ }
129
+ if (status === "ready") this.dispatchEvent(new CustomEvent("vitral-ready", { bubbles: true, detail: { route: this.#route } }));
130
+ if (status === "error") this.dispatchEvent(new CustomEvent("vitral-error", { bubbles: true, detail: { error } }));
131
+ }
132
+ };
133
+ function defineVitralOutlet(tag = "vitral-outlet") {
134
+ if (typeof customElements !== "undefined" && !customElements.get(tag)) {
135
+ customElements.define(tag, class extends VitralOutletElement {
136
+ });
137
+ }
138
+ }
139
+ export {
140
+ VitralOutletElement,
141
+ defineVitralOutlet,
142
+ matchRoute,
143
+ routes
144
+ };
@@ -0,0 +1,25 @@
1
+ import { R as RemoteError } from './errors-kjBv6IH_.js';
2
+
3
+ /**
4
+ * Erros dos remotes no Sentry, sem depender do SDK:
5
+ *
6
+ * import * as Sentry from '@sentry/browser'
7
+ * import { sentryOnError } from 'vitral/sentry'
8
+ *
9
+ * configure({ onError: sentryOnError(Sentry) })
10
+ *
11
+ * Cada `RemoteError` vira um `captureException` com as tags `vitral.remote`,
12
+ * `vitral.version` e `vitral.code`, e com `entry`, `route` e `docs` no `extra`.
13
+ */
14
+
15
+ /** A parte do SDK do Sentry que o adaptador usa (`@sentry/browser`, `@sentry/react`…). */
16
+ interface SentryLike {
17
+ captureException(exception: unknown, hint?: {
18
+ tags?: Record<string, string>;
19
+ extra?: Record<string, unknown>;
20
+ }): unknown;
21
+ }
22
+ /** `onError` para o `configure` que manda cada `RemoteError` ao Sentry. */
23
+ declare function sentryOnError(sentry: SentryLike): (error: RemoteError) => void;
24
+
25
+ export { type SentryLike, sentryOnError };
package/dist/sentry.js ADDED
@@ -0,0 +1,11 @@
1
+ // src/sentry.ts
2
+ function sentryOnError(sentry) {
3
+ return (error) => {
4
+ const tags = { "vitral.remote": error.remote, "vitral.code": error.code };
5
+ if (error.version) tags["vitral.version"] = error.version;
6
+ sentry.captureException(error, { tags, extra: { entry: error.entry, route: error.route, docs: error.docs } });
7
+ };
8
+ }
9
+ export {
10
+ sentryOnError
11
+ };
@@ -0,0 +1,98 @@
1
+ import {
2
+ fetchCssText,
3
+ injectCss
4
+ } from "./chunk-ZAC6QQI6.js";
5
+ import "./chunk-GNHCZRQP.js";
6
+ import "./chunk-AKNNHQ2H.js";
7
+ import "./chunk-GNPFWISJ.js";
8
+
9
+ // src/core/shadow.ts
10
+ var sheets = /* @__PURE__ */ new Map();
11
+ var noop = () => {
12
+ };
13
+ var hoisted = /* @__PURE__ */ new Set();
14
+ var RELATIVE_URL = /url\(\s*(['"]?)(?![a-z]+:|\/\/|#)([^'")]+)\1\s*\)/gi;
15
+ var GLOBAL_RULES = /@property\s+(--[\w-]+)\s*\{[^}]*\}|@font-face\s*\{[^}]*\}|@import\s+(?:url\(\s*)?(?:(['"])(.*?)\2|([^'"\s);]+))\s*\)?[^;]*;/gi;
16
+ function plan({ css, shadow: s }) {
17
+ const at = (u) => new URL(u, css[0]).href;
18
+ const ready = s ? s.css.map(at) : [];
19
+ return [s ? [...(s.imports ?? []).map(at), ...ready, ...css.slice(ready.length)] : css, ready, (s?.global ?? []).map(at)];
20
+ }
21
+ function prefetch(r, priority) {
22
+ const [urls, , global] = plan(r);
23
+ for (const u of urls) fetchCssText(u, r.sri?.[u], priority).catch(noop);
24
+ injectCss(global, null, r.sri);
25
+ }
26
+ async function attachStyles(root, el, r, global = {}, local = {}) {
27
+ const sri = r.sri ?? {};
28
+ const [css, ready, up] = plan(r);
29
+ const portal = el.cloneNode();
30
+ portal.setAttribute("data-vitral-portal", "");
31
+ el.after(portal);
32
+ const urls = [...global.inherit ?? [], ...local.inherit ?? []].map((u) => new URL(u, document.baseURI).href).concat(css);
33
+ const props = injectCss(up, null, sri);
34
+ if (typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
35
+ const loaded = await Promise.all(urls.map((u) => loadSheet(u, [], sri[u], ready.includes(u) ? !!r.shadow.rebase : void 0)));
36
+ root.adoptedStyleSheets = [.../* @__PURE__ */ new Set([...root.adoptedStyleSheets, ...loaded.flat()])];
37
+ } else {
38
+ await injectCss(urls, root, sri);
39
+ }
40
+ await props;
41
+ const stop = (local.mirrorTheme ?? global.mirrorTheme) === false ? [] : [mirrorTheme(el), mirrorTheme(portal)];
42
+ return [() => (stop.forEach((fn) => fn()), portal.remove()), portal];
43
+ }
44
+ function loadSheet(href, chain, integrity, ready) {
45
+ let p = sheets.get(href);
46
+ if (!p) {
47
+ p = fetchCssText(href, integrity).then((text) => {
48
+ const sheet = new CSSStyleSheet();
49
+ if (ready !== false) text = text.replace(RELATIVE_URL, (_, q, u) => `url(${q}${new URL(u, href).href}${q})`);
50
+ if (ready != null) return sheet.replaceSync(text), [sheet];
51
+ const up = [];
52
+ const imports = [];
53
+ const rest = text.replace(GLOBAL_RULES, (rule, prop, _q, quoted, bare) => {
54
+ const url = quoted ?? bare;
55
+ if (url) imports.push(new URL(url, href).href);
56
+ else if (!hoisted.has(prop ?? rule)) {
57
+ hoisted.add(prop ?? rule);
58
+ up.push(rule);
59
+ }
60
+ return "";
61
+ });
62
+ if (up.length) {
63
+ const style = document.createElement("style");
64
+ style.setAttribute("data-vitral-properties", "");
65
+ style.textContent = up.join("\n");
66
+ document.head.appendChild(style);
67
+ }
68
+ sheet.replaceSync(rest);
69
+ const next = [...chain, href];
70
+ return Promise.all(imports.filter((u) => !next.includes(u)).map((u) => loadSheet(u, next))).then((found) => [...found.flat(), sheet]);
71
+ }).catch(() => {
72
+ sheets.delete(href);
73
+ return [];
74
+ });
75
+ sheets.set(href, p);
76
+ }
77
+ return p;
78
+ }
79
+ function mirrorTheme(el) {
80
+ const html = document.documentElement;
81
+ let added = [];
82
+ const sync = () => {
83
+ el.classList.remove(...added);
84
+ added = [...html.classList].filter((c) => !el.classList.contains(c));
85
+ el.classList.add(...added);
86
+ const theme = html.getAttribute("data-theme");
87
+ if (theme === null) el.removeAttribute("data-theme");
88
+ else el.setAttribute("data-theme", theme);
89
+ };
90
+ sync();
91
+ const observer = new MutationObserver(sync);
92
+ observer.observe(html, { attributeFilter: ["class", "data-theme"] });
93
+ return () => observer.disconnect();
94
+ }
95
+ export {
96
+ attachStyles,
97
+ prefetch
98
+ };
@@ -0,0 +1,36 @@
1
+ import { R as RemoteError } from './errors-kjBv6IH_.js';
2
+ import { P as Props, I as Isolation, b as StyleOptions } from './types-Czvm-siZ.js';
3
+
4
+ type SlotStatus = 'loading' | 'ready' | 'error';
5
+ interface SlotOptions<P extends Props = Props> {
6
+ /** Nome registrado. Com `src`, é o nome sob o qual a URL é registrada (opcional). */
7
+ name?: string;
8
+ /** URL do `vitral.json` (ou do JS). Registra o remote sem `configure()`. */
9
+ src?: string;
10
+ props?: P;
11
+ isolate?: Isolation;
12
+ /** `'high'` para o remote que aparece logo ao abrir a página. */
13
+ priority?: RequestPriority;
14
+ /** Estilos do host no Shadow DOM (somados aos do `configure`). */
15
+ styles?: StyleOptions;
16
+ /** Chamado a cada mudança de estado (para mostrar fallback / erro). */
17
+ onStatus?: (status: SlotStatus, error: RemoteError | null) => void;
18
+ }
19
+ interface RemoteSlot<P extends Props = Props> {
20
+ /** Atualiza as props sem remontar. */
21
+ update(props: P): void;
22
+ /** Troca de remote ou de isolamento (remonta). */
23
+ set(options: Partial<Pick<SlotOptions<P>, 'name' | 'src' | 'isolate'>>): void;
24
+ /** Remonta do zero (botão "tentar de novo"). */
25
+ retry(): void;
26
+ destroy(): void;
27
+ readonly status: SlotStatus;
28
+ }
29
+ /**
30
+ * Cuida do ciclo de vida de um remote dentro de `target`: monta, atualiza,
31
+ * remonta ao trocar de nome, ignora respostas atrasadas e limpa tudo no fim.
32
+ * Os adaptadores de host (Web Component, Svelte, Solid, Preact…) usam isto.
33
+ */
34
+ declare function createSlot<P extends Props = Props>(target: HTMLElement, options: SlotOptions<P>): RemoteSlot<P>;
35
+
36
+ export { type RemoteSlot as R, type SlotStatus as S, type SlotOptions as a, createSlot as c };