@elysiajs/openapi 1.3.12 → 1.4.0-exp.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.
package/dist/index.d.ts CHANGED
@@ -19,16 +19,19 @@ export declare const openapi: <const Enabled extends boolean = true, const Path
19
19
  macro: {};
20
20
  macroFn: {};
21
21
  parser: {};
22
+ response: {};
22
23
  }, {}, {
23
24
  derive: {};
24
25
  resolve: {};
25
26
  schema: {};
26
27
  standaloneSchema: {};
28
+ response: {};
27
29
  }, {
28
30
  derive: {};
29
31
  resolve: {};
30
32
  schema: {};
31
33
  standaloneSchema: {};
34
+ response: {};
32
35
  }>;
33
36
  export { toOpenAPISchema, withHeaders } from './openapi';
34
37
  export type { ElysiaOpenAPIConfig };
package/dist/index.mjs CHANGED
@@ -268,6 +268,7 @@ var Hint = Symbol.for("TypeBox.Hint");
268
268
  var Kind = Symbol.for("TypeBox.Kind");
269
269
 
270
270
  // src/openapi.ts
271
+ import { toJsonSchema } from "xsschema";
271
272
  var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
272
273
  var toRef = (name) => t.Ref(`#/components/schemas/${name}`);
273
274
  var toOperationId = (method, paths) => {
@@ -296,7 +297,14 @@ var getLoosePath = (path) => {
296
297
  return path.slice(0, path.length - 1);
297
298
  return path + "/";
298
299
  };
299
- function toOpenAPISchema(app, exclude, references) {
300
+ var unwrapSchema = (schema) => {
301
+ if (!schema) return;
302
+ if (typeof schema === "string") schema = toRef(schema);
303
+ if (Kind in schema) return schema;
304
+ if (Kind in schema === false && schema["~standard"])
305
+ return toJsonSchema(schema);
306
+ };
307
+ async function toOpenAPISchema(app, exclude, references) {
300
308
  const {
301
309
  methods: excludeMethods = ["OPTIONS"],
302
310
  staticFile: excludeStaticFile = true,
@@ -349,11 +357,11 @@ function toOpenAPISchema(app, exclude, references) {
349
357
  };
350
358
  const parameters = [];
351
359
  if (hooks.params) {
352
- if (typeof hooks.params === "string")
353
- hooks.params = toRef(hooks.params);
354
- if (hooks.params.type === "object" && hooks.params.properties) {
360
+ let params = unwrapSchema(hooks.params);
361
+ if (params) params = await params;
362
+ if (params && params.type === "object" && params.properties)
355
363
  for (const [paramName, paramSchema] of Object.entries(
356
- hooks.params.properties
364
+ params.properties
357
365
  ))
358
366
  parameters.push({
359
367
  name: paramName,
@@ -362,15 +370,14 @@ function toOpenAPISchema(app, exclude, references) {
362
370
  // Path parameters are always required
363
371
  schema: paramSchema
364
372
  });
365
- }
366
373
  }
367
374
  if (hooks.query) {
368
- if (typeof hooks.query === "string")
369
- hooks.query = toRef(hooks.query);
370
- if (hooks.query.type === "object" && hooks.query.properties) {
371
- const required = hooks.query.required || [];
375
+ let query = unwrapSchema(hooks.query);
376
+ if (query) query = await query;
377
+ if (query && query.type === "object" && query.properties) {
378
+ const required = query.required || [];
372
379
  for (const [queryName, querySchema] of Object.entries(
373
- hooks.query.properties
380
+ query.properties
374
381
  ))
375
382
  parameters.push({
376
383
  name: queryName,
@@ -381,12 +388,12 @@ function toOpenAPISchema(app, exclude, references) {
381
388
  }
382
389
  }
383
390
  if (hooks.headers) {
384
- if (typeof hooks.headers === "string")
385
- hooks.headers = toRef(hooks.headers);
386
- if (hooks.headers.type === "object" && hooks.headers.properties) {
387
- const required = hooks.headers.required || [];
391
+ let headers = unwrapSchema(hooks.query);
392
+ if (headers) headers = await headers;
393
+ if (headers && headers.type === "object" && headers.properties) {
394
+ const required = headers.required || [];
388
395
  for (const [headerName, headerSchema] of Object.entries(
389
- hooks.headers.properties
396
+ headers.properties
390
397
  ))
391
398
  parameters.push({
392
399
  name: headerName,
@@ -397,12 +404,12 @@ function toOpenAPISchema(app, exclude, references) {
397
404
  }
398
405
  }
399
406
  if (hooks.cookie) {
400
- if (typeof hooks.cookie === "string")
401
- hooks.cookie = toRef(hooks.cookie);
402
- if (hooks.cookie.type === "object" && hooks.cookie.properties) {
403
- const required = hooks.cookie.required || [];
407
+ let cookie = unwrapSchema(hooks.cookie);
408
+ if (cookie) cookie = await cookie;
409
+ if (cookie && cookie.type === "object" && cookie.properties) {
410
+ const required = cookie.required || [];
404
411
  for (const [cookieName, cookieSchema] of Object.entries(
405
- hooks.cookie.properties
412
+ cookie.properties
406
413
  ))
407
414
  parameters.push({
408
415
  name: cookieName,
@@ -414,80 +421,107 @@ function toOpenAPISchema(app, exclude, references) {
414
421
  }
415
422
  if (parameters.length > 0) operation.parameters = parameters;
416
423
  if (hooks.body && method !== "get" && method !== "head") {
417
- if (typeof hooks.body === "string") hooks.body = toRef(hooks.body);
418
- if (hooks.parse) {
419
- const content = {};
420
- const parsers = hooks.parse;
421
- for (const parser of parsers) {
422
- if (typeof parser.fn === "function") continue;
423
- switch (parser.fn) {
424
- case "text":
425
- case "text/plain":
426
- content["text/plain"] = { schema: hooks.body };
427
- continue;
428
- case "urlencoded":
429
- case "application/x-www-form-urlencoded":
430
- content["application/x-www-form-urlencoded"] = {
431
- schema: hooks.body
432
- };
433
- continue;
434
- case "json":
435
- case "application/json":
436
- content["application/json"] = { schema: hooks.body };
437
- continue;
438
- case "formdata":
439
- case "multipart/form-data":
440
- content["multipart/form-data"] = {
441
- schema: hooks.body
442
- };
443
- continue;
424
+ let body = unwrapSchema(hooks.body);
425
+ if (body) body = await body;
426
+ if (body) {
427
+ const { type: _type, description, ...options } = body;
428
+ const type = _type;
429
+ if (hooks.parse) {
430
+ const content = {};
431
+ const parsers = hooks.parse;
432
+ for (const parser of parsers) {
433
+ if (typeof parser.fn === "function") continue;
434
+ switch (parser.fn) {
435
+ case "text":
436
+ case "text/plain":
437
+ content["text/plain"] = { schema: body };
438
+ continue;
439
+ case "urlencoded":
440
+ case "application/x-www-form-urlencoded":
441
+ content["application/x-www-form-urlencoded"] = {
442
+ schema: body
443
+ };
444
+ continue;
445
+ case "json":
446
+ case "application/json":
447
+ content["application/json"] = { schema: body };
448
+ continue;
449
+ case "formdata":
450
+ case "multipart/form-data":
451
+ content["multipart/form-data"] = {
452
+ schema: body
453
+ };
454
+ continue;
455
+ }
444
456
  }
445
- }
446
- operation.requestBody = { content, required: true };
447
- } else {
448
- operation.requestBody = {
449
- content: {
450
- "application/json": {
451
- schema: hooks.body
452
- },
453
- "application/x-www-form-urlencoded": {
454
- schema: hooks.body
457
+ operation.requestBody = {
458
+ description,
459
+ content,
460
+ required: true
461
+ };
462
+ } else {
463
+ operation.requestBody = {
464
+ description,
465
+ content: type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
466
+ "text/plain": body
467
+ } : {
468
+ "application/json": {
469
+ schema: body
470
+ },
471
+ "application/x-www-form-urlencoded": {
472
+ schema: body
473
+ },
474
+ "multipart/form-data": {
475
+ schema: body
476
+ }
455
477
  },
456
- "multipart/form-data": {
457
- schema: hooks.body
458
- }
459
- },
460
- required: true
461
- };
478
+ required: true
479
+ };
480
+ }
462
481
  }
463
482
  }
464
483
  if (hooks.response) {
465
484
  operation.responses = {};
466
485
  if (typeof hooks.response === "object" && !hooks.response.type && !hooks.response.$ref) {
467
486
  for (let [status, schema] of Object.entries(hooks.response)) {
468
- if (typeof schema === "string") schema = toRef(schema);
469
- const { type, examples, $ref, ...options } = schema;
487
+ let response = unwrapSchema(schema);
488
+ if (response) response = await response;
489
+ if (!response) continue;
490
+ const { type: _type, description, ...options } = response;
491
+ const type = _type;
470
492
  operation.responses[status] = {
471
- description: `Response for status ${status}`,
493
+ description: description ?? `Response for status ${status}`,
472
494
  ...options,
473
- content: type === "void" || type === "null" || type === "undefined" ? schema : {
495
+ content: type === "void" || type === "null" || type === "undefined" ? response : type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
496
+ "text/plain": {
497
+ schema: response
498
+ }
499
+ } : {
474
500
  "application/json": {
475
- schema
501
+ schema: response
476
502
  }
477
503
  }
478
504
  };
479
505
  }
480
506
  } else {
481
- if (typeof hooks.response === "string")
482
- hooks.response = toRef(hooks.response);
483
- operation.responses["200"] = {
484
- description: "Successful response",
485
- content: {
486
- "application/json": {
487
- schema: hooks.response
507
+ let response = unwrapSchema(hooks.response);
508
+ if (response) response = await response;
509
+ if (response) {
510
+ const { type: _type, description, ...options } = response;
511
+ const type = _type;
512
+ operation.responses["200"] = {
513
+ description: description ?? `Response for status 200`,
514
+ content: type === "void" || type === "null" || type === "undefined" ? response : type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
515
+ "text/plain": {
516
+ schema: response
517
+ }
518
+ } : {
519
+ "application/json": {
520
+ schema: response
521
+ }
488
522
  }
489
- }
490
- };
523
+ };
524
+ }
491
525
  }
492
526
  }
493
527
  for (let path of getPossiblePath(route.path)) {
@@ -518,7 +552,14 @@ function toOpenAPISchema(app, exclude, references) {
518
552
  };
519
553
  }
520
554
  }
521
- const schemas = app.getGlobalDefinitions?.().type;
555
+ const _schemas = app.getGlobalDefinitions?.().type;
556
+ const schemas = /* @__PURE__ */ Object.create(null);
557
+ if (_schemas)
558
+ for (const [name, schema] of Object.entries(_schemas)) {
559
+ let jsonSchema = unwrapSchema(schema);
560
+ if (jsonSchema instanceof Promise) jsonSchema = await jsonSchema;
561
+ if (jsonSchema) schemas[name] = jsonSchema;
562
+ }
522
563
  return {
523
564
  components: {
524
565
  schemas
@@ -584,13 +625,13 @@ var openapi = ({
584
625
  );
585
626
  }).get(
586
627
  specPath,
587
- function openAPISchema() {
628
+ async function openAPISchema() {
588
629
  if (totalRoutes === app.routes.length) return cachedSchema;
589
630
  totalRoutes = app.routes.length;
590
631
  const {
591
632
  paths,
592
633
  components: { schemas }
593
- } = toOpenAPISchema(app, exclude, references);
634
+ } = await toOpenAPISchema(app, exclude, references);
594
635
  return cachedSchema = {
595
636
  openapi: "3.0.3",
596
637
  ...documentation,
package/dist/openapi.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type AnyElysia, type TSchema } from 'elysia';
1
+ import { type AnyElysia, type TSchema, type InputSchema } from 'elysia';
2
2
  import type { OpenAPIV3 } from 'openapi-types';
3
3
  import { type TProperties } from '@sinclair/typebox';
4
4
  import type { AdditionalReferences, ElysiaOpenAPIConfig } from './types';
@@ -10,17 +10,20 @@ export declare const capitalize: (word: string) => string;
10
10
  */
11
11
  export declare const getPossiblePath: (path: string) => string[];
12
12
  export declare const getLoosePath: (path: string) => string;
13
+ type MaybePromise<T> = T | Promise<T>;
14
+ export declare const unwrapSchema: (schema: InputSchema["body"]) => MaybePromise<OpenAPIV3.SchemaObject | undefined>;
13
15
  /**
14
16
  * Converts Elysia routes to OpenAPI 3.0.3 paths schema
15
17
  * @param routes Array of Elysia route objects
16
18
  * @returns OpenAPI paths object
17
19
  */
18
- export declare function toOpenAPISchema(app: AnyElysia, exclude?: ElysiaOpenAPIConfig['exclude'], references?: AdditionalReferences): {
20
+ export declare function toOpenAPISchema(app: AnyElysia, exclude?: ElysiaOpenAPIConfig['exclude'], references?: AdditionalReferences): Promise<{
19
21
  components: {
20
- schemas: Record<string, TSchema>;
22
+ schemas: any;
21
23
  };
22
24
  paths: OpenAPIV3.PathsObject<{}, {}>;
23
- };
25
+ }>;
24
26
  export declare const withHeaders: (schema: TSchema, headers: TProperties) => TSchema & {
25
27
  headers: TProperties;
26
28
  };
29
+ export {};
package/dist/openapi.mjs CHANGED
@@ -9,6 +9,7 @@ var Hint = Symbol.for("TypeBox.Hint");
9
9
  var Kind = Symbol.for("TypeBox.Kind");
10
10
 
11
11
  // src/openapi.ts
12
+ import { toJsonSchema } from "xsschema";
12
13
  var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
13
14
  var toRef = (name) => t.Ref(`#/components/schemas/${name}`);
14
15
  var toOperationId = (method, paths) => {
@@ -37,7 +38,14 @@ var getLoosePath = (path) => {
37
38
  return path.slice(0, path.length - 1);
38
39
  return path + "/";
39
40
  };
40
- function toOpenAPISchema(app, exclude, references) {
41
+ var unwrapSchema = (schema) => {
42
+ if (!schema) return;
43
+ if (typeof schema === "string") schema = toRef(schema);
44
+ if (Kind in schema) return schema;
45
+ if (Kind in schema === false && schema["~standard"])
46
+ return toJsonSchema(schema);
47
+ };
48
+ async function toOpenAPISchema(app, exclude, references) {
41
49
  const {
42
50
  methods: excludeMethods = ["OPTIONS"],
43
51
  staticFile: excludeStaticFile = true,
@@ -90,11 +98,11 @@ function toOpenAPISchema(app, exclude, references) {
90
98
  };
91
99
  const parameters = [];
92
100
  if (hooks.params) {
93
- if (typeof hooks.params === "string")
94
- hooks.params = toRef(hooks.params);
95
- if (hooks.params.type === "object" && hooks.params.properties) {
101
+ let params = unwrapSchema(hooks.params);
102
+ if (params) params = await params;
103
+ if (params && params.type === "object" && params.properties)
96
104
  for (const [paramName, paramSchema] of Object.entries(
97
- hooks.params.properties
105
+ params.properties
98
106
  ))
99
107
  parameters.push({
100
108
  name: paramName,
@@ -103,15 +111,14 @@ function toOpenAPISchema(app, exclude, references) {
103
111
  // Path parameters are always required
104
112
  schema: paramSchema
105
113
  });
106
- }
107
114
  }
108
115
  if (hooks.query) {
109
- if (typeof hooks.query === "string")
110
- hooks.query = toRef(hooks.query);
111
- if (hooks.query.type === "object" && hooks.query.properties) {
112
- const required = hooks.query.required || [];
116
+ let query = unwrapSchema(hooks.query);
117
+ if (query) query = await query;
118
+ if (query && query.type === "object" && query.properties) {
119
+ const required = query.required || [];
113
120
  for (const [queryName, querySchema] of Object.entries(
114
- hooks.query.properties
121
+ query.properties
115
122
  ))
116
123
  parameters.push({
117
124
  name: queryName,
@@ -122,12 +129,12 @@ function toOpenAPISchema(app, exclude, references) {
122
129
  }
123
130
  }
124
131
  if (hooks.headers) {
125
- if (typeof hooks.headers === "string")
126
- hooks.headers = toRef(hooks.headers);
127
- if (hooks.headers.type === "object" && hooks.headers.properties) {
128
- const required = hooks.headers.required || [];
132
+ let headers = unwrapSchema(hooks.query);
133
+ if (headers) headers = await headers;
134
+ if (headers && headers.type === "object" && headers.properties) {
135
+ const required = headers.required || [];
129
136
  for (const [headerName, headerSchema] of Object.entries(
130
- hooks.headers.properties
137
+ headers.properties
131
138
  ))
132
139
  parameters.push({
133
140
  name: headerName,
@@ -138,12 +145,12 @@ function toOpenAPISchema(app, exclude, references) {
138
145
  }
139
146
  }
140
147
  if (hooks.cookie) {
141
- if (typeof hooks.cookie === "string")
142
- hooks.cookie = toRef(hooks.cookie);
143
- if (hooks.cookie.type === "object" && hooks.cookie.properties) {
144
- const required = hooks.cookie.required || [];
148
+ let cookie = unwrapSchema(hooks.cookie);
149
+ if (cookie) cookie = await cookie;
150
+ if (cookie && cookie.type === "object" && cookie.properties) {
151
+ const required = cookie.required || [];
145
152
  for (const [cookieName, cookieSchema] of Object.entries(
146
- hooks.cookie.properties
153
+ cookie.properties
147
154
  ))
148
155
  parameters.push({
149
156
  name: cookieName,
@@ -155,80 +162,107 @@ function toOpenAPISchema(app, exclude, references) {
155
162
  }
156
163
  if (parameters.length > 0) operation.parameters = parameters;
157
164
  if (hooks.body && method !== "get" && method !== "head") {
158
- if (typeof hooks.body === "string") hooks.body = toRef(hooks.body);
159
- if (hooks.parse) {
160
- const content = {};
161
- const parsers = hooks.parse;
162
- for (const parser of parsers) {
163
- if (typeof parser.fn === "function") continue;
164
- switch (parser.fn) {
165
- case "text":
166
- case "text/plain":
167
- content["text/plain"] = { schema: hooks.body };
168
- continue;
169
- case "urlencoded":
170
- case "application/x-www-form-urlencoded":
171
- content["application/x-www-form-urlencoded"] = {
172
- schema: hooks.body
173
- };
174
- continue;
175
- case "json":
176
- case "application/json":
177
- content["application/json"] = { schema: hooks.body };
178
- continue;
179
- case "formdata":
180
- case "multipart/form-data":
181
- content["multipart/form-data"] = {
182
- schema: hooks.body
183
- };
184
- continue;
165
+ let body = unwrapSchema(hooks.body);
166
+ if (body) body = await body;
167
+ if (body) {
168
+ const { type: _type, description, ...options } = body;
169
+ const type = _type;
170
+ if (hooks.parse) {
171
+ const content = {};
172
+ const parsers = hooks.parse;
173
+ for (const parser of parsers) {
174
+ if (typeof parser.fn === "function") continue;
175
+ switch (parser.fn) {
176
+ case "text":
177
+ case "text/plain":
178
+ content["text/plain"] = { schema: body };
179
+ continue;
180
+ case "urlencoded":
181
+ case "application/x-www-form-urlencoded":
182
+ content["application/x-www-form-urlencoded"] = {
183
+ schema: body
184
+ };
185
+ continue;
186
+ case "json":
187
+ case "application/json":
188
+ content["application/json"] = { schema: body };
189
+ continue;
190
+ case "formdata":
191
+ case "multipart/form-data":
192
+ content["multipart/form-data"] = {
193
+ schema: body
194
+ };
195
+ continue;
196
+ }
185
197
  }
186
- }
187
- operation.requestBody = { content, required: true };
188
- } else {
189
- operation.requestBody = {
190
- content: {
191
- "application/json": {
192
- schema: hooks.body
193
- },
194
- "application/x-www-form-urlencoded": {
195
- schema: hooks.body
198
+ operation.requestBody = {
199
+ description,
200
+ content,
201
+ required: true
202
+ };
203
+ } else {
204
+ operation.requestBody = {
205
+ description,
206
+ content: type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
207
+ "text/plain": body
208
+ } : {
209
+ "application/json": {
210
+ schema: body
211
+ },
212
+ "application/x-www-form-urlencoded": {
213
+ schema: body
214
+ },
215
+ "multipart/form-data": {
216
+ schema: body
217
+ }
196
218
  },
197
- "multipart/form-data": {
198
- schema: hooks.body
199
- }
200
- },
201
- required: true
202
- };
219
+ required: true
220
+ };
221
+ }
203
222
  }
204
223
  }
205
224
  if (hooks.response) {
206
225
  operation.responses = {};
207
226
  if (typeof hooks.response === "object" && !hooks.response.type && !hooks.response.$ref) {
208
227
  for (let [status, schema] of Object.entries(hooks.response)) {
209
- if (typeof schema === "string") schema = toRef(schema);
210
- const { type, examples, $ref, ...options } = schema;
228
+ let response = unwrapSchema(schema);
229
+ if (response) response = await response;
230
+ if (!response) continue;
231
+ const { type: _type, description, ...options } = response;
232
+ const type = _type;
211
233
  operation.responses[status] = {
212
- description: `Response for status ${status}`,
234
+ description: description ?? `Response for status ${status}`,
213
235
  ...options,
214
- content: type === "void" || type === "null" || type === "undefined" ? schema : {
236
+ content: type === "void" || type === "null" || type === "undefined" ? response : type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
237
+ "text/plain": {
238
+ schema: response
239
+ }
240
+ } : {
215
241
  "application/json": {
216
- schema
242
+ schema: response
217
243
  }
218
244
  }
219
245
  };
220
246
  }
221
247
  } else {
222
- if (typeof hooks.response === "string")
223
- hooks.response = toRef(hooks.response);
224
- operation.responses["200"] = {
225
- description: "Successful response",
226
- content: {
227
- "application/json": {
228
- schema: hooks.response
248
+ let response = unwrapSchema(hooks.response);
249
+ if (response) response = await response;
250
+ if (response) {
251
+ const { type: _type, description, ...options } = response;
252
+ const type = _type;
253
+ operation.responses["200"] = {
254
+ description: description ?? `Response for status 200`,
255
+ content: type === "void" || type === "null" || type === "undefined" ? response : type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
256
+ "text/plain": {
257
+ schema: response
258
+ }
259
+ } : {
260
+ "application/json": {
261
+ schema: response
262
+ }
229
263
  }
230
- }
231
- };
264
+ };
265
+ }
232
266
  }
233
267
  }
234
268
  for (let path of getPossiblePath(route.path)) {
@@ -259,7 +293,14 @@ function toOpenAPISchema(app, exclude, references) {
259
293
  };
260
294
  }
261
295
  }
262
- const schemas = app.getGlobalDefinitions?.().type;
296
+ const _schemas = app.getGlobalDefinitions?.().type;
297
+ const schemas = /* @__PURE__ */ Object.create(null);
298
+ if (_schemas)
299
+ for (const [name, schema] of Object.entries(_schemas)) {
300
+ let jsonSchema = unwrapSchema(schema);
301
+ if (jsonSchema instanceof Promise) jsonSchema = await jsonSchema;
302
+ if (jsonSchema) schemas[name] = jsonSchema;
303
+ }
263
304
  return {
264
305
  components: {
265
306
  schemas
@@ -275,5 +316,6 @@ export {
275
316
  getLoosePath,
276
317
  getPossiblePath,
277
318
  toOpenAPISchema,
319
+ unwrapSchema,
278
320
  withHeaders
279
321
  };