@elysiajs/openapi 1.4.15 → 2.0.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/README.md +101 -125
- package/bun.lock +28 -28
- package/dist/cjs/gen/index.js +295 -9240
- package/dist/cjs/index.d.ts +18 -26
- package/dist/cjs/index.js +947 -9905
- package/dist/cjs/openapi.d.ts +12 -5
- package/dist/cjs/openapi.js +28 -38
- package/dist/cjs/types.d.ts +2 -2
- package/dist/gen/index.d.ts +7 -2
- package/dist/gen/index.mjs +291 -9243
- package/dist/index.d.ts +18 -26
- package/dist/index.mjs +947 -9911
- package/dist/openapi.d.ts +12 -5
- package/dist/openapi.mjs +28 -38
- package/dist/types.d.ts +2 -2
- package/memory/MIGRATION.md +241 -0
- package/package.json +92 -90
- package/bunfig.toml +0 -2
package/dist/openapi.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AnyElysia } from 'elysia/base';
|
|
2
|
+
import type { InputSchema } from 'elysia/types';
|
|
2
3
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
3
|
-
|
|
4
|
+
type TSchema = OpenAPIV3.SchemaObject & {
|
|
5
|
+
$ref?: string;
|
|
6
|
+
$schema?: string;
|
|
7
|
+
const?: unknown;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
};
|
|
4
10
|
import type { AdditionalReferences, ElysiaOpenAPIConfig, MapJsonSchema } from './types';
|
|
5
11
|
export declare const capitalize: (word: string) => string;
|
|
6
12
|
/**
|
|
@@ -16,7 +22,7 @@ export declare const unwrapSchema: (schema: InputSchema["body"], mapJsonSchema?:
|
|
|
16
22
|
*
|
|
17
23
|
* Otherwise, return the schema as is
|
|
18
24
|
*/
|
|
19
|
-
export declare const enumToOpenApi: <T extends
|
|
25
|
+
export declare const enumToOpenApi: <T extends TSchema | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined>(_schema: T) => T;
|
|
20
26
|
/**
|
|
21
27
|
* Converts Elysia routes to OpenAPI 3.0.3 paths schema
|
|
22
28
|
* @param routes Array of Elysia route objects
|
|
@@ -28,6 +34,7 @@ export declare function toOpenAPISchema(app: AnyElysia, exclude?: ElysiaOpenAPIC
|
|
|
28
34
|
};
|
|
29
35
|
paths: OpenAPIV3.PathsObject<{}, {}>;
|
|
30
36
|
};
|
|
31
|
-
export declare const withHeaders: (schema:
|
|
32
|
-
headers:
|
|
37
|
+
export declare const withHeaders: <const T, const H>(schema: T, headers: H) => T & {
|
|
38
|
+
headers: H;
|
|
33
39
|
};
|
|
40
|
+
export {};
|
package/dist/openapi.mjs
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
// src/openapi.ts
|
|
2
2
|
import { t } from "elysia";
|
|
3
|
-
|
|
4
|
-
// node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
|
|
5
|
-
var Kind = /* @__PURE__ */ Symbol.for("TypeBox.Kind");
|
|
6
|
-
|
|
7
|
-
// src/openapi.ts
|
|
8
3
|
var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
9
|
-
var toRef = (name) => t.Ref(
|
|
10
|
-
name.startsWith("#/") ? name : `#/components/schemas/${name}`
|
|
11
|
-
);
|
|
4
|
+
var toRef = (name) => t.Ref(name.startsWith("#/") ? name : `#/components/schemas/${name}`);
|
|
12
5
|
var toOperationId = (method, paths) => {
|
|
13
6
|
let operationId = method.toLowerCase();
|
|
14
7
|
if (!paths || paths === "/") return operationId + "Index";
|
|
@@ -29,12 +22,8 @@ var getPossiblePath = (path) => {
|
|
|
29
22
|
}
|
|
30
23
|
return paths;
|
|
31
24
|
};
|
|
32
|
-
var isValidSchema = (schema) => schema && typeof schema === "object" && (
|
|
33
|
-
var getLoosePath = (path) =>
|
|
34
|
-
if (path.charCodeAt(path.length - 1) === 47)
|
|
35
|
-
return path.slice(0, path.length - 1);
|
|
36
|
-
return path + "/";
|
|
37
|
-
};
|
|
25
|
+
var isValidSchema = (schema) => schema && typeof schema === "object" && (schema.type || schema.properties || schema.items || schema.anyOf || schema.allOf || schema.oneOf || schema.$ref || schema.enum || schema.const !== void 0);
|
|
26
|
+
var getLoosePath = (path) => path.charCodeAt(path.length - 1) === 47 ? path.slice(0, path.length - 1) : path + "/";
|
|
38
27
|
var warnings = {
|
|
39
28
|
zod4: `import openapi from '@elysiajs/openapi'
|
|
40
29
|
import * as z from 'zod'
|
|
@@ -130,12 +119,10 @@ var mergeObjectSchemas = (schemas) => {
|
|
|
130
119
|
};
|
|
131
120
|
var isTSchema = (value) => {
|
|
132
121
|
if (!value || typeof value !== "object") return false;
|
|
133
|
-
if (
|
|
122
|
+
if (value["~standard"]) return false;
|
|
134
123
|
const keys = Object.keys(value);
|
|
135
|
-
if (keys.length > 0 && keys.every((k) => !isNaN(Number(k))))
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
return false;
|
|
124
|
+
if (keys.length > 0 && keys.every((k) => !isNaN(Number(k)))) return false;
|
|
125
|
+
return isValidSchema(value);
|
|
139
126
|
};
|
|
140
127
|
var normalizeSchemaReference = (schema) => {
|
|
141
128
|
if (!schema) return void 0;
|
|
@@ -213,8 +200,8 @@ var mergeResponseSchema = (_existing, _incoming, vendors) => {
|
|
|
213
200
|
};
|
|
214
201
|
var mergeStandaloneValidators = (hooks, vendors) => {
|
|
215
202
|
const merged = { ...hooks };
|
|
216
|
-
if (!hooks.
|
|
217
|
-
for (const validator of hooks.
|
|
203
|
+
if (!hooks.schemas?.length) return merged;
|
|
204
|
+
for (const validator of hooks.schemas) {
|
|
218
205
|
if (validator.body)
|
|
219
206
|
merged.body = mergeSchemaProperty(
|
|
220
207
|
merged.body,
|
|
@@ -267,16 +254,15 @@ var mergeStandaloneValidators = (hooks, vendors) => {
|
|
|
267
254
|
if ("type" in response || "$ref" in response) {
|
|
268
255
|
if (typeof response === "string")
|
|
269
256
|
merged.response = normalizeSchemaReference(response);
|
|
270
|
-
} else
|
|
257
|
+
} else
|
|
271
258
|
for (const [status, schema] of Object.entries(response))
|
|
272
259
|
if (typeof schema === "string")
|
|
273
260
|
response[status] = normalizeSchemaReference(schema);
|
|
274
|
-
}
|
|
275
261
|
}
|
|
276
262
|
return merged;
|
|
277
263
|
};
|
|
278
264
|
var flattenRoutes = (routes, vendors) => routes.map((route) => {
|
|
279
|
-
if (!route.hooks?.
|
|
265
|
+
if (!route.hooks?.schemas?.length) return route;
|
|
280
266
|
return {
|
|
281
267
|
...route,
|
|
282
268
|
hooks: mergeStandaloneValidators(route.hooks, vendors)
|
|
@@ -292,19 +278,19 @@ var unwrapReference = (schema, definitions) => {
|
|
|
292
278
|
var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
|
|
293
279
|
if (!schema) return;
|
|
294
280
|
if (typeof schema === "string") schema = toRef(schema);
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
(schema.$schema || schema.type || schema.properties || schema.items))
|
|
298
|
-
return schema;
|
|
281
|
+
if (!schema?.["~standard"] && isValidSchema(schema))
|
|
282
|
+
return enumToOpenApi(schema);
|
|
299
283
|
if (!schema?.["~standard"]) return;
|
|
300
284
|
const vendor = schema["~standard"].vendor;
|
|
301
285
|
try {
|
|
302
286
|
if (mapJsonSchema?.[vendor] && typeof mapJsonSchema[vendor] === "function")
|
|
303
287
|
return enumToOpenApi(mapJsonSchema[vendor](schema));
|
|
304
288
|
if (schema["~standard"]?.jsonSchema?.[io])
|
|
305
|
-
return enumToOpenApi(
|
|
306
|
-
|
|
307
|
-
|
|
289
|
+
return enumToOpenApi(
|
|
290
|
+
schema["~standard"].jsonSchema[io]({
|
|
291
|
+
target: "draft-2020-12"
|
|
292
|
+
})
|
|
293
|
+
);
|
|
308
294
|
switch (vendor) {
|
|
309
295
|
case "zod":
|
|
310
296
|
if (warned.zod4 || warned.zod3) break;
|
|
@@ -360,9 +346,9 @@ var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
|
|
|
360
346
|
};
|
|
361
347
|
var enumToOpenApi = (_schema) => {
|
|
362
348
|
if (!_schema || typeof _schema !== "object") return _schema;
|
|
363
|
-
|
|
349
|
+
{
|
|
364
350
|
const schema2 = _schema;
|
|
365
|
-
if (schema2
|
|
351
|
+
if (schema2.anyOf && Array.isArray(schema2.anyOf) && schema2.anyOf.length > 0 && schema2.anyOf.every(
|
|
366
352
|
(item) => item && typeof item === "object" && item.const !== void 0
|
|
367
353
|
))
|
|
368
354
|
return {
|
|
@@ -396,7 +382,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
396
382
|
excludeMethods = excludeMethods.map((method) => method.toLowerCase());
|
|
397
383
|
const excludePaths = Array.isArray(exclude?.paths) ? exclude.paths : typeof exclude?.paths !== "undefined" ? [exclude.paths] : [];
|
|
398
384
|
const paths = /* @__PURE__ */ Object.create(null);
|
|
399
|
-
const definitions = app.
|
|
385
|
+
const definitions = app.models;
|
|
400
386
|
if (references) {
|
|
401
387
|
if (!Array.isArray(references)) references = [references];
|
|
402
388
|
for (let i = 0; i < references.length; i++) {
|
|
@@ -404,7 +390,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
404
390
|
if (typeof reference === "function") references[i] = reference();
|
|
405
391
|
}
|
|
406
392
|
}
|
|
407
|
-
const routes = flattenRoutes(app.
|
|
393
|
+
const routes = flattenRoutes(app.routes, vendors);
|
|
408
394
|
for (const route of routes) {
|
|
409
395
|
if (route.hooks?.detail?.hide) continue;
|
|
410
396
|
const method = route.method.toLowerCase();
|
|
@@ -446,7 +432,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
446
432
|
}
|
|
447
433
|
}
|
|
448
434
|
}
|
|
449
|
-
if (excludeTags && hooks.detail
|
|
435
|
+
if (excludeTags && hooks.detail?.tags?.some((tag) => excludeTags?.includes(tag)))
|
|
450
436
|
continue;
|
|
451
437
|
const operation = {
|
|
452
438
|
...hooks.detail
|
|
@@ -643,7 +629,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
643
629
|
path = path.replace(/:([^/]+)/g, "{$1}");
|
|
644
630
|
if (!paths[path]) paths[path] = {};
|
|
645
631
|
const current = paths[path];
|
|
646
|
-
if (method !== "all") {
|
|
632
|
+
if (method !== "all" && method !== "*") {
|
|
647
633
|
current[method] = {
|
|
648
634
|
...operation,
|
|
649
635
|
operationId
|
|
@@ -670,7 +656,11 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
670
656
|
if (definitions)
|
|
671
657
|
for (const [name, schema] of Object.entries(definitions)) {
|
|
672
658
|
const jsonSchema = unwrapSchema(schema, vendors);
|
|
673
|
-
if (jsonSchema)
|
|
659
|
+
if (jsonSchema)
|
|
660
|
+
schemas[name] = {
|
|
661
|
+
...jsonSchema,
|
|
662
|
+
$id: `#/components/schemas/${name}`
|
|
663
|
+
};
|
|
674
664
|
}
|
|
675
665
|
return {
|
|
676
666
|
components: {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TSchema } from '
|
|
1
|
+
import type { TSchema } from 'typebox';
|
|
2
2
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
3
3
|
import type { ApiReferenceConfiguration } from '@scalar/types';
|
|
4
4
|
import type { SwaggerUIOptions } from './swagger/types';
|
|
@@ -102,7 +102,7 @@ export interface ElysiaOpenAPIConfig<Enabled extends boolean = true, Path extend
|
|
|
102
102
|
*'
|
|
103
103
|
* @see https://github.com/scalar/scalar/blob/main/documentation/configuration.md
|
|
104
104
|
*/
|
|
105
|
-
scalar?: ApiReferenceConfiguration & {
|
|
105
|
+
scalar?: Partial<ApiReferenceConfiguration> & {
|
|
106
106
|
/**
|
|
107
107
|
* Version to use for Scalar cdn bundle
|
|
108
108
|
*
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
## 1. Hook and handler argument are swapped
|
|
2
|
+
|
|
3
|
+
The verb methods take the **schema/hook object before the handler**.
|
|
4
|
+
|
|
5
|
+
Applies to `get`/`post`/`put`/`patch`/`delete`/`options`/`head`/`all`/`method`
|
|
6
|
+
|
|
7
|
+
**Migration:** swap position of hook and handler
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// 1.x
|
|
11
|
+
app.get('/user/:id', ({ params, query }) => params.id, {
|
|
12
|
+
params: t.Object({ id: t.Number() }),
|
|
13
|
+
query: t.Object({ name: t.String() })
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
// 2.0
|
|
17
|
+
app.get('/user/:id', {
|
|
18
|
+
params: t.Object({ id: t.Number() }),
|
|
19
|
+
query: t.Object({ name: t.String() })
|
|
20
|
+
}, ({ params, query }) => params.id)
|
|
21
|
+
|
|
22
|
+
// no hook, unchanged
|
|
23
|
+
app.get('/', () => 'hi')
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. WebSocket
|
|
29
|
+
|
|
30
|
+
- `.ws()` now accept 2-3 arguments
|
|
31
|
+
- 2-arg forms (`.ws('/ws', handler)`, `.ws('/ws', options)`) are unchanged
|
|
32
|
+
- 3-arg form is now `.ws('/ws', options, handler)`
|
|
33
|
+
- `ws.data` is now inline to `ws` directly
|
|
34
|
+
- generator function and `yield` is now preferred way of sending data instead of `ws.send` for type safety
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// 1.x
|
|
38
|
+
new Elysia()
|
|
39
|
+
.ws('/', {
|
|
40
|
+
message({ send, data: { params: { id } } }) {
|
|
41
|
+
send(id)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// 2.x
|
|
46
|
+
new Elysia()
|
|
47
|
+
.ws('/', ({ params: { id } }) => id)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 3. Drop `on` prefix for event
|
|
51
|
+
|
|
52
|
+
Use the bare-named methods.
|
|
53
|
+
|
|
54
|
+
| Removed | Use |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `onRequest` | `request` |
|
|
57
|
+
| `onParse` | `parse` |
|
|
58
|
+
| `onTransform` | `transform` |
|
|
59
|
+
| `onBeforeHandle` | `beforeHandle` |
|
|
60
|
+
| `onAfterHandle` | `afterHandle` |
|
|
61
|
+
| `onAfterResponse` | `afterResponse` |
|
|
62
|
+
| `onError` | `error` |
|
|
63
|
+
|
|
64
|
+
The lifecycle hooks are also **renamed** (not just de-prefixed): `onStart` → **`setup`**, `onStop`
|
|
65
|
+
→ **`cleanup`**.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// 1.x
|
|
69
|
+
app.
|
|
70
|
+
onRequest(fn)
|
|
71
|
+
.onBeforeHandle(fn)
|
|
72
|
+
.onAfterResponse(fn)
|
|
73
|
+
|
|
74
|
+
// 2.0
|
|
75
|
+
app
|
|
76
|
+
.request(fn)
|
|
77
|
+
.beforeHandle(fn)
|
|
78
|
+
.afterResponse(fn)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 4. Code is drop from error
|
|
84
|
+
|
|
85
|
+
- `error(ErrorClass, fn)` registers a per-class handler
|
|
86
|
+
- `error(fn)` registers the general handler
|
|
87
|
+
- **`error.code` is removed**: dispatch with `instanceof` or `error(SomeError, fn)`
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// 1.x
|
|
91
|
+
app
|
|
92
|
+
.onError(({ code, error }) => {
|
|
93
|
+
if (code === 'NOT_FOUND') return 'nope'
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// 2.0
|
|
97
|
+
app.error(NotFound, () => 'nope')
|
|
98
|
+
app.error(({ error }) => { /* ... */ })
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 5. `resolve` removed entirely
|
|
104
|
+
|
|
105
|
+
- `derive` now run on `beforeHandle` (previous `resolve` behavior)
|
|
106
|
+
- `resolve` are now removed
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// 1.x
|
|
110
|
+
app.resolve(({ headers }) => ({ user: auth(headers) }))
|
|
111
|
+
// 2.0
|
|
112
|
+
app.derive(({ headers }) => ({ user: auth(headers) }))
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 6. Scope changes
|
|
116
|
+
|
|
117
|
+
- The `'scoped'` scope is **renamed to `'plugin'`**
|
|
118
|
+
- The `{ as: 'scope' }` **object form is removed**
|
|
119
|
+
- `.decorate()` / `.state()` `{ as: 'append' | 'override' }`
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
// 1.x
|
|
123
|
+
app.beforeHandle({ as: 'scoped' }, fn)
|
|
124
|
+
app.as('scoped')
|
|
125
|
+
app.guard({ as: 'scoped' }, fn)
|
|
126
|
+
app.decorate({ as: 'override' }, 'db', db)
|
|
127
|
+
|
|
128
|
+
// 2.0
|
|
129
|
+
app.beforeHandle('plugin', fn)
|
|
130
|
+
app.as('plugin')
|
|
131
|
+
app.guard('plugin', fn)
|
|
132
|
+
app.decorate('override', 'db', db)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 7. Guard/group default to OVERRIDE channel
|
|
138
|
+
|
|
139
|
+
**Every** `.guard()` and `.group()` is default to **override**
|
|
140
|
+
|
|
141
|
+
- the closer to the route, the more power, the nearer schema **replaces** an inherited one
|
|
142
|
+
- `schema: 'standalone'` is explicitly required across all APIs
|
|
143
|
+
|
|
144
|
+
**Migration:** if you use `guard`, add `schema: 'standalone'`:
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// 1.x string-scope & run forms were implicitly additive (standalone)
|
|
148
|
+
app.guard({ body: t.Object({ a: t.String() }) })
|
|
149
|
+
|
|
150
|
+
// 2.0 now overrides by default; prefer closer schema first
|
|
151
|
+
app.guard({ schema: 'standalone', body: t.Object({ a: t.String() }) })
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 8. TypeBox 1.0 alignment
|
|
157
|
+
|
|
158
|
+
See [TypeBox 1.0 migration](https://github.com/sinclairzx81/typebox/blob/main/changelog/1.0.0-migration.md)
|
|
159
|
+
|
|
160
|
+
But to summarize:
|
|
161
|
+
- `t.Transform` → **`t.Codec`**.
|
|
162
|
+
- Removed `t.Recursive`, `t.Not`, `t.RegExp`
|
|
163
|
+
- **`t.NoValidate` semantics changed:** now skips `Check` only `Default`/`Convert`/`Decode`/`Encode` still run.
|
|
164
|
+
- `NoValidate` will throw `ValidationError` if Encode runs.
|
|
165
|
+
- `Error.summary` now uses TypeBox's default message (and supports Standard Schema).
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 9. Macros
|
|
170
|
+
|
|
171
|
+
- **Functional macro must use the object form:** `.macro({ name: fn })`.
|
|
172
|
+
- **`.macro(name, definition)` removed**, use `.macro({ [name]: definition })`.
|
|
173
|
+
- The object form is now fully inferred (own schema, derive results, function-form arg, typo rejection)
|
|
174
|
+
- **Requires TypeScript ≥ 5.7** for macro definition inference.
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
// 1.x named form
|
|
178
|
+
app.macro('auth', {
|
|
179
|
+
resolve: ({ headers }) => ({ user: auth(headers) })
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
// 2.0 object form only (fully inferred)
|
|
183
|
+
app.macro({
|
|
184
|
+
auth: {
|
|
185
|
+
resolve: ({ headers }) => ({ user: auth(headers) })
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 10. Removed / renamed APIs & exports
|
|
191
|
+
|
|
192
|
+
- `NotFoundError` → **`NotFound`** (a thrown 404 is `instanceof NotFound`)
|
|
193
|
+
- `getSchemaValidator` → **`Validator.create`**
|
|
194
|
+
- `set.redirect`: use the `redirect()` context helper
|
|
195
|
+
- `context.contentType` is removed from `Context` in `parse`, use `context.contentType` instead
|
|
196
|
+
- Deprecated `response` field on `mapResponse`/`afterResponse` is removed
|
|
197
|
+
- Removed instance methods `.route()`, `.connect()`, `.env()`,
|
|
198
|
+
`.affix()`/`.prefix()`/`.suffix()` and the `.store`/`.decorator`/`.config`
|
|
199
|
+
**instance getters**, use the verb methods, `new Elysia({ name, prefix })` for
|
|
200
|
+
plugin naming, and in-handler `context.store`/`context.decorator`
|
|
201
|
+
- Passing an Elysia instance to `.mount` is deprecated, use `.use` instead
|
|
202
|
+
- `config.encodeSchema` dropped (always enabled now)
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { NotFound } from 'elysia' // was NotFoundError
|
|
206
|
+
import { Validator } from 'elysia' // getSchemaValidator → Validator.create
|
|
207
|
+
|
|
208
|
+
// redirect
|
|
209
|
+
;({ set }) => { set.redirect = '/' } // 1.x
|
|
210
|
+
;({ redirect }) => redirect('/') // 2.0
|
|
211
|
+
|
|
212
|
+
// afterResponse / mapResponse field
|
|
213
|
+
app.afterResponse(({ responseValue }) => {}) // was `response`
|
|
214
|
+
|
|
215
|
+
// parse contentType
|
|
216
|
+
app.parse((ctx, contentType) => {}) // 1.x (2nd param)
|
|
217
|
+
app.parse((ctx) => ctx.contentType) // 2.0
|
|
218
|
+
|
|
219
|
+
// removed instance getters / methods → use context or constructor
|
|
220
|
+
new Elysia({ name: 'x', prefix: '/v1' }) // was .prefix()/.affix()/.suffix()/name
|
|
221
|
+
;({ store, decorator }) => {} // was app.store / app.decorator getters
|
|
222
|
+
|
|
223
|
+
// mount an instance
|
|
224
|
+
app.use(plugin) // was app.mount(plugin)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 11. Behavior changes worth knowing (no API change, but observable)
|
|
230
|
+
|
|
231
|
+
- **`afterHandle` skips the rest on short-circuit.**
|
|
232
|
+
- **Bodyless `GET`/`HEAD` no longer run `parse` hooks**, a `parse` hook that must run on every request belongs in `request`/`transform`
|
|
233
|
+
- **422 response no longer echoes large bodies**, `found` is scoped; a request body whose JSON exceeds 4KB isn't reflected back in full. `error.value` still exposes the full value to custom handlers.
|
|
234
|
+
- **Returned `Response` passed by reference when `set` is untouched** (preserves
|
|
235
|
+
`content-length`).
|
|
236
|
+
- **Trap:** returning the *same* `Response` object across requests while writing per-request `set.headers` now mutates the shared object and leaks headers (previously errored loudly). Return a fresh `Response` per
|
|
237
|
+
request.
|
|
238
|
+
- **`streamResponse` yields raw bytes**, re-streamed bodies are now byte-identical; a headerless binary-first chunked stream defaults to `application/octet-stream` (was `application/json`)
|
|
239
|
+
- **WS query parsing** now matches HTTP (duplicate keys → arrays, not last-wins; null-prototype records)
|
|
240
|
+
- **Validator runs `Convert → Check → DecodeUnsafe`** for codec schemas (fixes `t.Numeric({ minimum, maximum })` and `t.Codec(...).Decode(...)` against wire input)
|
|
241
|
+
- When file use `t.File` has `type` **`t.File({ type: 'image/jpg' })`**, project must initialize `setFileTypeDetector` with a function that returns the MIME type. (By default Elysia use `file-type` package to detect file type)
|
package/package.json
CHANGED
|
@@ -1,92 +1,94 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
2
|
+
"name": "@elysiajs/openapi",
|
|
3
|
+
"version": "2.0.0-exp.0",
|
|
4
|
+
"description": "Plugin for Elysia to auto-generate API documentation",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "saltyAom",
|
|
7
|
+
"url": "https://github.com/SaltyAom",
|
|
8
|
+
"email": "saltyaom@gmail.com"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/cjs/index.js",
|
|
11
|
+
"module": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
"./package.json": "./package.json",
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
|
+
"require": "./dist/cjs/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./gen": {
|
|
21
|
+
"types": "./dist/gen/index.d.ts",
|
|
22
|
+
"import": "./dist/gen/index.mjs",
|
|
23
|
+
"require": "./dist/cjs/gen/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./openapi": {
|
|
26
|
+
"types": "./dist/openapi.d.ts",
|
|
27
|
+
"import": "./dist/openapi.mjs",
|
|
28
|
+
"require": "./dist/cjs/openapi.js"
|
|
29
|
+
},
|
|
30
|
+
"./scalar": {
|
|
31
|
+
"types": "./dist/scalar/index.d.ts",
|
|
32
|
+
"import": "./dist/scalar/index.mjs",
|
|
33
|
+
"require": "./dist/cjs/scalar/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./scalar/theme": {
|
|
36
|
+
"types": "./dist/scalar/theme.d.ts",
|
|
37
|
+
"import": "./dist/scalar/theme.mjs",
|
|
38
|
+
"require": "./dist/cjs/scalar/theme.js"
|
|
39
|
+
},
|
|
40
|
+
"./swagger": {
|
|
41
|
+
"types": "./dist/swagger/index.d.ts",
|
|
42
|
+
"import": "./dist/swagger/index.mjs",
|
|
43
|
+
"require": "./dist/cjs/swagger/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./swagger/types": {
|
|
46
|
+
"types": "./dist/swagger/types.d.ts",
|
|
47
|
+
"import": "./dist/swagger/types.mjs",
|
|
48
|
+
"require": "./dist/cjs/swagger/types.js"
|
|
49
|
+
},
|
|
50
|
+
"./types": {
|
|
51
|
+
"types": "./dist/types.d.ts",
|
|
52
|
+
"import": "./dist/types.mjs",
|
|
53
|
+
"require": "./dist/cjs/types.js"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"keywords": [
|
|
57
|
+
"elysia",
|
|
58
|
+
"openapi",
|
|
59
|
+
"swagger",
|
|
60
|
+
"scalar"
|
|
61
|
+
],
|
|
62
|
+
"homepage": "https://github.com/elysiajs/elysia-openapi",
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "https://github.com/elysiajs/elysia-openapi"
|
|
66
|
+
},
|
|
67
|
+
"bugs": "https://github.com/elysiajs/elysia-openapi/issues",
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"scripts": {
|
|
70
|
+
"dev": "bun run --watch example/index.ts",
|
|
71
|
+
"test": "bun test && npm run test:node",
|
|
72
|
+
"test:node": "npm install --prefix ./test/node/cjs/ && npm install --prefix ./test/node/esm/ && node ./test/node/cjs/index.js && node ./test/node/esm/index.js",
|
|
73
|
+
"build": "bun build.ts",
|
|
74
|
+
"release": "npm run build && npm run test && npm publish --access public"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@apidevtools/swagger-parser": "^12.0.0",
|
|
78
|
+
"@scalar/types": "^0.2.13",
|
|
79
|
+
"@types/bun": "1.2.20",
|
|
80
|
+
"effect": "^3.17.13",
|
|
81
|
+
"elysia": "2.0.0-exp.12",
|
|
82
|
+
"eslint": "9.6.0",
|
|
83
|
+
"file-type": "^22.0.0",
|
|
84
|
+
"openapi-types": "^12.1.3",
|
|
85
|
+
"tsup": "^8.5.0",
|
|
86
|
+
"typebox": "1.2.16",
|
|
87
|
+
"typescript": "^5.9.2",
|
|
88
|
+
"zod": "^4.2.1"
|
|
89
|
+
},
|
|
90
|
+
"peerDependencies": {
|
|
91
|
+
"elysia": "2.0.0-exp.12",
|
|
92
|
+
"typebox": "1.2.16"
|
|
93
|
+
}
|
|
92
94
|
}
|
package/bunfig.toml
DELETED