zeti-framework-backend 0.2.4
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/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/chunk-K2E6XKVB.js +18 -0
- package/dist/chunk-K2E6XKVB.js.map +1 -0
- package/dist/chunk-KIOZSPU2.js +690 -0
- package/dist/chunk-KIOZSPU2.js.map +1 -0
- package/dist/chunk-LCNZVWVO.js +581 -0
- package/dist/chunk-LCNZVWVO.js.map +1 -0
- package/dist/chunk-TTILJJ3O.js +324 -0
- package/dist/chunk-TTILJJ3O.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +418 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config-VWgz0Iq_.d.ts +647 -0
- package/dist/generator-CK-ZmWQj.d.ts +197 -0
- package/dist/generator-KC24DE6M.js +8 -0
- package/dist/generator-KC24DE6M.js.map +1 -0
- package/dist/index.d.ts +333 -0
- package/dist/index.js +11675 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/index.d.ts +34 -0
- package/dist/scripts/index.js +12 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/swagger/index.d.ts +10 -0
- package/dist/swagger/index.js +14 -0
- package/dist/swagger/index.js.map +1 -0
- package/dist/tenants/index.d.ts +146 -0
- package/dist/tenants/index.js +10 -0
- package/dist/tenants/index.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
import * as hono from 'hono';
|
|
2
|
+
import { Context, Next } from 'hono';
|
|
3
|
+
import Redis, { RedisOptions } from 'ioredis';
|
|
4
|
+
import { HTTPException } from 'hono/http-exception';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tipo da função do Worker
|
|
8
|
+
* Recebe o db e opcionalmente o tenantId
|
|
9
|
+
*/
|
|
10
|
+
type WorkerFn = (db: any, tenantId?: string) => Promise<void> | void;
|
|
11
|
+
/**
|
|
12
|
+
* Configuração de um Worker individual (quando precisa de opções extras)
|
|
13
|
+
*/
|
|
14
|
+
interface WorkerConfigObject {
|
|
15
|
+
/**
|
|
16
|
+
* Função que será executada periodicamente
|
|
17
|
+
*/
|
|
18
|
+
fn: WorkerFn;
|
|
19
|
+
/**
|
|
20
|
+
* Intervalo de execução em segundos
|
|
21
|
+
* @default 30
|
|
22
|
+
*/
|
|
23
|
+
intervalSeconds?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Se true, executa para cada tenant separadamente (multi-tenant)
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
multiTenant?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Se true, executa imediatamente ao iniciar
|
|
31
|
+
* @default true
|
|
32
|
+
*/
|
|
33
|
+
runImmediately?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Worker pode ser apenas a função ou um objeto com configurações
|
|
37
|
+
*
|
|
38
|
+
* @example Apenas função (usa defaults)
|
|
39
|
+
* ```typescript
|
|
40
|
+
* workers: {
|
|
41
|
+
* email: emailWorker,
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example Com configurações
|
|
46
|
+
* ```typescript
|
|
47
|
+
* workers: {
|
|
48
|
+
* email: {
|
|
49
|
+
* fn: emailWorker,
|
|
50
|
+
* intervalSeconds: 60,
|
|
51
|
+
* },
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
type WorkerConfig = WorkerFn | WorkerConfigObject;
|
|
56
|
+
/**
|
|
57
|
+
* Configuração de workers no zetiConfig
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* workers: {
|
|
62
|
+
* // Apenas a função (usa intervalSeconds: 30 por padrão)
|
|
63
|
+
* email: emailWorker,
|
|
64
|
+
*
|
|
65
|
+
* // Com configurações customizadas
|
|
66
|
+
* sync: {
|
|
67
|
+
* fn: syncWorker,
|
|
68
|
+
* intervalSeconds: 60,
|
|
69
|
+
* multiTenant: true,
|
|
70
|
+
* },
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
type WorkersConfig = Record<string, WorkerConfig>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Redis Client para o Zeti Framework
|
|
78
|
+
*
|
|
79
|
+
* Fornece um cliente Redis singleton com configuração flexível
|
|
80
|
+
* e integração com o ciclo de vida do framework.
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
interface RedisConfig {
|
|
84
|
+
/** URL de conexão Redis (ex: redis://localhost:6379) */
|
|
85
|
+
url?: string;
|
|
86
|
+
/** Host do Redis (default: localhost) */
|
|
87
|
+
host?: string;
|
|
88
|
+
/** Porta do Redis (default: 6379) */
|
|
89
|
+
port?: number;
|
|
90
|
+
/** Senha do Redis */
|
|
91
|
+
password?: string;
|
|
92
|
+
/** Número do database (default: 0) */
|
|
93
|
+
db?: number;
|
|
94
|
+
/** Prefixo para todas as chaves (ex: 'auth:') */
|
|
95
|
+
keyPrefix?: string;
|
|
96
|
+
/** Máximo de retries por request (default: 3) */
|
|
97
|
+
maxRetriesPerRequest?: number;
|
|
98
|
+
/** Verificar conexão ao iniciar (default: true) */
|
|
99
|
+
enableReadyCheck?: boolean;
|
|
100
|
+
/** Conectar sob demanda (default: false) */
|
|
101
|
+
lazyConnect?: boolean;
|
|
102
|
+
/** TLS options */
|
|
103
|
+
tls?: RedisOptions['tls'];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Inicializa o cliente Redis com a configuração fornecida.
|
|
107
|
+
*
|
|
108
|
+
* **Fail-Fast**: Se o Redis não conseguir conectar, a aplicação falha ao iniciar.
|
|
109
|
+
* Isso garante que se o Redis está configurado, ele DEVE estar disponível.
|
|
110
|
+
*
|
|
111
|
+
* @param config - Configuração do Redis
|
|
112
|
+
* @returns Promise com a instância do cliente Redis
|
|
113
|
+
* @throws Error se não conseguir conectar ao Redis
|
|
114
|
+
*/
|
|
115
|
+
declare function initRedis(config: RedisConfig): Promise<Redis>;
|
|
116
|
+
/**
|
|
117
|
+
* Retorna o cliente Redis singleton.
|
|
118
|
+
*
|
|
119
|
+
* @throws Error se o Redis não foi inicializado
|
|
120
|
+
* @returns Instância do cliente Redis (ioredis)
|
|
121
|
+
*/
|
|
122
|
+
declare function getRedisClient(): Redis;
|
|
123
|
+
/**
|
|
124
|
+
* Fecha a conexão Redis graciosamente.
|
|
125
|
+
*/
|
|
126
|
+
declare function closeRedis(): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Retorna a configuração atual do Redis.
|
|
129
|
+
*/
|
|
130
|
+
declare function getRedisConfig(): RedisConfig | null;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Tipos próprios para Prisma
|
|
134
|
+
*
|
|
135
|
+
* Estes tipos são usados para evitar dependência direta de @prisma/client
|
|
136
|
+
* durante o build da biblioteca, já que Prisma é uma peer dependency.
|
|
137
|
+
*
|
|
138
|
+
* O usuário passa o PrismaClient real como generic, então o TypeScript
|
|
139
|
+
* vai inferir os tipos corretos em tempo de uso.
|
|
140
|
+
*/
|
|
141
|
+
type PrismaClientBase = {
|
|
142
|
+
$connect: () => Promise<void>;
|
|
143
|
+
$disconnect: () => Promise<void>;
|
|
144
|
+
$transaction: <T>(fn: (client: any) => Promise<T>) => Promise<T>;
|
|
145
|
+
$queryRaw: any;
|
|
146
|
+
$executeRaw: any;
|
|
147
|
+
[key: string]: any;
|
|
148
|
+
};
|
|
149
|
+
declare namespace Prisma {
|
|
150
|
+
interface PrismaClientKnownRequestError extends Error {
|
|
151
|
+
code: string;
|
|
152
|
+
meta?: any;
|
|
153
|
+
clientVersion?: string;
|
|
154
|
+
}
|
|
155
|
+
interface PrismaClientValidationError extends Error {
|
|
156
|
+
message: string;
|
|
157
|
+
}
|
|
158
|
+
interface PrismaClientInitializationError extends Error {
|
|
159
|
+
errorCode?: string;
|
|
160
|
+
clientVersion?: string;
|
|
161
|
+
}
|
|
162
|
+
interface PrismaClientRustPanicError extends Error {
|
|
163
|
+
requestId?: string;
|
|
164
|
+
clientVersion?: string;
|
|
165
|
+
}
|
|
166
|
+
type PrismaClientError = PrismaClientKnownRequestError | PrismaClientValidationError | PrismaClientInitializationError | PrismaClientRustPanicError;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
interface ValidationError {
|
|
170
|
+
field: string;
|
|
171
|
+
errors: string[];
|
|
172
|
+
}
|
|
173
|
+
interface ErrorTrace {
|
|
174
|
+
path: string;
|
|
175
|
+
method: string;
|
|
176
|
+
timestamp: string;
|
|
177
|
+
errorType: string;
|
|
178
|
+
stack?: string;
|
|
179
|
+
}
|
|
180
|
+
interface ErrorResponse {
|
|
181
|
+
data: null;
|
|
182
|
+
status: number;
|
|
183
|
+
message: string;
|
|
184
|
+
validationErrors?: Record<string, {
|
|
185
|
+
errors: string[];
|
|
186
|
+
}>;
|
|
187
|
+
trace?: ErrorTrace;
|
|
188
|
+
}
|
|
189
|
+
interface ZetiErrorHandlerConfig {
|
|
190
|
+
formatError?: (error: any, context: Context) => ErrorResponse;
|
|
191
|
+
logError?: (error: any, context: Context) => void;
|
|
192
|
+
/** Incluir trace de erro na resposta (default: true em dev, false em prod) */
|
|
193
|
+
includeTrace?: boolean;
|
|
194
|
+
/** Incluir stack trace na resposta (default: false) */
|
|
195
|
+
includeStack?: boolean;
|
|
196
|
+
}
|
|
197
|
+
declare function createErrorHandler(config?: ZetiErrorHandlerConfig): (c: Context, next: () => Promise<void>) => Promise<(Response & hono.TypedResponse<{
|
|
198
|
+
data: null;
|
|
199
|
+
status: number;
|
|
200
|
+
message: string;
|
|
201
|
+
validationErrors?: {
|
|
202
|
+
[x: string]: {
|
|
203
|
+
errors: string[];
|
|
204
|
+
};
|
|
205
|
+
} | undefined;
|
|
206
|
+
trace?: {
|
|
207
|
+
path: string;
|
|
208
|
+
method: string;
|
|
209
|
+
timestamp: string;
|
|
210
|
+
errorType: string;
|
|
211
|
+
stack?: string | undefined;
|
|
212
|
+
} | undefined;
|
|
213
|
+
}, any, "json">) | undefined>;
|
|
214
|
+
declare function handleError(exception: Error | HTTPException | Prisma.PrismaClientKnownRequestError | ValidationError[] | any, config?: ZetiErrorHandlerConfig, trace?: ErrorTrace, context?: {
|
|
215
|
+
tenant?: string;
|
|
216
|
+
}): ErrorResponse;
|
|
217
|
+
|
|
218
|
+
type Middleware = (c: Context, next: Next) => Promise<Response | void> | Response | void;
|
|
219
|
+
interface ZetiDatabaseConfig {
|
|
220
|
+
/**
|
|
221
|
+
* Conexões de banco de dados.
|
|
222
|
+
*
|
|
223
|
+
* Para single-tenant: { default: "connection_string" }
|
|
224
|
+
* Para multi-tenant: { tenantName: "connection_string", ... }
|
|
225
|
+
*
|
|
226
|
+
* O valor do header x-tenant (ou headerName configurado) é usado como chave.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* connections: {
|
|
231
|
+
* mulherdevalor: env("TENANT_MULHERDEVALOR_DATABASE_URL"),
|
|
232
|
+
* outroTenant: env("TENANT_OUTRO_DATABASE_URL"),
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
connections: Record<string, string>;
|
|
237
|
+
/**
|
|
238
|
+
* Resolver dinâmico para conexões não encontradas em `connections`.
|
|
239
|
+
* Útil para cenários onde os tenants são criados dinamicamente.
|
|
240
|
+
*/
|
|
241
|
+
resolver?: (tenantId: string) => Promise<string> | string;
|
|
242
|
+
/** Configuração de cache de conexões */
|
|
243
|
+
cache?: {
|
|
244
|
+
maxClients?: number;
|
|
245
|
+
ttl?: number;
|
|
246
|
+
cleanupInterval?: number;
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
interface ZetiPrismaConfig {
|
|
250
|
+
adapter?: 'pg' | 'mysql' | 'sqlite' | 'custom';
|
|
251
|
+
logLevel?: ('query' | 'error' | 'warn')[];
|
|
252
|
+
connectionPool?: {
|
|
253
|
+
max?: number;
|
|
254
|
+
min?: number;
|
|
255
|
+
idleTimeoutMillis?: number;
|
|
256
|
+
connectionTimeoutMillis?: number;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Estratégia de conexão com o banco de dados.
|
|
261
|
+
*
|
|
262
|
+
* - `single`: Usa DATABASE_URL único, zero overhead de multi-tenancy
|
|
263
|
+
* - `dynamic`: Usa tenantSelector para resolver URL e tenantId por request
|
|
264
|
+
*/
|
|
265
|
+
type ConnectionStrategy = 'single' | 'dynamic';
|
|
266
|
+
/**
|
|
267
|
+
* Resultado do tenantSelector.
|
|
268
|
+
*
|
|
269
|
+
* @example Row-level isolation (mesmo banco)
|
|
270
|
+
* ```typescript
|
|
271
|
+
* { tenantId: 'abc-123' }
|
|
272
|
+
* ```
|
|
273
|
+
*
|
|
274
|
+
* @example Database sharding (bancos diferentes)
|
|
275
|
+
* ```typescript
|
|
276
|
+
* { databaseUrl: process.env.DB_TENANT_A }
|
|
277
|
+
* ```
|
|
278
|
+
*
|
|
279
|
+
* @example Combinado
|
|
280
|
+
* ```typescript
|
|
281
|
+
* { tenantId: 'abc-123', databaseUrl: process.env.DB_TENANT_A }
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
interface TenantSelection {
|
|
285
|
+
/** ID do tenant para filtro automático via $extends */
|
|
286
|
+
tenantId?: string;
|
|
287
|
+
/** URL do banco de dados (se diferente de DATABASE_URL) */
|
|
288
|
+
databaseUrl?: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Escopo de segurança definido pelo middleware.
|
|
292
|
+
*
|
|
293
|
+
* Quando definido via `context.set('securityScope', scope)`, o framework
|
|
294
|
+
* automaticamente aplica validações em todas as operações do Prisma:
|
|
295
|
+
*
|
|
296
|
+
* - **Leitura**: Adiciona campos ao WHERE (filtro automático)
|
|
297
|
+
* - **Criação**: VALIDA que os campos passados correspondem ao escopo
|
|
298
|
+
* - **Atualização/Deleção**: Adiciona campos ao WHERE (proteção)
|
|
299
|
+
*
|
|
300
|
+
* @example No middleware
|
|
301
|
+
* ```typescript
|
|
302
|
+
* context.set('securityScope', {
|
|
303
|
+
* tenantId: tenant.id,
|
|
304
|
+
* productId: product.id,
|
|
305
|
+
* });
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @example No controller (proteção automática)
|
|
309
|
+
* ```typescript
|
|
310
|
+
* // Isso vai FALHAR se tenantId for diferente do escopo:
|
|
311
|
+
* await db.role.create({ data: { name: 'Admin', tenantId: 'outro-tenant' } });
|
|
312
|
+
* // Error: [Zeti Security] Campo 'tenantId' inválido...
|
|
313
|
+
*
|
|
314
|
+
* // Isso funciona:
|
|
315
|
+
* await db.role.create({ data: { name: 'Admin', tenantId: scopeTenantId } });
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
interface SecurityScope {
|
|
319
|
+
/** ID do tenant - obrigatório em creates, filtrado em reads */
|
|
320
|
+
tenantId?: string;
|
|
321
|
+
/** ID do produto - obrigatório em creates, filtrado em reads */
|
|
322
|
+
productId?: string;
|
|
323
|
+
/** Campos adicionais customizados */
|
|
324
|
+
[key: string]: string | undefined;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Configuração de conexão do Prisma com suporte a multi-tenancy.
|
|
328
|
+
*
|
|
329
|
+
* @example Single database (app simples)
|
|
330
|
+
* ```typescript
|
|
331
|
+
* prisma: {
|
|
332
|
+
* client: PrismaClient,
|
|
333
|
+
* connectionStrategy: 'single',
|
|
334
|
+
* }
|
|
335
|
+
* ```
|
|
336
|
+
*
|
|
337
|
+
* @example Multi-tenant com row-level isolation
|
|
338
|
+
* ```typescript
|
|
339
|
+
* prisma: {
|
|
340
|
+
* client: PrismaClient,
|
|
341
|
+
* connectionStrategy: 'dynamic',
|
|
342
|
+
* tenantSelector: (context) => ({
|
|
343
|
+
* tenantId: context.req.header('x-tenant-id'),
|
|
344
|
+
* }),
|
|
345
|
+
* }
|
|
346
|
+
* ```
|
|
347
|
+
*
|
|
348
|
+
* @example Multi-database (sharding)
|
|
349
|
+
* ```typescript
|
|
350
|
+
* prisma: {
|
|
351
|
+
* client: PrismaClient,
|
|
352
|
+
* connectionStrategy: 'dynamic',
|
|
353
|
+
* tenantSelector: (context) => {
|
|
354
|
+
* const product = context.req.header('x-product-name');
|
|
355
|
+
* return {
|
|
356
|
+
* tenantId: context.req.header('x-tenant-id'),
|
|
357
|
+
* databaseUrl: process.env[`DB_${product?.toUpperCase()}`],
|
|
358
|
+
* };
|
|
359
|
+
* },
|
|
360
|
+
* }
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
interface ZetiPrismaConnectionConfig<TPrisma = any> {
|
|
364
|
+
/** Classe do PrismaClient do projeto */
|
|
365
|
+
client: new (...args: any[]) => TPrisma;
|
|
366
|
+
/**
|
|
367
|
+
* Estratégia de conexão.
|
|
368
|
+
* - `single`: Usa DATABASE_URL, sem multi-tenancy
|
|
369
|
+
* - `dynamic`: Usa tenantSelector para resolver conexão
|
|
370
|
+
* @default 'single'
|
|
371
|
+
*/
|
|
372
|
+
connectionStrategy?: ConnectionStrategy;
|
|
373
|
+
/**
|
|
374
|
+
* Função que resolve tenantId e/ou databaseUrl por request.
|
|
375
|
+
* Obrigatório se connectionStrategy = 'dynamic'.
|
|
376
|
+
*/
|
|
377
|
+
tenantSelector?: (context: Context) => TenantSelection | Promise<TenantSelection>;
|
|
378
|
+
/**
|
|
379
|
+
* Extension customizada aplicada após o filtro de tenant.
|
|
380
|
+
* Permite encadear $extends adicionais.
|
|
381
|
+
*/
|
|
382
|
+
customExtension?: (baseClient: TPrisma, selection: TenantSelection) => TPrisma;
|
|
383
|
+
}
|
|
384
|
+
interface ZetiCorsConfig {
|
|
385
|
+
enabled?: boolean;
|
|
386
|
+
origin?: string | string[] | ((origin: string) => boolean);
|
|
387
|
+
allowMethods?: string[];
|
|
388
|
+
allowHeaders?: string[];
|
|
389
|
+
credentials?: boolean;
|
|
390
|
+
maxAge?: number;
|
|
391
|
+
}
|
|
392
|
+
interface ZetiSwaggerHeaderParam {
|
|
393
|
+
name: string;
|
|
394
|
+
description?: string;
|
|
395
|
+
required?: boolean;
|
|
396
|
+
example?: string;
|
|
397
|
+
}
|
|
398
|
+
interface ZetiSwaggerConfig {
|
|
399
|
+
enabled?: boolean;
|
|
400
|
+
title: string;
|
|
401
|
+
version?: string;
|
|
402
|
+
description?: string;
|
|
403
|
+
servers?: Array<{
|
|
404
|
+
url: string;
|
|
405
|
+
description?: string;
|
|
406
|
+
}>;
|
|
407
|
+
outputPath?: string;
|
|
408
|
+
generateOnBuild?: boolean;
|
|
409
|
+
uiPath?: string;
|
|
410
|
+
docPath?: string;
|
|
411
|
+
globalHeaders?: ZetiSwaggerHeaderParam[];
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Configuração de headers customizados.
|
|
415
|
+
*
|
|
416
|
+
* Cada header declarado aqui:
|
|
417
|
+
* - Será acessível via `c.req.header(name)`
|
|
418
|
+
* - Aparecerá automaticamente como parâmetro opcional no Swagger
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```typescript
|
|
422
|
+
* headers: {
|
|
423
|
+
* tenant: "x-tenant", // Header para multi-tenancy
|
|
424
|
+
* timezone: "timezone", // Header de timezone
|
|
425
|
+
* apiKey: "x-internal-api-key", // Header customizado
|
|
426
|
+
* }
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
interface ZetiHeadersConfig {
|
|
430
|
+
/** Header de tenant para multi-tenancy. Default: "x-tenant" */
|
|
431
|
+
tenant?: string;
|
|
432
|
+
/** Header de timezone. Default: "timezone" */
|
|
433
|
+
timezone?: string;
|
|
434
|
+
/** Permite qualquer header customizado adicional */
|
|
435
|
+
[key: string]: string | undefined;
|
|
436
|
+
}
|
|
437
|
+
interface ZetiTenantConfig {
|
|
438
|
+
enabled?: boolean;
|
|
439
|
+
required?: boolean;
|
|
440
|
+
headerName?: string;
|
|
441
|
+
defaultDatabase?: string;
|
|
442
|
+
}
|
|
443
|
+
interface ZetiMiddlewareConfig {
|
|
444
|
+
global?: Middleware[];
|
|
445
|
+
named?: Record<string, Middleware | ((...args: any[]) => Middleware)>;
|
|
446
|
+
}
|
|
447
|
+
/** Configuração de desenvolvimento do projeto */
|
|
448
|
+
interface ZetiDevConfig {
|
|
449
|
+
/** Porta do servidor. Default: 3333 */
|
|
450
|
+
port?: number;
|
|
451
|
+
/** Caminho do docker-compose. Default: "../infra/local/docker-compose.yaml" */
|
|
452
|
+
dockerCompose?: string;
|
|
453
|
+
/** Portas para limpar antes de iniciar. Default: [3333, 5432] */
|
|
454
|
+
ports?: number[];
|
|
455
|
+
/** Configuração do framework local (para desenvolvimento) */
|
|
456
|
+
framework?: {
|
|
457
|
+
/** Caminho do framework. Default: "../_developer/_npm" */
|
|
458
|
+
path?: string;
|
|
459
|
+
/** Observar mudanças no framework. Default: true */
|
|
460
|
+
watch?: boolean;
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Configuração interna completa do Zeti (após normalização) */
|
|
465
|
+
interface ZetiConfigInternal<TPrisma = any> {
|
|
466
|
+
databases: ZetiDatabaseConfig;
|
|
467
|
+
specialDatabases?: Record<string, string>;
|
|
468
|
+
prisma: ZetiPrismaConfig;
|
|
469
|
+
/** Nova configuração de conexão Prisma com modos de operação */
|
|
470
|
+
prismaConnection?: ZetiPrismaConnectionConfig<TPrisma>;
|
|
471
|
+
swagger: Required<Omit<ZetiSwaggerConfig, 'globalHeaders' | 'description'>> & {
|
|
472
|
+
globalHeaders?: ZetiSwaggerHeaderParam[];
|
|
473
|
+
description?: string;
|
|
474
|
+
};
|
|
475
|
+
tenant?: ZetiTenantConfig;
|
|
476
|
+
cors: Required<Omit<ZetiCorsConfig, 'maxAge'>> & {
|
|
477
|
+
maxAge?: number;
|
|
478
|
+
};
|
|
479
|
+
logger: boolean;
|
|
480
|
+
debug: boolean;
|
|
481
|
+
headers?: ZetiHeadersConfig;
|
|
482
|
+
middlewares: ZetiMiddlewareConfig;
|
|
483
|
+
errorHandler: ZetiErrorHandlerConfig | boolean;
|
|
484
|
+
hooks?: {
|
|
485
|
+
onRouteRegister?: (route: any) => void;
|
|
486
|
+
onRequest?: (context: any) => void | Promise<void>;
|
|
487
|
+
onResponse?: (context: any, response: any) => any;
|
|
488
|
+
};
|
|
489
|
+
dev: Required<ZetiDevConfig>;
|
|
490
|
+
workers?: WorkersConfig;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Configuração do Zeti Framework.
|
|
494
|
+
*
|
|
495
|
+
* A maioria das opções tem defaults sensatos - você só precisa configurar o que for diferente.
|
|
496
|
+
*
|
|
497
|
+
* @example Configuração mínima
|
|
498
|
+
* ```typescript
|
|
499
|
+
* defineZetiConfig({
|
|
500
|
+
* swagger: { title: "My API" },
|
|
501
|
+
* });
|
|
502
|
+
* ```
|
|
503
|
+
*/
|
|
504
|
+
interface ZetiConfig {
|
|
505
|
+
/**
|
|
506
|
+
* URL de conexão do banco de dados (para apps single-tenant).
|
|
507
|
+
* Se não informado, usa DATABASE_URL do .env automaticamente.
|
|
508
|
+
*/
|
|
509
|
+
databaseUrl?: string;
|
|
510
|
+
/**
|
|
511
|
+
* Configuração de databases (para apps multi-tenant).
|
|
512
|
+
* Se não informado, o framework usa databaseUrl ou DATABASE_URL do .env.
|
|
513
|
+
*/
|
|
514
|
+
databases?: ZetiDatabaseConfig;
|
|
515
|
+
specialDatabases?: Record<string, string>;
|
|
516
|
+
/** Configuração do Prisma. Opcional - usa defaults sensatos. */
|
|
517
|
+
prisma?: ZetiPrismaConfig;
|
|
518
|
+
/**
|
|
519
|
+
* Configuração do Swagger. Apenas `title` é obrigatório.
|
|
520
|
+
* Defaults: enabled=true, version="1.0.0", uiPath="/swagger", docPath="/swagger/doc"
|
|
521
|
+
*/
|
|
522
|
+
swagger: {
|
|
523
|
+
/** Título da API (obrigatório) */
|
|
524
|
+
title: string;
|
|
525
|
+
/** Versão da API. Default: "1.0.0" */
|
|
526
|
+
version?: string;
|
|
527
|
+
/** Descrição da API */
|
|
528
|
+
description?: string;
|
|
529
|
+
/** Servidores. Default: [{ url: "http://localhost:{port}" }] */
|
|
530
|
+
servers?: Array<{
|
|
531
|
+
url: string;
|
|
532
|
+
description?: string;
|
|
533
|
+
}>;
|
|
534
|
+
/** Habilitar Swagger UI. Default: true */
|
|
535
|
+
enabled?: boolean;
|
|
536
|
+
/** Caminho do arquivo de schemas. Default: "./.zeti/generated/swagger-schemas.ts" */
|
|
537
|
+
outputPath?: string;
|
|
538
|
+
/** Gerar schemas no build. Default: true */
|
|
539
|
+
generateOnBuild?: boolean;
|
|
540
|
+
/** Caminho da UI. Default: "/swagger" */
|
|
541
|
+
uiPath?: string;
|
|
542
|
+
/** Caminho do JSON. Default: "/swagger/doc" */
|
|
543
|
+
docPath?: string;
|
|
544
|
+
/** Headers globais */
|
|
545
|
+
globalHeaders?: ZetiSwaggerHeaderParam[];
|
|
546
|
+
};
|
|
547
|
+
/** Configuração de multi-tenancy. Se não informado, tenant fica desabilitado. */
|
|
548
|
+
tenant?: ZetiTenantConfig;
|
|
549
|
+
/**
|
|
550
|
+
* Configuração de CORS. Opcional - usa defaults permissivos para desenvolvimento.
|
|
551
|
+
* Defaults: enabled=true, origin="*", credentials=true, allowHeaders=["*"]
|
|
552
|
+
*/
|
|
553
|
+
cors?: ZetiCorsConfig;
|
|
554
|
+
/** Habilitar logger de requisições. Default: true */
|
|
555
|
+
logger?: boolean;
|
|
556
|
+
/** Habilitar logs de debug. Default: false */
|
|
557
|
+
debug?: boolean;
|
|
558
|
+
/** Configuração de headers customizados */
|
|
559
|
+
headers?: ZetiHeadersConfig;
|
|
560
|
+
/** Configuração de middlewares */
|
|
561
|
+
middlewares?: ZetiMiddlewareConfig;
|
|
562
|
+
/** Configuração do error handler. Default: {} (habilitado com defaults) */
|
|
563
|
+
errorHandler?: ZetiErrorHandlerConfig | boolean;
|
|
564
|
+
/** Hooks do ciclo de vida */
|
|
565
|
+
hooks?: {
|
|
566
|
+
onRouteRegister?: (route: any) => void;
|
|
567
|
+
onRequest?: (context: any) => void | Promise<void>;
|
|
568
|
+
onResponse?: (context: any, response: any) => any;
|
|
569
|
+
};
|
|
570
|
+
/**
|
|
571
|
+
* Configuração de desenvolvimento (usado pelo CLI `zeti dev`).
|
|
572
|
+
* Opcional - usa defaults sensatos.
|
|
573
|
+
*/
|
|
574
|
+
dev?: ZetiDevConfig;
|
|
575
|
+
/**
|
|
576
|
+
* Workers que serão iniciados automaticamente com o servidor.
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```typescript
|
|
580
|
+
* workers: {
|
|
581
|
+
* email: {
|
|
582
|
+
* fn: async (db) => {
|
|
583
|
+
* const emails = await db.email.findMany({ where: { status: 'PENDING' } });
|
|
584
|
+
* // processar...
|
|
585
|
+
* },
|
|
586
|
+
* intervalSeconds: 30,
|
|
587
|
+
* },
|
|
588
|
+
* sync: {
|
|
589
|
+
* fn: async (db, tenantId) => {
|
|
590
|
+
* // sincroniza dados do tenant
|
|
591
|
+
* },
|
|
592
|
+
* intervalSeconds: 60,
|
|
593
|
+
* multiTenant: true,
|
|
594
|
+
* },
|
|
595
|
+
* }
|
|
596
|
+
* ```
|
|
597
|
+
*/
|
|
598
|
+
workers?: WorkersConfig;
|
|
599
|
+
/**
|
|
600
|
+
* Configuração do Redis.
|
|
601
|
+
*
|
|
602
|
+
* Se fornecido, o cliente Redis será inicializado automaticamente
|
|
603
|
+
* e disponibilizado via `import { redis } from '@zeti/app'`.
|
|
604
|
+
*
|
|
605
|
+
* @example
|
|
606
|
+
* ```typescript
|
|
607
|
+
* redis: {
|
|
608
|
+
* host: process.env.REDIS_HOST ?? 'localhost',
|
|
609
|
+
* port: parseInt(process.env.REDIS_PORT ?? '6379'),
|
|
610
|
+
* keyPrefix: 'myapp:',
|
|
611
|
+
* }
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
redis?: RedisConfig;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Define a configuração do Zeti Framework.
|
|
619
|
+
*
|
|
620
|
+
* Detecta automaticamente se é single-tenant ou multi-tenant e aplica defaults sensatos.
|
|
621
|
+
*
|
|
622
|
+
* @example Configuração mínima (single-tenant)
|
|
623
|
+
* ```typescript
|
|
624
|
+
* export const zetiConfig = defineZetiConfig({
|
|
625
|
+
* swagger: { title: "My API" },
|
|
626
|
+
* });
|
|
627
|
+
* ```
|
|
628
|
+
*
|
|
629
|
+
* @example Multi-tenant
|
|
630
|
+
* ```typescript
|
|
631
|
+
* export const zetiConfig = defineZetiConfig({
|
|
632
|
+
* databases: {
|
|
633
|
+
* connections: {
|
|
634
|
+
* mulherdevalor: env("TENANT_MULHERDEVALOR_DATABASE_URL"),
|
|
635
|
+
* outroTenant: env("TENANT_OUTRO_DATABASE_URL"),
|
|
636
|
+
* },
|
|
637
|
+
* },
|
|
638
|
+
* tenant: { enabled: true, required: true },
|
|
639
|
+
* swagger: { title: "Multi-tenant API" },
|
|
640
|
+
* });
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
declare function defineZetiConfig(config: ZetiConfig, options?: {
|
|
644
|
+
port?: number;
|
|
645
|
+
}): ZetiConfigInternal;
|
|
646
|
+
|
|
647
|
+
export { type ConnectionStrategy as C, type ErrorResponse as E, type Middleware as M, Prisma as P, type RedisConfig as R, type SecurityScope as S, type TenantSelection as T, type ValidationError as V, type WorkerConfig as W, type ZetiSwaggerConfig as Z, type ZetiConfigInternal as a, type ZetiPrismaConnectionConfig as b, type ErrorTrace as c, type PrismaClientBase as d, type WorkersConfig as e, type ZetiConfig as f, type ZetiCorsConfig as g, type ZetiDatabaseConfig as h, type ZetiDevConfig as i, type ZetiErrorHandlerConfig as j, type ZetiHeadersConfig as k, type ZetiMiddlewareConfig as l, type ZetiPrismaConfig as m, type ZetiSwaggerHeaderParam as n, type ZetiTenantConfig as o, closeRedis as p, createErrorHandler as q, defineZetiConfig as r, getRedisClient as s, getRedisConfig as t, handleError as u, initRedis as v };
|