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/index.d.ts CHANGED
@@ -1,17 +1,119 @@
1
+ import { V as VitralConfig, c as RemoteEntry, P as Props, a as RemoteModule, I as Isolation, b as StyleOptions, M as MountedRemote, E as EventBus, R as RemoteContext, d as SharedValue } from './types-Czvm-siZ.js';
2
+ export { C as CheckedProps, H as Handler, e as PropsOf, f as ProvideOptions, g as ProvidedValue, h as RemoteContract, i as RemoteManifest, j as RemoteMetric, k as Remotes, S as Shared, l as SharedApi, m as SharedModules, n as SharedType, o as batch, p as provide, s as shared } from './types-Czvm-siZ.js';
3
+ import { R as RemoteError } from './errors-kjBv6IH_.js';
4
+ export { a as RemoteErrorCode } from './errors-kjBv6IH_.js';
5
+ export { R as RemoteSlot, a as SlotOptions, S as SlotStatus, c as createSlot } from './slot-DqXTwGbs.js';
6
+ export { e as events } from './events-D5gs7rff.js';
7
+ export { n as navigate } from './navigate-BRG1WJUM.js';
8
+ export { r as __reset } from './state-BDdCwc21.js';
9
+
10
+ /** Uma chave do store vista de fora (devtools, SSR, ponte do iframe). */
11
+ interface SharedEntry {
12
+ key: string;
13
+ value: unknown;
14
+ /** `false` quando só o dono altera. */
15
+ writable: boolean;
16
+ /** Quem é o dono (nome do remote; vazio para o host ou sem nome). */
17
+ owner?: string;
18
+ /** Quem fez a última mudança. */
19
+ by?: string;
20
+ /** Quantas assinaturas ativas a chave tem. */
21
+ subscribers: number;
22
+ }
23
+ /**
24
+ * Store guardado no protocolo global (`globalThis[Symbol.for('vitral')].shared()`).
25
+ * Faz parte do protocolo v1: só cresce com métodos novos.
26
+ */
27
+ interface SharedStore {
28
+ /** Valor atual; `undefined` se a chave ainda não tem valor. */
29
+ get(key: string): unknown;
30
+ /**
31
+ * Troca o valor. Passa se `token` é o do dono ou se a chave aceita escrita.
32
+ * Devolve `false` quando a escrita foi bloqueada (`writable: false`).
33
+ */
34
+ set(key: string, value: unknown, token?: object, by?: string): boolean;
35
+ /** Chama `fn(valor)` a cada mudança (não na hora). Devolve a função que cancela. */
36
+ subscribe(key: string, fn: (value: unknown) => void): () => void;
37
+ /**
38
+ * Torna-se dono de uma chave sem dono e grava `value` (um valor vindo do
39
+ * SSR ainda não reivindicado é mantido). Devolve o token do dono, ou
40
+ * `undefined` se a chave já tem dono.
41
+ */
42
+ own(key: string, value: unknown, writable: boolean, by?: string): object | undefined;
43
+ /** O dono larga a chave. O valor fica e a chave volta a aceitar escrita. */
44
+ release(key: string, token: object): void;
45
+ /** Roda `fn` e notifica cada chave alterada uma vez só, no fim. */
46
+ batch<R>(fn: () => R): R;
47
+ /** Chaves com valor e seus metadados. */
48
+ list(): SharedEntry[];
49
+ }
50
+
51
+ /** Configura a lib. Pode ser chamada mais de uma vez; as opções são mescladas. */
52
+ declare function configure(config: VitralConfig): void;
53
+ /** Registra (ou substitui) um remote. */
54
+ declare function register(name: string, entry: string | RemoteEntry): void;
55
+ /**
56
+ * Registra a URL de um `src` e devolve o nome para montar. Sem `name`, o nome
57
+ * é a própria URL (e o nome do manifesto vira um apelido). Com `trusted`, a
58
+ * origem entra na allowlist mesmo com `allowedOrigins`: vale para URL escrita
59
+ * no código do host, nunca para URL vinda de dados.
60
+ */
61
+ declare function registerSrc(src: string, name?: string, trusted?: boolean): string;
62
+
63
+ /** Baixa (uma vez só) e devolve o módulo de um remote. */
64
+ declare function loadRemote<P extends Props = Props>(name: string): Promise<RemoteModule<P>>;
1
65
  /**
2
- * Remote em JS/TS puro sem escrever mount/update/unmount na mão.
66
+ * Carrega um módulo sem UI que um remote expõe (funções, stores, constantes),
67
+ * com a mesma verificação de SRI e de origem dos componentes.
3
68
  *
4
- * export default component<{ mensagem?: string }>({
5
- * state: { cliques: 0 },
6
- * render: ({ mensagem }, state, ctx) => html`
7
- * <p>${mensagem}</p>
8
- * <button onclick=${() => state.cliques++}>ping ${state.cliques}</button>
9
- * `,
10
- * })
69
+ * const api = await loadModule<typeof import('./tipos/carrinho-api')>('carrinho/api')
11
70
  *
12
- * Valores interpolados são escapados (sem XSS). Mudar `state` ou receber
13
- * props novas renderiza de novo. Funções em `on<evento>=${fn}` viram listeners.
71
+ * Sem `/`, devolve os exports do arquivo principal do remote.
72
+ */
73
+ declare function loadModule<T = Record<string, unknown>>(name: string): Promise<T>;
74
+ /** Começa a baixar um remote (JS e CSS) sem montar (ex.: no hover de um link). */
75
+ declare function preload(name: string): void;
76
+
77
+ interface MountOptions {
78
+ isolate?: Isolation;
79
+ /** `'high'` para o remote que aparece logo ao abrir a página: vira `fetchpriority` nos downloads. */
80
+ priority?: RequestPriority;
81
+ /** Estilos do host no Shadow DOM (somados aos do `configure`). */
82
+ styles?: StyleOptions;
83
+ /** Chamado quando o remote quebra depois de montado (erro de render, handler etc.). */
84
+ onError?: (error: RemoteError) => void;
85
+ }
86
+ /**
87
+ * Monta um remote dentro de `target`. Devolve um handle com `update` e
88
+ * `unmount` que funciona igual para qualquer framework. Com `refresh(nome)`,
89
+ * o mesmo handle passa a apontar para a versão nova.
90
+ */
91
+ declare function mountRemote<P extends Props = Props>(target: HTMLElement, name: string, props: P, options?: MountOptions): Promise<MountedRemote<P>>;
92
+
93
+ /** Declara um remote. É só uma função identidade com tipos. */
94
+ declare function defineRemote<P extends Props = Props>(remote: RemoteModule<P>): RemoteModule<P>;
95
+
96
+ declare function createEventBus(): EventBus;
97
+
98
+ /**
99
+ * Troca as montagens de `name` (e das partes, `name/…`) pela versão que o
100
+ * manifesto aponta agora, sem recarregar a página. Resolve quando todas as
101
+ * montagens já mostram a versão nova. Rejeita se a versão nova não carregar
102
+ * ou se o `mount` dela falhar; nesse caso a montagem antiga fica na tela.
103
+ */
104
+ declare function refresh(name: string): Promise<void>;
105
+ /**
106
+ * Revalida os manifestos dos remotes montados agora (os desmontados ficam de
107
+ * fora) e emite
108
+ * `vitral:update-available` com `{ name, entry }` para cada deploy novo.
109
+ * Devolve os nomes com versão nova. Falhas de rede são ignoradas.
14
110
  */
111
+ declare function checkUpdates(): Promise<string[]>;
112
+ /**
113
+ * Revalida os manifestos a cada navegação (`popstate`, que `navigate()` também
114
+ * dispara, e a Navigation API onde existe). Devolve a função que desliga.
115
+ */
116
+ declare function watchUpdates(): () => void;
15
117
 
16
118
  declare const TEMPLATE: unique symbol;
17
119
  interface Template {
@@ -41,151 +143,46 @@ interface ComponentOptions<P extends Props, S extends object> {
41
143
  declare function component<P extends Props = Props, S extends object = Record<string, never>>(options: RenderFn<P, S> | ComponentOptions<P, S>): RemoteModule<P>;
42
144
 
43
145
  /**
44
- * vitral: micro-frontends com um único contrato.
45
- *
46
- * Um remote é um módulo ES que exporta `mount(el, props, ctx)` e devolve
47
- * `{ update?, unmount }`. O host só precisa saber a URL. Nada de config
48
- * compartilhada em tempo de build, nada de container global de dependências.
146
+ * Extras opcionais do contexto compartilhado: guardar no storage, espelhar
147
+ * entre abas e levar os valores do SSR para o cliente. Ficam fora do store
148
+ * para só entrar no bundle de quem usa.
49
149
  */
50
- type Props = Record<string, unknown>;
51
- interface RemoteContext {
52
- /** Nome com que o host registrou este remote. */
53
- name: string;
54
- /** URL base de onde o remote foi carregado (útil para assets). */
55
- baseUrl: string;
56
- /**
57
- * Barramento de eventos compartilhado entre host e todos os remotes. As
58
- * assinaturas feitas por aqui são canceladas sozinhas no unmount.
59
- */
60
- events: EventBus;
61
- /** Shadow root quando o host pediu isolamento, senão `null`. */
62
- shadowRoot: ShadowRoot | null;
63
- /** Avisa o host de um erro em tempo de execução (os adaptadores já chamam). */
64
- reportError(error: unknown): void;
65
- /** Navega a página inteira (host e todos os roteadores) para `url`. */
66
- navigate(url: string, options?: {
67
- replace?: boolean;
68
- }): void;
69
- }
70
- interface MountedRemote<P extends Props = Props> {
71
- update?(props: P): void;
72
- unmount(): void;
73
- }
74
- interface RemoteModule<P extends Props = Props> {
75
- mount(el: HTMLElement, props: P, ctx: RemoteContext): MountedRemote<P> | Promise<MountedRemote<P>>;
76
- }
77
- interface RemoteEntry {
78
- /** URL do módulo JS do remote, ou do `vitral.json` gerado pelo plugin. */
79
- url?: string;
80
- /**
81
- * Remote local, sem rede: o próprio módulo ou uma função que o importa
82
- * (ex.: `() => import('./carrinho')`). Útil em monorepos e testes.
83
- */
84
- module?: RemoteModule<any> | (() => Promise<RemoteModule<any> | {
85
- default: RemoteModule<any>;
86
- }>);
87
- /** Hash SRI (`sha256-…`, `sha384-…`, `sha512-…`) do JS. Verificado antes de executar. */
88
- integrity?: string;
89
- /** CSS extra para carregar junto. */
90
- css?: string[];
91
- /** Isolamento padrão para este remote. */
92
- isolate?: Isolation;
93
- }
94
- type Isolation = 'shadow' | 'none';
95
- interface VitralConfig {
96
- /** Mapa nome → URL (ou entrada completa), ou a URL de um JSON com esse mapa. */
97
- remotes?: Record<string, string | RemoteEntry> | string;
150
+
151
+ interface PersistOptions {
152
+ /** `'local'` (padrão) ou `'session'`. */
153
+ storage?: 'local' | 'session';
98
154
  /**
99
- * Origens de onde é permitido carregar código. Padrão: a própria origem da
100
- * página mais as origens das URLs registradas. Use `['*']` para liberar tudo.
155
+ * Versão do formato do valor. Faz parte da chave do storage
156
+ * (`vitral:<chave>:<versão>`): ao mudar o formato, suba a versão e o valor
157
+ * antigo é ignorado. Padrão `1`.
101
158
  */
102
- allowedOrigins?: string[];
103
- /** Tempo máximo para baixar um remote, em ms. Padrão 15000. */
104
- timeout?: number;
105
- /** Tentativas extras se o download falhar. Padrão 1. */
106
- retries?: number;
107
- /** Isolamento padrão para todos os remotes. Padrão `'none'`. */
108
- isolate?: Isolation;
109
- }
110
- type RemoteErrorCode = 'NOT_REGISTERED' | 'ORIGIN_BLOCKED' | 'TIMEOUT' | 'INTEGRITY' | 'INVALID_MODULE' | 'LOAD_FAILED' | 'MOUNT_FAILED' | 'RENDER_FAILED';
111
- declare class RemoteError extends Error {
112
- code: RemoteErrorCode;
113
- remote: string;
114
- cause?: unknown | undefined;
115
- constructor(code: RemoteErrorCode, remote: string, message: string, cause?: unknown | undefined);
116
- }
117
- /** Formato do `vitral.json` emitido pelo plugin de build. */
118
- interface RemoteManifest {
119
- name: string;
120
- version?: string;
121
- entry: string;
122
- css?: string[];
123
- integrity?: string;
124
- /** Escopo usado pelo plugin para prefixar o CSS (`[data-vitral-scope]`). */
125
- scope?: string;
126
- }
127
- /** Configura a lib. Pode ser chamada mais de uma vez; as opções são mescladas. */
128
- declare function configure(config: VitralConfig): void;
129
- /** Registra (ou substitui) um remote. */
130
- declare function register(name: string, entry: string | RemoteEntry): void;
131
- /** Baixa (uma vez só) e devolve o módulo de um remote. */
132
- declare function loadRemote<P extends Props = Props>(name: string): Promise<RemoteModule<P>>;
133
- /** Começa a baixar um remote sem montar (ex.: no hover de um link). */
134
- declare function preload(name: string): void;
135
- interface MountOptions {
136
- isolate?: Isolation;
137
- /** Chamado quando o remote quebra depois de montado (erro de render, handler etc.). */
138
- onError?: (error: RemoteError) => void;
159
+ version?: string | number;
139
160
  }
140
161
  /**
141
- * Monta um remote dentro de `target`. Devolve um handle com `update` e
142
- * `unmount` que funciona igual para qualquer framework.
162
+ * Restaura o valor guardado (se houver) e guarda cada mudança. Valores que
163
+ * não viram JSON (funções, por exemplo) não são guardados. Sem storage
164
+ * (servidor, modo privado bloqueado), não faz nada.
165
+ *
166
+ * const carrinho = persist(provide('carrinho', []), { version: 2 })
143
167
  */
144
- declare function mountRemote<P extends Props = Props>(target: HTMLElement, name: string, props: P, options?: MountOptions): Promise<MountedRemote<P>>;
145
- type SlotStatus = 'loading' | 'ready' | 'error';
146
- interface SlotOptions<P extends Props = Props> {
147
- name: string;
148
- props?: P;
149
- isolate?: Isolation;
150
- /** Chamado a cada mudança de estado (para mostrar fallback / erro). */
151
- onStatus?: (status: SlotStatus, error: RemoteError | null) => void;
152
- }
153
- interface RemoteSlot<P extends Props = Props> {
154
- /** Atualiza as props sem remontar. */
155
- update(props: P): void;
156
- /** Troca de remote ou de isolamento (remonta). */
157
- set(options: Partial<Pick<SlotOptions<P>, 'name' | 'isolate'>>): void;
158
- /** Remonta do zero (botão "tentar de novo"). */
159
- retry(): void;
160
- destroy(): void;
161
- readonly status: SlotStatus;
162
- }
168
+ declare function persist<V extends SharedValue<any>>(value: V, options?: PersistOptions): V;
163
169
  /**
164
- * Cuida do ciclo de vida de um remote dentro de `target`: monta, atualiza,
165
- * remonta ao trocar de nome, ignora respostas atrasadas e limpa tudo no fim.
166
- * Os adaptadores de host (Web Component, Svelte, Solid, Preact…) usam isto.
170
+ * Espelha as mudanças entre abas da mesma origem (`BroadcastChannel`). Chame
171
+ * nas duas abas, de preferência no dono da chave: assim a mudança que chega
172
+ * passa mesmo com `writable: false`. Só dados que o `structuredClone` aceita
173
+ * atravessam. Junto com `persist`, uma aba nova começa com o último valor.
174
+ *
175
+ * const carrinho = syncTabs(persist(provide('carrinho', [])))
167
176
  */
168
- declare function createSlot<P extends Props = Props>(target: HTMLElement, options: SlotOptions<P>): RemoteSlot<P>;
169
- /** Declara um remote. É só uma função identidade com tipos. */
170
- declare function defineRemote<P extends Props = Props>(remote: RemoteModule<P>): RemoteModule<P>;
171
- type Handler<T = unknown> = (payload: T) => void;
172
- interface EventBus {
173
- emit<T = unknown>(type: string, payload?: T): void;
174
- on<T = unknown>(type: string, handler: Handler<T>): () => void;
175
- /** Último valor emitido em `type` (útil para estado como "usuário logado"). */
176
- last<T = unknown>(type: string): T | undefined;
177
- }
178
- declare function createEventBus(): EventBus;
179
- /** Barramento global. É o mesmo objeto que os remotes recebem em `ctx.events`. */
180
- declare const events: EventBus;
177
+ declare function syncTabs<V extends SharedValue<any>>(value: V): V;
181
178
  /**
182
- * Navega mantendo todos os roteadores em sincronia (React Router, Vue Router,
183
- * Next, Nuxt…): atualiza o histórico e dispara `popstate`, que todos escutam.
179
+ * SSR: transforma os valores de uma requisição no conteúdo do
180
+ * `<script type="application/json" data-vitral-shared>`, que o store do
181
+ * cliente lê antes dos remotes montarem. Funções e `undefined` ficam de fora;
182
+ * `<` é escapado para o JSON não fechar o `<script>`.
183
+ *
184
+ * `<script type="application/json" data-vitral-shared>${serializeShared({ usuario })}</script>`
184
185
  */
185
- declare function navigate(url: string, options?: {
186
- replace?: boolean;
187
- }): void;
188
- /** Só para testes: limpa todo o estado global. */
189
- declare function __reset(): void;
186
+ declare function serializeShared(values: Record<string, unknown>): string;
190
187
 
191
- export { type ComponentOptions, type EventBus, type Handler, type Isolation, type MountOptions, type MountedRemote, type Props, type RemoteContext, type RemoteEntry, RemoteError, type RemoteErrorCode, type RemoteManifest, type RemoteModule, type RemoteSlot, type RenderFn, type SlotOptions, type SlotStatus, type Template, type View, type VitralConfig, __reset, component, configure, createEventBus, createSlot, defineRemote, events, html, loadRemote, mountRemote, navigate, preload, register, render, unsafeHTML };
188
+ export { type ComponentOptions, EventBus, Isolation, type MountOptions, MountedRemote, type PersistOptions, Props, RemoteContext, RemoteEntry, RemoteError, RemoteModule, type RenderFn, type SharedEntry, type SharedStore, SharedValue, StyleOptions, type Template, type View, VitralConfig, checkUpdates, component, configure, createEventBus, defineRemote, html, loadModule, loadRemote, mountRemote, persist, preload, refresh, register, registerSrc, render, serializeShared, syncTabs, unsafeHTML, watchUpdates };
package/dist/index.js CHANGED
@@ -1,24 +1,45 @@
1
1
  import {
2
- RemoteError,
3
- __reset,
2
+ batch,
3
+ checkUpdates,
4
4
  component,
5
- configure,
6
- createEventBus,
7
5
  createSlot,
8
6
  defineRemote,
9
7
  events,
10
8
  html,
11
- loadRemote,
12
9
  mountRemote,
13
10
  navigate,
11
+ persist,
12
+ provide,
13
+ refresh,
14
+ render,
15
+ serializeShared,
16
+ shared,
17
+ syncTabs,
18
+ unsafeHTML,
19
+ watchUpdates
20
+ } from "./chunk-I3VSKSAZ.js";
21
+ import {
22
+ configure,
23
+ loadModule,
24
+ loadRemote,
14
25
  preload,
15
26
  register,
16
- render,
17
- unsafeHTML
18
- } from "./chunk-TTL52BF2.js";
27
+ registerSrc
28
+ } from "./chunk-TD4S3IHA.js";
29
+ import "./chunk-ZAC6QQI6.js";
30
+ import "./chunk-GNHCZRQP.js";
31
+ import {
32
+ RemoteError
33
+ } from "./chunk-AKNNHQ2H.js";
34
+ import {
35
+ createEventBus,
36
+ resetProtocol
37
+ } from "./chunk-GNPFWISJ.js";
19
38
  export {
20
39
  RemoteError,
21
- __reset,
40
+ resetProtocol as __reset,
41
+ batch,
42
+ checkUpdates,
22
43
  component,
23
44
  configure,
24
45
  createEventBus,
@@ -26,11 +47,20 @@ export {
26
47
  defineRemote,
27
48
  events,
28
49
  html,
50
+ loadModule,
29
51
  loadRemote,
30
52
  mountRemote,
31
53
  navigate,
54
+ persist,
32
55
  preload,
56
+ provide,
57
+ refresh,
33
58
  register,
59
+ registerSrc,
34
60
  render,
35
- unsafeHTML
61
+ serializeShared,
62
+ shared,
63
+ syncTabs,
64
+ unsafeHTML,
65
+ watchUpdates
36
66
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Navega mantendo todos os roteadores em sincronia (React Router, Vue Router,
3
+ * Next, Nuxt…): atualiza o histórico e dispara `popstate`, que todos escutam.
4
+ */
5
+ declare function navigate(url: string, options?: {
6
+ replace?: boolean;
7
+ }): void;
8
+
9
+ export { navigate as n };
package/dist/otel.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { R as RemoteError } from './errors-kjBv6IH_.js';
2
+
3
+ /**
4
+ * Erros dos remotes no OpenTelemetry, sem depender do `@opentelemetry/api`:
5
+ *
6
+ * import { trace } from '@opentelemetry/api'
7
+ * import { otelOnError } from 'vitral/otel'
8
+ *
9
+ * configure({ onError: otelOnError({ trace, tracer: trace.getTracer('host') }) })
10
+ *
11
+ * Com um span ativo, o erro vira um evento `exception` nele. Sem span ativo
12
+ * (ou sem `trace`), o `tracer` abre e fecha um span `vitral.error` com o erro.
13
+ * Os atributos são os de exceção do OpenTelemetry mais `vitral.remote`,
14
+ * `vitral.version`, `vitral.code`, `vitral.entry` e `vitral.route`.
15
+ */
16
+
17
+ /** Atributos de span e de evento. */
18
+ type Attributes = Record<string, string>;
19
+ /** A parte de um `Span` que o adaptador usa. */
20
+ interface SpanLike {
21
+ addEvent(name: string, attributes?: Attributes): unknown;
22
+ recordException(exception: Error): void;
23
+ setStatus(status: {
24
+ code: number;
25
+ message?: string;
26
+ }): unknown;
27
+ end(): void;
28
+ }
29
+ interface OtelOptions {
30
+ /** O `trace` de `@opentelemetry/api`, para achar o span ativo. */
31
+ trace?: {
32
+ getActiveSpan(): SpanLike | undefined;
33
+ };
34
+ /** Tracer que abre um span quando não há span ativo. */
35
+ tracer?: {
36
+ startSpan(name: string, options?: {
37
+ attributes?: Attributes;
38
+ }): SpanLike;
39
+ };
40
+ }
41
+ /** `onError` para o `configure` que registra cada `RemoteError` no OpenTelemetry. */
42
+ declare function otelOnError({ trace, tracer }: OtelOptions): (error: RemoteError) => void;
43
+
44
+ export { type Attributes, type OtelOptions, type SpanLike, otelOnError };
package/dist/otel.js ADDED
@@ -0,0 +1,27 @@
1
+ // src/otel.ts
2
+ function otelOnError({ trace, tracer }) {
3
+ return (error) => {
4
+ const all = {
5
+ "exception.type": error.name,
6
+ "exception.message": error.message,
7
+ "exception.stacktrace": error.stack,
8
+ "vitral.remote": error.remote,
9
+ "vitral.version": error.version,
10
+ "vitral.code": error.code,
11
+ "vitral.entry": error.entry,
12
+ "vitral.route": error.route
13
+ };
14
+ const attributes = {};
15
+ for (const k in all) if (all[k] !== void 0) attributes[k] = all[k];
16
+ const active = trace?.getActiveSpan();
17
+ if (active) return void active.addEvent("exception", attributes);
18
+ const span = tracer?.startSpan("vitral.error", { attributes });
19
+ if (!span) return;
20
+ span.recordException(error);
21
+ span.setStatus({ code: 2, message: error.message });
22
+ span.end();
23
+ };
24
+ }
25
+ export {
26
+ otelOnError
27
+ };
@@ -0,0 +1,15 @@
1
+ import {
2
+ OVERRIDES_KEY,
3
+ manifestUrl,
4
+ overrideFor,
5
+ overridesEnabled,
6
+ storedOverrides
7
+ } from "./chunk-DXORSF4X.js";
8
+ import "./chunk-GNPFWISJ.js";
9
+ export {
10
+ OVERRIDES_KEY,
11
+ manifestUrl,
12
+ overrideFor,
13
+ overridesEnabled,
14
+ storedOverrides
15
+ };
package/dist/preact.d.ts CHANGED
@@ -1,22 +1,45 @@
1
1
  import * as preact from 'preact';
2
2
  import { VNode, ComponentType } from 'preact';
3
- import { Props, Isolation, RemoteError, SlotStatus, RemoteModule } from './index.js';
4
- export { RemoteContext, events, navigate } from './index.js';
3
+ import { P as Props, I as Isolation, C as CheckedProps, a as RemoteModule, S as Shared } from './types-Czvm-siZ.js';
4
+ export { R as RemoteContext } from './types-Czvm-siZ.js';
5
+ import { R as RemoteError } from './errors-kjBv6IH_.js';
6
+ import { S as SlotStatus } from './slot-DqXTwGbs.js';
7
+ export { e as events } from './events-D5gs7rff.js';
8
+ export { n as navigate } from './navigate-BRG1WJUM.js';
9
+ import { L as Loading, P as Prefetch } from './host-slot-Cz6EiGsB.js';
5
10
 
6
11
  /** Transforma um componente Preact em um remote. O contexto chega na prop `vitral`. */
7
12
  declare function preactRemote<P extends Props>(Component: ComponentType<any>): RemoteModule<P>;
8
13
  interface RemoteProps<P extends Props = Props> {
9
- name: string;
14
+ name?: string;
15
+ /** URL do `vitral.json`. Dispensa `configure()`. */
16
+ src?: string;
10
17
  props?: P;
11
18
  isolate?: Isolation;
12
19
  fallback?: VNode | string | null;
13
20
  error?: VNode | string | ((error: RemoteError, retry: () => void) => VNode | string | null) | null;
14
21
  class?: string;
22
+ /** `'lazy'`: monta perto de aparecer na tela; `'idle'`: com o navegador ocioso. */
23
+ loading?: Loading;
24
+ /** Baixa antes de montar: `'hover'`, `'visible'` ou `'idle'`. */
25
+ prefetch?: Prefetch;
26
+ /** `'high'` para o remote que aparece logo ao abrir a página. */
27
+ priority?: RequestPriority;
28
+ /** Ao sair da página, guarda o remote montado (LRU, padrão 5) e na volta só atualiza as props. */
29
+ keepAlive?: boolean | number;
15
30
  }
16
- declare function Remote<P extends Props = Props>({ name, props, isolate, fallback, error, ...rest }: RemoteProps<P>): VNode<preact.ClassAttributes<HTMLElement> & {
17
- 'data-vitral': string;
31
+ declare function Remote<P extends Props = Props, N extends string = string>({ name, src, props, isolate, fallback, error, loading, prefetch, priority, keepAlive, ...rest }: RemoteProps<P> & CheckedProps<N>): VNode<preact.ClassAttributes<HTMLElement> & {
32
+ 'data-vitral': string | undefined;
18
33
  'data-vitral-status': SlotStatus;
19
- class: string | undefined;
34
+ class: (RemoteProps<P> & CheckedProps<N>)["class"] | undefined;
20
35
  }>;
36
+ /**
37
+ * Lê uma chave compartilhada (`provide`/`shared`) e re-renderiza só quando
38
+ * ela muda. Com seletor, só quando o resultado do seletor muda (`Object.is`).
39
+ *
40
+ * const nome = useShared('usuario', (u) => u?.nome)
41
+ */
42
+ declare function useShared<K extends keyof Shared, S = Shared[K] | undefined>(key: K, select?: (value: Shared[K] | undefined) => S): S;
43
+ declare function useShared<T = unknown, S = T | undefined>(key: string, select?: (value: T | undefined) => S): S;
21
44
 
22
- export { Remote, type RemoteProps, preactRemote };
45
+ export { Remote, type RemoteProps, preactRemote, useShared };
package/dist/preact.js CHANGED
@@ -1,13 +1,23 @@
1
1
  import {
2
- createSlot,
2
+ hostSlot
3
+ } from "./chunk-IHTUM6LT.js";
4
+ import {
3
5
  defineRemote,
4
6
  events,
5
- navigate
6
- } from "./chunk-TTL52BF2.js";
7
+ memoSelect,
8
+ navigate,
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 "./chunk-GNPFWISJ.js";
7
17
 
8
18
  // src/preact.ts
9
19
  import { h, render } from "preact";
10
- import { useEffect, useRef, useState } from "preact/hooks";
20
+ import { useEffect, useMemo, useRef, useState } from "preact/hooks";
11
21
  function preactRemote(Component) {
12
22
  return defineRemote({
13
23
  mount(el, props, ctx) {
@@ -17,27 +27,46 @@ function preactRemote(Component) {
17
27
  }
18
28
  });
19
29
  }
20
- function Remote({ name, props, isolate, fallback = null, error = null, ...rest }) {
30
+ function Remote({ name, src, props, isolate, fallback = null, error = null, loading, prefetch, priority, keepAlive, ...rest }) {
21
31
  const ref = useRef(null);
22
32
  const slot = useRef(null);
23
33
  const [state, setState] = useState({ status: "loading", error: null });
24
34
  useEffect(() => {
25
- slot.current = createSlot(ref.current, { name, props: props ?? {}, isolate, onStatus: (status, error2) => setState({ status, error: error2 }) });
35
+ slot.current = hostSlot(ref.current, { name, src, props: props ?? {}, isolate, loading, prefetch, priority, keepAlive, onStatus: (status, error2) => setState({ status, error: error2 }) });
26
36
  return () => slot.current?.destroy();
27
37
  }, []);
28
- useEffect(() => slot.current?.set({ name, isolate }), [name, isolate]);
38
+ useEffect(() => slot.current?.set({ name, src, isolate }), [name, src, isolate]);
29
39
  useEffect(() => slot.current?.update(props ?? {}), [props]);
30
40
  const retry = () => slot.current?.retry();
31
- return h("div", { "data-vitral": name, "data-vitral-status": state.status, class: rest.class }, [
41
+ return h("div", { "data-vitral": name ?? src, "data-vitral-status": state.status, class: rest.class }, [
32
42
  state.status === "loading" ? fallback : null,
33
43
  state.status === "error" && state.error ? typeof error === "function" ? error(state.error, retry) : error : null,
34
44
  // O Preact nunca coloca filhos neste div: ele pertence ao remote.
35
45
  h("div", { ref })
36
46
  ]);
37
47
  }
48
+ function useShared(key, select = same) {
49
+ const handle = useMemo(() => shared(key), [key]);
50
+ const [pick] = useState(memoSelect);
51
+ const [, rerender] = useState(0);
52
+ const value = pick(handle.get(), select);
53
+ const latest = useRef({ value, select });
54
+ latest.current = { value, select };
55
+ useEffect(
56
+ () => (
57
+ // subscribe chama na hora: pega mudanças entre o render e o efeito.
58
+ handle.subscribe((v) => {
59
+ if (!Object.is(pick(v, latest.current.select), latest.current.value)) rerender((n) => n + 1);
60
+ })
61
+ ),
62
+ [handle]
63
+ );
64
+ return value;
65
+ }
38
66
  export {
39
67
  Remote,
40
68
  events,
41
69
  navigate,
42
- preactRemote
70
+ preactRemote,
71
+ useShared
43
72
  };