zeti-framework 0.1.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 (70) hide show
  1. package/README.md +244 -0
  2. package/dist/core/framework.d.ts +48 -0
  3. package/dist/core/framework.d.ts.map +1 -0
  4. package/dist/core/framework.js +236 -0
  5. package/dist/core/framework.js.map +1 -0
  6. package/dist/index.d.ts +12 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +12 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/scripts/generate-registry.d.ts +8 -0
  11. package/dist/scripts/generate-registry.d.ts.map +1 -0
  12. package/dist/scripts/generate-registry.js +34 -0
  13. package/dist/scripts/generate-registry.js.map +1 -0
  14. package/dist/scripts/generate-swagger-types.d.ts +6 -0
  15. package/dist/scripts/generate-swagger-types.d.ts.map +1 -0
  16. package/dist/scripts/generate-swagger-types.js +196 -0
  17. package/dist/scripts/generate-swagger-types.js.map +1 -0
  18. package/dist/scripts/index.d.ts +3 -0
  19. package/dist/scripts/index.d.ts.map +1 -0
  20. package/dist/scripts/index.js +3 -0
  21. package/dist/scripts/index.js.map +1 -0
  22. package/dist/swagger/generator.d.ts +14 -0
  23. package/dist/swagger/generator.d.ts.map +1 -0
  24. package/dist/swagger/generator.js +146 -0
  25. package/dist/swagger/generator.js.map +1 -0
  26. package/dist/swagger/index.d.ts +4 -0
  27. package/dist/swagger/index.d.ts.map +1 -0
  28. package/dist/swagger/index.js +4 -0
  29. package/dist/swagger/index.js.map +1 -0
  30. package/dist/swagger/registry.d.ts +8 -0
  31. package/dist/swagger/registry.d.ts.map +1 -0
  32. package/dist/swagger/registry.js +13 -0
  33. package/dist/swagger/registry.js.map +1 -0
  34. package/dist/swagger/zod-converter.d.ts +3 -0
  35. package/dist/swagger/zod-converter.d.ts.map +1 -0
  36. package/dist/swagger/zod-converter.js +48 -0
  37. package/dist/swagger/zod-converter.js.map +1 -0
  38. package/dist/tenants/index.d.ts +3 -0
  39. package/dist/tenants/index.d.ts.map +1 -0
  40. package/dist/tenants/index.js +3 -0
  41. package/dist/tenants/index.js.map +1 -0
  42. package/dist/tenants/manager.d.ts +24 -0
  43. package/dist/tenants/manager.d.ts.map +1 -0
  44. package/dist/tenants/manager.js +179 -0
  45. package/dist/tenants/manager.js.map +1 -0
  46. package/dist/tenants/metrics.d.ts +31 -0
  47. package/dist/tenants/metrics.d.ts.map +1 -0
  48. package/dist/tenants/metrics.js +51 -0
  49. package/dist/tenants/metrics.js.map +1 -0
  50. package/dist/types/config.d.ts +67 -0
  51. package/dist/types/config.d.ts.map +1 -0
  52. package/dist/types/config.js +4 -0
  53. package/dist/types/config.js.map +1 -0
  54. package/dist/types/framework.d.ts +65 -0
  55. package/dist/types/framework.d.ts.map +1 -0
  56. package/dist/types/framework.js +2 -0
  57. package/dist/types/framework.js.map +1 -0
  58. package/dist/types/prisma.d.ts +37 -0
  59. package/dist/types/prisma.d.ts.map +1 -0
  60. package/dist/types/prisma.js +11 -0
  61. package/dist/types/prisma.js.map +1 -0
  62. package/dist/utils/error-handler.d.ts +31 -0
  63. package/dist/utils/error-handler.d.ts.map +1 -0
  64. package/dist/utils/error-handler.js +102 -0
  65. package/dist/utils/error-handler.js.map +1 -0
  66. package/dist/utils/index.d.ts +2 -0
  67. package/dist/utils/index.d.ts.map +1 -0
  68. package/dist/utils/index.js +2 -0
  69. package/dist/utils/index.js.map +1 -0
  70. package/package.json +67 -0
@@ -0,0 +1,179 @@
1
+ import { PrismaPg } from '@prisma/adapter-pg';
2
+ import pg from 'pg';
3
+ import { MetricsCollector } from './metrics';
4
+ export class TenantManager {
5
+ MAX_RECOMMENDED_DATABASES = 5;
6
+ databaseConnections = {};
7
+ specialDatabases = {};
8
+ clients = new Map();
9
+ config;
10
+ databaseConfig;
11
+ metrics;
12
+ cleanupInterval;
13
+ constructor(databaseConfig, prismaConfig, specialDatabases) {
14
+ this.config = prismaConfig;
15
+ this.databaseConfig = databaseConfig;
16
+ this.specialDatabases = specialDatabases || {};
17
+ this.metrics = new MetricsCollector();
18
+ if (databaseConfig.autoLoadFromEnv) {
19
+ this.loadFromEnv(databaseConfig.envPattern || 'DATABASE_{name}_URL');
20
+ }
21
+ else if (databaseConfig.connections) {
22
+ this.databaseConnections = databaseConfig.connections;
23
+ }
24
+ const totalDatabases = Object.keys(this.databaseConnections).length +
25
+ Object.keys(this.specialDatabases).length;
26
+ if (totalDatabases > this.MAX_RECOMMENDED_DATABASES) {
27
+ console.warn(`⚠️ You have ${totalDatabases} databases configured. ` +
28
+ `For high multi-tenancy scenarios, consider using a connection pooler like PgBouncer.`);
29
+ }
30
+ this.metrics.updateMetrics({
31
+ totalTenants: Object.keys(this.databaseConnections).length,
32
+ });
33
+ this.startCleanupInterval();
34
+ }
35
+ startCleanupInterval() {
36
+ const cleanupInterval = this.databaseConfig.cache?.cleanupInterval || 60000;
37
+ this.cleanupInterval = setInterval(() => {
38
+ this.cleanupExpiredConnections();
39
+ }, cleanupInterval);
40
+ }
41
+ cleanupExpiredConnections() {
42
+ const ttl = (this.databaseConfig.cache?.ttl || 300000);
43
+ const maxClients = this.databaseConfig.cache?.maxClients || 50;
44
+ const now = Date.now();
45
+ const expiredKeys = [];
46
+ const clientsToRemove = [];
47
+ for (const [key, cached] of this.clients.entries()) {
48
+ const age = now - cached.lastAccessed.getTime();
49
+ if (age > ttl) {
50
+ expiredKeys.push(key);
51
+ }
52
+ }
53
+ for (const key of expiredKeys) {
54
+ const cached = this.clients.get(key);
55
+ if (cached) {
56
+ cached.client.$disconnect().catch(() => { });
57
+ this.clients.delete(key);
58
+ }
59
+ }
60
+ if (this.clients.size > maxClients) {
61
+ const sorted = Array.from(this.clients.entries())
62
+ .sort((a, b) => a[1].lastAccessed.getTime() - b[1].lastAccessed.getTime());
63
+ const toRemove = sorted.slice(0, this.clients.size - maxClients);
64
+ for (const [key, cached] of toRemove) {
65
+ cached.client.$disconnect().catch(() => { });
66
+ this.clients.delete(key);
67
+ clientsToRemove.push(key);
68
+ }
69
+ }
70
+ this.metrics.updateMetrics({
71
+ cachedConnections: this.clients.size,
72
+ lastCleanup: new Date(),
73
+ });
74
+ }
75
+ getMetrics() {
76
+ return this.metrics.getMetrics();
77
+ }
78
+ loadFromEnv(pattern) {
79
+ for (const [key, value] of Object.entries(process.env)) {
80
+ if (key.startsWith('DATABASE_') && key.endsWith('_URL') && value) {
81
+ const databaseName = key
82
+ .replace('DATABASE_', '')
83
+ .replace('_URL', '')
84
+ .toLowerCase();
85
+ this.databaseConnections[databaseName] = value;
86
+ }
87
+ else if (key.startsWith('TENANT_') && key.endsWith('_DATABASE_URL') && value) {
88
+ const databaseName = key
89
+ .replace('TENANT_', '')
90
+ .replace('_DATABASE_URL', '')
91
+ .toLowerCase();
92
+ this.databaseConnections[databaseName] = value;
93
+ }
94
+ }
95
+ }
96
+ async getTenantDatabase(databaseId) {
97
+ const connectionString = this.databaseConnections[databaseId];
98
+ if (!connectionString) {
99
+ this.metrics.incrementError();
100
+ const available = Object.keys(this.databaseConnections).join(', ');
101
+ throw new Error(`Database '${databaseId}' not found. Available: ${available || 'none'}`);
102
+ }
103
+ return this.getOrCreateClient(`database:${databaseId}`, connectionString);
104
+ }
105
+ getSpecialDatabase(key) {
106
+ const connectionString = this.specialDatabases[key];
107
+ if (!connectionString) {
108
+ this.metrics.incrementError();
109
+ const available = Object.keys(this.specialDatabases).join(', ');
110
+ throw new Error(`Special database '${key}' not found. Available: ${available || 'none'}`);
111
+ }
112
+ return this.getOrCreateClient(`special:${key}`, connectionString);
113
+ }
114
+ getOrCreateClient(cacheKey, connectionString) {
115
+ const cached = this.clients.get(cacheKey);
116
+ if (cached) {
117
+ cached.lastAccessed = new Date();
118
+ this.metrics.incrementCacheHit();
119
+ this.metrics.updateMetrics({
120
+ cachedConnections: this.clients.size,
121
+ });
122
+ return cached.client;
123
+ }
124
+ this.metrics.incrementCacheMiss();
125
+ const pool = new pg.Pool({
126
+ connectionString,
127
+ max: this.config.connectionPool?.max || 10,
128
+ min: this.config.connectionPool?.min || 2,
129
+ idleTimeoutMillis: this.config.connectionPool?.idleTimeoutMillis || 30000,
130
+ connectionTimeoutMillis: this.config.connectionPool?.connectionTimeoutMillis || 5000,
131
+ });
132
+ const adapter = new PrismaPg(pool);
133
+ // Usamos require dinâmico para evitar erro de build
134
+ // O PrismaClient real será usado em runtime pelo usuário
135
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
136
+ const PrismaModule = require('@prisma/client');
137
+ const PrismaClient = PrismaModule.PrismaClient || PrismaModule.default?.PrismaClient || PrismaModule;
138
+ const client = new PrismaClient({
139
+ adapter,
140
+ log: this.config.logLevel || ['error'],
141
+ });
142
+ this.clients.set(cacheKey, {
143
+ client,
144
+ createdAt: new Date(),
145
+ lastAccessed: new Date(),
146
+ });
147
+ this.metrics.updateMetrics({
148
+ cachedConnections: this.clients.size,
149
+ activeConnections: this.clients.size,
150
+ });
151
+ return client;
152
+ }
153
+ isValidDatabase(databaseId) {
154
+ return databaseId in this.databaseConnections;
155
+ }
156
+ getAllDatabases() {
157
+ return Object.keys(this.databaseConnections);
158
+ }
159
+ async shutdown() {
160
+ if (this.cleanupInterval) {
161
+ clearInterval(this.cleanupInterval);
162
+ }
163
+ const disconnectPromises = [];
164
+ for (const [key, cached] of this.clients.entries()) {
165
+ disconnectPromises.push(cached.client
166
+ .$disconnect()
167
+ .then(() => {
168
+ console.log(`🔌 Disconnected: ${key}`);
169
+ })
170
+ .catch((error) => {
171
+ console.error(`❌ Error disconnecting ${key}:`, error);
172
+ }));
173
+ }
174
+ await Promise.all(disconnectPromises);
175
+ this.clients.clear();
176
+ console.log('✅ All database connections closed');
177
+ }
178
+ }
179
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/tenants/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface TenantMetrics {
2
+ totalTenants: number;
3
+ activeConnections: number;
4
+ cachedConnections: number;
5
+ connectionPoolSize: number;
6
+ cacheHits: number;
7
+ cacheMisses: number;
8
+ errors: number;
9
+ lastCleanup?: Date;
10
+ uptime: number;
11
+ }
12
+ export declare class MetricsCollector {
13
+ private metrics;
14
+ private startTime;
15
+ private cacheHitCount;
16
+ private cacheMissCount;
17
+ private errorCount;
18
+ incrementCacheHit(): void;
19
+ incrementCacheMiss(): void;
20
+ incrementError(): void;
21
+ updateMetrics(data: {
22
+ totalTenants?: number;
23
+ activeConnections?: number;
24
+ cachedConnections?: number;
25
+ connectionPoolSize?: number;
26
+ lastCleanup?: Date;
27
+ }): void;
28
+ getMetrics(): TenantMetrics;
29
+ reset(): void;
30
+ }
31
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/tenants/metrics.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CASb;IAEF,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,UAAU,CAAK;IAEvB,iBAAiB,IAAI,IAAI;IAIzB,kBAAkB,IAAI,IAAI;IAI1B,cAAc,IAAI,IAAI;IAItB,aAAa,CAAC,IAAI,EAAE;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,WAAW,CAAC,EAAE,IAAI,CAAC;KACpB,GAAG,IAAI;IAWR,UAAU,IAAI,aAAa;IAU3B,KAAK,IAAI,IAAI;CAMd"}
@@ -0,0 +1,51 @@
1
+ export class MetricsCollector {
2
+ metrics = {
3
+ totalTenants: 0,
4
+ activeConnections: 0,
5
+ cachedConnections: 0,
6
+ connectionPoolSize: 0,
7
+ cacheHits: 0,
8
+ cacheMisses: 0,
9
+ errors: 0,
10
+ uptime: 0,
11
+ };
12
+ startTime = new Date();
13
+ cacheHitCount = 0;
14
+ cacheMissCount = 0;
15
+ errorCount = 0;
16
+ incrementCacheHit() {
17
+ this.cacheHitCount++;
18
+ }
19
+ incrementCacheMiss() {
20
+ this.cacheMissCount++;
21
+ }
22
+ incrementError() {
23
+ this.errorCount++;
24
+ }
25
+ updateMetrics(data) {
26
+ this.metrics = {
27
+ ...this.metrics,
28
+ ...data,
29
+ cacheHits: this.cacheHitCount,
30
+ cacheMisses: this.cacheMissCount,
31
+ errors: this.errorCount,
32
+ uptime: Date.now() - this.startTime.getTime(),
33
+ };
34
+ }
35
+ getMetrics() {
36
+ return {
37
+ ...this.metrics,
38
+ cacheHits: this.cacheHitCount,
39
+ cacheMisses: this.cacheMissCount,
40
+ errors: this.errorCount,
41
+ uptime: Date.now() - this.startTime.getTime(),
42
+ };
43
+ }
44
+ reset() {
45
+ this.cacheHitCount = 0;
46
+ this.cacheMissCount = 0;
47
+ this.errorCount = 0;
48
+ this.startTime = new Date();
49
+ }
50
+ }
51
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/tenants/metrics.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,gBAAgB;IACnB,OAAO,GAAkB;QAC/B,YAAY,EAAE,CAAC;QACf,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,kBAAkB,EAAE,CAAC;QACrB,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,CAAC;KACV,CAAC;IAEM,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAC7B,aAAa,GAAG,CAAC,CAAC;IAClB,cAAc,GAAG,CAAC,CAAC;IACnB,UAAU,GAAG,CAAC,CAAC;IAEvB,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,aAAa,CAAC,IAMb;QACC,IAAI,CAAC,OAAO,GAAG;YACb,GAAG,IAAI,CAAC,OAAO;YACf,GAAG,IAAI;YACP,SAAS,EAAE,IAAI,CAAC,aAAa;YAC7B,WAAW,EAAE,IAAI,CAAC,cAAc;YAChC,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;SAC9C,CAAC;IACJ,CAAC;IAED,UAAU;QACR,OAAO;YACL,GAAG,IAAI,CAAC,OAAO;YACf,SAAS,EAAE,IAAI,CAAC,aAAa;YAC7B,WAAW,EAAE,IAAI,CAAC,cAAc;YAChC,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE;SAC9C,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,67 @@
1
+ import type { Context, Next } from 'hono';
2
+ export type Middleware = (c: Context, next: Next) => Promise<Response | void> | Response | void;
3
+ export interface ZetiDatabaseConfig {
4
+ autoLoadFromEnv?: boolean;
5
+ envPattern?: string;
6
+ connections?: Record<string, string>;
7
+ resolver?: (databaseId: string) => Promise<string> | string;
8
+ cache?: {
9
+ maxClients?: number;
10
+ ttl?: number;
11
+ cleanupInterval?: number;
12
+ };
13
+ }
14
+ export interface ZetiPrismaConfig {
15
+ adapter?: 'pg' | 'mysql' | 'sqlite' | 'custom';
16
+ logLevel?: ('query' | 'error' | 'warn')[];
17
+ connectionPool?: {
18
+ max?: number;
19
+ min?: number;
20
+ idleTimeoutMillis?: number;
21
+ connectionTimeoutMillis?: number;
22
+ };
23
+ }
24
+ export interface ZetiSwaggerConfig {
25
+ enabled: boolean;
26
+ title: string;
27
+ version: string;
28
+ servers: Array<{
29
+ url: string;
30
+ description?: string;
31
+ }>;
32
+ outputPath?: string;
33
+ generateOnBuild?: boolean;
34
+ }
35
+ export interface ZetiHeadersConfig {
36
+ tenant?: string;
37
+ timezone?: string;
38
+ }
39
+ export interface ZetiTenantConfig {
40
+ enabled?: boolean;
41
+ required?: boolean;
42
+ headerName?: string;
43
+ defaultDatabase?: string;
44
+ }
45
+ export interface ZetiMiddlewareConfig {
46
+ global?: Middleware[];
47
+ named?: Record<string, Middleware | ((...args: any[]) => Middleware)>;
48
+ }
49
+ import type { ZetiErrorHandlerConfig } from '../utils/error-handler';
50
+ export interface ZetiConfig {
51
+ databases: ZetiDatabaseConfig;
52
+ specialDatabases?: Record<string, string>;
53
+ prisma: ZetiPrismaConfig;
54
+ swagger: ZetiSwaggerConfig;
55
+ tenant?: ZetiTenantConfig;
56
+ auth?: Record<string, any>;
57
+ headers?: ZetiHeadersConfig;
58
+ middlewares?: ZetiMiddlewareConfig;
59
+ errorHandler?: ZetiErrorHandlerConfig | boolean;
60
+ hooks?: {
61
+ onRouteRegister?: (route: any) => void;
62
+ onRequest?: (context: any) => void | Promise<void>;
63
+ onResponse?: (context: any, response: any) => any;
64
+ };
65
+ }
66
+ export declare function defineZetiConfig(config: ZetiConfig): ZetiConfig;
67
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC;AAEhG,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5D,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC/C,QAAQ,CAAC,EAAE,CAAC,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC;IAC1C,cAAc,CAAC,EAAE;QACf,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC;CACvE;AAED,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,YAAY,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAChD,KAAK,CAAC,EAAE;QACN,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;QACvC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,GAAG,CAAC;KACnD,CAAC;CACH;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAE/D"}
@@ -0,0 +1,4 @@
1
+ export function defineZetiConfig(config) {
2
+ return config;
3
+ }
4
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAwEA,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { z, ZodTypeAny, ZodRawShape, ZodObject } from 'zod';
2
+ import { Context, Next } from 'hono';
3
+ import type { PrismaClientBase } from './prisma';
4
+ export type SchemaDefinition = {
5
+ body?: ZodRawShape | ZodTypeAny;
6
+ query?: ZodRawShape | ZodTypeAny;
7
+ response?: ZodRawShape | ZodTypeAny;
8
+ };
9
+ type NormalizeZod<T> = T extends ZodTypeAny ? T : T extends ZodRawShape ? ZodObject<T> : never;
10
+ export type InferBody<S extends SchemaDefinition> = S['body'] extends undefined ? unknown : z.infer<NormalizeZod<S['body']>>;
11
+ export type InferQuery<S extends SchemaDefinition> = S['query'] extends undefined ? unknown : z.infer<NormalizeZod<S['query']>>;
12
+ export type ExtractParams<T extends string> = T extends `${infer _Start}:${infer Param}/${infer Rest}` ? {
13
+ [K in Param]: string;
14
+ } & ExtractParams<Rest> : T extends `${infer _Start}:${infer Param}` ? {
15
+ [K in Param]: string;
16
+ } : {};
17
+ export type ZetiContextExtensions = {
18
+ ipAddress?: string;
19
+ userAgent?: string;
20
+ timezone: string;
21
+ tenantId: string;
22
+ };
23
+ export type ZetiContext<TContext extends Context = Context> = TContext & ZetiContextExtensions;
24
+ export interface ZetiRouteProps<TParams extends Record<string, string>, TBody, TQuery, TPrisma extends PrismaClientBase = PrismaClientBase, TUser = any> {
25
+ context: ZetiContext;
26
+ next: Next;
27
+ params: TParams;
28
+ body: TBody;
29
+ query: TQuery;
30
+ user?: TUser;
31
+ db: TPrisma;
32
+ res: ZetiResponseHelpers;
33
+ }
34
+ export interface ZetiResponseHelpers {
35
+ goneError: (params: {
36
+ message: string;
37
+ code?: string;
38
+ }) => never;
39
+ unauthorizedError: (message: string) => never;
40
+ badRequestError: (message: string) => never;
41
+ }
42
+ export interface ZetiMethodOptions<TPath extends string, TSchema extends SchemaDefinition, TPrisma extends PrismaClientBase = PrismaClientBase, TUser = any> {
43
+ middleware?: {
44
+ use?: string[];
45
+ schema?: (zod: typeof z) => TSchema;
46
+ database?: string;
47
+ tenant?: boolean;
48
+ };
49
+ route: (props: ZetiRouteProps<ExtractParams<TPath>, InferBody<TSchema>, InferQuery<TSchema>, TPrisma, TUser>) => Promise<any>;
50
+ }
51
+ export interface RouteMetadata {
52
+ path: string;
53
+ method: 'get' | 'post' | 'put' | 'delete' | 'patch';
54
+ auth: boolean;
55
+ claims?: string[];
56
+ roles?: string[];
57
+ bodySchema?: ZodTypeAny;
58
+ querySchema?: ZodTypeAny;
59
+ responseSchema?: ZodTypeAny;
60
+ summary?: string;
61
+ description?: string;
62
+ tags?: string[];
63
+ }
64
+ export {};
65
+ //# sourceMappingURL=framework.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework.d.ts","sourceRoot":"","sources":["../../src/types/framework.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=framework.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework.js","sourceRoot":"","sources":["../../src/types/framework.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Tipos próprios para Prisma
3
+ *
4
+ * Estes tipos são usados para evitar dependência direta de @prisma/client
5
+ * durante o build da biblioteca, já que Prisma é uma peer dependency.
6
+ *
7
+ * O usuário passa o PrismaClient real como generic, então o TypeScript
8
+ * vai inferir os tipos corretos em tempo de uso.
9
+ */
10
+ export type PrismaClientBase = {
11
+ $connect: () => Promise<void>;
12
+ $disconnect: () => Promise<void>;
13
+ $transaction: <T>(fn: (client: any) => Promise<T>) => Promise<T>;
14
+ $queryRaw: (query: string, ...values: any[]) => Promise<any>;
15
+ $executeRaw: (query: string, ...values: any[]) => Promise<number>;
16
+ [key: string]: any;
17
+ };
18
+ export declare namespace Prisma {
19
+ interface PrismaClientKnownRequestError extends Error {
20
+ code: string;
21
+ meta?: any;
22
+ clientVersion?: string;
23
+ }
24
+ interface PrismaClientValidationError extends Error {
25
+ message: string;
26
+ }
27
+ interface PrismaClientInitializationError extends Error {
28
+ errorCode?: string;
29
+ clientVersion?: string;
30
+ }
31
+ interface PrismaClientRustPanicError extends Error {
32
+ requestId?: string;
33
+ clientVersion?: string;
34
+ }
35
+ type PrismaClientError = PrismaClientKnownRequestError | PrismaClientValidationError | PrismaClientInitializationError | PrismaClientRustPanicError;
36
+ }
37
+ //# sourceMappingURL=prisma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../../src/types/prisma.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACjE,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7D,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAGF,yBAAiB,MAAM,CAAC;IACtB,UAAiB,6BAA8B,SAAQ,KAAK;QAC1D,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAED,UAAiB,2BAA4B,SAAQ,KAAK;QACxD,OAAO,EAAE,MAAM,CAAC;KACjB;IAED,UAAiB,+BAAgC,SAAQ,KAAK;QAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAED,UAAiB,0BAA2B,SAAQ,KAAK;QACvD,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAED,KAAY,iBAAiB,GACzB,6BAA6B,GAC7B,2BAA2B,GAC3B,+BAA+B,GAC/B,0BAA0B,CAAC;CAChC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tipos próprios para Prisma
3
+ *
4
+ * Estes tipos são usados para evitar dependência direta de @prisma/client
5
+ * durante o build da biblioteca, já que Prisma é uma peer dependency.
6
+ *
7
+ * O usuário passa o PrismaClient real como generic, então o TypeScript
8
+ * vai inferir os tipos corretos em tempo de uso.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=prisma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.js","sourceRoot":"","sources":["../../src/types/prisma.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,31 @@
1
+ import type { Context } from 'hono';
2
+ import { HTTPException } from 'hono/http-exception';
3
+ import type { Prisma } from '../types/prisma';
4
+ export interface ValidationError {
5
+ field: string;
6
+ errors: string[];
7
+ }
8
+ export interface ErrorResponse {
9
+ data: null;
10
+ status: number;
11
+ message: string;
12
+ validationErrors?: Record<string, {
13
+ errors: string[];
14
+ }>;
15
+ }
16
+ export interface ZetiErrorHandlerConfig {
17
+ formatError?: (error: any, context: Context) => ErrorResponse;
18
+ logError?: (error: any, context: Context) => void;
19
+ }
20
+ export declare function createErrorHandler(config?: ZetiErrorHandlerConfig): (c: Context, next: () => Promise<void>) => Promise<(Response & import("hono").TypedResponse<{
21
+ data: null;
22
+ status: number;
23
+ message: string;
24
+ validationErrors?: {
25
+ [x: string]: {
26
+ errors: string[];
27
+ };
28
+ } | undefined;
29
+ }, any, "json">) | undefined>;
30
+ export declare function handleError(exception: Error | HTTPException | Prisma.PrismaClientKnownRequestError | ValidationError[] | any, config?: ZetiErrorHandlerConfig): ErrorResponse;
31
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,KAAK,aAAa,CAAC;IAC9D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,sBAAsB,IAClD,GAAG,OAAO,EAAE,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC;UAZ7C,IAAI;YACF,MAAM;aACL,MAAM;;;oBAC6B,MAAM,EAAE;;;8BAsBrD;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,KAAK,GAAG,aAAa,GAAG,MAAM,CAAC,6BAA6B,GAAG,eAAe,EAAE,GAAG,GAAG,EACjG,MAAM,CAAC,EAAE,sBAAsB,GAC9B,aAAa,CAyFf"}
@@ -0,0 +1,102 @@
1
+ import { HTTPException } from 'hono/http-exception';
2
+ export function createErrorHandler(config) {
3
+ return async (c, next) => {
4
+ try {
5
+ await next();
6
+ }
7
+ catch (err) {
8
+ const response = handleError(err, config);
9
+ if (config?.logError) {
10
+ config.logError(err, c);
11
+ }
12
+ return c.json(response, response.status);
13
+ }
14
+ };
15
+ }
16
+ export function handleError(exception, config) {
17
+ if (config?.formatError) {
18
+ return config.formatError(exception, {});
19
+ }
20
+ let status = 500;
21
+ let message = 'Internal server error';
22
+ let validationErrors = undefined;
23
+ if (exception instanceof HTTPException) {
24
+ status = exception.status;
25
+ message = exception.message || 'Erro na requisição';
26
+ if (status === 400 || status === 422) {
27
+ if (exception.cause && typeof exception.cause === 'object') {
28
+ const cause = exception.cause;
29
+ if (cause.validationErrors) {
30
+ validationErrors = cause.validationErrors;
31
+ }
32
+ else if (cause.issues && Array.isArray(cause.issues)) {
33
+ validationErrors = cause.issues.reduce((acc, issue) => {
34
+ const field = issue.path?.join('.') || 'unknown';
35
+ if (!acc[field]) {
36
+ acc[field] = { errors: [] };
37
+ }
38
+ acc[field].errors.push(issue.message);
39
+ return acc;
40
+ }, {});
41
+ }
42
+ }
43
+ }
44
+ }
45
+ else if (exception && typeof exception === 'object' && 'code' in exception && exception.code && typeof exception.code === 'string' && exception.code.startsWith('P')) {
46
+ const prismaError = exception;
47
+ switch (prismaError.code) {
48
+ case 'P2003': {
49
+ status = 422;
50
+ const fieldName = prismaError.meta?.field_name;
51
+ if (fieldName) {
52
+ validationErrors = {
53
+ [fieldName]: {
54
+ errors: ['Campo inválido ou o registro não existe'],
55
+ },
56
+ };
57
+ }
58
+ else {
59
+ message = 'Campo inválido ou o registro não existe';
60
+ }
61
+ break;
62
+ }
63
+ case 'P2002': {
64
+ status = 409;
65
+ message = 'Registro já cadastrado';
66
+ break;
67
+ }
68
+ case 'P2025': {
69
+ status = 404;
70
+ message = 'Registro não encontrado';
71
+ break;
72
+ }
73
+ default: {
74
+ message = prismaError.message || 'Erro no banco de dados';
75
+ break;
76
+ }
77
+ }
78
+ }
79
+ else if (Array.isArray(exception)) {
80
+ status = 422;
81
+ message = '';
82
+ validationErrors = exception.reduce((acc, error) => {
83
+ acc[error.field] = {
84
+ errors: error.errors,
85
+ };
86
+ return acc;
87
+ }, {});
88
+ }
89
+ else if (exception instanceof Error) {
90
+ message = exception.message || 'Erro interno do servidor';
91
+ }
92
+ const response = {
93
+ data: null,
94
+ status,
95
+ message,
96
+ };
97
+ if ((status === 400 || status === 422) && validationErrors && Object.keys(validationErrors).length > 0) {
98
+ response.validationErrors = validationErrors;
99
+ }
100
+ return response;
101
+ }
102
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/utils/error-handler.ts"],"names":[],"mappings":"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"}