forlogic-core 1.16.3 → 1.16.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -109
- package/dist/README.md +113 -109
- package/dist/components/modules/AccessDeniedDialog.d.ts +41 -0
- package/dist/components/modules/ModuleAccessGuard.d.ts +3 -1
- package/dist/components/modules/ModuleOfferContent.d.ts +20 -0
- package/dist/components/modules/ModulesContent.d.ts +15 -0
- package/dist/components/modules/ModulesFooterCards.d.ts +6 -0
- package/dist/components/modules/index.d.ts +8 -0
- package/dist/components/modules/types.d.ts +2 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/docs/DESIGN_SYSTEM.md +17 -32
- package/package.json +4 -2
- package/dist/assets/AccordionDoc-BnfxyOi9.js +0 -31
- package/dist/assets/ActionButtonDoc-b4F_J8gn.js +0 -47
- package/dist/assets/AlertDoc-PkiHguSJ.js +0 -37
- package/dist/assets/AppHeaderDoc-CsFMZGV0.js +0 -67
- package/dist/assets/AppSidebarDoc-Bg71N-zq.js +0 -196
- package/dist/assets/AuthDoc-DDm57y_J.js +0 -192
- package/dist/assets/AvatarDoc-C6wiZIZR.js +0 -11
- package/dist/assets/BadgeDoc-Bsg7cfm0.js +0 -36
- package/dist/assets/BaseFormDoc-DeIlV273.js +0 -169
- package/dist/assets/BodyContentDoc-Q3DGvyN9.js +0 -83
- package/dist/assets/BreadcrumbDoc-ChsVFjMF.js +0 -75
- package/dist/assets/ButtonDoc-C7Q31Bh3.js +0 -41
- package/dist/assets/ButtonGroupDoc-Bn5vhjBq.js +0 -7
- package/dist/assets/CalendarDoc-iVjNyxyr.js +0 -81
- package/dist/assets/CardDoc-D511dll7.js +0 -49
- package/dist/assets/ChartDoc-CQyYOEHL.js +0 -111
- package/dist/assets/CheckboxDoc-Cjsy4XAq.js +0 -55
- package/dist/assets/ColorPickerDoc-hnYJUWpF.js +0 -10
- package/dist/assets/ColorsFoundationDoc-B8Z4tAyZ.js +0 -13
- package/dist/assets/ComboTreeDoc-ChEbW4a3.js +0 -21
- package/dist/assets/ComboboxDoc-CHWeGE_F.js +0 -134
- package/dist/assets/ComponentDocTemplate-BtOCnlM2.js +0 -1
- package/dist/assets/ContextMenuDoc-C3mFO_Yx.js +0 -182
- package/dist/assets/ContextsDoc-ChEbQxom.js +0 -184
- package/dist/assets/CreateCrudPageDoc-C9tXisCF.js +0 -106
- package/dist/assets/CrudActionBarDoc-Cp1L4gpO.js +0 -112
- package/dist/assets/CrudGridDoc-D-kSFBAQ.js +0 -85
- package/dist/assets/CrudOverviewDoc-CeLBwg-B.js +0 -14
- package/dist/assets/CrudPrimitivesDoc-B2u1vZog.js +0 -164
- package/dist/assets/CrudTableDoc-CvV-II_X.js +0 -95
- package/dist/assets/DataListDoc-BLRii0jB.js +0 -13
- package/dist/assets/DesignSystemHome-TE0Ubaup.js +0 -1
- package/dist/assets/DialogDoc--LC5Jvat.js +0 -981
- package/dist/assets/DropdownMenuDoc-oPlEriRY.js +0 -175
- package/dist/assets/EmptyStateDoc-rNqfWKok.js +0 -35
- package/dist/assets/EnvironmentsDoc-CT7l5s2u.js +0 -96
- package/dist/assets/ErrorBoundaryDoc-rPHOUygA.js +0 -111
- package/dist/assets/ExampleCard-DfuMYM6E.js +0 -1
- package/dist/assets/FormDoc-B0L_QaCT.js +0 -81
- package/dist/assets/FoundationOverview-Dbb8rBsU.js +0 -1
- package/dist/assets/GridDoc-ifcGA2Yw.js +0 -28
- package/dist/assets/HooksDoc-CUOT_3Du.js +0 -665
- package/dist/assets/HoverCardDoc-CdTU2QkI.js +0 -31
- package/dist/assets/I18nDoc-CMEvFqsz.js +0 -232
- package/dist/assets/IconPickerDoc-DF9hEwnJ.js +0 -10
- package/dist/assets/IconsFoundationDoc-D4Y0wKbm.js +0 -33
- package/dist/assets/InputDoc-d_IL4dsq.js +0 -211
- package/dist/assets/LabelDoc-Dr64ISiJ.js +0 -42
- package/dist/assets/LeadershipDoc-BnrTuaeV.js +0 -416
- package/dist/assets/MediaDoc-CLuVprAr.js +0 -459
- package/dist/assets/MenubarDoc-CW7L4QJ4.js +0 -165
- package/dist/assets/ModulesDialogDoc-CUb_g4X-.js +0 -71
- package/dist/assets/NavigationMenuDoc-Csc0U6bV.js +0 -116
- package/dist/assets/OnboardingDialogDoc-3RtjNH1O.js +0 -55
- package/dist/assets/PaginationDoc-BGurD4xQ.js +0 -27
- package/dist/assets/PaginationDoc-DqFyou6O.js +0 -98
- package/dist/assets/PlacesDoc-Dyx8gsqb.js +0 -226
- package/dist/assets/PopoverDoc-DHF-ItUX.js +0 -64
- package/dist/assets/ProgressDoc-DXKV-fkI.js +0 -29
- package/dist/assets/QualiexUserFieldDoc-BbP7w-Pu.js +0 -149
- package/dist/assets/RadioGroupDoc-D845uweM.js +0 -57
- package/dist/assets/RadiusDoc-vN4tTsay.js +0 -7
- package/dist/assets/RequiredFieldsCounterDoc-TzR9r-U9.js +0 -58
- package/dist/assets/ResizableDoc-Bkfz_25O.js +0 -104
- package/dist/assets/RichTextEditorDoc-BUQrg7M8.js +0 -24
- package/dist/assets/ScrollAreaDoc-B6ODYHMX.js +0 -28
- package/dist/assets/SecurityDoc-Chbt6w1s.js +0 -204
- package/dist/assets/SelectDoc-BhcpBIAO.js +0 -80
- package/dist/assets/SeparatorDoc-C3fhatb0.js +0 -4
- package/dist/assets/ServicesDoc-_uao-HA_.js +0 -308
- package/dist/assets/ShadowsDoc-DpkO_TZQ.js +0 -9
- package/dist/assets/SignDoc-BJtnoT6I.js +0 -66
- package/dist/assets/SkeletonDoc-BZS07PJh.js +0 -54
- package/dist/assets/SliderDoc-D2ApV3XT.js +0 -41
- package/dist/assets/SpacingDoc-PNrU24B2.js +0 -12
- package/dist/assets/SplitButtonDoc-D5tUF2Ja.js +0 -53
- package/dist/assets/StepSelectorDoc-Cj0ALYar.js +0 -41
- package/dist/assets/SwitchDoc-DtsT8oh_.js +0 -56
- package/dist/assets/TableDoc-BC-jQnXu.js +0 -128
- package/dist/assets/TableOfContents-DBMJMbI4.js +0 -1
- package/dist/assets/TabsDoc-DtXJ0xY5.js +0 -42
- package/dist/assets/TextareaDoc-nuW5tqBQ.js +0 -46
- package/dist/assets/ToastDoc-D1aX5zda.js +0 -157
- package/dist/assets/ToggleDoc-ILass4CS.js +0 -51
- package/dist/assets/TooltipDoc-lPbdWe_9.js +0 -58
- package/dist/assets/TruncatedCellDoc-DOAzbF2F.js +0 -12
- package/dist/assets/TypographyFoundationDoc-3ZD-rQZw.js +0 -7
- package/dist/assets/UtilitiesDoc-D7lkYhuz.js +0 -145
- package/dist/assets/blocks-Jy49RoqJ.js +0 -1
- package/dist/assets/calendar-days-Cvf2zLJl.js +0 -1
- package/dist/assets/circle-plus-MnG9kjyq.js +0 -1
- package/dist/assets/circle-x-B9ouupla.js +0 -1
- package/dist/assets/crown-BweN5jpI.js +0 -1
- package/dist/assets/date-picker-ttyYeYvC.js +0 -1
- package/dist/assets/disabled-menu-item-WlpPOqxg.js +0 -1
- package/dist/assets/drawer-DvU6_eK5.js +0 -3
- package/dist/assets/file-pen-line-C0VV-QjF.js +0 -1
- package/dist/assets/git-branch-DCjGGwvF.js +0 -1
- package/dist/assets/globe-BdFDFP_k.js +0 -1
- package/dist/assets/grip-vertical-CgXp0oI-.js +0 -1
- package/dist/assets/hash-BAYi_wfk.js +0 -1
- package/dist/assets/index-BtX5DZqb.js +0 -310
- package/dist/assets/index-C1So5Sai.css +0 -1
- package/dist/assets/life-buoy-BydIgTyJ.js +0 -1
- package/dist/assets/lucide-react-ZIMhRYmb.js +0 -1
- package/dist/assets/monitor-B6txWJPg.js +0 -1
- package/dist/assets/package-DNe3FsCh.js +0 -1
- package/dist/assets/pen-CzTmQ16z.js +0 -1
- package/dist/assets/pin-CJJgLEBz.js +0 -1
- package/dist/assets/radio-group-Btv_BY60.js +0 -1
- package/dist/assets/server-XQDXtrjm.js +0 -1
- package/dist/assets/share-2-Dz_89MJb.js +0 -1
- package/dist/assets/step-selector-D0_Y1dow.js +0 -1
- package/dist/assets/text-align-start-WsHo7CNJ.js +0 -1
- package/dist/assets/trash-CeK-mWnM.js +0 -1
- package/dist/assets/useMockCrud-RV9z9n5x.js +0 -1
- package/dist/assets/user-check-CrbWcnPN.js +0 -1
- package/dist/assets/user-plus-Dce9DbqQ.js +0 -1
- package/dist/index.html +0 -35
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import{j as e,C as s,B as r,aq as n,aA as c,b7 as d,aC as l,bZ as o,ba as p,bB as m,bd as u}from"./index-BtX5DZqb.js";import{C as g}from"./ComponentDocTemplate-BtOCnlM2.js";import{S as f}from"./server-XQDXtrjm.js";import{G as x}from"./globe-BdFDFP_k.js";import"./ExampleCard-DfuMYM6E.js";import"./TableOfContents-DBMJMbI4.js";function h(){return e.jsx("div",{className:"space-y-6",children:e.jsxs("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-4",children:[e.jsxs(s,{className:"p-4 border-2",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-2",children:[e.jsx("div",{className:"p-2 rounded-lg bg-green-500/10",children:e.jsx(o,{className:"h-5 w-5 text-green-500"})}),e.jsx("h4",{className:"font-semibold",children:"CSP"})]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Content Security Policy para prevenir XSS e injeção de código"})]}),e.jsxs(s,{className:"p-4 border-2",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-2",children:[e.jsx("div",{className:"p-2 rounded-lg bg-blue-500/10",children:e.jsx(x,{className:"h-5 w-5 text-blue-500"})}),e.jsx("h4",{className:"font-semibold",children:"CORS"})]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Controle de origens confiáveis sem usar wildcards inseguros"})]}),e.jsxs(s,{className:"p-4 border-2",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-2",children:[e.jsx("div",{className:"p-2 rounded-lg bg-orange-500/10",children:e.jsx(m,{className:"h-5 w-5 text-orange-500"})}),e.jsx("h4",{className:"font-semibold",children:"HSTS"})]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Força HTTPS com preload e inclusão de subdomínios"})]}),e.jsxs(s,{className:"p-4 border-2",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-2",children:[e.jsx("div",{className:"p-2 rounded-lg bg-purple-500/10",children:e.jsx(u,{className:"h-5 w-5 text-purple-500"})}),e.jsx("h4",{className:"font-semibold",children:"Headers OWASP"})]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Headers recomendados pela OWASP para proteção adicional"})]})]})})}function v(){const i=[{name:"Strict-Transport-Security",value:"max-age=31536000; includeSubDomains; preload",desc:"Força HTTPS por 1 ano"},{name:"X-Content-Type-Options",value:"nosniff",desc:"Previne MIME sniffing"},{name:"X-Frame-Options",value:"DENY",desc:"Bloqueia iframe embedding"},{name:"X-XSS-Protection",value:"1; mode=block",desc:"Filtro XSS do navegador"},{name:"Referrer-Policy",value:"strict-origin-when-cross-origin",desc:"Controla vazamento de referrer"},{name:"Permissions-Policy",value:"camera=(), microphone=()...",desc:"Desabilita APIs sensíveis"}];return e.jsxs(s,{className:"p-4 bg-muted/50",children:[e.jsxs("h4",{className:"font-semibold mb-3 flex items-center gap-2",children:[e.jsx(f,{className:"h-4 w-4"}),"Headers de Segurança Aplicados"]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b",children:[e.jsx("th",{className:"text-left py-2 px-3 font-medium",children:"Header"}),e.jsx("th",{className:"text-left py-2 px-3 font-medium",children:"Valor"}),e.jsx("th",{className:"text-left py-2 px-3 font-medium",children:"Proteção"})]})}),e.jsx("tbody",{className:"divide-y",children:i.map((a,t)=>e.jsxs("tr",{children:[e.jsx("td",{className:"py-2 px-3",children:e.jsx("code",{className:"text-xs",children:a.name})}),e.jsx("td",{className:"py-2 px-3 text-muted-foreground text-xs font-mono",children:a.value}),e.jsx("td",{className:"py-2 px-3 text-muted-foreground text-xs",children:a.desc})]},t))})]})})]})}function j(){const i=[{name:"default-src",value:"'self'",prod:!0,dev:!0},{name:"script-src",value:"'self' + CDNs",prod:!0,dev:!0},{name:"style-src",value:"'self' + fonts",prod:!0,dev:!0},{name:"connect-src",value:"'self' + Supabase",prod:!0,dev:!0},{name:"img-src",value:"'self' data: https:",prod:!0,dev:!0},{name:"frame-ancestors",value:"'self' lovable.dev",prod:!0,dev:!0},{name:"upgrade-insecure-requests",value:"(automático)",prod:!0,dev:!1},{name:"require-trusted-types-for",value:"'script'",prod:!0,dev:!1}];return e.jsxs(s,{className:"p-4 space-y-3",children:[e.jsxs("h4",{className:"font-medium flex items-center gap-2",children:[e.jsx(p,{className:"h-4 w-4"}),"Diretivas CSP"]}),e.jsx("div",{className:"space-y-2",children:i.map((a,t)=>e.jsxs("div",{className:"flex items-center justify-between text-sm py-1 border-b last:border-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("code",{className:"text-xs bg-muted px-1 rounded",children:a.name}),e.jsx("span",{className:"text-muted-foreground text-xs",children:a.value})]}),e.jsxs("div",{className:"flex gap-1",children:[a.prod&&e.jsx(r,{variant:"secondary",className:"text-[10px]",children:"PROD"}),a.dev&&e.jsx(r,{variant:"outline",className:"text-[10px]",children:"DEV"})]})]},t))})]})}function O(){return e.jsx(g,{title:"Segurança (Vite Config)",description:"Plugin de segurança para Vite que aplica headers OWASP, CSP configurável, CORS seguro e proteções contra ataques comuns. Configuração centralizada para todos os projetos Forlogic.",installation:`// vite.config.ts
|
|
2
|
-
import { defineConfig } from 'vite';
|
|
3
|
-
import react from '@vitejs/plugin-react-swc';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { createForlogicViteConfig } from 'forlogic-core/vite';
|
|
6
|
-
|
|
7
|
-
const forlogicConfig = createForlogicViteConfig({
|
|
8
|
-
security: {
|
|
9
|
-
supabaseUrls: ['https://seu-projeto.supabase.co'],
|
|
10
|
-
trustedOrigins: ['https://seu-app.com'],
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export default defineConfig(({ mode }) => {
|
|
15
|
-
const isDev = mode === 'development';
|
|
16
|
-
const baseConfig = forlogicConfig(isDev);
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
...baseConfig,
|
|
20
|
-
plugins: [react(), ...baseConfig.plugins],
|
|
21
|
-
resolve: {
|
|
22
|
-
alias: {
|
|
23
|
-
'@': path.resolve(__dirname, './src'),
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
});`,component:e.jsx(h,{}),usage:`// Importar do módulo /vite
|
|
28
|
-
import {
|
|
29
|
-
createForlogicViteConfig,
|
|
30
|
-
createSecurityHeadersPlugin,
|
|
31
|
-
defaultForlogicViteConfig
|
|
32
|
-
} from 'forlogic-core/vite';
|
|
33
|
-
|
|
34
|
-
// Opção 1: Configuração completa (recomendado)
|
|
35
|
-
const forlogicConfig = createForlogicViteConfig({
|
|
36
|
-
security: { ... },
|
|
37
|
-
server: { port: 3000 },
|
|
38
|
-
build: { sourcemap: true },
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Opção 2: Apenas plugin de segurança
|
|
42
|
-
const securityPlugin = createSecurityHeadersPlugin(isDev, {
|
|
43
|
-
supabaseUrls: ['https://xyz.supabase.co'],
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Opção 3: Configuração padrão mínima
|
|
47
|
-
const baseConfig = defaultForlogicViteConfig(isDev);`,examples:[{title:"Headers de Segurança OWASP",description:"Headers aplicados automaticamente seguindo recomendações OWASP",preview:e.jsx(v,{}),code:`// Headers aplicados automaticamente pelo plugin:
|
|
48
|
-
|
|
49
|
-
// HSTS - Força HTTPS por 1 ano
|
|
50
|
-
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload'
|
|
51
|
-
|
|
52
|
-
// Previne MIME type sniffing
|
|
53
|
-
'X-Content-Type-Options': 'nosniff'
|
|
54
|
-
|
|
55
|
-
// Bloqueia embedding em iframes (proteção clickjacking)
|
|
56
|
-
'X-Frame-Options': 'DENY'
|
|
57
|
-
|
|
58
|
-
// Ativa filtro XSS do navegador
|
|
59
|
-
'X-XSS-Protection': '1; mode=block'
|
|
60
|
-
|
|
61
|
-
// Controla vazamento de informações via referrer
|
|
62
|
-
'Referrer-Policy': 'strict-origin-when-cross-origin'
|
|
63
|
-
|
|
64
|
-
// Desabilita APIs potencialmente perigosas
|
|
65
|
-
'Permissions-Policy': 'camera=(), microphone=(), geolocation=(), fullscreen=(self), payment=(), display-capture=()'`},{title:"Content Security Policy (CSP)",description:"Política de segurança de conteúdo configurável por ambiente",preview:e.jsx(j,{}),code:`// CSP gerado automaticamente baseado no ambiente
|
|
66
|
-
|
|
67
|
-
// DESENVOLVIMENTO: Permite HMR e eval do Vite
|
|
68
|
-
"script-src 'self' https://cdn.gpteng.co 'unsafe-inline' 'unsafe-eval'"
|
|
69
|
-
"style-src 'self' https://fonts.googleapis.com 'unsafe-inline'"
|
|
70
|
-
|
|
71
|
-
// PRODUÇÃO: CSP estrito
|
|
72
|
-
"script-src 'self' https://cdn.gpteng.co"
|
|
73
|
-
"style-src 'self' https://fonts.googleapis.com"
|
|
74
|
-
"require-trusted-types-for 'script'"
|
|
75
|
-
"upgrade-insecure-requests"
|
|
76
|
-
|
|
77
|
-
// Customizar via opções:
|
|
78
|
-
createForlogicViteConfig({
|
|
79
|
-
security: {
|
|
80
|
-
additionalScriptSrc: ['https://cdn.minha-lib.com'],
|
|
81
|
-
additionalStyleSrc: ['https://fonts.custom.com'],
|
|
82
|
-
additionalConnectSrc: ['https://api.terceiros.com'],
|
|
83
|
-
cspReportUri: 'https://meu-app.com/csp-report',
|
|
84
|
-
enableTrustedTypes: true,
|
|
85
|
-
upgradeInsecureRequests: true,
|
|
86
|
-
}
|
|
87
|
-
});`},{title:"CORS Seguro",description:"Controle de origens sem usar wildcards (*) com credenciais",preview:e.jsxs(s,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"Origens Confiáveis Padrão:"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(r,{variant:"secondary",children:"lovableproject.com"}),e.jsx(r,{variant:"secondary",children:"lovable.dev"}),e.jsx(r,{variant:"outline",children:"localhost:* (dev)"})]})]}),e.jsx(n,{}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"font-medium text-sm",children:"Origens Customizadas:"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(r,{children:"seu-app.com"}),e.jsx(r,{children:"admin.seu-app.com"})]})]})]}),code:`// CORS seguro - nunca usa '*' com credenciais
|
|
88
|
-
|
|
89
|
-
createForlogicViteConfig({
|
|
90
|
-
security: {
|
|
91
|
-
trustedOrigins: [
|
|
92
|
-
'https://seu-app.com',
|
|
93
|
-
'https://admin.seu-app.com',
|
|
94
|
-
'https://*.subdominio.com', // Suporte a wildcards
|
|
95
|
-
],
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Headers CORS aplicados quando origem é confiável:
|
|
100
|
-
'Access-Control-Allow-Origin': origin // Origem específica, nunca '*'
|
|
101
|
-
'Access-Control-Allow-Credentials': 'true'
|
|
102
|
-
'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS'
|
|
103
|
-
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type, x-csrf-token, x-nonce'
|
|
104
|
-
'Access-Control-Max-Age': '86400'
|
|
105
|
-
'Vary': 'Origin'
|
|
106
|
-
|
|
107
|
-
// ⚠️ Origens não confiáveis são bloqueadas e logadas:
|
|
108
|
-
// 🚨 CORS BLOCKED: Untrusted origin attempted access: https://malicious.com`},{title:"Opções Completas de Configuração",description:"Todas as opções disponíveis para personalização",preview:e.jsxs(s,{className:"p-4 space-y-3",children:[e.jsx("h4",{className:"font-medium",children:"ForlogicViteOptions:"}),e.jsxs("div",{className:"text-sm space-y-2",children:[e.jsxs("div",{className:"flex justify-between py-1 border-b",children:[e.jsx("code",{className:"text-xs",children:"security"}),e.jsx("span",{className:"text-muted-foreground text-xs",children:"SecurityHeadersOptions"})]}),e.jsxs("div",{className:"flex justify-between py-1 border-b",children:[e.jsx("code",{className:"text-xs",children:"server"}),e.jsx("span",{className:"text-muted-foreground text-xs",children:"{ host, port }"})]}),e.jsxs("div",{className:"flex justify-between py-1 border-b",children:[e.jsx("code",{className:"text-xs",children:"build"}),e.jsx("span",{className:"text-muted-foreground text-xs",children:"{ chunkSizeWarningLimit, sourcemap }"})]}),e.jsxs("div",{className:"flex justify-between py-1 border-b",children:[e.jsx("code",{className:"text-xs",children:"additionalPlugins"}),e.jsx("span",{className:"text-muted-foreground text-xs",children:"VitePlugin[]"})]}),e.jsxs("div",{className:"flex justify-between py-1",children:[e.jsx("code",{className:"text-xs",children:"disableSecurity"}),e.jsx("span",{className:"text-muted-foreground text-xs",children:"boolean (não recomendado)"})]})]})]}),code:`import { createForlogicViteConfig } from 'forlogic-core/vite';
|
|
109
|
-
|
|
110
|
-
const forlogicConfig = createForlogicViteConfig({
|
|
111
|
-
// Configurações de segurança
|
|
112
|
-
security: {
|
|
113
|
-
supabaseUrls: ['https://xyz.supabase.co'],
|
|
114
|
-
trustedOrigins: ['https://meu-app.com'],
|
|
115
|
-
additionalScriptSrc: [],
|
|
116
|
-
additionalStyleSrc: [],
|
|
117
|
-
additionalConnectSrc: ['https://api.terceiros.com'],
|
|
118
|
-
cspReportUri: 'https://meu-app.com/csp-violations',
|
|
119
|
-
enableTrustedTypes: true,
|
|
120
|
-
upgradeInsecureRequests: true,
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
// Configurações do servidor dev
|
|
124
|
-
server: {
|
|
125
|
-
host: '::',
|
|
126
|
-
port: 8080,
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
// Configurações de build
|
|
130
|
-
build: {
|
|
131
|
-
chunkSizeWarningLimit: 4000,
|
|
132
|
-
sourcemap: true,
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
// Plugins Vite adicionais
|
|
136
|
-
additionalPlugins: [],
|
|
137
|
-
|
|
138
|
-
// ⚠️ Desabilitar segurança (NÃO RECOMENDADO)
|
|
139
|
-
disableSecurity: false,
|
|
140
|
-
});`},{title:"Exemplo Completo vite.config.ts",description:"Configuração completa pronta para uso em produção",preview:e.jsxs(c,{children:[e.jsx(d,{className:"h-4 w-4 text-green-500"}),e.jsx(l,{children:e.jsxs("div",{className:"space-y-1 text-sm",children:[e.jsx("p",{className:"font-medium",children:"Configuração pronta para produção:"}),e.jsx("p",{children:"• Headers OWASP aplicados automaticamente"}),e.jsx("p",{children:"• CSP estrito em produção"}),e.jsx("p",{children:"• CORS seguro sem wildcards"}),e.jsx("p",{children:"• Trusted Types habilitado"})]})})]}),code:`// vite.config.ts
|
|
141
|
-
import { defineConfig } from 'vite';
|
|
142
|
-
import react from '@vitejs/plugin-react-swc';
|
|
143
|
-
import path from 'path';
|
|
144
|
-
import { createForlogicViteConfig } from 'forlogic-core/vite';
|
|
145
|
-
|
|
146
|
-
const forlogicConfig = createForlogicViteConfig({
|
|
147
|
-
security: {
|
|
148
|
-
supabaseUrls: [
|
|
149
|
-
'https://tskpcuganynhsppzoqgj.supabase.co',
|
|
150
|
-
'https://ccjfvpnndclajkleyqkc.supabase.co',
|
|
151
|
-
],
|
|
152
|
-
trustedOrigins: [
|
|
153
|
-
'https://meu-app.lovable.app',
|
|
154
|
-
'https://meu-dominio.com',
|
|
155
|
-
],
|
|
156
|
-
additionalConnectSrc: [
|
|
157
|
-
'https://api.qualiex.com',
|
|
158
|
-
],
|
|
159
|
-
},
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
export default defineConfig(({ mode }) => {
|
|
163
|
-
const isDev = mode === 'development';
|
|
164
|
-
const baseConfig = forlogicConfig(isDev);
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
...baseConfig,
|
|
168
|
-
plugins: [react(), ...baseConfig.plugins],
|
|
169
|
-
resolve: {
|
|
170
|
-
alias: {
|
|
171
|
-
// ⚠️ IMPORTANTE: Usar path.resolve() para caminhos absolutos
|
|
172
|
-
'@': path.resolve(__dirname, './src'),
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
// Sobrescrever configurações se necessário
|
|
176
|
-
server: {
|
|
177
|
-
...baseConfig.server,
|
|
178
|
-
port: 3000, // Porta customizada
|
|
179
|
-
},
|
|
180
|
-
// Forçar re-bundle de dependências
|
|
181
|
-
optimizeDeps: {
|
|
182
|
-
force: true,
|
|
183
|
-
},
|
|
184
|
-
};
|
|
185
|
-
});`},{title:"Apenas Plugin de Segurança",description:"Usar somente o plugin de headers sem a configuração completa",preview:e.jsxs(s,{className:"p-4 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(o,{className:"h-5 w-5 text-green-500"}),e.jsx("span",{className:"font-medium",children:"createSecurityHeadersPlugin"})]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Use quando você já tem uma configuração Vite e quer adicionar apenas os headers de segurança."})]}),code:`// vite.config.ts existente
|
|
186
|
-
import { defineConfig } from 'vite';
|
|
187
|
-
import react from '@vitejs/plugin-react-swc';
|
|
188
|
-
import { createSecurityHeadersPlugin } from 'forlogic-core/vite';
|
|
189
|
-
|
|
190
|
-
export default defineConfig(({ mode }) => {
|
|
191
|
-
const isDev = mode === 'development';
|
|
192
|
-
|
|
193
|
-
return {
|
|
194
|
-
plugins: [
|
|
195
|
-
react(),
|
|
196
|
-
// Adicionar apenas o plugin de segurança
|
|
197
|
-
createSecurityHeadersPlugin(isDev, {
|
|
198
|
-
supabaseUrls: ['https://xyz.supabase.co'],
|
|
199
|
-
trustedOrigins: ['https://meu-app.com'],
|
|
200
|
-
}),
|
|
201
|
-
],
|
|
202
|
-
// ... resto da sua configuração
|
|
203
|
-
};
|
|
204
|
-
});`}],props:[{name:"supabaseUrls",type:"string[]",default:"[]",description:"URLs do Supabase para permitir em connect-src."},{name:"trustedOrigins",type:"string[]",default:"[]",description:"Origens confiáveis para CORS (suporta wildcards *.dominio.com)."},{name:"additionalScriptSrc",type:"string[]",default:"[]",description:"CDNs e fontes de script adicionais para CSP."},{name:"additionalStyleSrc",type:"string[]",default:"[]",description:"Fontes de estilo adicionais (fontes, CSS CDNs)."},{name:"additionalConnectSrc",type:"string[]",default:"[]",description:"APIs e WebSockets adicionais para CSP."},{name:"cspReportUri",type:"string",default:"-",description:"URI para receber relatórios de violações CSP."},{name:"enableTrustedTypes",type:"boolean",default:"true",description:"Habilitar Trusted Types em produção (proteção XSS)."},{name:"upgradeInsecureRequests",type:"boolean",default:"true",description:"Atualizar automaticamente HTTP para HTTPS em produção."},{name:"server.host",type:"string",default:'"::"',description:"Host do servidor de desenvolvimento."},{name:"server.port",type:"number",default:"8080",description:"Porta do servidor de desenvolvimento."},{name:"build.sourcemap",type:"boolean",default:"true",description:"Gerar sourcemaps para debug."},{name:"build.chunkSizeWarningLimit",type:"number",default:"4000",description:"Limite de tamanho de chunk (KB) para avisos."},{name:"disableSecurity",type:"boolean",default:"false",description:"Desabilitar plugin de segurança (NÃO recomendado)."}],accessibility:["Os headers de segurança protegem usuários de ataques como XSS, clickjacking e MIME sniffing.","CSP estrito em produção previne execução de scripts maliciosos.","CORS seguro impede vazamento de dados para origens não autorizadas.","Trusted Types fornece proteção adicional contra injeção de DOM."],notes:['**IMPORTANTE**: O alias `@` deve ser configurado com `path.resolve(__dirname, "./src")` - caminhos relativos falham no build.',"Em **desenvolvimento**, CSP permite unsafe-inline e unsafe-eval para suportar HMR do Vite.","Em **produção**, CSP é estrito e inclui Trusted Types e upgrade-insecure-requests.","Origens não confiáveis são **logadas** no console para auditoria de segurança.","Use `cspReportUri` para receber relatórios de violações e monitorar ataques.","O plugin é aplicado apenas ao **servidor de desenvolvimento** - em produção, configure headers no seu servidor/CDN."]})}export{O as SecurityDoc};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import{j as e,cX as t,cY as a,cZ as c,c_ as r,c$ as l,d0 as n,d1 as i,L as s}from"./index-BtX5DZqb.js";import{C as o}from"./ComponentDocTemplate-BtOCnlM2.js";import"./ExampleCard-DfuMYM6E.js";import"./TableOfContents-DBMJMbI4.js";function m(){return e.jsx(o,{title:"Select",description:"Exibe uma lista de opções para o usuário escolher—acionada por um botão.",component:e.jsxs(t,{children:[e.jsx(a,{className:"w-[180px]",children:e.jsx(c,{placeholder:"Select a fruit"})}),e.jsxs(r,{children:[e.jsx(l,{value:"apple",children:"Apple"}),e.jsx(l,{value:"banana",children:"Banana"}),e.jsx(l,{value:"orange",children:"Orange"})]})]}),usage:`import {
|
|
2
|
-
Select,
|
|
3
|
-
SelectContent,
|
|
4
|
-
SelectItem,
|
|
5
|
-
SelectTrigger,
|
|
6
|
-
SelectValue,
|
|
7
|
-
} from "forlogic-core"
|
|
8
|
-
|
|
9
|
-
<Select>
|
|
10
|
-
<SelectTrigger className="w-[180px]">
|
|
11
|
-
<SelectValue placeholder="Theme" />
|
|
12
|
-
</SelectTrigger>
|
|
13
|
-
<SelectContent>
|
|
14
|
-
<SelectItem value="light">Light</SelectItem>
|
|
15
|
-
<SelectItem value="dark">Dark</SelectItem>
|
|
16
|
-
</SelectContent>
|
|
17
|
-
</Select>`,examples:[{title:"Select Básico",preview:e.jsxs(t,{children:[e.jsx(a,{className:"w-[280px]",children:e.jsx(c,{placeholder:"Select a fruit"})}),e.jsxs(r,{children:[e.jsx(l,{value:"apple",children:"Apple"}),e.jsx(l,{value:"banana",children:"Banana"}),e.jsx(l,{value:"orange",children:"Orange"}),e.jsx(l,{value:"grape",children:"Grape"})]})]}),code:`<Select>
|
|
18
|
-
<SelectTrigger className="w-[280px]">
|
|
19
|
-
<SelectValue placeholder="Select a fruit" />
|
|
20
|
-
</SelectTrigger>
|
|
21
|
-
<SelectContent>
|
|
22
|
-
<SelectItem value="apple">Apple</SelectItem>
|
|
23
|
-
<SelectItem value="banana">Banana</SelectItem>
|
|
24
|
-
<SelectItem value="orange">Orange</SelectItem>
|
|
25
|
-
</SelectContent>
|
|
26
|
-
</Select>`},{title:"Com Grupos",preview:e.jsxs(t,{children:[e.jsx(a,{className:"w-[280px]",children:e.jsx(c,{placeholder:"Select a timezone"})}),e.jsxs(r,{children:[e.jsxs(n,{children:[e.jsx(i,{children:"North America"}),e.jsx(l,{value:"est",children:"Eastern Standard Time (EST)"}),e.jsx(l,{value:"cst",children:"Central Standard Time (CST)"}),e.jsx(l,{value:"pst",children:"Pacific Standard Time (PST)"})]}),e.jsxs(n,{children:[e.jsx(i,{children:"Europe"}),e.jsx(l,{value:"gmt",children:"Greenwich Mean Time (GMT)"}),e.jsx(l,{value:"cet",children:"Central European Time (CET)"})]})]})]}),code:`<Select>
|
|
27
|
-
<SelectTrigger>
|
|
28
|
-
<SelectValue placeholder="Select a timezone" />
|
|
29
|
-
</SelectTrigger>
|
|
30
|
-
<SelectContent>
|
|
31
|
-
<SelectGroup>
|
|
32
|
-
<SelectLabel>North America</SelectLabel>
|
|
33
|
-
<SelectItem value="est">Eastern Standard Time (EST)</SelectItem>
|
|
34
|
-
<SelectItem value="cst">Central Standard Time (CST)</SelectItem>
|
|
35
|
-
</SelectGroup>
|
|
36
|
-
<SelectGroup>
|
|
37
|
-
<SelectLabel>Europe</SelectLabel>
|
|
38
|
-
<SelectItem value="gmt">Greenwich Mean Time (GMT)</SelectItem>
|
|
39
|
-
</SelectGroup>
|
|
40
|
-
</SelectContent>
|
|
41
|
-
</Select>`},{title:"Estados",preview:e.jsxs("div",{className:"space-y-4",children:[e.jsxs(t,{children:[e.jsx(a,{className:"w-[280px]",children:e.jsx(c,{placeholder:"Normal state"})}),e.jsxs(r,{children:[e.jsx(l,{value:"1",children:"Option 1"}),e.jsx(l,{value:"2",children:"Option 2"})]})]}),e.jsxs(t,{disabled:!0,children:[e.jsx(a,{className:"w-[280px]",children:e.jsx(c,{placeholder:"Disabled state"})}),e.jsx(r,{children:e.jsx(l,{value:"1",children:"Option 1"})})]})]}),code:`<Select>
|
|
42
|
-
<SelectTrigger>
|
|
43
|
-
<SelectValue placeholder="Normal state" />
|
|
44
|
-
</SelectTrigger>
|
|
45
|
-
<SelectContent>
|
|
46
|
-
<SelectItem value="1">Option 1</SelectItem>
|
|
47
|
-
</SelectContent>
|
|
48
|
-
</Select>
|
|
49
|
-
|
|
50
|
-
<Select disabled>
|
|
51
|
-
<SelectTrigger>
|
|
52
|
-
<SelectValue placeholder="Disabled state" />
|
|
53
|
-
</SelectTrigger>
|
|
54
|
-
<SelectContent>
|
|
55
|
-
<SelectItem value="1">Option 1</SelectItem>
|
|
56
|
-
</SelectContent>
|
|
57
|
-
</Select>`},{title:"Com Label",preview:e.jsxs("div",{className:"space-y-2 w-[280px]",children:[e.jsx(s,{htmlFor:"country",children:"Country"}),e.jsxs(t,{children:[e.jsx(a,{id:"country",children:e.jsx(c,{placeholder:"Select your country"})}),e.jsxs(r,{children:[e.jsx(l,{value:"br",children:"Brazil"}),e.jsx(l,{value:"us",children:"United States"}),e.jsx(l,{value:"uk",children:"United Kingdom"}),e.jsx(l,{value:"ca",children:"Canada"})]})]})]}),code:`<div className="space-y-2">
|
|
58
|
-
<Label htmlFor="country">Country</Label>
|
|
59
|
-
<Select>
|
|
60
|
-
<SelectTrigger id="country">
|
|
61
|
-
<SelectValue placeholder="Select your country" />
|
|
62
|
-
</SelectTrigger>
|
|
63
|
-
<SelectContent>
|
|
64
|
-
<SelectItem value="br">Brazil</SelectItem>
|
|
65
|
-
<SelectItem value="us">United States</SelectItem>
|
|
66
|
-
</SelectContent>
|
|
67
|
-
</Select>
|
|
68
|
-
</div>`},{title:"Casos de Uso - Form",preview:e.jsxs("div",{className:"space-y-4 w-[280px]",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(s,{htmlFor:"role",children:"User Role"}),e.jsxs(t,{children:[e.jsx(a,{id:"role",children:e.jsx(c,{placeholder:"Select a role"})}),e.jsxs(r,{children:[e.jsx(l,{value:"admin",children:"Administrator"}),e.jsx(l,{value:"user",children:"User"}),e.jsx(l,{value:"guest",children:"Guest"})]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(s,{htmlFor:"status",children:"Status"}),e.jsxs(t,{children:[e.jsx(a,{id:"status",children:e.jsx(c,{placeholder:"Select status"})}),e.jsxs(r,{children:[e.jsx(l,{value:"active",children:"Active"}),e.jsx(l,{value:"inactive",children:"Inactive"}),e.jsx(l,{value:"pending",children:"Pending"})]})]})]})]}),code:`<div className="space-y-2">
|
|
69
|
-
<Label htmlFor="role">User Role</Label>
|
|
70
|
-
<Select>
|
|
71
|
-
<SelectTrigger id="role">
|
|
72
|
-
<SelectValue placeholder="Select a role" />
|
|
73
|
-
</SelectTrigger>
|
|
74
|
-
<SelectContent>
|
|
75
|
-
<SelectItem value="admin">Administrator</SelectItem>
|
|
76
|
-
<SelectItem value="user">User</SelectItem>
|
|
77
|
-
<SelectItem value="guest">Guest</SelectItem>
|
|
78
|
-
</SelectContent>
|
|
79
|
-
</Select>
|
|
80
|
-
</div>`}],props:[{name:"defaultValue",type:"string",default:"-",description:"O valor selecionado padrão."},{name:"value",type:"string",default:"-",description:"O valor selecionado controlado."},{name:"onValueChange",type:"(value: string) => void",default:"-",description:"Manipulador de evento quando o valor muda."},{name:"disabled",type:"boolean",default:"false",description:"Se o select está desabilitado."},{name:"container (SelectContent)",type:"HTMLElement",default:"-",description:"Container HTML para portal (útil dentro de Dialog)."},{name:"collisionBoundary (SelectContent)",type:"HTMLElement",default:"-",description:"Elemento para detecção de colisão de posicionamento."}],accessibility:["Navegação completa por teclado","Busca por digitação antecipada","Segue o padrão de listbox WAI-ARIA","Anúncios para leitores de tela"],notes:["💡 Use `container` e `collisionBoundary` quando o Select estiver dentro de um Dialog para evitar problemas de scroll","💡 Para seleção com busca, considere usar `Combobox` ao invés de `Select`"]})}export{m as SelectDoc};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{j as e,aq as t}from"./index-BtX5DZqb.js";import{C as a}from"./ComponentDocTemplate-BtOCnlM2.js";import"./ExampleCard-DfuMYM6E.js";import"./TableOfContents-DBMJMbI4.js";function c(){return e.jsx(a,{title:"Separator",description:"Separa visual ou semanticamente o conteúdo.",component:e.jsxs("div",{className:"space-y-4 w-full max-w-md",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-sm font-medium",children:"Primitivos Radix"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Uma biblioteca de componentes UI de código aberto."})]}),e.jsx(t,{}),e.jsxs("div",{children:[e.jsx("h4",{className:"text-sm font-medium",children:"Recursos"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Acessível, customizável, código aberto."})]})]}),usage:`import { Separator } from "forlogic-core"
|
|
2
|
-
|
|
3
|
-
<Separator />
|
|
4
|
-
<Separator orientation="vertical" />`,examples:[{title:"Horizontal",preview:e.jsxs("div",{className:"w-full max-w-md space-y-2",children:[e.jsx("p",{className:"text-sm",children:"Conteúdo acima"}),e.jsx(t,{}),e.jsx("p",{className:"text-sm",children:"Conteúdo abaixo"})]}),code:"<Separator />"},{title:"Vertical",preview:e.jsxs("div",{className:"flex h-20 items-center gap-4",children:[e.jsx("p",{className:"text-sm",children:"Esquerda"}),e.jsx(t,{orientation:"vertical"}),e.jsx("p",{className:"text-sm",children:"Direita"})]}),code:'<Separator orientation="vertical" />'}],props:[{name:"orientation",type:'"horizontal" | "vertical"',default:'"horizontal"',description:"A orientação do separador."},{name:"decorative",type:"boolean",default:"true",description:"Se o separador é decorativo ou semântico."}],accessibility:["HTML semântico com role adequado","Pode ser decorativo ou estrutural","Atributos ARIA adequados"]})}export{c as SeparatorDoc};
|
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import{j as e}from"./index-BtX5DZqb.js";import{C as o}from"./ComponentDocTemplate-BtOCnlM2.js";import"./ExampleCard-DfuMYM6E.js";import"./TableOfContents-DBMJMbI4.js";const t=`import {
|
|
2
|
-
// Services
|
|
3
|
-
createService,
|
|
4
|
-
emailService,
|
|
5
|
-
errorService,
|
|
6
|
-
// Qualiex Enrichment
|
|
7
|
-
QualiexEnrichmentService,
|
|
8
|
-
resolveFieldMappings,
|
|
9
|
-
deriveNameField,
|
|
10
|
-
deriveEmailField,
|
|
11
|
-
deriveUsernameField,
|
|
12
|
-
} from 'forlogic-core';`,d=`import { createService } from 'forlogic-core';
|
|
13
|
-
|
|
14
|
-
// Definir tipos
|
|
15
|
-
interface Employee {
|
|
16
|
-
id: string;
|
|
17
|
-
name: string;
|
|
18
|
-
email: string;
|
|
19
|
-
department_id: string;
|
|
20
|
-
is_removed: boolean;
|
|
21
|
-
created_at: string;
|
|
22
|
-
updated_at: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface EmployeeInsert {
|
|
26
|
-
name: string;
|
|
27
|
-
email: string;
|
|
28
|
-
department_id: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface EmployeeUpdate {
|
|
32
|
-
name?: string;
|
|
33
|
-
email?: string;
|
|
34
|
-
department_id?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Criar serviço CRUD
|
|
38
|
-
const employeeService = createService<Employee, EmployeeInsert, EmployeeUpdate>({
|
|
39
|
-
tableName: 'employees',
|
|
40
|
-
schemaName: 'common',
|
|
41
|
-
searchFields: ['name', 'email'],
|
|
42
|
-
selectFields: '*, departments(name)', // Joins automáticos
|
|
43
|
-
enableQualiexEnrichment: true, // Enriquecer com dados do Qualiex
|
|
44
|
-
userIdFields: ['id_user'], // Campos de usuário para enriquecimento
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Uso do serviço
|
|
48
|
-
async function loadEmployees() {
|
|
49
|
-
// Buscar com paginação e filtros
|
|
50
|
-
const result = await employeeService.getAll({
|
|
51
|
-
search: 'João',
|
|
52
|
-
sortField: 'name',
|
|
53
|
-
sortDirection: 'asc',
|
|
54
|
-
page: 1,
|
|
55
|
-
limit: 25,
|
|
56
|
-
department_id: 'dept-123', // Filtro adicional
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
console.log(result.data); // Array de funcionários
|
|
60
|
-
console.log(result.totalItems); // Total de registros
|
|
61
|
-
console.log(result.hasNextPage); // Se há próxima página
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// CRUD completo
|
|
65
|
-
const employee = await employeeService.create({
|
|
66
|
-
name: 'Maria Silva',
|
|
67
|
-
email: 'maria@empresa.com',
|
|
68
|
-
department_id: 'dept-123'
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const updated = await employeeService.update(employee.id, {
|
|
72
|
-
name: 'Maria Santos'
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
await employeeService.delete(employee.id); // Soft delete (is_removed = true)`,n=`import { emailService } from 'forlogic-core';
|
|
76
|
-
|
|
77
|
-
// Enviar email de boas-vindas
|
|
78
|
-
await emailService.sendEmail({
|
|
79
|
-
templateCode: 'WELCOME',
|
|
80
|
-
to: 'usuario@exemplo.com',
|
|
81
|
-
variables: {
|
|
82
|
-
userName: 'João Silva',
|
|
83
|
-
activationLink: 'https://app.com/activate',
|
|
84
|
-
companyName: 'Minha Empresa'
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Enviar para múltiplos destinatários com cópia
|
|
89
|
-
await emailService.sendEmail({
|
|
90
|
-
templateCode: 'NOTIFICATION',
|
|
91
|
-
to: ['usuario1@exemplo.com', 'usuario2@exemplo.com'],
|
|
92
|
-
variables: {
|
|
93
|
-
title: 'Novo documento disponível',
|
|
94
|
-
message: 'Um novo documento foi compartilhado com você',
|
|
95
|
-
actionUrl: 'https://app.com/documents/123',
|
|
96
|
-
actionLabel: 'Ver Documento'
|
|
97
|
-
},
|
|
98
|
-
cc: ['gestor@exemplo.com'],
|
|
99
|
-
bcc: ['admin@exemplo.com'],
|
|
100
|
-
replyTo: 'suporte@empresa.com'
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// Templates são cadastrados na tabela common.email_templates
|
|
104
|
-
// Variáveis são substituídas automaticamente: {{userName}} -> João Silva`,l=`import { errorService } from 'forlogic-core';
|
|
105
|
-
|
|
106
|
-
// Tratamento de erros com toast automático
|
|
107
|
-
try {
|
|
108
|
-
await fetchData();
|
|
109
|
-
} catch (error) {
|
|
110
|
-
errorService.handleError(error);
|
|
111
|
-
// Exibe toast com título apropriado baseado no erro
|
|
112
|
-
// Ex: "Sessão Expirada", "Erro de Conexão", "Erro de Autenticação"
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Tratamento silencioso (sem toast)
|
|
116
|
-
try {
|
|
117
|
-
await fetchData();
|
|
118
|
-
} catch (error) {
|
|
119
|
-
errorService.handleError(error, false); // showToast = false
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Notificação de sucesso
|
|
123
|
-
errorService.success('Sucesso!', 'Dados salvos com sucesso');
|
|
124
|
-
|
|
125
|
-
// Acessar histórico de erros
|
|
126
|
-
const recentErrors = errorService.getErrors(); // Últimos 50 erros
|
|
127
|
-
console.log(recentErrors);
|
|
128
|
-
|
|
129
|
-
// Limpar histórico
|
|
130
|
-
errorService.clearErrors();
|
|
131
|
-
|
|
132
|
-
// Rate limiting automático: máximo 3 toasts por minuto`,m=`import { QualiexEnrichmentService } from 'forlogic-core';
|
|
133
|
-
|
|
134
|
-
// Enriquecer entidades com dados de usuário do Qualiex
|
|
135
|
-
// Adiciona automaticamente: nome, email, username dos usuários
|
|
136
|
-
|
|
137
|
-
// Uso simples: lista de campos de ID
|
|
138
|
-
const enrichedItems = await QualiexEnrichmentService.enrichWithUserData(items, {
|
|
139
|
-
entityName: 'Avaliações',
|
|
140
|
-
userIdFields: ['target_user_id', 'evaluator_user_id']
|
|
141
|
-
});
|
|
142
|
-
// Resultado: target_user_name, evaluator_user_name preenchidos automaticamente
|
|
143
|
-
|
|
144
|
-
// Uso avançado: mapeamento customizado de campos
|
|
145
|
-
const enrichedItems = await QualiexEnrichmentService.enrichWithUserData(items, {
|
|
146
|
-
entityName: 'Avaliações',
|
|
147
|
-
userFieldsMapping: [
|
|
148
|
-
{
|
|
149
|
-
idField: 'target_user_id',
|
|
150
|
-
nameField: 'avaliado_nome',
|
|
151
|
-
emailField: 'avaliado_email'
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
idField: 'evaluator_user_id',
|
|
155
|
-
nameField: 'avaliador_nome'
|
|
156
|
-
}
|
|
157
|
-
]
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Características:
|
|
161
|
-
// - Cache inteligente de 5 minutos por companyId
|
|
162
|
-
// - Validação automática de tokens
|
|
163
|
-
// - Resiliência: retorna entidades originais em caso de erro
|
|
164
|
-
// - Suporta múltiplos campos de usuário por entidade`,c=`import {
|
|
165
|
-
resolveFieldMappings,
|
|
166
|
-
deriveNameField,
|
|
167
|
-
deriveEmailField,
|
|
168
|
-
deriveUsernameField
|
|
169
|
-
} from 'forlogic-core';
|
|
170
|
-
|
|
171
|
-
// Derivar nome do campo de saída baseado no campo de ID
|
|
172
|
-
deriveNameField('target_user_id'); // → 'target_user_name'
|
|
173
|
-
deriveNameField('id_user'); // → 'id_user_name'
|
|
174
|
-
deriveNameField('id_user', '_nome'); // → 'id_user_nome' (sufixo customizado)
|
|
175
|
-
|
|
176
|
-
deriveEmailField('target_user_id'); // → 'target_user_email'
|
|
177
|
-
deriveUsernameField('target_user_id'); // → 'target_user_username'
|
|
178
|
-
|
|
179
|
-
// Resolver mapeamentos automaticamente
|
|
180
|
-
// Prioridade: userFieldsMapping > userIdFields > default
|
|
181
|
-
|
|
182
|
-
// Uso com lista simples de campos
|
|
183
|
-
const mappings = resolveFieldMappings(['target_user_id', 'evaluator_user_id']);
|
|
184
|
-
// Resultado:
|
|
185
|
-
// [
|
|
186
|
-
// { idField: 'target_user_id', nameField: 'target_user_name', ... },
|
|
187
|
-
// { idField: 'evaluator_user_id', nameField: 'evaluator_user_name', ... }
|
|
188
|
-
// ]
|
|
189
|
-
|
|
190
|
-
// Uso com mapeamento explícito
|
|
191
|
-
const mappings = resolveFieldMappings(undefined, [
|
|
192
|
-
{ idField: 'id_user', nameField: 'responsible_name' }
|
|
193
|
-
]);
|
|
194
|
-
|
|
195
|
-
// Default (sem parâmetros): id_user → responsible_name
|
|
196
|
-
const mappings = resolveFieldMappings();
|
|
197
|
-
// [{ idField: 'id_user', nameField: 'responsible_name' }]`,u=[{name:"createService<T, TInsert, TUpdate>(options)",type:"CrudService<T>",default:"-",description:"Factory para criar serviço CRUD completo com Supabase. Implementa soft delete e RLS."},{name:"options.tableName",type:"string",default:"-",description:"Nome da tabela no Supabase."},{name:"options.schemaName",type:"string",default:"'common'",description:"Schema do banco de dados."},{name:"options.searchFields",type:"string[]",default:"[]",description:"Campos para busca textual (ilike)."},{name:"options.selectFields",type:"string",default:"'*'",description:'Campos para select, suporta joins (ex: "*, categories(name)").'},{name:"options.enableQualiexEnrichment",type:"boolean",default:"false",description:"Se deve enriquecer dados com informações do Qualiex."},{name:"emailService.sendEmail(params)",type:"Promise<any>",default:"-",description:"Envia email usando template do banco de dados via edge function."},{name:"params.templateCode",type:"string",default:"-",description:"Código do template em common.email_templates."},{name:"params.to",type:"string | string[]",default:"-",description:"Destinatário(s) do email."},{name:"params.variables",type:"Record<string, any>",default:"-",description:"Variáveis para substituição no template ({{variableName}})."},{name:"errorService.handleError(error, showToast?)",type:"void",default:"showToast: true",description:"Trata erro e exibe toast com título apropriado. Rate limiting: máx 3/min."},{name:"errorService.success(title, description?)",type:"void",default:"-",description:"Exibe toast de sucesso."},{name:"errorService.getErrors()",type:"ErrorEntry[]",default:"-",description:"Retorna os últimos 50 erros registrados."},{name:"QualiexEnrichmentService.enrichWithUserData(entities, options)",type:"Promise<T[]>",default:"-",description:"Enriquece entidades com dados de usuários do Qualiex (nome, email, username). Cache de 5 min."},{name:"options.entityName",type:"string",default:"-",description:"Nome da entidade para logs de debug."},{name:"options.userIdFields",type:"string[]",default:"-",description:"Lista de campos de ID de usuário para enriquecer."},{name:"options.userFieldsMapping",type:"QualiexUserFieldMapping[]",default:"-",description:"Mapeamento customizado de campos (prioridade sobre userIdFields)."},{name:"deriveNameField(idField, suffix?)",type:"string",default:"suffix: '_name'",description:"Deriva campo de nome a partir do ID (ex: target_user_id → target_user_name)."},{name:"deriveEmailField(idField, suffix?)",type:"string",default:"suffix: '_email'",description:"Deriva campo de email a partir do ID (ex: target_user_id → target_user_email)."},{name:"deriveUsernameField(idField, suffix?)",type:"string",default:"suffix: '_username'",description:"Deriva campo de username a partir do ID."},{name:"resolveFieldMappings(userIdFields?, userFieldsMapping?)",type:"QualiexUserFieldMapping[]",default:"-",description:"Resolve mapeamentos com prioridade: userFieldsMapping > userIdFields > default."}];function a({title:i,description:r,code:s}){return e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:i}),e.jsx("p",{className:"text-sm text-muted-foreground",children:r})]}),e.jsx("pre",{className:"rounded-lg border bg-muted/50 p-4 overflow-x-auto",children:e.jsx("code",{className:"text-sm font-mono",children:s})})]})}function f(){const i=[{id:"exemplos",label:"Exemplos"},{id:"baseservice-createservice",label:"BaseService (createService)"},{id:"emailservice",label:"EmailService"},{id:"errorservice",label:"ErrorService"},{id:"qualiexenrichmentservice",label:"QualiexEnrichmentService"},{id:"qualiexenrichmentservice",label:"QualiexEnrichmentService"},{id:"qualiexfieldhelpers",label:"QualiexFieldHelpers"},{id:"tipos",label:"Tipos"}];return e.jsx(o,{title:"Services",description:"Serviços utilitários da biblioteca forlogic-core para operações CRUD, envio de emails, tratamento de erros e gerenciamento de traduções. Todos os serviços são singletons prontos para uso.",usage:t,props:u,tocItems:i,notes:["createService implementa soft delete automaticamente (is_removed = true).","createService valida token de autenticação antes de cada operação.","EmailService usa templates cadastrados em common.email_templates via edge function send-email.","ErrorService possui rate limiting: máximo 3 toasts por minuto para evitar spam.","createService suporta joins automáticos via selectFields.","QualiexEnrichmentService usa cache de 5 minutos por companyId para evitar chamadas desnecessárias.","QualiexEnrichmentService é resiliente: retorna entidades originais em caso de erro.",'QualiexFieldHelpers remove sufixo "_id" automaticamente antes de adicionar o novo sufixo.'],children:e.jsxs("div",{id:"exemplos",className:"space-y-8 scroll-mt-4",children:[e.jsx("h2",{className:"text-2xl font-semibold tracking-tight border-b pb-2",children:"Exemplos"}),e.jsx("div",{id:"baseservice-createservice",className:"scroll-mt-4",children:e.jsx(a,{title:"BaseService (createService)",description:"Factory para criar serviços CRUD completos com Supabase. Suporta paginação, busca, ordenação, filtros, joins e soft delete.",code:d})}),e.jsx("div",{id:"emailservice",className:"scroll-mt-4",children:e.jsx(a,{title:"EmailService",description:"Envia emails usando templates cadastrados no banco de dados. Suporta variáveis de substituição e múltiplos destinatários.",code:n})}),e.jsx("div",{id:"errorservice",className:"scroll-mt-4",children:e.jsx(a,{title:"ErrorService",description:"Tratamento centralizado de erros com toasts inteligentes e rate limiting. Mantém histórico dos últimos 50 erros.",code:l})}),e.jsx("div",{id:"qualiexenrichmentservice",className:"scroll-mt-4",children:e.jsx(a,{title:"QualiexEnrichmentService",description:"Enriquece entidades com dados de usuários do Qualiex (nome, email, username). Usa cache inteligente de 5 minutos por companyId.",code:m})}),e.jsx("div",{id:"qualiexfieldhelpers",className:"scroll-mt-4",children:e.jsx(a,{title:"QualiexFieldHelpers",description:"Utilitários para derivar automaticamente nomes de campos de saída baseado nos campos de ID de usuário.",code:c})}),e.jsx("div",{id:"tipos",className:"scroll-mt-4",children:e.jsx("h2",{className:"text-2xl font-semibold tracking-tight border-b pb-2",children:"Tipos"})}),e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"QualiexUserFieldMapping"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Define o mapeamento entre um campo de ID de usuário e seus campos de saída correspondentes (nome, email, username)."}),e.jsx("pre",{className:"rounded-lg border bg-muted/50 p-4 overflow-x-auto",children:e.jsx("code",{className:"text-sm font-mono",children:`interface QualiexUserFieldMapping {
|
|
198
|
-
/** Nome do campo de ID de usuário na entidade (ex: "target_user_id") */
|
|
199
|
-
idField: string;
|
|
200
|
-
|
|
201
|
-
/** Nome do campo de saída para o nome (ex: "target_user_name")
|
|
202
|
-
* Default: idField + "_name" (remove "_id" se presente) */
|
|
203
|
-
nameField?: string;
|
|
204
|
-
|
|
205
|
-
/** Nome do campo de saída para o email (ex: "target_user_email")
|
|
206
|
-
* Default: idField + "_email" (remove "_id" se presente) */
|
|
207
|
-
emailField?: string;
|
|
208
|
-
|
|
209
|
-
/** Nome do campo de saída para o username (ex: "target_user_username")
|
|
210
|
-
* Default: idField + "_username" (remove "_id" se presente) */
|
|
211
|
-
usernameField?: string;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Exemplos de uso:
|
|
215
|
-
const mappings: QualiexUserFieldMapping[] = [
|
|
216
|
-
// Mapeamento simples (só nome)
|
|
217
|
-
{ idField: 'id_user', nameField: 'responsible_name' },
|
|
218
|
-
|
|
219
|
-
// Mapeamento completo
|
|
220
|
-
{
|
|
221
|
-
idField: 'target_user_id',
|
|
222
|
-
nameField: 'target_name',
|
|
223
|
-
emailField: 'target_email',
|
|
224
|
-
usernameField: 'target_username'
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
// Mapeamento parcial (nome e email)
|
|
228
|
-
{
|
|
229
|
-
idField: 'evaluator_user_id',
|
|
230
|
-
nameField: 'evaluator_name',
|
|
231
|
-
emailField: 'evaluator_email'
|
|
232
|
-
}
|
|
233
|
-
];`})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"QualiexEnrichmentConfig"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Configuração global de sufixos padrão para derivação automática de campos. Usado internamente pelo QualiexFieldHelpers."}),e.jsx("pre",{className:"rounded-lg border bg-muted/50 p-4 overflow-x-auto",children:e.jsx("code",{className:"text-sm font-mono",children:`interface QualiexEnrichmentConfig {
|
|
234
|
-
/** Sufixo padrão para campos de nome (default: "_name") */
|
|
235
|
-
userNameFieldSuffix?: string;
|
|
236
|
-
|
|
237
|
-
/** Sufixo padrão para campos de email (default: "_email") */
|
|
238
|
-
userEmailFieldSuffix?: string;
|
|
239
|
-
|
|
240
|
-
/** Sufixo padrão para campos de username (default: "_username") */
|
|
241
|
-
userUsernameFieldSuffix?: string;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Exemplo de configuração customizada:
|
|
245
|
-
const config: QualiexEnrichmentConfig = {
|
|
246
|
-
userNameFieldSuffix: '_nome', // target_user_id → target_user_nome
|
|
247
|
-
userEmailFieldSuffix: '_email', // target_user_id → target_user_email
|
|
248
|
-
userUsernameFieldSuffix: '_login' // target_user_id → target_user_login
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// Valores padrão:
|
|
252
|
-
// - userNameFieldSuffix: '_name'
|
|
253
|
-
// - userEmailFieldSuffix: '_email'
|
|
254
|
-
// - userUsernameFieldSuffix: '_username'`})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"QualiexUser"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Representa um usuário do sistema Qualiex. Retornado pelo hook useQualiexUsers e usado internamente pelo QualiexEnrichmentService."}),e.jsx("pre",{className:"rounded-lg border bg-muted/50 p-4 overflow-x-auto",children:e.jsx("code",{className:"text-sm font-mono",children:`interface QualiexUser {
|
|
255
|
-
/** ID único do usuário (formato UUID) */
|
|
256
|
-
id?: string;
|
|
257
|
-
|
|
258
|
-
/** ID alternativo do usuário (alguns endpoints retornam neste campo) */
|
|
259
|
-
userId?: string;
|
|
260
|
-
|
|
261
|
-
/** Nome de usuário (login) */
|
|
262
|
-
userName?: string;
|
|
263
|
-
|
|
264
|
-
/** Email do usuário */
|
|
265
|
-
userEmail?: string;
|
|
266
|
-
|
|
267
|
-
/** Nome de exibição (nome completo) */
|
|
268
|
-
displayName?: string;
|
|
269
|
-
|
|
270
|
-
/** ID do local/unidade do usuário */
|
|
271
|
-
placeId?: string | null;
|
|
272
|
-
|
|
273
|
-
/** Nome do local/unidade do usuário */
|
|
274
|
-
placeName?: string | null;
|
|
275
|
-
|
|
276
|
-
/** ID do cargo/função do usuário */
|
|
277
|
-
roleId?: string;
|
|
278
|
-
|
|
279
|
-
/** Nome do cargo/função do usuário */
|
|
280
|
-
roleName?: string;
|
|
281
|
-
|
|
282
|
-
/** ID da empresa do usuário */
|
|
283
|
-
companyId?: string;
|
|
284
|
-
|
|
285
|
-
/** Nome da empresa do usuário */
|
|
286
|
-
companyName?: string;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Exemplo de uso com useQualiexUsers:
|
|
290
|
-
import { useQualiexUsers } from 'forlogic-core';
|
|
291
|
-
|
|
292
|
-
function UserSelector() {
|
|
293
|
-
const { data: users, isLoading } = useQualiexUsers({ enabled: true });
|
|
294
|
-
|
|
295
|
-
// users é QualiexUser[]
|
|
296
|
-
return (
|
|
297
|
-
<select>
|
|
298
|
-
{users?.map(user => (
|
|
299
|
-
<option key={user.id || user.userId} value={user.id || user.userId}>
|
|
300
|
-
{user.displayName || user.userName} ({user.userEmail})
|
|
301
|
-
</option>
|
|
302
|
-
))}
|
|
303
|
-
</select>
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Nota: A API retorna apenas usuários ativos (filterStatus='active').
|
|
308
|
-
// O campo isActive foi removido pois a API não o fornece.`})})]})]})]})})}export{f as ServicesDoc};
|