# Eventos, RPC e contratos

Três mecanismos concretos de comunicação: notificar fatos, pedir respostas e consumir serviços versionados.

<span id="elige-por-el-tipo-de-interacción"></span>

<span class="section-anchor" id="section-1"></span>

## Escolha pelo tipo de interação

| Necessidade | API | Resultado |
| --- | --- | --- |
| Notificar um fato sem resposta | `emit` / `on` | Evento com identidade e dados |
| Pedir uma resposta a um provedor | `request` / `handle` | Promise com valor ou erro |
| Invocar métodos de um serviço local | `provide` / `consume` | Proxy de um contrato versionado |

Os três mecanismos vivem no processo JavaScript do navegador. RPC neste contexto não implica HTTP nem transporte entre servidores. Uma implementação pode fazer fetch internamente, mas esse efeito e sua autorização pertencem à implementação.

Os fragmentos que usam `wu` pressupõem `import { wu } from 'wu-framework'` no módulo cliente do shell e sua inicialização com `await wu.init(...)`. Os fragmentos com `appWu` usam o `context.wu` entregue a uma app em `mount(container, context)`. Para copiar um exemplo completo, siga [Uma soma entre aplicações](/pt/docs/guides/rpc-between-apps/): cliente, provedor, manifestos, concessões e página Astro, com uma resposta observável e um caso de erro recuperável.

<span id="eventos-y-envelope"></span>

<span class="section-anchor" id="section-2"></span>

## Eventos e envelope

```js
// Código del shell, con autoridad host.
const stop = wu.on('catalog:*', (event) => {
  console.log(event.name, event.data, event.appName, event.verified);
});

const accepted = wu.emit('catalog:selected', { productId: 'p-42' });
if (!accepted) console.info('El bus rechazó el evento');
stop();
```

O callback recebe um objeto com `name`, `data`, `timestamp`, `appName`, `meta` e `verified`. Os dados são separados e congelados ao cruzar a fronteira do barramento. `once` remove sua inscrição após a primeira entrega; `off` remove uma inscrição específica.

Em uma app, use `context.wu.on` e `context.wu.emit`. A fachada anexa sua identidade e verifica as concessões. No modo estrito, emitir sem identidade válida, sem capacidade ou para um namespace reservado retorna `false`. Inscrições e RPC negados podem lançar erros: verifique o booleano de `emit` e trate as exceções das APIs que as produzem.

O barramento guarda até 100 eventos por padrão. `eventBus.replay(pattern, callback)` entrega novamente entradas existentes ao callback fornecido; não executa novamente o sistema nem garante recuperar efeitos externos. `history: false` permite excluir uma emissão do histórico.

<span id="rpc-con-timeout-y-versión"></span>

<span class="section-anchor" id="section-3"></span>

## RPC com timeout e versão

```js
const release = wu.eventBus.handle('catalog:lookup', ({ productId }) => {
  return { productId, title: 'Producto de demostración' };
}, { version: '1.0.0', allow: ['search'] });

// Dentro del lifecycle de la app search, con rpc.call:catalog:lookup:
async function lookup(appWu, productId, signal) {
  return appWu.request('catalog:lookup', { productId }, {
    version: '^1.0.0',
    timeout: 2500,
    signal,
  });
}

// Cuando el proveedor del shell ya no deba atender:
release();
```

Uma app provedora precisa de `rpc.provide` e uma consumidora, de `rpc.call` sobre o canal. Além disso, `allow` filtra identidades das chamadas. Para um provedor de app com escopo no modo estrito, o allow padrão permite essa mesma app; para comunicação entre apps, declare os consumidores explicitamente.

`wu.handle(channel, handler, options)` preserva `version`, `allow` e `replace`. Dentro do lifecycle, `context.wu.handle` também adiciona a identidade e os grants da app; use essa facade para handlers de uma microapp.

O timeout padrão de `request` é **0**, sem limite de tempo. Use um valor finito para interações de UI. O handler recebe um segundo argumento com dados de correlação e identidade e um `signal`. Deve cooperar com esse signal para cancelar seu próprio trabalho; rejeitar a espera não reverte uma operação já realizada.

Um canal tem um provedor ativo. Substituir o mesmo provedor requer `{ replace: true }` nas condições estritas; outra identidade não pode se apropriar de um canal que já tem proprietário. Liberação, substituição e revogação do provedor abortam as solicitações associadas. O barramento emite rastros `<canal>:request`, `<canal>:response` e `<canal>:error` com correlação.

<span id="contratos-de-métodos-locales"></span>

<span class="section-anchor" id="section-4"></span>

## Contratos de métodos locais

```js
const handle = wu.provide('formatters', {
  price(value) {
    return new Intl.NumberFormat('es-MX', {
      style: 'currency', currency: 'MXN',
    }).format(value);
  },
}, {
  version: '1.0.0',
  shape: { price: 'function' },
});

const formatters = wu.consume('formatters', '^1.0.0');
console.log(formatters.price(120));
handle.revoke();
```

`consume` entrega um proxy vivo. Sem `{ wait: true }`, criar o proxy não exige a existência do provedor: o primeiro acesso a um membro valida existência e versão. Com `{ wait: true, timeout: 2500 }`, espera até encontrar um provedor compatível.

A versão padrão de `provide` é `0.0.0`, diferente de `handle` RPC, cujo padrão é `1.0.0`. `shape` verifica a presença ou o `typeof` dos membros; não substitui um schema completo de argumentos/resultados.

Uma fachada de app exige `rpc.provide`/`rpc.call` também para contratos e associa automaticamente o provedor à app. Os proxies consumidos não são promises; um método chamado literalmente `then` não é acessível por essa via. Contratos não implementa a mesma lista de permissões nem a mesma separação de payloads que o RPC do barramento; escolha o contrato considerando esse limite.

<span id="errores-que-conviene-manejar"></span>

<span class="section-anchor" id="section-5"></span>

## Erros que convém tratar

| Código RPC | Causa |
| --- | --- |
| `WU_RPC_NO_HANDLER` | Não há provedor do canal |
| `WU_RPC_VERSION_MISMATCH` | A versão não atende ao intervalo |
| `WU_RPC_CALLER_DENIED` | O consumidor não está em `allow` |
| `WU_RPC_CALL_DENIED` / `WU_RPC_PROVIDE_DENIED` | Falta uma concessão efetiva |
| `WU_RPC_CHANNEL_OWNED` | Outro proprietário já registrou o canal |
| `WU_RPC_REPLACE_REQUIRED` | Falta intenção explícita de substituição |
| `WU_RPC_PROVIDER_RELEASED` / `WU_RPC_PROVIDER_REPLACED` | O provedor deixou de ser o mesmo durante a solicitação |

<span id="referencia-de-implementación"></span>

<span class="section-anchor" id="section-6"></span>

## Referência de implementação

Eventos: `src/core/wu-event-bus.js`; RPC: `src/core/wu-event-bus.js` e `src/core/wu-event-bus.js`; atalho handle do singleton: `src/index.js`; replay: `src/core/wu-event-bus.js`; contratos: `src/core/wu-contracts.js` e `src/core/wu-contracts.js`; fachada: `src/core/wu-core.js`. Testes: `tests/unit/event-bus.test.js`, `tests/unit/contracts.test.js`, `tests/unit/capability-security-v3.test.js`, `tests/unit/scoped-events-teardown.test.js`.

O primeiro provider é dono do nome de um contrato. Outra app, ou o host substituindo um contrato de app, recebe `WU_CAPABILITY_OWNED` até o proprietário revogar o contrato ou desmontar. O mesmo proprietário pode substituir sua implementação. Quando há `shape`, portas remotas só expõem os métodos declarados por ela.