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,324 @@
|
|
|
1
|
+
// src/swagger/zod-converter.ts
|
|
2
|
+
import { ZodObject, ZodString, ZodNumber, ZodBoolean, ZodArray, ZodOptional, ZodNullable, ZodEnum, ZodUnion, ZodEffects, ZodDefault, ZodLiteral, ZodDate } from "zod";
|
|
3
|
+
function checkIsOptional(schema) {
|
|
4
|
+
if (schema instanceof ZodOptional) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
if (schema instanceof ZodDefault) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (schema instanceof ZodEffects) {
|
|
11
|
+
const innerSchema = schema._def.schema;
|
|
12
|
+
if (innerSchema) {
|
|
13
|
+
return checkIsOptional(innerSchema);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
function zodToJsonSchema(schema) {
|
|
19
|
+
if (schema instanceof ZodEffects) {
|
|
20
|
+
const innerSchema = schema._def.schema;
|
|
21
|
+
if (innerSchema) {
|
|
22
|
+
return zodToJsonSchema(innerSchema);
|
|
23
|
+
}
|
|
24
|
+
return { type: "string" };
|
|
25
|
+
}
|
|
26
|
+
if (schema instanceof ZodDefault) {
|
|
27
|
+
return zodToJsonSchema(schema._def.innerType);
|
|
28
|
+
}
|
|
29
|
+
if (schema instanceof ZodString) {
|
|
30
|
+
return { type: "string" };
|
|
31
|
+
}
|
|
32
|
+
if (schema instanceof ZodNumber) {
|
|
33
|
+
return { type: "number" };
|
|
34
|
+
}
|
|
35
|
+
if (schema instanceof ZodBoolean) {
|
|
36
|
+
return { type: "boolean" };
|
|
37
|
+
}
|
|
38
|
+
if (schema instanceof ZodDate) {
|
|
39
|
+
return { type: "string", format: "date-time" };
|
|
40
|
+
}
|
|
41
|
+
if (schema instanceof ZodLiteral) {
|
|
42
|
+
const value = schema._def.value;
|
|
43
|
+
const type = typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string";
|
|
44
|
+
return { type, enum: [value] };
|
|
45
|
+
}
|
|
46
|
+
if (schema instanceof ZodArray) {
|
|
47
|
+
return { type: "array", items: zodToJsonSchema(schema._def.type) };
|
|
48
|
+
}
|
|
49
|
+
if (schema instanceof ZodOptional) {
|
|
50
|
+
return zodToJsonSchema(schema._def.innerType);
|
|
51
|
+
}
|
|
52
|
+
if (schema instanceof ZodNullable) {
|
|
53
|
+
return { ...zodToJsonSchema(schema._def.innerType), nullable: true };
|
|
54
|
+
}
|
|
55
|
+
if (schema instanceof ZodEnum) {
|
|
56
|
+
return { type: "string", enum: schema._def.values };
|
|
57
|
+
}
|
|
58
|
+
if (schema instanceof ZodUnion) {
|
|
59
|
+
const options = schema._def.options.map((option) => {
|
|
60
|
+
return zodToJsonSchema(option);
|
|
61
|
+
});
|
|
62
|
+
return { oneOf: options };
|
|
63
|
+
}
|
|
64
|
+
if (schema instanceof ZodObject) {
|
|
65
|
+
const shape = schema.shape;
|
|
66
|
+
const properties = {};
|
|
67
|
+
const required = [];
|
|
68
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
69
|
+
properties[key] = zodToJsonSchema(value);
|
|
70
|
+
const isOptional = checkIsOptional(value);
|
|
71
|
+
if (!isOptional) {
|
|
72
|
+
required.push(key);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties,
|
|
78
|
+
...required.length > 0 ? { required } : {}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const typeName = schema?._def?.typeName;
|
|
82
|
+
if (typeName === "ZodString") return { type: "string" };
|
|
83
|
+
if (typeName === "ZodNumber") return { type: "number" };
|
|
84
|
+
if (typeName === "ZodBoolean") return { type: "boolean" };
|
|
85
|
+
return { type: "string" };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/utils/zod-file.ts
|
|
89
|
+
import { z as z2 } from "zod";
|
|
90
|
+
var FILE_SCHEMA_SYMBOL = /* @__PURE__ */ Symbol.for("zeti:file-schema");
|
|
91
|
+
function zFile(description) {
|
|
92
|
+
const schema = z2.any().describe(description || "File upload");
|
|
93
|
+
schema._def[FILE_SCHEMA_SYMBOL] = true;
|
|
94
|
+
schema._def.isFile = true;
|
|
95
|
+
return schema;
|
|
96
|
+
}
|
|
97
|
+
function zFiles(description) {
|
|
98
|
+
const schema = z2.array(z2.any()).describe(description || "Multiple file upload");
|
|
99
|
+
schema._def[FILE_SCHEMA_SYMBOL] = true;
|
|
100
|
+
schema._def.isFile = true;
|
|
101
|
+
schema._def.isMultiple = true;
|
|
102
|
+
return schema;
|
|
103
|
+
}
|
|
104
|
+
function isFileSchema(schema) {
|
|
105
|
+
return schema?._def?.[FILE_SCHEMA_SYMBOL] === true || schema?._def?.isFile === true;
|
|
106
|
+
}
|
|
107
|
+
function isMultipleFileSchema(schema) {
|
|
108
|
+
return isFileSchema(schema) && schema?._def?.isMultiple === true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/swagger/generator.ts
|
|
112
|
+
function extractPathParams(path) {
|
|
113
|
+
const matches = path.match(/:([^/]+)/g);
|
|
114
|
+
return matches ? matches.map((m) => m.slice(1)) : [];
|
|
115
|
+
}
|
|
116
|
+
function pathToOpenAPI(path) {
|
|
117
|
+
return path.replace(/:([^/]+)/g, "{$1}");
|
|
118
|
+
}
|
|
119
|
+
function extractTag(path) {
|
|
120
|
+
const parts = path.split("/").filter(Boolean);
|
|
121
|
+
return parts[0] || "default";
|
|
122
|
+
}
|
|
123
|
+
async function generateSwagger(registry, config, options) {
|
|
124
|
+
const routes = registry.getAll();
|
|
125
|
+
const paths = {};
|
|
126
|
+
let routeResponseSchemas = {};
|
|
127
|
+
let namedSchemas = {};
|
|
128
|
+
if (options?.loadGeneratedSchemas) {
|
|
129
|
+
try {
|
|
130
|
+
const schemas = await options.loadGeneratedSchemas();
|
|
131
|
+
if (schemas.routeResponseSchemas) {
|
|
132
|
+
routeResponseSchemas = schemas.routeResponseSchemas;
|
|
133
|
+
}
|
|
134
|
+
if (schemas.namedSchemas) {
|
|
135
|
+
namedSchemas = schemas.namedSchemas;
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const route of routes) {
|
|
141
|
+
const openApiPath = pathToOpenAPI(route.path);
|
|
142
|
+
const pathParams = extractPathParams(route.path);
|
|
143
|
+
const tag = route.tags?.[0] || extractTag(route.path);
|
|
144
|
+
if (!paths[openApiPath]) {
|
|
145
|
+
paths[openApiPath] = {};
|
|
146
|
+
}
|
|
147
|
+
const generated = routeResponseSchemas[route.path]?.[route.method];
|
|
148
|
+
let responseJsonSchema;
|
|
149
|
+
if (generated?.ref) {
|
|
150
|
+
responseJsonSchema = { $ref: `#/components/schemas/${generated.ref}` };
|
|
151
|
+
} else if (generated?.schema) {
|
|
152
|
+
responseJsonSchema = zodToJsonSchema(generated.schema);
|
|
153
|
+
} else if (route.responseSchema) {
|
|
154
|
+
responseJsonSchema = zodToJsonSchema(route.responseSchema);
|
|
155
|
+
} else {
|
|
156
|
+
responseJsonSchema = { type: "object" };
|
|
157
|
+
}
|
|
158
|
+
const operation = {
|
|
159
|
+
tags: route.tags || [tag],
|
|
160
|
+
summary: route.summary || `${route.method.toUpperCase()} ${route.path}`,
|
|
161
|
+
description: route.description,
|
|
162
|
+
parameters: [],
|
|
163
|
+
responses: {
|
|
164
|
+
"200": {
|
|
165
|
+
description: "Successful response",
|
|
166
|
+
content: {
|
|
167
|
+
"application/json": {
|
|
168
|
+
schema: responseJsonSchema
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
if (config.globalHeaders?.length) {
|
|
175
|
+
for (const header of config.globalHeaders) {
|
|
176
|
+
operation.parameters.push({
|
|
177
|
+
name: header.name,
|
|
178
|
+
in: "header",
|
|
179
|
+
required: header.required ?? false,
|
|
180
|
+
schema: { type: "string" },
|
|
181
|
+
description: header.description || `Header ${header.name}`,
|
|
182
|
+
...header.example ? { example: header.example } : {}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const param of pathParams) {
|
|
187
|
+
operation.parameters.push({
|
|
188
|
+
name: param,
|
|
189
|
+
in: "path",
|
|
190
|
+
required: true,
|
|
191
|
+
schema: { type: "string" }
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (route.querySchema) {
|
|
195
|
+
const queryJsonSchema = zodToJsonSchema(route.querySchema);
|
|
196
|
+
if (queryJsonSchema.properties) {
|
|
197
|
+
for (const [name, schema] of Object.entries(queryJsonSchema.properties)) {
|
|
198
|
+
operation.parameters.push({
|
|
199
|
+
name,
|
|
200
|
+
in: "query",
|
|
201
|
+
required: queryJsonSchema.required?.includes(name) || false,
|
|
202
|
+
schema
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (route.formDataSchema && ["post", "put", "patch"].includes(route.method)) {
|
|
208
|
+
const formDataJsonSchema = zodToJsonSchema(route.formDataSchema);
|
|
209
|
+
const properties = { ...formDataJsonSchema.properties || {} };
|
|
210
|
+
const required = formDataJsonSchema.required || [];
|
|
211
|
+
const originalSchema = route.formDataSchema;
|
|
212
|
+
if (originalSchema && typeof originalSchema === "object" && "shape" in originalSchema) {
|
|
213
|
+
const shape = originalSchema.shape || {};
|
|
214
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
215
|
+
const zodField = fieldSchema;
|
|
216
|
+
if (isFileSchema(zodField)) {
|
|
217
|
+
const isMultiple = isMultipleFileSchema(zodField);
|
|
218
|
+
const description = zodField.description || "File upload";
|
|
219
|
+
if (isMultiple) {
|
|
220
|
+
properties[key] = {
|
|
221
|
+
type: "array",
|
|
222
|
+
items: {
|
|
223
|
+
type: "string",
|
|
224
|
+
format: "binary"
|
|
225
|
+
},
|
|
226
|
+
description
|
|
227
|
+
};
|
|
228
|
+
} else {
|
|
229
|
+
properties[key] = {
|
|
230
|
+
type: "string",
|
|
231
|
+
format: "binary",
|
|
232
|
+
description
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
239
|
+
const propObj = prop;
|
|
240
|
+
if (propObj.format !== "binary") {
|
|
241
|
+
if (propObj.description?.toLowerCase().includes("file") || propObj.description?.toLowerCase().includes("arquivo") || propObj.description?.toLowerCase().includes("upload")) {
|
|
242
|
+
properties[key] = {
|
|
243
|
+
type: "string",
|
|
244
|
+
format: "binary",
|
|
245
|
+
description: propObj.description || "File upload"
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
operation.requestBody = {
|
|
251
|
+
required: true,
|
|
252
|
+
content: {
|
|
253
|
+
"multipart/form-data": {
|
|
254
|
+
schema: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties,
|
|
257
|
+
...required.length > 0 ? { required } : {}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
} else if (route.bodySchema && ["post", "put", "patch"].includes(route.method)) {
|
|
263
|
+
const bodySchema = zodToJsonSchema(route.bodySchema);
|
|
264
|
+
operation.requestBody = {
|
|
265
|
+
required: true,
|
|
266
|
+
content: {
|
|
267
|
+
"application/json": {
|
|
268
|
+
schema: bodySchema
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
if (route.auth) {
|
|
274
|
+
operation.security = [{ bearerAuth: [] }];
|
|
275
|
+
operation.responses["401"] = { description: "Unauthorized" };
|
|
276
|
+
}
|
|
277
|
+
if (route.claims?.length) {
|
|
278
|
+
operation.responses["403"] = {
|
|
279
|
+
description: `Forbidden - requires claims: ${route.claims.join(", ")}`
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
if (route.roles?.length) {
|
|
283
|
+
operation.responses["403"] = {
|
|
284
|
+
description: `Forbidden - requires roles: ${route.roles.join(", ")}`
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
paths[openApiPath][route.method] = operation;
|
|
288
|
+
}
|
|
289
|
+
const componentsSchemas = {};
|
|
290
|
+
for (const [name, schema] of Object.entries(namedSchemas)) {
|
|
291
|
+
componentsSchemas[name] = zodToJsonSchema(schema);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
openapi: "3.0.3",
|
|
295
|
+
info: {
|
|
296
|
+
title: config.title,
|
|
297
|
+
version: config.version,
|
|
298
|
+
description: "Auto-generated API documentation"
|
|
299
|
+
},
|
|
300
|
+
servers: config.servers,
|
|
301
|
+
paths,
|
|
302
|
+
components: {
|
|
303
|
+
...Object.keys(componentsSchemas).length > 0 ? { schemas: componentsSchemas } : {},
|
|
304
|
+
securitySchemes: {
|
|
305
|
+
bearerAuth: {
|
|
306
|
+
type: "http",
|
|
307
|
+
scheme: "bearer",
|
|
308
|
+
bearerFormat: "JWT"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export {
|
|
316
|
+
zodToJsonSchema,
|
|
317
|
+
FILE_SCHEMA_SYMBOL,
|
|
318
|
+
zFile,
|
|
319
|
+
zFiles,
|
|
320
|
+
isFileSchema,
|
|
321
|
+
isMultipleFileSchema,
|
|
322
|
+
generateSwagger
|
|
323
|
+
};
|
|
324
|
+
//# sourceMappingURL=chunk-TTILJJ3O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/swagger/zod-converter.ts","../src/utils/zod-file.ts","../src/swagger/generator.ts"],"sourcesContent":["import { z, ZodTypeAny, ZodObject, ZodString, ZodNumber, ZodBoolean, ZodArray, ZodOptional, ZodNullable, ZodEnum, ZodUnion, ZodEffects, ZodDefault, ZodLiteral, ZodDate } from 'zod';\n\n/**\n * Extrai o tipo base de um schema Zod, removendo wrappers como ZodEffects, ZodOptional, etc.\n */\nfunction unwrapZodType(schema: ZodTypeAny): ZodTypeAny {\n if (schema instanceof ZodEffects) {\n const innerSchema = schema._def.schema;\n if (innerSchema) {\n return unwrapZodType(innerSchema);\n }\n }\n if (schema instanceof ZodOptional) {\n return unwrapZodType(schema._def.innerType);\n }\n if (schema instanceof ZodNullable) {\n return unwrapZodType(schema._def.innerType);\n }\n if (schema instanceof ZodDefault) {\n return unwrapZodType(schema._def.innerType);\n }\n return schema;\n}\n\n/**\n * Verifica se um schema é opcional em algum nível da cadeia de wrappers.\n */\nfunction checkIsOptional(schema: ZodTypeAny): boolean {\n if (schema instanceof ZodOptional) {\n return true;\n }\n if (schema instanceof ZodDefault) {\n return true; // ZodDefault implica em opcional (tem valor padrão)\n }\n if (schema instanceof ZodEffects) {\n const innerSchema = schema._def.schema;\n if (innerSchema) {\n return checkIsOptional(innerSchema);\n }\n }\n return false;\n}\n\nexport function zodToJsonSchema(schema: ZodTypeAny): any {\n // ZodEffects (preprocess, refine, transform) - pega o tipo interno\n if (schema instanceof ZodEffects) {\n // O tipo interno está em schema._def.schema\n const innerSchema = schema._def.schema;\n if (innerSchema) {\n return zodToJsonSchema(innerSchema);\n }\n // Fallback: tenta detectar pelo typeName do inner\n return { type: 'string' };\n }\n \n // ZodDefault - pega o tipo interno\n if (schema instanceof ZodDefault) {\n return zodToJsonSchema(schema._def.innerType);\n }\n \n if (schema instanceof ZodString) {\n return { type: 'string' };\n }\n if (schema instanceof ZodNumber) {\n return { type: 'number' };\n }\n if (schema instanceof ZodBoolean) {\n return { type: 'boolean' };\n }\n if (schema instanceof ZodDate) {\n return { type: 'string', format: 'date-time' };\n }\n if (schema instanceof ZodLiteral) {\n const value = schema._def.value;\n const type = typeof value === 'number' ? 'number' : typeof value === 'boolean' ? 'boolean' : 'string';\n return { type, enum: [value] };\n }\n if (schema instanceof ZodArray) {\n return { type: 'array', items: zodToJsonSchema(schema._def.type) };\n }\n if (schema instanceof ZodOptional) {\n return zodToJsonSchema(schema._def.innerType);\n }\n if (schema instanceof ZodNullable) {\n return { ...zodToJsonSchema(schema._def.innerType), nullable: true };\n }\n if (schema instanceof ZodEnum) {\n return { type: 'string', enum: schema._def.values };\n }\n if (schema instanceof ZodUnion) {\n const options = schema._def.options.map((option: ZodTypeAny) => {\n return zodToJsonSchema(option);\n });\n return { oneOf: options };\n }\n if (schema instanceof ZodObject) {\n const shape = schema.shape;\n const properties: Record<string, any> = {};\n const required: string[] = [];\n\n for (const [key, value] of Object.entries(shape)) {\n properties[key] = zodToJsonSchema(value as ZodTypeAny);\n // Verifica se é opcional verificando se existe ZodOptional em algum nível\n const isOptional = checkIsOptional(value as ZodTypeAny);\n if (!isOptional) {\n required.push(key);\n }\n }\n\n return {\n type: 'object',\n properties,\n ...(required.length > 0 ? { required } : {}),\n };\n }\n\n // Fallback: tenta detectar pelo _def.typeName\n const typeName = (schema as any)?._def?.typeName;\n if (typeName === 'ZodString') return { type: 'string' };\n if (typeName === 'ZodNumber') return { type: 'number' };\n if (typeName === 'ZodBoolean') return { type: 'boolean' };\n\n return { type: 'string' };\n}\n","import { z } from 'zod';\r\n\r\n/**\r\n * Symbol usado para identificar schemas de arquivo\r\n */\r\nexport const FILE_SCHEMA_SYMBOL = Symbol.for('zeti:file-schema');\r\n\r\n/**\r\n * Cria um schema Zod para upload de arquivo\r\n * \r\n * @example\r\n * ```typescript\r\n * app.post(\"/upload\", {\r\n * middleware: {\r\n * schema: (zod) => ({\r\n * formData: zod.object({\r\n * file: zFile(),\r\n * avatar: zFile(\"Foto de perfil\"),\r\n * documents: zFiles(\"Documentos PDF\"),\r\n * }),\r\n * }),\r\n * },\r\n * route: async ({ formData }) => {\r\n * const file = formData.file as File;\r\n * // ...\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport function zFile(description?: string) {\r\n const schema = z.any().describe(description || 'File upload');\r\n // Marca o schema como arquivo usando metadata\r\n (schema as any)._def[FILE_SCHEMA_SYMBOL] = true;\r\n (schema as any)._def.isFile = true;\r\n return schema;\r\n}\r\n\r\n/**\r\n * Cria um schema Zod para upload de múltiplos arquivos\r\n */\r\nexport function zFiles(description?: string) {\r\n const schema = z.array(z.any()).describe(description || 'Multiple file upload');\r\n // Marca o schema como array de arquivos\r\n (schema as any)._def[FILE_SCHEMA_SYMBOL] = true;\r\n (schema as any)._def.isFile = true;\r\n (schema as any)._def.isMultiple = true;\r\n return schema;\r\n}\r\n\r\n/**\r\n * Verifica se um schema Zod é um schema de arquivo\r\n */\r\nexport function isFileSchema(schema: z.ZodTypeAny): boolean {\r\n return (schema as any)?._def?.[FILE_SCHEMA_SYMBOL] === true || \r\n (schema as any)?._def?.isFile === true;\r\n}\r\n\r\n/**\r\n * Verifica se um schema Zod é um schema de múltiplos arquivos\r\n */\r\nexport function isMultipleFileSchema(schema: z.ZodTypeAny): boolean {\r\n return isFileSchema(schema) && (schema as any)?._def?.isMultiple === true;\r\n}\r\n","import type { SwaggerRegistry } from './registry';\r\nimport type { ZetiSwaggerConfig } from '../types/config';\r\nimport { zodToJsonSchema } from './zod-converter';\r\nimport type { RouteMetadata } from '../types/framework';\r\nimport type { ZodTypeAny, ZodObject } from 'zod';\r\nimport { isFileSchema, isMultipleFileSchema } from '../utils/zod-file';\r\n\r\nfunction extractPathParams(path: string): string[] {\r\n const matches = path.match(/:([^/]+)/g);\r\n return matches ? matches.map((m) => m.slice(1)) : [];\r\n}\r\n\r\nfunction pathToOpenAPI(path: string): string {\r\n return path.replace(/:([^/]+)/g, '{$1}');\r\n}\r\n\r\nfunction extractTag(path: string): string {\r\n const parts = path.split('/').filter(Boolean);\r\n return parts[0] || 'default';\r\n}\r\n\r\nexport interface SwaggerGeneratorOptions {\r\n loadGeneratedSchemas?: () => Promise<{\r\n routeResponseSchemas?: Record<string, Record<string, { schema: ZodTypeAny; ref: string | null }>>;\r\n namedSchemas?: Record<string, ZodTypeAny>;\r\n }>;\r\n}\r\n\r\nexport async function generateSwagger(\r\n registry: SwaggerRegistry,\r\n config: ZetiSwaggerConfig,\r\n options?: SwaggerGeneratorOptions\r\n): Promise<object> {\r\n const routes = registry.getAll();\r\n const paths: Record<string, any> = {};\r\n \r\n // Try to load generated schemas\r\n let routeResponseSchemas: Record<string, Record<string, { schema: ZodTypeAny; ref: string | null }>> = {};\r\n let namedSchemas: Record<string, ZodTypeAny> = {};\r\n \r\n if (options?.loadGeneratedSchemas) {\r\n try {\r\n const schemas = await options.loadGeneratedSchemas();\r\n if (schemas.routeResponseSchemas) {\r\n routeResponseSchemas = schemas.routeResponseSchemas;\r\n }\r\n if (schemas.namedSchemas) {\r\n namedSchemas = schemas.namedSchemas;\r\n }\r\n } catch {\r\n // File doesn't exist yet (first build) - ignore\r\n }\r\n }\r\n\r\n for (const route of routes) {\r\n const openApiPath = pathToOpenAPI(route.path);\r\n const pathParams = extractPathParams(route.path);\r\n const tag = route.tags?.[0] || extractTag(route.path);\r\n\r\n if (!paths[openApiPath]) {\r\n paths[openApiPath] = {};\r\n }\r\n\r\n // Try to get response schema: 1) from generated types, 2) from manual schema, 3) fallback\r\n const generated = routeResponseSchemas[route.path]?.[route.method];\r\n let responseJsonSchema: any;\r\n \r\n if (generated?.ref) {\r\n // Use $ref to reference named schema\r\n responseJsonSchema = { $ref: `#/components/schemas/${generated.ref}` };\r\n } else if (generated?.schema) {\r\n responseJsonSchema = zodToJsonSchema(generated.schema);\r\n } else if (route.responseSchema) {\r\n responseJsonSchema = zodToJsonSchema(route.responseSchema);\r\n } else {\r\n responseJsonSchema = { type: 'object' };\r\n }\r\n\r\n const operation: any = {\r\n tags: route.tags || [tag],\r\n summary: route.summary || `${route.method.toUpperCase()} ${route.path}`,\r\n description: route.description,\r\n parameters: [],\r\n responses: {\r\n '200': {\r\n description: 'Successful response',\r\n content: {\r\n 'application/json': {\r\n schema: responseJsonSchema,\r\n },\r\n },\r\n },\r\n },\r\n };\r\n\r\n // Adiciona headers globais configurados\r\n if (config.globalHeaders?.length) {\r\n for (const header of config.globalHeaders) {\r\n operation.parameters.push({\r\n name: header.name,\r\n in: 'header',\r\n required: header.required ?? false,\r\n schema: { type: 'string' },\r\n description: header.description || `Header ${header.name}`,\r\n ...(header.example ? { example: header.example } : {}),\r\n });\r\n }\r\n }\r\n\r\n for (const param of pathParams) {\r\n operation.parameters.push({\r\n name: param,\r\n in: 'path',\r\n required: true,\r\n schema: { type: 'string' },\r\n });\r\n }\r\n\r\n if (route.querySchema) {\r\n const queryJsonSchema = zodToJsonSchema(route.querySchema);\r\n if (queryJsonSchema.properties) {\r\n for (const [name, schema] of Object.entries(queryJsonSchema.properties)) {\r\n operation.parameters.push({\r\n name,\r\n in: 'query',\r\n required: queryJsonSchema.required?.includes(name) || false,\r\n schema,\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (route.formDataSchema && ['post', 'put', 'patch'].includes(route.method)) {\r\n const formDataJsonSchema = zodToJsonSchema(route.formDataSchema);\r\n \r\n // Detecta campos de arquivo e ajusta o schema para OpenAPI\r\n const properties: Record<string, any> = { ...(formDataJsonSchema.properties || {}) };\r\n const required: string[] = formDataJsonSchema.required || [];\r\n \r\n // Verifica cada campo do schema original para detectar arquivos\r\n const originalSchema = route.formDataSchema as ZodObject<any>;\r\n if (originalSchema && typeof originalSchema === 'object' && 'shape' in originalSchema) {\r\n const shape = (originalSchema as any).shape || {};\r\n \r\n for (const [key, fieldSchema] of Object.entries(shape)) {\r\n const zodField = fieldSchema as ZodTypeAny;\r\n \r\n // Verifica se é um schema de arquivo usando nosso helper\r\n if (isFileSchema(zodField)) {\r\n const isMultiple = isMultipleFileSchema(zodField);\r\n const description = zodField.description || 'File upload';\r\n \r\n if (isMultiple) {\r\n properties[key] = {\r\n type: 'array',\r\n items: {\r\n type: 'string',\r\n format: 'binary',\r\n },\r\n description,\r\n };\r\n } else {\r\n properties[key] = {\r\n type: 'string',\r\n format: 'binary',\r\n description,\r\n };\r\n }\r\n }\r\n }\r\n }\r\n \r\n // Fallback: detecta por descrição ou tipo\r\n for (const [key, prop] of Object.entries(properties)) {\r\n const propObj = prop as any;\r\n // Se ainda não foi convertido e tem descrição indicando arquivo\r\n if (propObj.format !== 'binary') {\r\n if (propObj.description?.toLowerCase().includes('file') || \r\n propObj.description?.toLowerCase().includes('arquivo') ||\r\n propObj.description?.toLowerCase().includes('upload')) {\r\n properties[key] = {\r\n type: 'string',\r\n format: 'binary',\r\n description: propObj.description || 'File upload',\r\n };\r\n }\r\n }\r\n }\r\n \r\n operation.requestBody = {\r\n required: true,\r\n content: {\r\n 'multipart/form-data': {\r\n schema: {\r\n type: 'object',\r\n properties,\r\n ...(required.length > 0 ? { required } : {}),\r\n },\r\n },\r\n },\r\n };\r\n } else if (route.bodySchema && ['post', 'put', 'patch'].includes(route.method)) {\r\n const bodySchema = zodToJsonSchema(route.bodySchema);\r\n operation.requestBody = {\r\n required: true,\r\n content: {\r\n 'application/json': {\r\n schema: bodySchema,\r\n },\r\n },\r\n };\r\n }\r\n\r\n if (route.auth) {\r\n operation.security = [{ bearerAuth: [] }];\r\n operation.responses['401'] = { description: 'Unauthorized' };\r\n }\r\n\r\n if (route.claims?.length) {\r\n operation.responses['403'] = {\r\n description: `Forbidden - requires claims: ${route.claims.join(', ')}`,\r\n };\r\n }\r\n\r\n if (route.roles?.length) {\r\n operation.responses['403'] = {\r\n description: `Forbidden - requires roles: ${route.roles.join(', ')}`,\r\n };\r\n }\r\n\r\n paths[openApiPath][route.method] = operation;\r\n }\r\n\r\n // Build components.schemas from namedSchemas\r\n const componentsSchemas: Record<string, any> = {};\r\n for (const [name, schema] of Object.entries(namedSchemas)) {\r\n componentsSchemas[name] = zodToJsonSchema(schema);\r\n }\r\n\r\n return {\r\n openapi: '3.0.3',\r\n info: {\r\n title: config.title,\r\n version: config.version,\r\n description: 'Auto-generated API documentation',\r\n },\r\n servers: config.servers,\r\n paths,\r\n components: {\r\n ...(Object.keys(componentsSchemas).length > 0 ? { schemas: componentsSchemas } : {}),\r\n securitySchemes: {\r\n bearerAuth: {\r\n type: 'http',\r\n scheme: 'bearer',\r\n bearerFormat: 'JWT',\r\n },\r\n },\r\n },\r\n };\r\n}\r\n"],"mappings":"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","names":["z"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|