@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.
Files changed (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -2
  3. package/dist/adapters/claude.js +114 -0
  4. package/dist/adapters/codex.js +108 -0
  5. package/dist/adapters/index.js +17 -0
  6. package/dist/adapters/shared.js +142 -0
  7. package/dist/adapters/types.js +1 -0
  8. package/dist/cli.js +203 -0
  9. package/dist/commands/common.js +98 -0
  10. package/dist/commands/doctor.js +290 -0
  11. package/dist/commands/init.js +9 -0
  12. package/dist/commands/install.js +107 -0
  13. package/dist/commands/remove.js +54 -0
  14. package/dist/commands/review.js +127 -0
  15. package/dist/commands/status.js +73 -0
  16. package/dist/commands/update.js +8 -0
  17. package/dist/commands/validate.js +27 -0
  18. package/dist/core/apply.js +181 -0
  19. package/dist/core/blocks.js +64 -0
  20. package/dist/core/content.js +528 -0
  21. package/dist/core/env.js +40 -0
  22. package/dist/core/frontmatter.js +29 -0
  23. package/dist/core/hash.js +14 -0
  24. package/dist/core/inspect.js +51 -0
  25. package/dist/core/lock.js +124 -0
  26. package/dist/core/paths.js +65 -0
  27. package/dist/core/plan.js +242 -0
  28. package/dist/core/tools.js +62 -0
  29. package/dist/core/types.js +11 -0
  30. package/dist/core/updates.js +121 -0
  31. package/docs/arquitetura.md +80 -0
  32. package/docs/compatibilidade.md +50 -0
  33. package/docs/formato.md +155 -0
  34. package/docs/instalacao.md +105 -0
  35. package/docs/manutencao.md +115 -0
  36. package/package.json +43 -4
  37. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
  38. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
  39. package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
  40. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
  41. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
  42. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
  43. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
  44. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
  45. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
  46. package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
  47. package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
  48. package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
  49. package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
  50. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
  51. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
  52. package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
  53. package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
  54. package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
  55. package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
  56. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
  57. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
  58. package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
  59. package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
  60. package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
  61. package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
  62. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
  63. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
  64. package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
  65. package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
  66. package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
  67. package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
  68. package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
  69. package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
  70. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
  71. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
  72. package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
  73. package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
  74. package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
  75. package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
  76. package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
  77. package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
  78. package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
  79. package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
  80. package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
  81. package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
  82. package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
  83. package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
  84. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
  85. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
  86. package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
  87. package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
  88. package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
  89. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
  90. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
  91. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
  92. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
  93. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
  94. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
  95. package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
  96. package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
  97. package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
  98. package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
  99. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
  100. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
  101. package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
  102. package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
  103. package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
  104. package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
  105. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
  106. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
  107. package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
  108. package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
  109. package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
  110. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
  111. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
  112. package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
  113. package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
  114. package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
  115. package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
  116. package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
  117. package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
  118. package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
  119. package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
  120. package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
  121. package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
  122. package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
  123. package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
  124. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
  125. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
  126. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
  127. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
  128. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
  129. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
  130. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
  131. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
  132. package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
  133. package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
  134. package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
  135. package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
  136. package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
  137. package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
  138. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
  139. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
  140. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
  141. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
  142. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
  143. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
  144. package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
  145. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
  146. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
  147. package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
  148. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
  149. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
  150. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
  151. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
  152. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
  153. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
  154. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
  155. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
  156. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
  157. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
  158. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
  159. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
  160. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
  161. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
  162. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
  163. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
  164. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
  165. package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
  166. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
  167. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
  168. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
  169. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
  170. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
  171. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
  172. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
  173. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
  174. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
  175. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
  176. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
  177. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
  178. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
  179. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
  180. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
  181. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
  182. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
  183. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
  184. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
  185. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
  186. package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
  187. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
  188. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
  189. package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
  190. package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
  191. package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
  192. package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
  193. package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
  194. package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
  195. package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
  196. package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
  197. package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
  198. package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
  199. package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
  200. package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
  201. package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
  202. package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
  203. package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
  204. package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
  205. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
  206. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
  207. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
  208. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
  209. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
  210. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
  211. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
  212. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
  213. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
  214. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
  215. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
  216. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
  217. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
  218. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
  219. package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
  220. package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
  221. package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
  222. package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
  223. package/seedgridKB/SeedGrid/Versoes.md +64 -0
  224. package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
  225. 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`.