spiceflow 1.1.8 → 1.1.9

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 (58) hide show
  1. package/README.md +177 -92
  2. package/dist/benchmark.benchmark.js.map +1 -1
  3. package/dist/client/errors.d.ts.map +1 -1
  4. package/dist/client/errors.js.map +1 -1
  5. package/dist/client/index.d.ts.map +1 -1
  6. package/dist/client/index.js +8 -12
  7. package/dist/client/index.js.map +1 -1
  8. package/dist/client/types.d.ts.map +1 -1
  9. package/dist/client/utils.js.map +1 -1
  10. package/dist/client/ws.d.ts.map +1 -1
  11. package/dist/client/ws.js +1 -3
  12. package/dist/client/ws.js.map +1 -1
  13. package/dist/client.test.js.map +1 -1
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/cors.d.ts.map +1 -1
  16. package/dist/cors.js.map +1 -1
  17. package/dist/cors.test.js.map +1 -1
  18. package/dist/error.d.ts.map +1 -1
  19. package/dist/error.js.map +1 -1
  20. package/dist/middleware.test.js.map +1 -1
  21. package/dist/openapi.d.ts.map +1 -1
  22. package/dist/openapi.js +1 -1
  23. package/dist/openapi.js.map +1 -1
  24. package/dist/openapi.test.js.map +1 -1
  25. package/dist/spiceflow.d.ts.map +1 -1
  26. package/dist/spiceflow.js +4 -2
  27. package/dist/spiceflow.js.map +1 -1
  28. package/dist/spiceflow.test.js.map +1 -1
  29. package/dist/stream.test.js.map +1 -1
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/types.js.map +1 -1
  32. package/dist/types.test.js +2 -6
  33. package/dist/types.test.js.map +1 -1
  34. package/dist/utils.d.ts.map +1 -1
  35. package/dist/utils.js.map +1 -1
  36. package/dist/zod.test.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/benchmark.benchmark.ts +8 -8
  39. package/src/client/errors.ts +17 -17
  40. package/src/client/index.ts +437 -469
  41. package/src/client/types.ts +168 -191
  42. package/src/client/utils.ts +5 -5
  43. package/src/client/ws.ts +87 -89
  44. package/src/client.test.ts +176 -183
  45. package/src/context.ts +82 -82
  46. package/src/cors.test.ts +38 -38
  47. package/src/cors.ts +87 -92
  48. package/src/error.ts +13 -13
  49. package/src/middleware.test.ts +201 -201
  50. package/src/openapi.test.ts +97 -97
  51. package/src/openapi.ts +365 -365
  52. package/src/spiceflow.test.ts +461 -467
  53. package/src/spiceflow.ts +1117 -1161
  54. package/src/stream.test.ts +310 -310
  55. package/src/types.test.ts +46 -50
  56. package/src/types.ts +698 -701
  57. package/src/utils.ts +79 -79
  58. package/src/zod.test.ts +64 -64
package/src/openapi.ts CHANGED
@@ -13,283 +13,283 @@ import { z } from 'zod'
13
13
  import zodToJsonSchema from 'zod-to-json-schema'
14
14
 
15
15
  export const toOpenAPIPath = (path: string) =>
16
- path
17
- .split('/')
18
- .map((x) => {
19
- if (x.startsWith(':')) {
20
- x = x.slice(1, x.length)
21
- if (x.endsWith('?')) x = x.slice(0, -1)
22
- x = `{${x}}`
23
- }
24
-
25
- return x
26
- })
27
- .join('/')
16
+ path
17
+ .split('/')
18
+ .map((x) => {
19
+ if (x.startsWith(':')) {
20
+ x = x.slice(1, x.length)
21
+ if (x.endsWith('?')) x = x.slice(0, -1)
22
+ x = `{${x}}`
23
+ }
24
+
25
+ return x
26
+ })
27
+ .join('/')
28
28
 
29
29
  export const mapProperties = (
30
- name: string,
31
- schema: TypeSchema | string | undefined,
32
- models: Record<string, TypeSchema>,
30
+ name: string,
31
+ schema: TypeSchema | string | undefined,
32
+ models: Record<string, TypeSchema>,
33
33
  ) => {
34
- if (schema === undefined) return []
35
-
36
- if (typeof schema === 'string')
37
- if (schema in models) schema = models[schema]
38
- else throw new Error(`Can't find model ${schema}`)
39
-
40
- let jsonSchema = getJsonSchema(schema)
41
-
42
- return Object.entries(jsonSchema?.properties ?? []).map(([key, value]) => {
43
- const {
44
- type: valueType = undefined,
45
- description,
46
- examples,
47
- ...schemaKeywords
48
- } = value as any
49
- return {
50
- // @ts-ignore
51
- description,
52
- examples,
53
- schema: { type: valueType, ...schemaKeywords },
54
- in: name,
55
- name: key,
56
-
57
- required: jsonSchema!.required?.includes(key) ?? false,
58
- }
59
- })
34
+ if (schema === undefined) return []
35
+
36
+ if (typeof schema === 'string')
37
+ if (schema in models) schema = models[schema]
38
+ else throw new Error(`Can't find model ${schema}`)
39
+
40
+ let jsonSchema = getJsonSchema(schema)
41
+
42
+ return Object.entries(jsonSchema?.properties ?? []).map(([key, value]) => {
43
+ const {
44
+ type: valueType = undefined,
45
+ description,
46
+ examples,
47
+ ...schemaKeywords
48
+ } = value as any
49
+ return {
50
+ // @ts-ignore
51
+ description,
52
+ examples,
53
+ schema: { type: valueType, ...schemaKeywords },
54
+ in: name,
55
+ name: key,
56
+
57
+ required: jsonSchema!.required?.includes(key) ?? false,
58
+ }
59
+ })
60
60
  }
61
61
 
62
62
  const mapTypesResponse = (
63
- types: string[],
64
- schema:
65
- | string
66
- | {
67
- type: string
68
- properties: Object
69
- required: string[]
70
- },
63
+ types: string[],
64
+ schema:
65
+ | string
66
+ | {
67
+ type: string
68
+ properties: Object
69
+ required: string[]
70
+ },
71
71
  ) => {
72
- if (
73
- typeof schema === 'object' &&
74
- ['void', 'undefined', 'null'].includes(schema.type)
75
- )
76
- return
77
-
78
- const responses: Record<string, OpenAPIV3.MediaTypeObject> = {}
79
-
80
- for (const type of types)
81
- responses[type] = {
82
- schema:
83
- typeof schema === 'string'
84
- ? {
85
- $ref: `#/components/schemas/${schema}`,
86
- }
87
- : { ...(schema as any) },
88
- }
89
-
90
- return responses
72
+ if (
73
+ typeof schema === 'object' &&
74
+ ['void', 'undefined', 'null'].includes(schema.type)
75
+ )
76
+ return
77
+
78
+ const responses: Record<string, OpenAPIV3.MediaTypeObject> = {}
79
+
80
+ for (const type of types)
81
+ responses[type] = {
82
+ schema:
83
+ typeof schema === 'string'
84
+ ? {
85
+ $ref: `#/components/schemas/${schema}`,
86
+ }
87
+ : { ...(schema as any) },
88
+ }
89
+
90
+ return responses
91
91
  }
92
92
 
93
93
  export const capitalize = (word: string) =>
94
- word.charAt(0).toUpperCase() + word.slice(1)
94
+ word.charAt(0).toUpperCase() + word.slice(1)
95
95
 
96
96
  export const generateOperationId = (method: string, paths: string) => {
97
- let operationId = method.toLowerCase()
97
+ let operationId = method.toLowerCase()
98
98
 
99
- if (paths === '/') return operationId + 'Index'
99
+ if (paths === '/') return operationId + 'Index'
100
100
 
101
- for (const path of paths.split('/')) {
102
- if (path.charCodeAt(0) === 123) {
103
- operationId += 'By' + capitalize(path.slice(1, -1))
104
- } else {
105
- operationId += capitalize(path)
106
- }
107
- }
101
+ for (const path of paths.split('/')) {
102
+ if (path.charCodeAt(0) === 123) {
103
+ operationId += 'By' + capitalize(path.slice(1, -1))
104
+ } else {
105
+ operationId += capitalize(path)
106
+ }
107
+ }
108
108
 
109
- return operationId
109
+ return operationId
110
110
  }
111
111
 
112
112
  export const registerSchemaPath = ({
113
- schema,
114
- path,
115
- method,
116
- hook,
117
- models,
113
+ schema,
114
+ path,
115
+ method,
116
+ hook,
117
+ models,
118
118
  }: {
119
- schema: Partial<OpenAPIV3.PathsObject>
120
- contentType?: string | string[]
121
- path: string
122
- method: HTTPMethod
123
- hook?: LocalHook<any, any, any, any, any, any, any>
124
- models: Record<string, TypeSchema>
119
+ schema: Partial<OpenAPIV3.PathsObject>
120
+ contentType?: string | string[]
121
+ path: string
122
+ method: HTTPMethod
123
+ hook?: LocalHook<any, any, any, any, any, any, any>
124
+ models: Record<string, TypeSchema>
125
125
  }) => {
126
- if (hook) hook = deepClone(hook)
127
-
128
- // TODO if a route uses an async generator, add text/event-stream. if a roue does not add an explicit schema, use all possible content types
129
- const contentType = hook?.type ?? [
130
- 'application/json',
131
- // 'multipart/form-data',
132
- // 'text/plain',
133
- ]
134
-
135
- path = toOpenAPIPath(path)
136
-
137
- const contentTypes =
138
- typeof contentType === 'string'
139
- ? [contentType]
140
- : contentType ?? ['application/json']
141
-
142
- const bodySchema = getJsonSchema(hook?.body)
143
- const paramsSchema = hook?.params
144
- // const headerSchema = hook?.headers
145
- const querySchema = hook?.query
146
- let responseSchema = hook?.response as unknown as TypeSchema
147
- let openapiResponse: OpenAPIV3.ResponsesObject = {}
148
-
149
- if (typeof responseSchema === 'object') {
150
- const isStatusMap = Object.keys(responseSchema).every(
151
- (key) => typeof key === 'number' || Number.isInteger(Number(key)),
152
- )
153
- if (!isStatusMap) {
154
- let jsonSchema = getJsonSchema(responseSchema)
155
- const {
156
- type,
157
- properties,
158
- required,
159
- additionalProperties,
160
- patternProperties,
161
- ...rest
162
- } = jsonSchema
163
-
164
- openapiResponse = {
165
- '200': {
166
- ...rest,
167
- description: rest.description as any,
168
- content: mapTypesResponse(
169
- contentTypes,
170
- type === 'object' || type === 'array'
171
- ? ({
172
- type,
173
- properties,
174
- patternProperties,
175
- items: jsonSchema.items,
176
- required,
177
- } as any)
178
- : jsonSchema,
179
- ),
180
- },
181
- }
182
- } else {
183
- Object.entries(
184
- responseSchema as Record<string, TypeSchema>,
185
- ).forEach(([key, value]) => {
186
- if (typeof value === 'string') {
187
- if (!models[value]) return
188
-
189
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
190
- const {
191
- type,
192
- properties,
193
- required,
194
- additionalProperties: _1,
195
- patternProperties: _2,
196
- ...rest
197
- } = getJsonSchema(models[value])
198
-
199
- openapiResponse[key] = {
200
- ...rest,
201
- description: rest.description as any,
202
- content: mapTypesResponse(contentTypes, value),
203
- }
204
- } else {
205
- const schema = getJsonSchema(value)
206
- const {
207
- type,
208
- properties,
209
- required,
210
- additionalProperties,
211
- patternProperties,
212
- ...rest
213
- } = schema
214
-
215
- openapiResponse[key] = {
216
- ...rest,
217
- description: rest.description as any,
218
- content: mapTypesResponse(
219
- contentTypes,
220
- type === 'object' || type === 'array'
221
- ? ({
222
- type,
223
- properties,
224
- patternProperties,
225
- items: rest.items,
226
- required,
227
- } as any)
228
- : schema,
229
- ),
230
- }
231
- }
232
- })
233
- }
234
- } else if (typeof responseSchema === 'string') {
235
- if (!(responseSchema in models)) return
236
-
237
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
238
- const {
239
- type,
240
- properties,
241
- required,
242
- additionalProperties: _1,
243
- patternProperties: _2,
244
- ...rest
245
- } = getJsonSchema(models[responseSchema])
246
-
247
- openapiResponse = {
248
- // @ts-ignore
249
- '200': {
250
- ...rest,
251
- content: mapTypesResponse(contentTypes, responseSchema),
252
- },
253
- }
254
- }
255
-
256
- const parameters = [
257
- // ...mapProperties('header', headerSchema, models),
258
- ...mapProperties('path', paramsSchema, models),
259
- ...mapProperties('query', querySchema, models),
260
- ]
261
-
262
- schema[path] = {
263
- ...(schema[path] ? schema[path] : {}),
264
- [method.toLowerCase()]: {
265
- ...((paramsSchema || querySchema || bodySchema
266
- ? ({ parameters } as any)
267
- : {}) satisfies OpenAPIV3.ParameterObject),
268
- ...(openapiResponse
269
- ? {
270
- responses: openapiResponse,
271
- }
272
- : {}),
273
- operationId:
274
- hook?.detail?.operationId ?? generateOperationId(method, path),
275
- ...hook?.detail,
276
- ...(bodySchema
277
- ? {
278
- requestBody: {
279
- required: true,
280
- content: mapTypesResponse(
281
- contentTypes,
282
- typeof bodySchema === 'string'
283
- ? {
284
- $ref: `#/components/schemas/${bodySchema}`,
285
- }
286
- : (bodySchema as any),
287
- ),
288
- },
289
- }
290
- : null),
291
- } satisfies OpenAPIV3.OperationObject,
292
- }
126
+ if (hook) hook = deepClone(hook)
127
+
128
+ // TODO if a route uses an async generator, add text/event-stream. if a roue does not add an explicit schema, use all possible content types
129
+ const contentType = hook?.type ?? [
130
+ 'application/json',
131
+ // 'multipart/form-data',
132
+ // 'text/plain',
133
+ ]
134
+
135
+ path = toOpenAPIPath(path)
136
+
137
+ const contentTypes =
138
+ typeof contentType === 'string'
139
+ ? [contentType]
140
+ : (contentType ?? ['application/json'])
141
+
142
+ const bodySchema = getJsonSchema(hook?.body)
143
+ const paramsSchema = hook?.params
144
+ // const headerSchema = hook?.headers
145
+ const querySchema = hook?.query
146
+ let responseSchema = hook?.response as unknown as TypeSchema
147
+ let openapiResponse: OpenAPIV3.ResponsesObject = {}
148
+
149
+ if (typeof responseSchema === 'object') {
150
+ const isStatusMap = Object.keys(responseSchema).every(
151
+ (key) => typeof key === 'number' || Number.isInteger(Number(key)),
152
+ )
153
+ if (!isStatusMap) {
154
+ let jsonSchema = getJsonSchema(responseSchema)
155
+ const {
156
+ type,
157
+ properties,
158
+ required,
159
+ additionalProperties,
160
+ patternProperties,
161
+ ...rest
162
+ } = jsonSchema
163
+
164
+ openapiResponse = {
165
+ '200': {
166
+ ...rest,
167
+ description: rest.description as any,
168
+ content: mapTypesResponse(
169
+ contentTypes,
170
+ type === 'object' || type === 'array'
171
+ ? ({
172
+ type,
173
+ properties,
174
+ patternProperties,
175
+ items: jsonSchema.items,
176
+ required,
177
+ } as any)
178
+ : jsonSchema,
179
+ ),
180
+ },
181
+ }
182
+ } else {
183
+ Object.entries(responseSchema as Record<string, TypeSchema>).forEach(
184
+ ([key, value]) => {
185
+ if (typeof value === 'string') {
186
+ if (!models[value]) return
187
+
188
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
189
+ const {
190
+ type,
191
+ properties,
192
+ required,
193
+ additionalProperties: _1,
194
+ patternProperties: _2,
195
+ ...rest
196
+ } = getJsonSchema(models[value])
197
+
198
+ openapiResponse[key] = {
199
+ ...rest,
200
+ description: rest.description as any,
201
+ content: mapTypesResponse(contentTypes, value),
202
+ }
203
+ } else {
204
+ const schema = getJsonSchema(value)
205
+ const {
206
+ type,
207
+ properties,
208
+ required,
209
+ additionalProperties,
210
+ patternProperties,
211
+ ...rest
212
+ } = schema
213
+
214
+ openapiResponse[key] = {
215
+ ...rest,
216
+ description: rest.description as any,
217
+ content: mapTypesResponse(
218
+ contentTypes,
219
+ type === 'object' || type === 'array'
220
+ ? ({
221
+ type,
222
+ properties,
223
+ patternProperties,
224
+ items: rest.items,
225
+ required,
226
+ } as any)
227
+ : schema,
228
+ ),
229
+ }
230
+ }
231
+ },
232
+ )
233
+ }
234
+ } else if (typeof responseSchema === 'string') {
235
+ if (!(responseSchema in models)) return
236
+
237
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
238
+ const {
239
+ type,
240
+ properties,
241
+ required,
242
+ additionalProperties: _1,
243
+ patternProperties: _2,
244
+ ...rest
245
+ } = getJsonSchema(models[responseSchema])
246
+
247
+ openapiResponse = {
248
+ // @ts-ignore
249
+ '200': {
250
+ ...rest,
251
+ content: mapTypesResponse(contentTypes, responseSchema),
252
+ },
253
+ }
254
+ }
255
+
256
+ const parameters = [
257
+ // ...mapProperties('header', headerSchema, models),
258
+ ...mapProperties('path', paramsSchema, models),
259
+ ...mapProperties('query', querySchema, models),
260
+ ]
261
+
262
+ schema[path] = {
263
+ ...(schema[path] ? schema[path] : {}),
264
+ [method.toLowerCase()]: {
265
+ ...((paramsSchema || querySchema || bodySchema
266
+ ? ({ parameters } as any)
267
+ : {}) satisfies OpenAPIV3.ParameterObject),
268
+ ...(openapiResponse
269
+ ? {
270
+ responses: openapiResponse,
271
+ }
272
+ : {}),
273
+ operationId:
274
+ hook?.detail?.operationId ?? generateOperationId(method, path),
275
+ ...hook?.detail,
276
+ ...(bodySchema
277
+ ? {
278
+ requestBody: {
279
+ required: true,
280
+ content: mapTypesResponse(
281
+ contentTypes,
282
+ typeof bodySchema === 'string'
283
+ ? {
284
+ $ref: `#/components/schemas/${bodySchema}`,
285
+ }
286
+ : (bodySchema as any),
287
+ ),
288
+ },
289
+ }
290
+ : null),
291
+ } satisfies OpenAPIV3.OperationObject,
292
+ }
293
293
  }
294
294
 
295
295
  /**
@@ -298,117 +298,117 @@ export const registerSchemaPath = ({
298
298
  * @see https://github.com/elysiajs/elysia-swagger
299
299
  */
300
300
  export const openapi = <Path extends string = '/openapi'>({
301
- path = '/openapi' as Path,
302
- documentation = {},
301
+ path = '/openapi' as Path,
302
+ documentation = {},
303
303
  }: {
304
- path?: Path
305
- /**
306
- * Customize Swagger config, refers to Swagger 2.0 config
307
- *
308
- * @see https://swagger.io/specification/v2/
309
- */
310
- documentation?: Omit<
311
- Partial<OpenAPIV3.Document>,
312
- | 'x-express-openapi-additional-middleware'
313
- | 'x-express-openapi-validation-strict'
314
- >
304
+ path?: Path
305
+ /**
306
+ * Customize Swagger config, refers to Swagger 2.0 config
307
+ *
308
+ * @see https://swagger.io/specification/v2/
309
+ */
310
+ documentation?: Omit<
311
+ Partial<OpenAPIV3.Document>,
312
+ | 'x-express-openapi-additional-middleware'
313
+ | 'x-express-openapi-validation-strict'
314
+ >
315
315
  } = {}) => {
316
- const schema = {}
317
- let totalRoutes = 0
318
-
319
- const relativePath = path.startsWith('/') ? path.slice(1) : path
320
-
321
- const app = new Spiceflow({ name: 'openapi' }).get(path, ({}) => {
322
- let routes = app.getAllRoutes()
323
- if (routes.length !== totalRoutes) {
324
- const ALLOWED_METHODS = [
325
- 'GET',
326
- 'PUT',
327
- 'POST',
328
- 'DELETE',
329
- 'OPTIONS',
330
- 'HEAD',
331
- 'PATCH',
332
- 'TRACE',
333
- ]
334
- totalRoutes = routes.length
335
-
336
- routes.forEach((route: InternalRoute) => {
337
- if (route.hooks?.detail?.hide === true) return
338
- // TODO: route.hooks?.detail?.hide !== false add ability to hide: false to prevent excluding
339
- if (excludeMethods.includes(route.method)) return
340
- if (
341
- ALLOWED_METHODS.includes(route.method) === false &&
342
- route.method !== 'ALL'
343
- )
344
- return
345
-
346
- if (route.method === 'ALL') {
347
- ALLOWED_METHODS.forEach((method) => {
348
- registerSchemaPath({
349
- schema,
350
- hook: route.hooks,
351
- method,
352
- path: route.path,
353
- // @ts-ignore
354
- models: app.definitions?.type,
355
- contentType: route.hooks?.type,
356
- })
357
- })
358
- return
359
- }
360
-
361
- registerSchemaPath({
362
- schema,
363
- hook: route.hooks,
364
- method: route.method,
365
- path: route.path,
366
- // @ts-ignore
367
- models: app.definitions?.type,
368
- contentType: route.hooks?.type,
369
- })
370
- })
371
- }
372
-
373
- return {
374
- openapi: '3.0.3',
375
- ...{
376
- ...documentation,
377
- // tags: documentation.tags?.filter(
378
- // (tag) => !excludeTags?.includes(tag?.name),
379
- // ),
380
- info: {
381
- title: 'Spiceflow Documentation',
382
- description: 'Development documentation',
383
- version: '0.0.0',
384
- ...documentation.info,
385
- },
386
- },
387
- paths: {
388
- ...schema,
389
- ...documentation.paths,
390
- },
391
- components: {
392
- ...documentation.components,
393
- schemas: {
394
- // @ts-ignore
395
- ...app.definitions?.type,
396
- ...documentation.components?.schemas,
397
- },
398
- },
399
- } satisfies OpenAPIV3.Document
400
- })
401
-
402
- return app
316
+ const schema = {}
317
+ let totalRoutes = 0
318
+
319
+ const relativePath = path.startsWith('/') ? path.slice(1) : path
320
+
321
+ const app = new Spiceflow({ name: 'openapi' }).get(path, ({}) => {
322
+ let routes = app.getAllRoutes()
323
+ if (routes.length !== totalRoutes) {
324
+ const ALLOWED_METHODS = [
325
+ 'GET',
326
+ 'PUT',
327
+ 'POST',
328
+ 'DELETE',
329
+ 'OPTIONS',
330
+ 'HEAD',
331
+ 'PATCH',
332
+ 'TRACE',
333
+ ]
334
+ totalRoutes = routes.length
335
+
336
+ routes.forEach((route: InternalRoute) => {
337
+ if (route.hooks?.detail?.hide === true) return
338
+ // TODO: route.hooks?.detail?.hide !== false add ability to hide: false to prevent excluding
339
+ if (excludeMethods.includes(route.method)) return
340
+ if (
341
+ ALLOWED_METHODS.includes(route.method) === false &&
342
+ route.method !== 'ALL'
343
+ )
344
+ return
345
+
346
+ if (route.method === 'ALL') {
347
+ ALLOWED_METHODS.forEach((method) => {
348
+ registerSchemaPath({
349
+ schema,
350
+ hook: route.hooks,
351
+ method,
352
+ path: route.path,
353
+ // @ts-ignore
354
+ models: app.definitions?.type,
355
+ contentType: route.hooks?.type,
356
+ })
357
+ })
358
+ return
359
+ }
360
+
361
+ registerSchemaPath({
362
+ schema,
363
+ hook: route.hooks,
364
+ method: route.method,
365
+ path: route.path,
366
+ // @ts-ignore
367
+ models: app.definitions?.type,
368
+ contentType: route.hooks?.type,
369
+ })
370
+ })
371
+ }
372
+
373
+ return {
374
+ openapi: '3.0.3',
375
+ ...{
376
+ ...documentation,
377
+ // tags: documentation.tags?.filter(
378
+ // (tag) => !excludeTags?.includes(tag?.name),
379
+ // ),
380
+ info: {
381
+ title: 'Spiceflow Documentation',
382
+ description: 'Development documentation',
383
+ version: '0.0.0',
384
+ ...documentation.info,
385
+ },
386
+ },
387
+ paths: {
388
+ ...schema,
389
+ ...documentation.paths,
390
+ },
391
+ components: {
392
+ ...documentation.components,
393
+ schemas: {
394
+ // @ts-ignore
395
+ ...app.definitions?.type,
396
+ ...documentation.components?.schemas,
397
+ },
398
+ },
399
+ } satisfies OpenAPIV3.Document
400
+ })
401
+
402
+ return app
403
403
  }
404
404
 
405
405
  function getJsonSchema(schema: TypeSchema): JSONSchemaType<any> {
406
- if (!schema) return undefined as any
407
- if (isZodSchema(schema)) {
408
- let fn = zodToJsonSchema.default ?? zodToJsonSchema
409
- let jsonSchema = fn(schema, {})
410
- return jsonSchema as any
411
- }
412
-
413
- return schema as any
406
+ if (!schema) return undefined as any
407
+ if (isZodSchema(schema)) {
408
+ let fn = zodToJsonSchema.default ?? zodToJsonSchema
409
+ let jsonSchema = fn(schema, {})
410
+ return jsonSchema as any
411
+ }
412
+
413
+ return schema as any
414
414
  }