@seedgrid/ai-toolkit 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +151 -2
- package/dist/adapters/claude.js +114 -0
- package/dist/adapters/codex.js +108 -0
- package/dist/adapters/index.js +17 -0
- package/dist/adapters/shared.js +142 -0
- package/dist/adapters/types.js +1 -0
- package/dist/cli.js +203 -0
- package/dist/commands/common.js +98 -0
- package/dist/commands/doctor.js +290 -0
- package/dist/commands/init.js +9 -0
- package/dist/commands/install.js +107 -0
- package/dist/commands/remove.js +54 -0
- package/dist/commands/review.js +127 -0
- package/dist/commands/status.js +73 -0
- package/dist/commands/update.js +8 -0
- package/dist/commands/validate.js +27 -0
- package/dist/core/apply.js +181 -0
- package/dist/core/blocks.js +64 -0
- package/dist/core/content.js +528 -0
- package/dist/core/env.js +40 -0
- package/dist/core/frontmatter.js +29 -0
- package/dist/core/hash.js +14 -0
- package/dist/core/inspect.js +51 -0
- package/dist/core/lock.js +124 -0
- package/dist/core/paths.js +65 -0
- package/dist/core/plan.js +242 -0
- package/dist/core/tools.js +62 -0
- package/dist/core/types.js +11 -0
- package/dist/core/updates.js +121 -0
- package/docs/arquitetura.md +80 -0
- package/docs/compatibilidade.md +50 -0
- package/docs/formato.md +155 -0
- package/docs/instalacao.md +105 -0
- package/docs/manutencao.md +115 -0
- package/package.json +43 -4
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
- package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
- package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
- package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
- package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
- package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
- package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
- package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
- package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
- package/seedgridKB/SeedGrid/Versoes.md +64 -0
- package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
- package/seedgridKB/manifest.json +142 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, front, component, providers]
|
|
3
|
+
fonte: front/seedgrid-fe-components/packages/seedgrid-fe-components/src/environment, front/seedgrid-fe-components/packages/seedgrid-fe-components/src/realtime
|
|
4
|
+
branch: main
|
|
5
|
+
commit: ad30fc11de
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# API — providers de ambiente e realtime
|
|
10
|
+
|
|
11
|
+
Visão geral: [[SeedGrid/SeedGrid-components/providers/Visao-geral|Providers — visão geral]] · Exemplos: [[SeedGrid/SeedGrid-components/providers/Exemplos|Exemplos dos providers]]
|
|
12
|
+
|
|
13
|
+
> **Como ler as tabelas.** Geradas a partir do tipo TypeScript real do 1º parâmetro de cada componente (TS checker, commit `ad30fc11de`) — lista completa das props próprias. **Padrão**: valor sem marca = inicializador na desestruturação do componente (Confirmado); `ᶠ` = fallback interno `??` no corpo do componente (Confirmado, expressão pode estar abreviada); `ᵇ` = padrão aplicado pelo componente base para o qual a prop é repassada; `ᵐ` = declarado só no `*.meta.ts`; `ˢ` = declarado só na tabela de props do showcase (`ᵐ`/`ˢ` = Não confirmado no código); `—` = sem padrão. **Descrição**: JSDoc > `*.meta.ts` > tabela do showcase (textos originais, sem acento quando assim na fonte); *(Inferência)* = escrita a partir da leitura do código. **Obrigatória** = prop não opcional no tipo.
|
|
14
|
+
|
|
15
|
+
## SgEnvironmentProvider
|
|
16
|
+
|
|
17
|
+
Provider de namespace, escopo e estratégia de persistência usados pelos componentes SeedGrid. Fonte: `src/environment/SgEnvironmentProvider.tsx` → `SgEnvironmentProvider`; tipos em `src/environment/persistence.ts`.
|
|
18
|
+
|
|
19
|
+
### Import
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import {
|
|
23
|
+
SgEnvironmentProvider,
|
|
24
|
+
useSgEnvironment,
|
|
25
|
+
useSgNamespaceProvider,
|
|
26
|
+
useSgPersistence,
|
|
27
|
+
useSgPersistentState,
|
|
28
|
+
buildSgPersistenceKey,
|
|
29
|
+
createLocalStorageStrategy,
|
|
30
|
+
createApiPersistenceStrategy,
|
|
31
|
+
createCompositePersistenceStrategy,
|
|
32
|
+
type SgEnvironmentValue,
|
|
33
|
+
type PersistenceStrategy,
|
|
34
|
+
type NamespaceProvider
|
|
35
|
+
} from "@seedgrid/fe-components";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Props
|
|
39
|
+
|
|
40
|
+
| Prop | Tipo | Padrão | Obrigatória | Descrição |
|
|
41
|
+
|---|---|---|---|---|
|
|
42
|
+
| `value` | `Partial<SgEnvironmentValue>` | — | Não | Sobrescritas parciais do ambiente (`namespaceProvider`, `persistenceStrategy`, `persistence.scope/mode/stateVersion`); cada campo ausente cai no padrão interno (namespace vazio, localStorage, `app:unknown`, `fallback`, `1`). |
|
|
43
|
+
| `children` | `React.ReactNode` | — | Sim | Arvore que consome o contexto de ambiente. |
|
|
44
|
+
|
|
45
|
+
- Tipo de props declarado inline na assinatura de `SgEnvironmentProvider` (não há tipo `SgEnvironmentProviderProps` exportado).
|
|
46
|
+
|
|
47
|
+
Resolução de `value` (Confirmado, `useMemo` do provider): cada campo é resolvido isoladamente com `??`.
|
|
48
|
+
|
|
49
|
+
| Campo de `value` | Tipo | Padrão quando ausente |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `namespaceProvider` | `NamespaceProvider` | `{ getNamespace: () => "" }` |
|
|
52
|
+
| `persistenceStrategy` | `PersistenceStrategy` | `createLocalStorageStrategy()` (sem prefixo) |
|
|
53
|
+
| `persistence.scope` | `string` | `"app:unknown"` |
|
|
54
|
+
| `persistence.mode` | `SgPersistenceMode` | `"fallback"` |
|
|
55
|
+
| `persistence.stateVersion` | `number` | `1` |
|
|
56
|
+
|
|
57
|
+
O valor do contexto só é recriado quando muda uma dessas cinco referências (dependências do `useMemo`).
|
|
58
|
+
|
|
59
|
+
### Eventos e callbacks
|
|
60
|
+
|
|
61
|
+
Nenhum evento próprio. Os callbacks relevantes estão nas estratégias (`load`/`save`/`clear`) — ver tipos abaixo.
|
|
62
|
+
|
|
63
|
+
### Ref
|
|
64
|
+
|
|
65
|
+
Não aceita `ref` (função simples, sem `forwardRef`).
|
|
66
|
+
|
|
67
|
+
### Children, slots e composição
|
|
68
|
+
|
|
69
|
+
`children` obrigatório: a árvore que consome o contexto. Pode ser aninhado; o provider mais próximo vence (contexto React). Componentes que leem este contexto: `SgFloatActionButton`, `SgCard`, `SgMenu`, `SgToolBar`, `SgDockMenu`, `SgDockLayout` (Confirmado por import).
|
|
70
|
+
|
|
71
|
+
### Contexto, providers e hooks
|
|
72
|
+
|
|
73
|
+
Contexto interno `SgEnvironmentContext` (não exportado). Hooks exportados:
|
|
74
|
+
|
|
75
|
+
| Hook | Assinatura | Retorno / comportamento (Confirmado) |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `useSgEnvironment` | `(): SgEnvironmentValue` | Contexto do provider mais próximo ou o ambiente padrão (namespace `""`, localStorage, `app:unknown`/`fallback`/`1`). |
|
|
78
|
+
| `useSgNamespaceProvider` | `(): NamespaceProvider` | `useSgEnvironment().namespaceProvider`. |
|
|
79
|
+
| `useSgPersistence` | `(): { namespace: string \| null; scope: string; mode: SgPersistenceMode; stateVersion: number; load(baseKey: string): Promise<unknown>; save(baseKey: string, state: unknown): Promise<void>; clear(baseKey: string): Promise<void> }` | Calcula a chave com `buildSgPersistenceKey(baseKey, namespace, scope)`; se a chave for `null` (namespace vazio) `load` retorna `null` e `save`/`clear` não fazem nada. `load/save/clear` são memoizados por estratégia, namespace e scope. |
|
|
80
|
+
| `useSgPersistentState<T>` | `(args: { baseKey: string; defaultValue: T; serialize?: (value: T) => unknown; deserialize?: (value: unknown) => T }): { value: T; setValue: (next: T \| ((prev: T) => T)) => void; clear: () => Promise<void>; hydrated: boolean }` | Começa com `defaultValue` e `hydrated=false`; no mount carrega (com provider: `useSgPersistence().load(baseKey)`; sem provider: `localStorage.getItem(baseKey)` + `JSON.parse`), aplica `deserialize` se o valor não for `null/undefined` e marca `hydrated=true` (em erro volta ao `defaultValue`). Depois de hidratado, cada mudança de `value` é salva (com provider: `save(baseKey, serialize(value))`; sem provider: `localStorage.setItem(baseKey, JSON.stringify(value))`, sem `serialize`). `clear` limpa e volta ao `defaultValue`. |
|
|
81
|
+
|
|
82
|
+
Observação (Inferência): o efeito de carregamento depende de `defaultValue` e `deserialize`; passar um objeto/função novo a cada render provoca recarga. `serialize`/`deserialize` são memoizados pela referência recebida.
|
|
83
|
+
|
|
84
|
+
### Funções e tipos de persistência (exportados)
|
|
85
|
+
|
|
86
|
+
| Símbolo | Assinatura | Comportamento (Confirmado — `src/environment/persistence.ts`) |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `buildSgPersistenceKey` | `(baseKey: string, namespace?: string \| null, scope?: string \| null) => string \| null` | `null` se namespace vazio; `sg:<namespace>:<baseKey>` se scope vazio (após `trim`); senão `sg:<namespace>:<scope>:<baseKey>`. |
|
|
89
|
+
| `createLocalStorageStrategy` | `(options?: { prefix?: string }) => PersistenceStrategy` | `window.localStorage` com `JSON.stringify/parse`; chave = `prefix + key`; erros engolidos (`load` → `null`). |
|
|
90
|
+
| `createApiPersistenceStrategy` | `(args: { baseUrl: string; fetcher?: (input: RequestInfo \| URL, init?: RequestInit) => Promise<Response>; scope: string; stateVersion: number }) => PersistenceStrategy` | `load`: `GET {baseUrl}/sg/persistence?key=…` → espera `{ found?: boolean; record?: SgPersistenceRecordDTO }` e devolve `record.state` ou `null`. `save`: `POST {baseUrl}/sg/persistence` com corpo `{ record }` (`protocolVersion: 1`, `key`, `scope`, `stateVersion`, `updatedAt` ISO, `state`). `clear`: `DELETE {baseUrl}/sg/persistence?key=…`. Resposta não-OK lança `Error("SG persistence <op> failed (<status>)")`. Barra final de `baseUrl` é removida; `fetcher` padrão = `fetch` global. |
|
|
91
|
+
| `createCompositePersistenceStrategy` | `(args: { mode: SgPersistenceMode; primary: PersistenceStrategy; secondary: PersistenceStrategy }) => PersistenceStrategy` | `strict`: só a primária. `fallback`: primária; se lançar, secundária. `mirror`: `load` tenta a primária e usa a secundária se der erro ou vier `null/undefined`; `save`/`clear` em ambas com `Promise.allSettled`. |
|
|
92
|
+
| `resolvePersistedStateValue<T>` | `(args: { loaded: unknown; defaultValue: T; deserialize: (value: unknown) => T }) => T` | `defaultValue` se `loaded` é `null/undefined`; senão `deserialize(loaded)`. |
|
|
93
|
+
| `readLocalPersistentState<T>` | `(args: { storage: Pick<Storage, "getItem">; baseKey: string; defaultValue: T; deserialize: (value: unknown) => T }) => T` | Lê e faz `JSON.parse`; ausência ou erro → `defaultValue`. |
|
|
94
|
+
| `writeLocalPersistentState<T>` | `(args: { storage: Pick<Storage, "setItem">; baseKey: string; value: T }) => void` | `setItem(baseKey, JSON.stringify(value))` (pode lançar). |
|
|
95
|
+
| `clearLocalPersistentState<T>` | `(args: { storage: Pick<Storage, "removeItem">; baseKey: string; defaultValue: T }) => T` | `removeItem(baseKey)` e devolve `defaultValue`. |
|
|
96
|
+
|
|
97
|
+
| Tipo | Definição (Confirmado) |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `NamespaceProvider` | `{ getNamespace: () => string \| null }` |
|
|
100
|
+
| `PersistenceStrategy` | `{ load: (key: string) => unknown \| Promise<unknown>; save: (key: string, state: unknown) => void \| Promise<void>; clear: (key: string) => void \| Promise<void> }` |
|
|
101
|
+
| `SgPersistenceMode` | `"strict" \| "fallback" \| "mirror"` |
|
|
102
|
+
| `SgPersistenceConfig` | `{ scope: string; mode: SgPersistenceMode; stateVersion: number }` |
|
|
103
|
+
| `SgEnvironmentValue` | `{ namespaceProvider: NamespaceProvider; persistenceStrategy: PersistenceStrategy; persistence: SgPersistenceConfig }` |
|
|
104
|
+
| `SgEnvironment` | alias de `SgEnvironmentValue` |
|
|
105
|
+
| `SgPersistenceRecordDTO` | `{ protocolVersion: 1; key: string; scope: string; stateVersion: number; updatedAt: string; state: unknown }` |
|
|
106
|
+
|
|
107
|
+
### Acessibilidade
|
|
108
|
+
|
|
109
|
+
Não se aplica (não renderiza DOM; só `Context.Provider`).
|
|
110
|
+
|
|
111
|
+
## SgRealtimeProvider
|
|
112
|
+
|
|
113
|
+
Avisos em tempo real para o usuário logado pelo SeedGrid Pulse. Fonte: `src/realtime/SgRealtimeProvider.tsx` → `SgRealtimeProvider`, `useSgRealtimeEvent`, `useSgRealtimeStatus`, `matchesSgRealtimeEvent`.
|
|
114
|
+
|
|
115
|
+
### Import
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import {
|
|
119
|
+
SgRealtimeProvider,
|
|
120
|
+
useSgRealtimeEvent,
|
|
121
|
+
useSgRealtimeStatus,
|
|
122
|
+
matchesSgRealtimeEvent,
|
|
123
|
+
type SgRealtimeProviderProps,
|
|
124
|
+
type SgRealtimeStatus,
|
|
125
|
+
type SgRealtimeEvent,
|
|
126
|
+
type SgRealtimeConnectResponse
|
|
127
|
+
} from "@seedgrid/fe-components";
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Props
|
|
131
|
+
|
|
132
|
+
| Prop | Tipo | Padrão | Obrigatória | Descrição |
|
|
133
|
+
|---|---|---|---|---|
|
|
134
|
+
| `children` | `React.ReactNode` | — | Sim | Arvore que ouve os avisos com useSgRealtimeEvent. |
|
|
135
|
+
| `channels` | `string[]` | — | Sim | Channels que a tela quer ouvir (ex.: `["backup"]`). |
|
|
136
|
+
| `tokenEndpoint` | `string` | `"/api/realtime/connect"` (`DEFAULT_TOKEN_ENDPOINT`) | Não | Rota que entrega o token de conexão do usuário logado. Default: `/api/realtime/connect` (a BFF, na mesma origem — o navegador manda o cookie da sessão). |
|
|
137
|
+
| `tokenRequestInit` | `RequestInit` | — | Não | Opções do `fetch` do token (ex.: `headers: { Authorization: ... }` quando não há cookie). |
|
|
138
|
+
| `fetchToken` | `() => Promise<SgRealtimeConnectResponse>` | — | Não | Substitui o pedido de token inteiro (apps sem BFF, testes). |
|
|
139
|
+
| `pulseUrl` | `string` | — | Não | Endereço do Pulse, usado quando o token não traz `connectUrl` (Pulse sem endereço público). |
|
|
140
|
+
| `enabled` | `boolean` | `true` | Não | Liga/desliga (ex.: `false` enquanto não há usuário logado). Default: `true`. |
|
|
141
|
+
| `connectOptions` | `Omit<ConnectInput, "getToken" \| "accountKey" \| "baseUrl">` | — | Não | Opções avançadas do cliente do Pulse (reconexão, `webSocketImpl` em testes...). |
|
|
142
|
+
|
|
143
|
+
`ConnectInput` vem de `@seedgrid/pulse-subscriber-react/core` (v3.0.0 instalada). Campos que restam após o `Omit` (lidos em `dist/core.d.ts` do pacote): `protocolVersion?` (padrão 1), `reconnect?: ReconnectOptions`, `auth?: PulseAuthOptions`, `connectPath?` (padrão `/api/v1/connect`), `webSocketImpl?`, `wsOptions?`, `connectTimeoutMs?` (padrão 10000), `logger?`. O provider sempre injeta `getToken` e, se informado, `baseUrl = pulseUrl`.
|
|
144
|
+
|
|
145
|
+
### Eventos e callbacks
|
|
146
|
+
|
|
147
|
+
- `fetchToken()` — chamado na conexão e em cada reconexão (o primeiro token é reaproveitado uma única vez). Sem `fetchToken`, o provider faz `fetch(tokenEndpoint, { method: "POST", credentials: "same-origin", ...tokenRequestInit })`; HTTP não-OK lança erro → status `unavailable`.
|
|
148
|
+
- Resposta `enabled: false` ou sem `token` → status `disabled` e nenhuma conexão.
|
|
149
|
+
- Mensagens recebidas viram `SgRealtimeEvent` e são entregues a todos os listeners; exceção num handler não afeta os demais.
|
|
150
|
+
|
|
151
|
+
### Ref
|
|
152
|
+
|
|
153
|
+
Não aceita `ref`.
|
|
154
|
+
|
|
155
|
+
### Children, slots e composição
|
|
156
|
+
|
|
157
|
+
`children` obrigatório. Montar uma vez (ex.: no layout autenticado). Sem `channels` (array vazio) ou com `enabled=false` não conecta (status `idle` ou `disabled`, respectivamente). Em SSR (`typeof window === "undefined"`) não conecta.
|
|
158
|
+
|
|
159
|
+
### Contexto, providers e hooks
|
|
160
|
+
|
|
161
|
+
Contexto interno `SgRealtimeContext` (`{ status, addListener }`, não exportado).
|
|
162
|
+
|
|
163
|
+
| Símbolo | Assinatura | Comportamento (Confirmado) |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| `useSgRealtimeEvent` | `(channel: string, events: string \| string[], handler: (event: SgRealtimeEvent) => void) => void` | Registra listener enquanto montado; chama `handler` quando `event.channel === channel` e o nome casa algum padrão de `events`. Usa sempre o `handler` mais recente (ref). Fora do provider, não faz nada. |
|
|
166
|
+
| `useSgRealtimeStatus` | `() => { status: SgRealtimeStatus; connected: boolean }` | `connected = status === "connected"`; fora do provider, `status = "disabled"`. |
|
|
167
|
+
| `matchesSgRealtimeEvent` | `(pattern: string, event: string) => boolean` | `true` para `"*"`, nome idêntico ou `prefixo.*` (casa nomes que começam com `prefixo.`). |
|
|
168
|
+
|
|
169
|
+
| Tipo | Definição (Confirmado) |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `SgRealtimeStatus` | `"idle" \| "disabled" \| "connecting" \| "connected" \| "reconnecting" \| "unavailable" \| "auth-error"` — JSDoc: fora de `connected`, a tela deve usar polling. |
|
|
172
|
+
| `SgRealtimeConnectResponse` | `{ enabled: boolean; token?: string; expiresAt?: number /* segundos desde a época */; connectUrl?: string }` — campos da resposta do `POST /realtime/connect` das extensões de realtime que o provider lê (Confirmado). |
|
|
173
|
+
| `SgRealtimeEvent` | `{ channel: string; event: string; data: unknown; messageId: string; publishedAt: string }` — JSDoc: `data` só traz identificadores; buscar o registro pela API. |
|
|
174
|
+
|
|
175
|
+
### Acessibilidade
|
|
176
|
+
|
|
177
|
+
Não se aplica (não renderiza DOM).
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, front, component, providers]
|
|
3
|
+
fonte: front/seedgrid-fe-components/apps/showcase/src/app/components/providers, front/seedgrid-fe-components/apps/showcase/src/app/components/hooks
|
|
4
|
+
branch: main
|
|
5
|
+
commit: ad30fc11de
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Exemplos — providers de ambiente e realtime
|
|
10
|
+
|
|
11
|
+
API: [[SeedGrid/SeedGrid-components/providers/API|API dos providers]] · Visão geral: [[SeedGrid/SeedGrid-components/providers/Visao-geral|Providers — visão geral]]
|
|
12
|
+
|
|
13
|
+
Todos os exemplos abaixo foram copiados 1:1 dos samples do showcase (exceto onde indicado) e passaram em type-check contra `packages/seedgrid-fe-components/src/index.ts` (TypeScript do monorepo, `strict`).
|
|
14
|
+
|
|
15
|
+
## SgEnvironmentProvider
|
|
16
|
+
|
|
17
|
+
### Namespace e escopo customizados
|
|
18
|
+
|
|
19
|
+
Mostra a chave final que os componentes usariam (`sg:u:123:app:crm:fab:theme`).
|
|
20
|
+
|
|
21
|
+
Fonte: `apps/showcase/src/app/components/providers/sg-environment-provider/samples/namespace-customizado.tsx.sample` (type-check: OK).
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { SgEnvironmentProvider, buildSgPersistenceKey, useSgEnvironment } from "@seedgrid/fe-components";
|
|
25
|
+
|
|
26
|
+
function EnvInfo() {
|
|
27
|
+
const env = useSgEnvironment();
|
|
28
|
+
const namespace = env.namespaceProvider.getNamespace();
|
|
29
|
+
const fullKey = buildSgPersistenceKey("fab:theme", namespace, env.persistence.scope);
|
|
30
|
+
return <div>fullKey: {fullKey ?? "null"}</div>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default function Example() {
|
|
34
|
+
return (
|
|
35
|
+
<SgEnvironmentProvider
|
|
36
|
+
value={{
|
|
37
|
+
namespaceProvider: { getNamespace: () => "u:123" },
|
|
38
|
+
persistence: { scope: "app:crm", mode: "fallback", stateVersion: 1 },
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<EnvInfo />
|
|
42
|
+
</SgEnvironmentProvider>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Persistência REST por usuário com fallback local
|
|
48
|
+
|
|
49
|
+
Adaptado do sample `providers/sg-environment-provider/samples/rest-por-usuario.tsx.sample`: o original **não importa** `createApiPersistenceStrategy`, `createLocalStorageStrategy` e `createCompositePersistenceStrategy` e falha no type-check; abaixo, o mesmo código com o import completo (type-check: OK). Em modo `fallback`, se a API lançar erro, a estratégia usa o `localStorage`. A URL é ilustrativa.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import {
|
|
53
|
+
SgEnvironmentProvider,
|
|
54
|
+
createApiPersistenceStrategy,
|
|
55
|
+
createCompositePersistenceStrategy,
|
|
56
|
+
createLocalStorageStrategy,
|
|
57
|
+
} from "@seedgrid/fe-components";
|
|
58
|
+
|
|
59
|
+
const api = createApiPersistenceStrategy({
|
|
60
|
+
baseUrl: "https://api.seedgrid.com",
|
|
61
|
+
scope: "app:crm",
|
|
62
|
+
stateVersion: 1,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const local = createLocalStorageStrategy();
|
|
66
|
+
const persistence = createCompositePersistenceStrategy({
|
|
67
|
+
mode: "fallback",
|
|
68
|
+
primary: api,
|
|
69
|
+
secondary: local,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export default function Example() {
|
|
73
|
+
return (
|
|
74
|
+
<SgEnvironmentProvider
|
|
75
|
+
value={{
|
|
76
|
+
namespaceProvider: { getNamespace: () => "u:123" },
|
|
77
|
+
persistenceStrategy: persistence,
|
|
78
|
+
persistence: { scope: "app:crm", mode: "fallback", stateVersion: 1 },
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
<div>componentes persistentes</div>
|
|
82
|
+
</SgEnvironmentProvider>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Para espelhar em ambos (`mirror`), troque `mode: "fallback"` por `mode: "mirror"` em `createCompositePersistenceStrategy` (é o que faz o sample `hybrid-local-rest`, com o mesmo problema de import).
|
|
88
|
+
|
|
89
|
+
## useSgEnvironment
|
|
90
|
+
|
|
91
|
+
### Lendo o ambiente fornecido
|
|
92
|
+
|
|
93
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-environment/samples/com-provider.tsx.sample` (type-check: OK).
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { SgEnvironmentProvider, useSgEnvironment } from "@seedgrid/fe-components";
|
|
97
|
+
|
|
98
|
+
function Consumer() {
|
|
99
|
+
const env = useSgEnvironment();
|
|
100
|
+
return <div>scope: {env.persistence.scope}</div>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default function App() {
|
|
104
|
+
return (
|
|
105
|
+
<SgEnvironmentProvider
|
|
106
|
+
value={{
|
|
107
|
+
namespaceProvider: { getNamespace: () => "user:42" },
|
|
108
|
+
persistence: { scope: "app:dashboard", mode: "strict", stateVersion: 3 },
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<Consumer />
|
|
112
|
+
</SgEnvironmentProvider>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## useSgPersistence
|
|
118
|
+
|
|
119
|
+
### load / save / clear sob demanda
|
|
120
|
+
|
|
121
|
+
Sem `SgEnvironmentProvider` o namespace padrão é vazio, portanto a chave é `null` e as três operações não fazem nada; para persistir de fato, envolva com um provider que tenha `namespaceProvider` (ver exemplo anterior).
|
|
122
|
+
|
|
123
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-persistence/samples/uso-basico.tsx.sample` (type-check: OK).
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { useSgPersistence } from "@seedgrid/fe-components";
|
|
127
|
+
|
|
128
|
+
export default function SaveOnAction() {
|
|
129
|
+
const persistence = useSgPersistence();
|
|
130
|
+
|
|
131
|
+
const handleSave = async () => {
|
|
132
|
+
await persistence.save("user:preferences", { theme: "dark", lang: "pt-BR" });
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleLoad = async () => {
|
|
136
|
+
const prefs = await persistence.load("user:preferences");
|
|
137
|
+
console.log(prefs);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const handleClear = async () => {
|
|
141
|
+
await persistence.clear("user:preferences");
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div>
|
|
146
|
+
<button onClick={handleSave}>Salvar</button>
|
|
147
|
+
<button onClick={handleLoad}>Carregar</button>
|
|
148
|
+
<button onClick={handleClear}>Limpar</button>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## useSgPersistentState
|
|
155
|
+
|
|
156
|
+
### Contador persistido
|
|
157
|
+
|
|
158
|
+
Sem provider, grava em `localStorage["app:counter"]`. `hydrated` indica que o valor salvo já foi carregado.
|
|
159
|
+
|
|
160
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-persistent-state/samples/uso-basico.tsx.sample` (type-check: OK).
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { useSgPersistentState } from "@seedgrid/fe-components";
|
|
164
|
+
|
|
165
|
+
export default function Counter() {
|
|
166
|
+
const { value, setValue, clear, hydrated } = useSgPersistentState({
|
|
167
|
+
baseKey: "app:counter",
|
|
168
|
+
defaultValue: 0,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div>
|
|
173
|
+
<span>{hydrated ? value : "..."}</span>
|
|
174
|
+
<button onClick={() => setValue((v) => v + 1)}>+1</button>
|
|
175
|
+
<button onClick={() => setValue((v) => v - 1)}>-1</button>
|
|
176
|
+
<button onClick={() => clear()}>Reset</button>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Isolamento por namespace (usuário)
|
|
183
|
+
|
|
184
|
+
Com provider, a chave vira `sg:user:<id>:app:crm:app:counter`.
|
|
185
|
+
|
|
186
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-persistent-state/samples/com-isolamento-por-namespace.tsx.sample` (type-check: OK).
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { SgEnvironmentProvider, useSgPersistentState } from "@seedgrid/fe-components";
|
|
190
|
+
|
|
191
|
+
function Counter() {
|
|
192
|
+
const { value, setValue } = useSgPersistentState({
|
|
193
|
+
baseKey: "app:counter",
|
|
194
|
+
defaultValue: 0,
|
|
195
|
+
});
|
|
196
|
+
return <button onClick={() => setValue((v) => v + 1)}>{value}</button>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export default function App({ userId }: { userId: string }) {
|
|
200
|
+
return (
|
|
201
|
+
<SgEnvironmentProvider
|
|
202
|
+
value={{
|
|
203
|
+
namespaceProvider: { getNamespace: () => `user:${userId}` },
|
|
204
|
+
persistence: { scope: "app:crm", mode: "fallback", stateVersion: 1 },
|
|
205
|
+
}}
|
|
206
|
+
>
|
|
207
|
+
<Counter />
|
|
208
|
+
</SgEnvironmentProvider>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### serialize / deserialize customizados
|
|
214
|
+
|
|
215
|
+
`serialize` só é aplicado quando há provider (sem provider o valor vai por `JSON.stringify`, que também converte `Date` em string ISO).
|
|
216
|
+
|
|
217
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-persistent-state/samples/serialize-e-deserialize-customizados.tsx.sample` (type-check: OK).
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import { useSgPersistentState } from "@seedgrid/fe-components";
|
|
221
|
+
|
|
222
|
+
export default function DatePicker() {
|
|
223
|
+
const { value: selectedDate, setValue } = useSgPersistentState<Date | null>({
|
|
224
|
+
baseKey: "app:selected-date",
|
|
225
|
+
defaultValue: null,
|
|
226
|
+
serialize: (date) => date?.toISOString() ?? null,
|
|
227
|
+
deserialize: (raw) => (typeof raw === "string" ? new Date(raw) : null),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<input
|
|
232
|
+
type="date"
|
|
233
|
+
value={selectedDate?.toISOString().slice(0, 10) ?? ""}
|
|
234
|
+
onChange={(e) => setValue(e.target.value ? new Date(e.target.value) : null)}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## SgRealtimeProvider
|
|
241
|
+
|
|
242
|
+
### Montagem no layout autenticado (com BFF)
|
|
243
|
+
|
|
244
|
+
Fonte: `apps/showcase/src/app/components/providers/sg-realtime-provider/samples/layout-com-bff.tsx.sample` (type-check: OK).
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
// app/(private)/layout.tsx — monte UMA vez, onde ja ha usuario logado.
|
|
248
|
+
"use client";
|
|
249
|
+
|
|
250
|
+
import { SgRealtimeProvider } from "@seedgrid/fe-components";
|
|
251
|
+
|
|
252
|
+
export default function PrivateLayout({ children }: { children: React.ReactNode }) {
|
|
253
|
+
// Pede o token a /api/realtime/connect (a BFF, mesma origem: vai o cookie da sessao),
|
|
254
|
+
// que repassa ao backend (POST /realtime/connect da seedgrid-quarkus-ext-realtime).
|
|
255
|
+
// O backend emite o token para o usuario DA SESSAO; o front conecta direto no Pulse.
|
|
256
|
+
return <SgRealtimeProvider channels={["backup"]}>{children}</SgRealtimeProvider>;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// app/api/realtime/connect/route.ts — a BFF so repassa, com o token da sessao.
|
|
260
|
+
//
|
|
261
|
+
// export async function POST() {
|
|
262
|
+
// const response = await backendFetch("/realtime/connect", { method: "POST" });
|
|
263
|
+
// return new Response(await response.text(), {
|
|
264
|
+
// status: response.status,
|
|
265
|
+
// headers: { "Content-Type": "application/json" },
|
|
266
|
+
// });
|
|
267
|
+
// }
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## useSgRealtimeEvent + useSgRealtimeStatus
|
|
271
|
+
|
|
272
|
+
### Aviso substitui o polling; polling volta quando não conectado
|
|
273
|
+
|
|
274
|
+
Fonte: `apps/showcase/src/app/components/providers/sg-realtime-provider/samples/polling-de-reserva.tsx.sample` (type-check: OK).
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import * as React from "react";
|
|
278
|
+
import { useSgRealtimeEvent, useSgRealtimeStatus } from "@seedgrid/fe-components";
|
|
279
|
+
|
|
280
|
+
// Tela de exports: o aviso do Pulse substitui o polling; o polling so volta quando o realtime
|
|
281
|
+
// nao esta conectado (desligado, Pulse fora, credencial revogada) E ha job em andamento.
|
|
282
|
+
export function ExportList({ jobs, reload }: { jobs: { status: string }[]; reload: () => void }) {
|
|
283
|
+
const { connected } = useSgRealtimeStatus();
|
|
284
|
+
const running = jobs.some((job) => job.status === "QUEUED" || job.status === "RUNNING");
|
|
285
|
+
|
|
286
|
+
useSgRealtimeEvent("backup", "backup.finished.*", () => reload());
|
|
287
|
+
|
|
288
|
+
React.useEffect(() => {
|
|
289
|
+
if (connected || !running) return undefined;
|
|
290
|
+
const timer = setInterval(reload, 15_000);
|
|
291
|
+
return () => clearInterval(timer);
|
|
292
|
+
}, [connected, running, reload]);
|
|
293
|
+
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Indicador de status
|
|
299
|
+
|
|
300
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-realtime-status/samples/uso-basico.tsx.sample` (type-check: OK).
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
import { useSgRealtimeStatus } from "@seedgrid/fe-components";
|
|
304
|
+
|
|
305
|
+
export function RealtimeBadge() {
|
|
306
|
+
const { status, connected } = useSgRealtimeStatus();
|
|
307
|
+
// connected === false: desligado, Pulse fora, reconectando ou credencial revogada.
|
|
308
|
+
// E o sinal para a tela voltar ao polling de reserva.
|
|
309
|
+
return <span>{connected ? "Ao vivo" : `Polling (${status})`}</span>;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Handler por padrão de evento
|
|
314
|
+
|
|
315
|
+
Fonte: `apps/showcase/src/app/components/hooks/use-sg-realtime-event/samples/uso-basico.tsx.sample` (type-check: OK).
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { useSgRealtimeEvent } from "@seedgrid/fe-components";
|
|
319
|
+
|
|
320
|
+
// Dentro de um SgRealtimeProvider com channels={["backup"]}.
|
|
321
|
+
export function ExportsNotices({ reload }: { reload: () => void }) {
|
|
322
|
+
// "backup.finished.*" casa backup.finished.success e backup.finished.error.
|
|
323
|
+
useSgRealtimeEvent("backup", "backup.finished.*", (event) => {
|
|
324
|
+
// event.data so traz identificadores ({ exportPublicId, status }):
|
|
325
|
+
// busque o registro pela API de sempre, onde a permissao e checada.
|
|
326
|
+
reload();
|
|
327
|
+
});
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Simulação completa sem rede (WebSocket de demonstração via `connectOptions.webSocketImpl` e `fetchToken` fixo): `apps/showcase/src/app/components/providers/sg-realtime-provider/samples/simulador.tsx.sample` (type-check: OK; não reproduzido aqui pelo tamanho).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, front, component, providers]
|
|
3
|
+
fonte: front/seedgrid-fe-components/packages/seedgrid-fe-components/src/environment, front/seedgrid-fe-components/packages/seedgrid-fe-components/src/realtime
|
|
4
|
+
branch: main
|
|
5
|
+
commit: ad30fc11de
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Providers de ambiente e realtime — visão geral
|
|
10
|
+
|
|
11
|
+
Este grupo reúne os dois providers "de aplicação" do `@seedgrid/fe-components`, montados uma vez perto da raiz da árvore React:
|
|
12
|
+
|
|
13
|
+
- **`SgEnvironmentProvider`** (`src/environment/`) — define *namespace* (ex.: usuário/tenant), *escopo* e a *estratégia de persistência* que os componentes SeedGrid usam para lembrar estado (posição de FAB/toolbar/dock-menu, layout do dock, cards recolhidos, menu etc.). Acompanha hooks (`useSgEnvironment`, `useSgPersistence`, `useSgPersistentState`…) e fábricas de estratégia (localStorage, API REST e composta).
|
|
14
|
+
- **`SgRealtimeProvider`** (`src/realtime/`) — conecta a tela ao SeedGrid Pulse para receber avisos em tempo real do usuário logado, com hooks `useSgRealtimeEvent` e `useSgRealtimeStatus` e degradação para *polling*.
|
|
15
|
+
|
|
16
|
+
- API completa: [[SeedGrid/SeedGrid-components/providers/API|API dos providers]]
|
|
17
|
+
- Exemplos: [[SeedGrid/SeedGrid-components/providers/Exemplos|Exemplos dos providers]]
|
|
18
|
+
- Fundamentos do pacote (instalação, i18n, `SgComponentsI18nProvider`, estilos): [[SeedGrid/SeedGrid-components/fundamentos/Visao-geral|Fundamentos]]
|
|
19
|
+
- Lado servidor do realtime: [[SeedGrid/Extensions/realtime/Visao-geral|extension realtime]]
|
|
20
|
+
|
|
21
|
+
Outros providers do pacote ficam nos grupos de origem: `SgTimeProvider` e `SgClockThemeProvider` em [[SeedGrid/SeedGrid-components/gadgets/API|gadgets]]; `SgComponentsI18nProvider` em [[SeedGrid/SeedGrid-components/fundamentos/API|fundamentos]].
|
|
22
|
+
|
|
23
|
+
## Componentes, hooks e funções
|
|
24
|
+
|
|
25
|
+
| Símbolo | Tipo | Exportado | Para que serve | Showcase |
|
|
26
|
+
|---|---|---|---|---|
|
|
27
|
+
| `SgEnvironmentProvider` | componente (provider) | sim | Fornece namespace, estratégia e configuração de persistência | `/components/providers/sg-environment-provider` |
|
|
28
|
+
| `useSgEnvironment` | hook | sim | Lê o ambiente (ou o padrão, sem provider) | `/components/hooks/use-sg-environment` |
|
|
29
|
+
| `useSgNamespaceProvider` | hook | sim | Atalho para `useSgEnvironment().namespaceProvider` | (página do provider) |
|
|
30
|
+
| `useSgPersistence` | hook | sim | `load`/`save`/`clear` com chave isolada por namespace e escopo | `/components/hooks/use-sg-persistence` |
|
|
31
|
+
| `useSgPersistentState` | hook | sim | "useState persistido" com hidratação assíncrona | `/components/hooks/use-sg-persistent-state` |
|
|
32
|
+
| `useHasSgEnvironmentProvider` | hook | não (interno) | Diz se há provider; usado por FAB, Card, Menu, ToolBar, DockMenu | — |
|
|
33
|
+
| `buildSgPersistenceKey` | função | sim | Monta a chave `sg:<namespace>[:<scope>]:<baseKey>` | — |
|
|
34
|
+
| `createLocalStorageStrategy` | função | sim | Estratégia sobre `window.localStorage` | — |
|
|
35
|
+
| `createApiPersistenceStrategy` | função | sim | Estratégia REST (`GET/POST/DELETE {baseUrl}/sg/persistence`) | — |
|
|
36
|
+
| `createCompositePersistenceStrategy` | função | sim | Combina primária + secundária (`strict`/`fallback`/`mirror`) | — |
|
|
37
|
+
| `readLocalPersistentState`, `writeLocalPersistentState`, `clearLocalPersistentState`, `resolvePersistedStateValue` | funções | sim | Helpers puros de estado persistido em `Storage` | — |
|
|
38
|
+
| `SgRealtimeProvider` | componente (provider) | sim | Conexão ao Pulse e distribuição de avisos | `/components/providers/sg-realtime-provider` |
|
|
39
|
+
| `useSgRealtimeEvent` | hook | sim | Registra handler por channel + padrão de evento | `/components/hooks/use-sg-realtime-event` |
|
|
40
|
+
| `useSgRealtimeStatus` | hook | sim | `{ status, connected }` para decidir aviso × polling | `/components/hooks/use-sg-realtime-status` |
|
|
41
|
+
| `matchesSgRealtimeEvent` | função | sim | Casa nome exato, `prefixo.*` ou `*` | — |
|
|
42
|
+
|
|
43
|
+
Tipos exportados: `NamespaceProvider`, `PersistenceStrategy`, `SgEnvironment`, `SgEnvironmentValue`, `SgPersistenceMode`, `SgPersistenceConfig`, `SgPersistenceRecordDTO`, `SgRealtimeProviderProps`, `SgRealtimeStatus`, `SgRealtimeEvent`, `SgRealtimeConnectResponse` (Confirmado em `src/index.ts`).
|
|
44
|
+
|
|
45
|
+
## Como funciona
|
|
46
|
+
|
|
47
|
+
### Ambiente e persistência (Confirmado — `src/environment/*.ts(x)`)
|
|
48
|
+
|
|
49
|
+
```mermaid
|
|
50
|
+
flowchart LR
|
|
51
|
+
P[SgEnvironmentProvider value] --> E[useSgEnvironment]
|
|
52
|
+
E --> PS[useSgPersistence]
|
|
53
|
+
PS -->|buildSgPersistenceKey| K["sg:namespace:scope:baseKey"]
|
|
54
|
+
PS --> S[persistenceStrategy.load/save/clear]
|
|
55
|
+
E -.sem provider.-> D[padrão: namespace vazio + localStorage]
|
|
56
|
+
PST[useSgPersistentState] -->|com provider| PS
|
|
57
|
+
PST -->|sem provider| LS[localStorage direto com baseKey]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- Sem provider, `useSgEnvironment()` devolve um ambiente padrão: `getNamespace: () => ""`, `createLocalStorageStrategy()`, `persistence = { scope: "app:unknown", mode: "fallback", stateVersion: 1 }`.
|
|
61
|
+
- `buildSgPersistenceKey` devolve `null` quando o namespace é vazio. Consequência: **com** `SgEnvironmentProvider` mas **sem** `namespaceProvider` que retorne algo, `useSgPersistence().load` retorna `null` e `save`/`clear` não fazem nada — a persistência fica desligada (Confirmado; coberto por `tests/providers-hooks.test.mjs` "returns null without namespace").
|
|
62
|
+
- `useSgPersistentState` sem provider grava direto em `localStorage` sob a própria `baseKey` (sem prefixo `sg:`), ignorando `serialize` ao gravar (Confirmado: `writeLocalPersistentState({ storage, baseKey, value })`).
|
|
63
|
+
- Componentes que consomem a persistência (Confirmado por import): `SgFloatActionButton`, `SgCard`, `SgMenu`, `SgToolBar`, `SgDockMenu` (via `useSgPersistence` + `useHasSgEnvironmentProvider`) e `SgDockLayout` (via `useSgPersistentState`). Também há menção em `SgDatatable` (grupo inputs, não analisado aqui).
|
|
64
|
+
- `persistence.mode` e `persistence.stateVersion` do ambiente ficam disponíveis para leitura em `useSgEnvironment().persistence` e no retorno de `useSgPersistence()`. O comportamento de persistência é definido pela estratégia: o modo efetivo é o `mode` passado a `createCompositePersistenceStrategy`, e a versão gravada no servidor é o `stateVersion` passado a `createApiPersistenceStrategy` (Confirmado).
|
|
65
|
+
|
|
66
|
+
### Realtime (Confirmado — `src/realtime/SgRealtimeProvider.tsx`)
|
|
67
|
+
|
|
68
|
+
```mermaid
|
|
69
|
+
sequenceDiagram
|
|
70
|
+
participant UI as SgRealtimeProvider
|
|
71
|
+
participant BFF as tokenEndpoint (POST)
|
|
72
|
+
participant Pulse as SeedGrid Pulse
|
|
73
|
+
UI->>BFF: POST /api/realtime/connect (credentials same-origin)
|
|
74
|
+
BFF-->>UI: { enabled, token, expiresAt, connectUrl }
|
|
75
|
+
alt enabled=false ou sem token
|
|
76
|
+
UI-->>UI: status = disabled
|
|
77
|
+
else
|
|
78
|
+
UI->>Pulse: PulseSubscriberClient.connect(getToken)
|
|
79
|
+
UI->>Pulse: subscribe({ channels })
|
|
80
|
+
Pulse-->>UI: message → listeners (useSgRealtimeEvent)
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- Usa `PulseSubscriberClient` de `@seedgrid/pulse-subscriber-react/core` (dependência direta do pacote, `^3.0.0`).
|
|
85
|
+
- Mapeamento de estado: `connected`/`subscribed` → `connected`; `connecting`, `reconnecting`, `auth-error`, `idle` mantidos; demais (`disconnected`, `error`) → `unavailable`. Falha no pedido do token → `unavailable`; resposta `enabled:false` → `disabled`.
|
|
86
|
+
- Reconexão: a cada nova conexão o provider pede um token novo (o primeiro é reaproveitado uma vez).
|
|
87
|
+
- Reconecta apenas quando mudam `enabled`, `channels` (comparado por `join(",")`) ou `pulseUrl`; `tokenEndpoint`, `tokenRequestInit`, `fetchToken` e `connectOptions` são lidos por *ref* (valor mais recente, sem reconectar).
|
|
88
|
+
|
|
89
|
+
## Dependências
|
|
90
|
+
|
|
91
|
+
- `react` (peer), `@seedgrid/pulse-subscriber-react` (dependência, só realtime).
|
|
92
|
+
- Persistência REST: o backend precisa expor `GET/POST/DELETE {baseUrl}/sg/persistence` com o contrato de `SgPersistenceRecordDTO` (ver [[SeedGrid/SeedGrid-components/providers/API|API]]). **Não confirmado** qual extension Java/Rust implementa essa rota — não foi verificado neste grupo.
|
|
93
|
+
- Realtime: rota de token (BFF) que repassa ao `POST /realtime/connect` da extension realtime (comentário do sample `layout-com-bff` e JSDoc de `SgRealtimeConnectResponse`).
|
|
94
|
+
|
|
95
|
+
## Testes existentes (não executados)
|
|
96
|
+
|
|
97
|
+
| Arquivo | Cobre |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `tests/providers-hooks.test.mjs` | `buildSgPersistenceKey` (incl. `null` sem namespace); `createLocalStorageStrategy`; `createCompositePersistenceStrategy` (fallback, mirror, strict); `createApiPersistenceStrategy` (fetcher injetado, erros determinísticos); helpers de persistent-state; `SgEnvironmentProvider` expondo sobrescritas; também `SgComponentsI18nProvider` e `SgTimeProvider` |
|
|
100
|
+
| `tests/providers-hooks-dom.test.mjs` | `useSgPersistentState` com localStorage e com estratégia do provider (hidratação e `clear`) |
|
|
101
|
+
| `tests/realtime-dom.test.mjs` | conexão com token e entrega ao handler (filtro por channel/evento); backend desligado → `disabled`; token 401/503 → `unavailable`; credencial revogada (4403) → `auth-error` sem reconectar; sem provider → `disabled`; `matchesSgRealtimeEvent` |
|
|
102
|
+
|
|
103
|
+
## Limitações e pontos de atenção
|
|
104
|
+
|
|
105
|
+
- Nomes de channel com vírgula quebrariam a assinatura (o provider serializa/deserializa `channels` com `","`) — Inferência a partir de `channelsKey.split(",")`.
|
|
106
|
+
- Fora de `SgRealtimeProvider`, `useSgRealtimeEvent` não faz nada e `useSgRealtimeStatus` devolve `disabled`.
|