teraprox-core-sdk 0.3.10 → 0.3.14
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.
- package/README.md +515 -0
- package/dist/{chunk-JK654W4P.mjs → chunk-CBKXJHPL.mjs} +195 -25
- package/dist/{federation-Bhx0XhSP.d.mts → federation-Cp_lk0Xd.d.mts} +231 -49
- package/dist/{federation-Bhx0XhSP.d.ts → federation-Cp_lk0Xd.d.ts} +231 -49
- package/dist/federation.d.mts +1 -1
- package/dist/federation.d.ts +1 -1
- package/dist/federation.js +199 -26
- package/dist/federation.mjs +9 -3
- package/dist/index.d.mts +1414 -21
- package/dist/index.d.ts +1414 -21
- package/dist/index.js +2467 -886
- package/dist/index.mjs +2172 -827
- package/package.json +2 -1
package/README.md
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
# teraprox-core-sdk
|
|
2
|
+
|
|
3
|
+
> Contrato tipado Core ↔ Federados — interfaces, context, hooks e componentes compartilhados.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Índice
|
|
8
|
+
|
|
9
|
+
1. [Visão geral](#visão-geral)
|
|
10
|
+
2. [Instalação](#instalação)
|
|
11
|
+
3. [Modo Standalone (`StandaloneProvider`)](#modo-standalone-standaloneprovider)
|
|
12
|
+
- [Setup mínimo](#setup-mínimo)
|
|
13
|
+
- [Toast: `toast` vs `addToast`](#toast-toast-vs-addtoast)
|
|
14
|
+
- [RTDB em tempo real](#rtdb-em-tempo-real)
|
|
15
|
+
- [Resolução automática do tenant](#resolução-automática-do-tenant)
|
|
16
|
+
- [Emulador vs Firebase Cloud](#emulador-vs-firebase-cloud)
|
|
17
|
+
- [Fallback controllers (dev)](#fallback-controllers-dev)
|
|
18
|
+
4. [Modo Hospedado (`FederatedBridge`)](#modo-hospedado-federatedbridge)
|
|
19
|
+
5. [CoreServiceBuilder (programático)](#coreservicebuilder-programático)
|
|
20
|
+
6. [Hooks](#hooks)
|
|
21
|
+
- [`useCoreService`](#usecoreservice)
|
|
22
|
+
- [`useMatchingObject`](#usematchingobject)
|
|
23
|
+
- [`useHttpController` / `useFetchData` / `usePostData`](#usehttpcontroller--usefetchdata--usepostdata)
|
|
24
|
+
- [`useAnexoManager`](#useanexomanager)
|
|
25
|
+
- [`useToast`](#usetoast)
|
|
26
|
+
7. [DevAutoLogin](#devautologin)
|
|
27
|
+
8. [Fluxo RTDB ponta a ponta](#fluxo-rtdb-ponta-a-ponta)
|
|
28
|
+
9. [Variáveis de ambiente](#variáveis-de-ambiente)
|
|
29
|
+
10. [Tipos exportados](#tipos-exportados)
|
|
30
|
+
11. [CHANGELOG](#changelog)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Visão geral
|
|
35
|
+
|
|
36
|
+
O `teraprox-core-sdk` é o contrato compartilhado entre o **shell Core** e os **microfrontends federados** (SGM-SS, SGM-OM, SGP etc.).
|
|
37
|
+
|
|
38
|
+
Ele provê:
|
|
39
|
+
|
|
40
|
+
| Camada | O que entrega |
|
|
41
|
+
|--------|--------------|
|
|
42
|
+
| **Contexto** | `CoreServiceContext` — acesso a `createController`, `toast`, `subscribe`/`unsubscribe` |
|
|
43
|
+
| **Standalone** | `StandaloneProvider` — modo dev/autônomo com Firebase RTDB integrado |
|
|
44
|
+
| **Hospedado** | `FederatedBridge` — ponte que injeta o `CoreService` provido pelo shell |
|
|
45
|
+
| **Hooks** | `useMatchingObject`, `useAnexoManager`, `useFetchData`, `usePostData`, `useToast`… |
|
|
46
|
+
| **Builder** | `CoreServiceBuilder` — construção programática do `CoreService` |
|
|
47
|
+
| **Tipos** | Interfaces para `CoreService`, `HttpController`, `ToastService`, `IAnexoPort`… |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Instalação
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install teraprox-core-sdk
|
|
55
|
+
# ou, a partir do monorepo local:
|
|
56
|
+
npm install file:../../packages/core-sdk
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Modo Standalone (`StandaloneProvider`)
|
|
62
|
+
|
|
63
|
+
Use quando o microfrontend roda de forma **autônoma** (`npm start`) fora do shell Core.
|
|
64
|
+
|
|
65
|
+
### Setup mínimo
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// App.tsx
|
|
69
|
+
import { StandaloneProvider } from 'teraprox-core-sdk/federation'
|
|
70
|
+
import { FetchHttpAdapter } from 'teraprox-core-sdk'
|
|
71
|
+
import { useSelector } from 'react-redux'
|
|
72
|
+
|
|
73
|
+
const API = process.env.REACT_APP_API_URL || 'http://localhost:4021'
|
|
74
|
+
|
|
75
|
+
function makeController(context: string, baseEndPoint?: string) {
|
|
76
|
+
const ep = baseEndPoint ?? (context ? `${API}/${context}` : API)
|
|
77
|
+
return new FetchHttpAdapter(ep, { 'x-teraprox-host': 'manutencao' })
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Wrapper dentro do Redux Provider
|
|
81
|
+
function StandaloneWrapper({ children }: { children: React.ReactNode }) {
|
|
82
|
+
const tenant = useSelector((s: any) => s.global?.companyId)
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<StandaloneProvider
|
|
86
|
+
createController={makeController}
|
|
87
|
+
toast={myToastService}
|
|
88
|
+
tenant={tenant}
|
|
89
|
+
>
|
|
90
|
+
{children}
|
|
91
|
+
</StandaloneProvider>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> **Importante:** `StandaloneWrapper` deve ser renderizado **dentro** do `Redux Provider`
|
|
97
|
+
> para que `useSelector` funcione. Coloque-o acima do `RouterProvider`.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Toast: `toast` vs `addToast`
|
|
102
|
+
|
|
103
|
+
O provider aceita dois formatos — **prefira `toast`**:
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
// ✅ Preferido — passa ToastService diretamente (sem bridge)
|
|
107
|
+
<StandaloneProvider toast={minhaImplementacaoDeToast} ...>
|
|
108
|
+
|
|
109
|
+
// ✅ Compatibilidade — react-toast-notifications
|
|
110
|
+
<StandaloneProvider addToast={addToast} ...>
|
|
111
|
+
|
|
112
|
+
// Se nenhum for passado, chamadas de toast vão para console.warn em dev.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Implementando `ToastService`:**
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import type { ToastService } from 'teraprox-core-sdk'
|
|
119
|
+
|
|
120
|
+
class DomToastAdapter implements ToastService {
|
|
121
|
+
success(msg: string) { /* renderiza toast verde */ }
|
|
122
|
+
warning(msg: string) { /* renderiza toast amarelo */ }
|
|
123
|
+
error(msg: string) { /* renderiza toast vermelho */ }
|
|
124
|
+
info(msg: string) { /* renderiza toast azul */ }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### RTDB em tempo real
|
|
131
|
+
|
|
132
|
+
Quando `tenant` está resolvido, o `StandaloneProvider` conecta ao Firebase RTDB e
|
|
133
|
+
despacha eventos para os listeners registrados via `useMatchingObject`.
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
// Escuta mudanças em tempo real de uma entidade específica
|
|
137
|
+
import { useMatchingObject } from 'teraprox-core-sdk'
|
|
138
|
+
|
|
139
|
+
useMatchingObject('solicitacaoDeServico', '*', (payload) => {
|
|
140
|
+
// payload = id da entidade que mudou
|
|
141
|
+
fetchById(payload).then(dispatch)
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
O listener recebe apenas o `id` afetado e faz um `GET` pontual —
|
|
146
|
+
**atualização granular**, sem refetch da lista inteira.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### Resolução automática do tenant
|
|
151
|
+
|
|
152
|
+
O tenant identifica o caminho no RTDB: `{tenant}/matchingObjects`.
|
|
153
|
+
|
|
154
|
+
**Ordem de prioridade (primeira que tiver valor):**
|
|
155
|
+
|
|
156
|
+
| # | Fonte | Quando usar |
|
|
157
|
+
|---|-------|-------------|
|
|
158
|
+
| 1 | `tenant` prop | Dinâmico — vem do Redux após login (`state.global.companyId`) |
|
|
159
|
+
| 2 | `REACT_APP_RTDB_TENANT` no `.env` | Estático — garante conexão imediata no boot, antes do Redux |
|
|
160
|
+
| 3 | `'dev-local'` (automático) | Último recurso em `NODE_ENV=development`, zero configuração |
|
|
161
|
+
|
|
162
|
+
**Configuração recomendada para dev:**
|
|
163
|
+
|
|
164
|
+
```dotenv
|
|
165
|
+
# .env do microfrontend
|
|
166
|
+
REACT_APP_RTDB_TENANT=1 # deve bater com o companyId do DevAutoLogin / API local
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
> Em produção o tenant **sempre** vem do Redux (login real). Os fallbacks 2 e 3
|
|
170
|
+
> são ignorados quando `NODE_ENV=production`.
|
|
171
|
+
|
|
172
|
+
Se o tenant não resolver em 5 s, um `console.warn` explica o problema e como corrigir.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### Emulador vs Firebase Cloud
|
|
177
|
+
|
|
178
|
+
**Resolução do emulador (mesma lógica de prioridade):**
|
|
179
|
+
|
|
180
|
+
| # | Fonte | Exemplo |
|
|
181
|
+
|---|-------|---------|
|
|
182
|
+
| 1 | `emulator` prop | `{ host: 'localhost', port: 9000, namespace: 'teraprox-default-rtdb' }` |
|
|
183
|
+
| 2 | `REACT_APP_RTDB_EMULATOR_HOST` env var | `localhost:9000` |
|
|
184
|
+
| 3 | Auto-probe `localhost:9000` | Detecta se o emulador está rodando |
|
|
185
|
+
| 4 | `firebaseConfig` prop | Objeto de config do Firebase Cloud |
|
|
186
|
+
| — | Nenhum encontrado | Popup de aviso em dev |
|
|
187
|
+
|
|
188
|
+
**Emulador Docker (recomendado para dev):**
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
// App.tsx — configuração explícita via prop (mais confiável que env var em node_modules)
|
|
192
|
+
<StandaloneProvider
|
|
193
|
+
createController={makeController}
|
|
194
|
+
toast={domToast}
|
|
195
|
+
tenant={tenant}
|
|
196
|
+
emulator={{ host: 'localhost', port: 9000, namespace: 'teraprox-default-rtdb' }}
|
|
197
|
+
>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```dotenv
|
|
201
|
+
# .env — alternativa via variável (lida pelo bundler na app, não no node_modules)
|
|
202
|
+
REACT_APP_RTDB_EMULATOR_HOST=localhost:9000
|
|
203
|
+
REACT_APP_RTDB_EMULATOR_NS=teraprox-default-rtdb
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
> **Nota sobre `process.env.*` em `node_modules`:** webpack's `DefinePlugin` pode não
|
|
207
|
+
> substituir variáveis dentro de dependências. Prefira sempre o **prop explícito** para
|
|
208
|
+
> garantir funcionamento (tanto para `emulator` quanto para `tenant`).
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### Fallback controllers (dev)
|
|
213
|
+
|
|
214
|
+
Use para simular endpoints que não existem localmente:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import { NullHttpController } from 'teraprox-core-sdk'
|
|
218
|
+
|
|
219
|
+
class ArvoreEstruturalFallback extends NullHttpController {
|
|
220
|
+
get(path?: string) {
|
|
221
|
+
if (path?.includes('branchByBranchLevel')) {
|
|
222
|
+
return Promise.resolve([
|
|
223
|
+
{ id: 1, branchLevel: { level: 1, nome: 'Empresa' }, branchNodes: [] }
|
|
224
|
+
])
|
|
225
|
+
}
|
|
226
|
+
return super.get(path)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function makeController(context: string, baseEndPoint?: string) {
|
|
231
|
+
// Intercepta contextos específicos antes de chegar ao HTTP
|
|
232
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
233
|
+
if (context === '') return new ArvoreEstruturalFallback()
|
|
234
|
+
if (context === 'branchLevel') return new BranchLevelFallback()
|
|
235
|
+
}
|
|
236
|
+
const ep = baseEndPoint ?? `${API}/${context}`
|
|
237
|
+
return new FetchHttpAdapter(ep, { 'x-teraprox-host': 'manutencao' })
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Modo Hospedado (`FederatedBridge`)
|
|
244
|
+
|
|
245
|
+
Quando o microfrontend é carregado pelo **shell Core**, ele recebe o `CoreService` via
|
|
246
|
+
Module Federation. Use o `FederatedBridge` para injetar esse serviço no contexto:
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
// O shell Core passa o CoreService por prop ou window
|
|
250
|
+
import { FederatedBridge } from 'teraprox-core-sdk/federation'
|
|
251
|
+
|
|
252
|
+
function RemoteRoot({ coreService }: { coreService: CoreService }) {
|
|
253
|
+
return (
|
|
254
|
+
<FederatedBridge coreService={coreService}>
|
|
255
|
+
<App />
|
|
256
|
+
</FederatedBridge>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
> `FederatedBridge` é o oposto do `StandaloneProvider` — não conecta ao RTDB
|
|
262
|
+
> (o shell já faz isso), apenas injeta o `CoreService` no contexto.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## CoreServiceBuilder (programático)
|
|
267
|
+
|
|
268
|
+
Útil para **testes** ou quando um componente React não é viável:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
import { CoreServiceBuilder, FetchHttpAdapter } from 'teraprox-core-sdk'
|
|
272
|
+
|
|
273
|
+
const service = new CoreServiceBuilder()
|
|
274
|
+
.withHttpEndpoint('http://localhost:4021')
|
|
275
|
+
.withGatewayHost('manutencao')
|
|
276
|
+
.withToast(myToast)
|
|
277
|
+
.withTracing(true) // adiciona header traceparent W3C
|
|
278
|
+
.withFallbackController('', new ArvoreFallback())
|
|
279
|
+
.build()
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
O `.build()` retorna um `CoreService` com `subscribe`/`unsubscribe` **funcionais**
|
|
283
|
+
(armazenam as subscriptions numa lista interna), prontos para serem consumidos por
|
|
284
|
+
`useMatchingObject`. **Não conecta ao RTDB por si só** — para RTDB em standalone,
|
|
285
|
+
use `StandaloneProvider`.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Hooks
|
|
290
|
+
|
|
291
|
+
### `useCoreService`
|
|
292
|
+
|
|
293
|
+
Acessa o `CoreService` do contexto. Deve estar dentro de `StandaloneProvider` ou `FederatedBridge`.
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
const { createController, toast, subscribe, unsubscribe } = useCoreService()
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### `useMatchingObject`
|
|
302
|
+
|
|
303
|
+
Registra um listener de tempo real com cleanup automático.
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
import { useMatchingObject } from 'teraprox-core-sdk'
|
|
307
|
+
|
|
308
|
+
// Dentro de um componente:
|
|
309
|
+
useMatchingObject(
|
|
310
|
+
'solicitacaoDeServico', // context — deve bater com o model do MatchingObject no backend
|
|
311
|
+
'*', // location — '*' captura qualquer target
|
|
312
|
+
(payload) => {
|
|
313
|
+
// payload = data do MatchingObject (geralmente o id da entidade)
|
|
314
|
+
fetchSolicitacao(payload).then(dispatch)
|
|
315
|
+
},
|
|
316
|
+
[dispatch] // deps extras para o useEffect interno
|
|
317
|
+
)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Por que `useMatchingObject` e não `subscribe` manual?**
|
|
321
|
+
|
|
322
|
+
- Registra e **remove** automaticamente no unmount (evita leak de memória)
|
|
323
|
+
- É seguro com React StrictMode (dupla montagem não duplica listeners)
|
|
324
|
+
- Expressivo: deixa explícito o contexto que o componente observa
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### `useHttpController` / `useFetchData` / `usePostData`
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
// Acesso direto ao controller
|
|
332
|
+
const controller = useHttpController('solicitacaoDeServico')
|
|
333
|
+
|
|
334
|
+
// GET com loading state
|
|
335
|
+
const { data, loading, error, refetch } = useFetchData('solicitacaoDeServico')
|
|
336
|
+
|
|
337
|
+
// POST com loading state
|
|
338
|
+
const { post, loading } = usePostData('solicitacaoDeServico')
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### `useAnexoManager`
|
|
344
|
+
|
|
345
|
+
Gerencia o ciclo completo de anexos com upload direto ao GCS via signed URLs.
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
const anexo = useAnexoManager({
|
|
349
|
+
entityId: form?.id, // id da entidade dona dos anexos
|
|
350
|
+
context: 'solicitacaoDeServico', // context para o path no GCS
|
|
351
|
+
port: 'anexo', // controller que expõe /intent, /confirm, etc.
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
// Uso:
|
|
355
|
+
anexo.addLocal(files) // adiciona arquivos locais (sem upload ainda)
|
|
356
|
+
await anexo.uploadAll(entityId) // faz intent → upload GCS → confirm para cada arquivo
|
|
357
|
+
anexo.locais // AnexoLocal[] — arquivos ainda não enviados
|
|
358
|
+
anexo.persistidos // AnexoPersistido[] — já salvos na API
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Fluxo de upload:**
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
addLocal(File[])
|
|
365
|
+
↓
|
|
366
|
+
uploadAll(entityId)
|
|
367
|
+
├─ POST /anexo/intent → { uploadUrl, key, fileName, contentType }
|
|
368
|
+
├─ PUT uploadUrl (GCS) → upload direto (sem passar pela API)
|
|
369
|
+
└─ POST /anexo/confirm → registra o anexo no banco
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### `useToast`
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
const toast = useToast()
|
|
378
|
+
|
|
379
|
+
toast.success('Salvo com sucesso!')
|
|
380
|
+
toast.warning('Verifique os campos obrigatórios.')
|
|
381
|
+
toast.error('Erro ao salvar.')
|
|
382
|
+
toast.info('Processando...')
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## DevAutoLogin
|
|
388
|
+
|
|
389
|
+
Popula automaticamente o Redux com um usuário de dev em `NODE_ENV=development`.
|
|
390
|
+
Não faz nada em produção nem quando o microfrontend está hospedado pelo shell Core.
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
import { DevAutoLogin } from 'teraprox-core-sdk/federation'
|
|
394
|
+
import { logIn, setCompany } from './Reducers/globalConfigReducer'
|
|
395
|
+
|
|
396
|
+
<DevAutoLogin actions={{ logIn, setCompany }}>
|
|
397
|
+
<App />
|
|
398
|
+
</DevAutoLogin>
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Usuário padrão injetado:**
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
{
|
|
405
|
+
id: '1', companyId: '1', role: 'admin',
|
|
406
|
+
firstName: 'Dev', lastName: 'User',
|
|
407
|
+
setor: 'Desenvolvimento', ...
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Para sobrescrever campos específicos:
|
|
412
|
+
|
|
413
|
+
```tsx
|
|
414
|
+
<DevAutoLogin
|
|
415
|
+
actions={{ logIn, setCompany }}
|
|
416
|
+
devUser={{ companyId: 'minha-empresa', role: 'operator' }}
|
|
417
|
+
>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Fluxo RTDB ponta a ponta
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
Backend (API)
|
|
426
|
+
sentinel.appendMo(new MatchingObject('solicitacaoDeServico', '*', id))
|
|
427
|
+
↓ (buffer durante a request)
|
|
428
|
+
afterCommit → publishMatchingObjects(tenant, mos)
|
|
429
|
+
↓
|
|
430
|
+
Firebase RTDB push em: {tenant}/matchingObjects
|
|
431
|
+
↓
|
|
432
|
+
Frontend (StandaloneProvider)
|
|
433
|
+
onChildAdded('{tenant}/matchingObjects')
|
|
434
|
+
↓
|
|
435
|
+
Encontra subscribers com context='solicitacaoDeServico' e location='*'
|
|
436
|
+
↓
|
|
437
|
+
refresher(payload=id)
|
|
438
|
+
↓
|
|
439
|
+
GET /solicitacaoDeServico/:id → dispatch(updateSingleSsRow(ss))
|
|
440
|
+
↓
|
|
441
|
+
Apenas a linha afetada é atualizada na UI — sem refetch da lista completa
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Variáveis de ambiente
|
|
447
|
+
|
|
448
|
+
Coloque no `.env` de cada microfrontend:
|
|
449
|
+
|
|
450
|
+
```dotenv
|
|
451
|
+
# Endpoint da API principal
|
|
452
|
+
REACT_APP_API_URL=http://localhost:4021
|
|
453
|
+
|
|
454
|
+
# Gateway host (header x-teraprox-host)
|
|
455
|
+
REACT_APP_TERAPROX_GATEWAY_HOST=manutencao
|
|
456
|
+
|
|
457
|
+
# ── RTDB ─────────────────────────────────────────────────────────────────────
|
|
458
|
+
|
|
459
|
+
# Tenant padrão para dev — deve bater com o companyId da API local.
|
|
460
|
+
# Garante que o RTDB conecta no boot, antes do Redux ser populado.
|
|
461
|
+
# Em produção é ignorado (tenant vem do Redux após login real).
|
|
462
|
+
REACT_APP_RTDB_TENANT=1
|
|
463
|
+
|
|
464
|
+
# Emulador Firebase RTDB (Docker / firebase-tools)
|
|
465
|
+
REACT_APP_RTDB_EMULATOR_HOST=localhost:9000
|
|
466
|
+
REACT_APP_RTDB_EMULATOR_NS=teraprox-default-rtdb
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
> **Nota:** variáveis `REACT_APP_RTDB_*` são substituídas pelo webpack `DefinePlugin`
|
|
470
|
+
> **no código da app**, mas podem não ser resolvidas dentro de `node_modules`.
|
|
471
|
+
> Para garantir, passe os valores como **props explícitas** ao `StandaloneProvider`:
|
|
472
|
+
>
|
|
473
|
+
> ```tsx
|
|
474
|
+
> <StandaloneProvider
|
|
475
|
+
> emulator={{ host: 'localhost', port: 9000, namespace: 'teraprox-default-rtdb' }}
|
|
476
|
+
> tenant={tenant ?? process.env.REACT_APP_RTDB_TENANT}
|
|
477
|
+
> ...
|
|
478
|
+
> >
|
|
479
|
+
> ```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Tipos exportados
|
|
484
|
+
|
|
485
|
+
```ts
|
|
486
|
+
import type {
|
|
487
|
+
CoreService, // interface principal do serviço
|
|
488
|
+
HttpController, // interface de controllers HTTP
|
|
489
|
+
ToastService, // interface de toast
|
|
490
|
+
MatchingObjectSubscription, // { context, location, refresher }
|
|
491
|
+
IAnexoPort, // interface para gerenciamento de anexos
|
|
492
|
+
AnexoPersistido, // anexo já salvo na API
|
|
493
|
+
AnexoLocal, // arquivo local ainda não enviado
|
|
494
|
+
UploadIntent, // resposta do /anexo/intent
|
|
495
|
+
IObservabilityPort, // interface de observabilidade
|
|
496
|
+
} from 'teraprox-core-sdk'
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## CHANGELOG
|
|
502
|
+
|
|
503
|
+
### 0.3.12
|
|
504
|
+
- **`StandaloneProvider`**: aceita `toast?: ToastService` diretamente (sem necessidade de bridge `addToast`)
|
|
505
|
+
- **`StandaloneProvider`**: resolução automática do tenant em 3 camadas (`tenant` prop → `REACT_APP_RTDB_TENANT` → `'dev-local'`)
|
|
506
|
+
- **`StandaloneProvider`**: aviso de `console.warn` após 5 s quando tenant não resolve
|
|
507
|
+
- **`CoreServiceBuilder`**: `subscribe`/`unsubscribe` armazenam subscriptions corretamente (não são mais stubs)
|
|
508
|
+
|
|
509
|
+
### 0.3.x
|
|
510
|
+
- `useAnexoManager`: suporte a `overrideEntityId` em `uploadAll(entityId?)` para entidades recém-criadas
|
|
511
|
+
- `FetchHttpAdapter`: tratamento correto de `FormData` vs JSON no body
|
|
512
|
+
- `TracingHttpAdapter`: injeção automática do header `traceparent` W3C
|
|
513
|
+
- `StandaloneProvider`: auto-detecção do emulador RTDB com probe em `localhost:9000`
|
|
514
|
+
- `DevAutoLogin`: suporte a `devUser` parcial para sobrescrever campos do usuário dev
|
|
515
|
+
- Hooks: `useFetchData`, `usePostData`, `useFormStorage`, `useSmartSearch`, `useValidation`
|