elysia 0.2.0 → 0.2.1
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 +2 -3
- package/dist/utils.d.ts +2 -2
- package/package.json +5 -4
- package/dist/context.js +0 -1
- package/dist/error.js +0 -7
- package/dist/handler.js +0 -173
- package/dist/index.js +0 -472
- package/dist/router.d.ts +0 -26
- package/dist/router.js +0 -201
- package/dist/schema.js +0 -109
- package/dist/types.js +0 -1
- package/dist/utils.js +0 -128
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/// <reference types="bun-types" />
|
|
2
2
|
import type { Serve, Server } from 'bun';
|
|
3
|
-
import { Router } from './router';
|
|
4
3
|
import { SCHEMA, DEFS } from './utils';
|
|
5
4
|
import type { Context } from './context';
|
|
6
5
|
import type { Handler, BeforeRequestHandler, TypedRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, InternalRoute, BodyParser, ErrorHandler, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, LifeCycleStore, VoidLifeCycle, AfterRequestHandler, MergeIfNotNull, IsAny, OverwritableTypeRoute, MergeSchema, ListenCallback, NoReturnHandler, ElysiaRoute, MaybePromise, IsNever } from './types';
|
|
@@ -107,8 +106,8 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
|
|
|
107
106
|
schema: Instance['schema'];
|
|
108
107
|
}>;
|
|
109
108
|
}
|
|
110
|
-
export { Elysia
|
|
109
|
+
export { Elysia };
|
|
111
110
|
export { Type as t } from '@sinclair/typebox';
|
|
112
|
-
export { SCHEMA, DEFS,
|
|
111
|
+
export { SCHEMA, DEFS, createValidationError, getSchemaValidator } from './utils';
|
|
113
112
|
export type { Context, PreContext } from './context';
|
|
114
113
|
export type { Handler, RegisteredHook, BeforeRequestHandler, TypedRoute, OverwritableTypeRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, ComposedHandler, InternalRoute, BodyParser, ErrorHandler, ErrorCode, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, AfterRequestHandler, HookHandler, TypedSchemaToRoute, UnwrapSchema, LifeCycleStore, VoidLifeCycle, SchemaValidator, ElysiaRoute, ExtractPath, IsPathParameter, IsAny, IsNever, UnknownFallback, WithArray, ObjectValues, PickInOrder, MaybePromise, MergeIfNotNull } from './types';
|
package/dist/utils.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export declare const DEFS: unique symbol;
|
|
|
6
6
|
export declare const mergeObjectArray: <T>(a: T | T[], b: T | T[]) => T[];
|
|
7
7
|
export declare const mergeHook: (a: LocalHook<any> | LifeCycleStore<any>, b: LocalHook<any>) => RegisteredHook<any>;
|
|
8
8
|
export declare const clone: <T extends Object | any[] = Object | any[]>(value: T) => T;
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const mapQuery: (url: string
|
|
9
|
+
export declare const mapPathnameAndQueryRegEx: RegExp;
|
|
10
|
+
export declare const mapQuery: (url: string) => Record<string, string>;
|
|
11
11
|
export declare const mergeDeep: <A extends Object = Object, B extends Object = Object>(target: A, source: B) => DeepMergeTwoTypes<A, B>;
|
|
12
12
|
export declare const createValidationError: (type: string, validator: TypeCheck<any>, value: any) => Error;
|
|
13
13
|
export declare const getSchemaValidator: (s: TSchema | string | undefined, models: Record<string, TSchema>, additionalProperties?: boolean) => TypeCheck<TSchema> | undefined;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elysia",
|
|
3
3
|
"description": "Fast, and friendly Bun web framework",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "saltyAom",
|
|
7
7
|
"url": "https://github.com/SaltyAom",
|
|
@@ -35,8 +35,9 @@
|
|
|
35
35
|
"release": "npm run build && npm run test && npm publish"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@sinclair/typebox": "0.25.21",
|
|
39
|
-
"openapi-types": "^12.1.0"
|
|
38
|
+
"@sinclair/typebox": "^0.25.21",
|
|
39
|
+
"openapi-types": "^12.1.0",
|
|
40
|
+
"raikiri": "0.0.0-beta.3"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@types/node": "^18.11.18",
|
|
@@ -47,4 +48,4 @@
|
|
|
47
48
|
"rimraf": "^3.0.2",
|
|
48
49
|
"typescript": "^4.9.4"
|
|
49
50
|
}
|
|
50
|
-
}
|
|
51
|
+
}
|
package/dist/context.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/error.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
const errorCodeToStatus = new Map();
|
|
2
|
-
errorCodeToStatus.set('INTERNAL_SERVER_ERROR', 500);
|
|
3
|
-
errorCodeToStatus.set('NOT_FOUND', 404);
|
|
4
|
-
errorCodeToStatus.set('VALIDATION', 400);
|
|
5
|
-
const knownErrors = new Set(errorCodeToStatus.keys());
|
|
6
|
-
export const mapErrorCode = (error) => knownErrors.has(error) ? error : 'UNKNOWN';
|
|
7
|
-
export const mapErrorStatus = (error) => errorCodeToStatus.get(error) ?? 500;
|
package/dist/handler.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
const isNotEmpty = (obj) => {
|
|
2
|
-
for (const x in obj)
|
|
3
|
-
return true;
|
|
4
|
-
return false;
|
|
5
|
-
};
|
|
6
|
-
export const mapEarlyResponse = (response, set) => {
|
|
7
|
-
if (set.redirect)
|
|
8
|
-
return Response.redirect(set.redirect, {
|
|
9
|
-
headers: set.headers
|
|
10
|
-
});
|
|
11
|
-
if (isNotEmpty(set.headers) || set.status !== 200)
|
|
12
|
-
switch (typeof response) {
|
|
13
|
-
case 'string':
|
|
14
|
-
return new Response(response, {
|
|
15
|
-
status: set.status,
|
|
16
|
-
headers: set.headers
|
|
17
|
-
});
|
|
18
|
-
case 'object':
|
|
19
|
-
if (response instanceof Error)
|
|
20
|
-
return errorToResponse(response, set.headers);
|
|
21
|
-
if (response instanceof Response) {
|
|
22
|
-
for (const key in set.headers)
|
|
23
|
-
response.headers.append(key, set.headers[key]);
|
|
24
|
-
return response;
|
|
25
|
-
}
|
|
26
|
-
if (response instanceof Blob)
|
|
27
|
-
return new Response(response, {
|
|
28
|
-
status: set.status,
|
|
29
|
-
headers: set.headers
|
|
30
|
-
});
|
|
31
|
-
if (!set.headers['Content-Type'])
|
|
32
|
-
set.headers['Content-Type'] = 'application/json';
|
|
33
|
-
return new Response(JSON.stringify(response), {
|
|
34
|
-
status: set.status,
|
|
35
|
-
headers: set.headers
|
|
36
|
-
});
|
|
37
|
-
case 'function':
|
|
38
|
-
if (response instanceof Blob)
|
|
39
|
-
return new Response(response, {
|
|
40
|
-
status: set.status,
|
|
41
|
-
headers: set.headers
|
|
42
|
-
});
|
|
43
|
-
for (const key in set.headers)
|
|
44
|
-
response.headers.append(key, set.headers[key]);
|
|
45
|
-
return response;
|
|
46
|
-
case 'number':
|
|
47
|
-
case 'boolean':
|
|
48
|
-
return new Response(response.toString(), {
|
|
49
|
-
status: set.status,
|
|
50
|
-
headers: set.headers
|
|
51
|
-
});
|
|
52
|
-
default:
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
else
|
|
56
|
-
switch (typeof response) {
|
|
57
|
-
case 'string':
|
|
58
|
-
return new Response(response);
|
|
59
|
-
case 'object':
|
|
60
|
-
if (response instanceof Response)
|
|
61
|
-
return response;
|
|
62
|
-
if (response instanceof Error)
|
|
63
|
-
return errorToResponse(response, set.headers);
|
|
64
|
-
if (response instanceof Blob)
|
|
65
|
-
return new Response(response);
|
|
66
|
-
return new Response(JSON.stringify(response), {
|
|
67
|
-
headers: {
|
|
68
|
-
'content-type': 'application/json'
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
case 'function':
|
|
72
|
-
if (response instanceof Blob)
|
|
73
|
-
return new Response(response);
|
|
74
|
-
return response;
|
|
75
|
-
case 'number':
|
|
76
|
-
case 'boolean':
|
|
77
|
-
return new Response(response.toString());
|
|
78
|
-
default:
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
export const mapResponse = (response, set) => {
|
|
83
|
-
if (set.redirect)
|
|
84
|
-
return Response.redirect(set.redirect, {
|
|
85
|
-
headers: set.headers
|
|
86
|
-
});
|
|
87
|
-
if (isNotEmpty(set.headers) || set.status !== 200)
|
|
88
|
-
switch (typeof response) {
|
|
89
|
-
case 'string':
|
|
90
|
-
return new Response(response, {
|
|
91
|
-
status: set.status,
|
|
92
|
-
headers: set.headers
|
|
93
|
-
});
|
|
94
|
-
case 'object':
|
|
95
|
-
if (response instanceof Error)
|
|
96
|
-
return errorToResponse(response, set.headers);
|
|
97
|
-
if (response instanceof Response) {
|
|
98
|
-
for (const key in set.headers)
|
|
99
|
-
response.headers.append(key, set.headers[key]);
|
|
100
|
-
return response;
|
|
101
|
-
}
|
|
102
|
-
if (response instanceof Blob)
|
|
103
|
-
return new Response(response, {
|
|
104
|
-
status: set.status,
|
|
105
|
-
headers: set.headers
|
|
106
|
-
});
|
|
107
|
-
if (!set.headers['Content-Type'])
|
|
108
|
-
set.headers['Content-Type'] = 'application/json';
|
|
109
|
-
return new Response(JSON.stringify(response), {
|
|
110
|
-
status: set.status,
|
|
111
|
-
headers: set.headers
|
|
112
|
-
});
|
|
113
|
-
case 'function':
|
|
114
|
-
if (response instanceof Blob)
|
|
115
|
-
return new Response(response, {
|
|
116
|
-
status: set.status,
|
|
117
|
-
headers: set.headers
|
|
118
|
-
});
|
|
119
|
-
return response();
|
|
120
|
-
case 'number':
|
|
121
|
-
case 'boolean':
|
|
122
|
-
return new Response(response.toString(), {
|
|
123
|
-
status: set.status,
|
|
124
|
-
headers: set.headers
|
|
125
|
-
});
|
|
126
|
-
case 'undefined':
|
|
127
|
-
return new Response('', {
|
|
128
|
-
status: set.status,
|
|
129
|
-
headers: set.headers
|
|
130
|
-
});
|
|
131
|
-
default:
|
|
132
|
-
return new Response(response, {
|
|
133
|
-
status: set.status,
|
|
134
|
-
headers: set.headers
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
else
|
|
138
|
-
switch (typeof response) {
|
|
139
|
-
case 'string':
|
|
140
|
-
return new Response(response);
|
|
141
|
-
case 'object':
|
|
142
|
-
if (response instanceof Response)
|
|
143
|
-
return response;
|
|
144
|
-
if (response instanceof Error)
|
|
145
|
-
return errorToResponse(response, set.headers);
|
|
146
|
-
if (response instanceof Blob)
|
|
147
|
-
return new Response(response);
|
|
148
|
-
return new Response(JSON.stringify(response), {
|
|
149
|
-
headers: {
|
|
150
|
-
'content-type': 'application/json'
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
case 'function':
|
|
154
|
-
if (response instanceof Blob)
|
|
155
|
-
return new Response(response);
|
|
156
|
-
return response();
|
|
157
|
-
case 'number':
|
|
158
|
-
case 'boolean':
|
|
159
|
-
return new Response(response.toString());
|
|
160
|
-
case 'undefined':
|
|
161
|
-
return new Response('');
|
|
162
|
-
default:
|
|
163
|
-
return new Response(response);
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
export const errorToResponse = (error, headers) => new Response(JSON.stringify({
|
|
167
|
-
name: error?.name,
|
|
168
|
-
message: error?.message,
|
|
169
|
-
cause: error?.cause
|
|
170
|
-
}), {
|
|
171
|
-
status: 500,
|
|
172
|
-
headers
|
|
173
|
-
});
|
package/dist/index.js
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
import { Router } from './router';
|
|
2
|
-
import { mapResponse, mapEarlyResponse } from './handler';
|
|
3
|
-
import { mapQuery, clone, mergeHook, mergeDeep, createValidationError, getSchemaValidator, SCHEMA, DEFS, getResponseSchemaValidator } from './utils';
|
|
4
|
-
import { registerSchemaPath } from './schema';
|
|
5
|
-
import { mapErrorCode, mapErrorStatus } from './error';
|
|
6
|
-
export default class Elysia {
|
|
7
|
-
constructor(config = {}) {
|
|
8
|
-
this.store = {
|
|
9
|
-
[SCHEMA]: {},
|
|
10
|
-
[DEFS]: {}
|
|
11
|
-
};
|
|
12
|
-
this.decorators = null;
|
|
13
|
-
this.event = {
|
|
14
|
-
start: [],
|
|
15
|
-
request: [],
|
|
16
|
-
parse: [],
|
|
17
|
-
transform: [],
|
|
18
|
-
beforeHandle: [],
|
|
19
|
-
afterHandle: [],
|
|
20
|
-
error: [],
|
|
21
|
-
stop: []
|
|
22
|
-
};
|
|
23
|
-
this.server = null;
|
|
24
|
-
this.$schema = null;
|
|
25
|
-
this.router = new Router();
|
|
26
|
-
this.fallbackRoute = {};
|
|
27
|
-
this.routes = [];
|
|
28
|
-
this.lazyLoadModules = [];
|
|
29
|
-
this.stop = async () => {
|
|
30
|
-
if (!this.server)
|
|
31
|
-
throw new Error("Elysia isn't running. Call `app.listen` to start the server.");
|
|
32
|
-
this.server.stop();
|
|
33
|
-
for (let i = 0; i < this.event.stop.length; i++)
|
|
34
|
-
await this.event.stop[i](this);
|
|
35
|
-
};
|
|
36
|
-
this.config = {
|
|
37
|
-
strictPath: false,
|
|
38
|
-
...config
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
_addHandler(method, path, handler, hook) {
|
|
42
|
-
path = path.startsWith('/') ? path : `/${path}`;
|
|
43
|
-
this.routes.push({
|
|
44
|
-
method,
|
|
45
|
-
path,
|
|
46
|
-
handler,
|
|
47
|
-
hooks: mergeHook(clone(this.event), hook)
|
|
48
|
-
});
|
|
49
|
-
const defs = this.store[DEFS];
|
|
50
|
-
const body = getSchemaValidator(hook?.schema?.body ?? this.$schema?.body, defs);
|
|
51
|
-
const header = getSchemaValidator(hook?.schema?.headers ?? this.$schema?.headers, defs, true);
|
|
52
|
-
const params = getSchemaValidator(hook?.schema?.params ?? this.$schema?.params, defs);
|
|
53
|
-
const query = getSchemaValidator(hook?.schema?.query ?? this.$schema?.query, defs);
|
|
54
|
-
const response = getResponseSchemaValidator(hook?.schema?.response ?? this.$schema?.response, defs);
|
|
55
|
-
registerSchemaPath({
|
|
56
|
-
schema: this.store[SCHEMA],
|
|
57
|
-
hook,
|
|
58
|
-
method,
|
|
59
|
-
path,
|
|
60
|
-
models: this.store[DEFS]
|
|
61
|
-
});
|
|
62
|
-
const validator = body || header || params || query || response
|
|
63
|
-
? {
|
|
64
|
-
body,
|
|
65
|
-
header,
|
|
66
|
-
params,
|
|
67
|
-
query,
|
|
68
|
-
response
|
|
69
|
-
}
|
|
70
|
-
: undefined;
|
|
71
|
-
if (path === '/*')
|
|
72
|
-
this.fallbackRoute[method] = {
|
|
73
|
-
handle: handler,
|
|
74
|
-
hooks: mergeHook(clone(this.event), hook),
|
|
75
|
-
validator
|
|
76
|
-
};
|
|
77
|
-
this.router.register(path)[method] = {
|
|
78
|
-
handle: handler,
|
|
79
|
-
hooks: mergeHook(clone(this.event), hook),
|
|
80
|
-
validator
|
|
81
|
-
};
|
|
82
|
-
if (!this.config.strictPath && path !== '/')
|
|
83
|
-
if (path.endsWith('/'))
|
|
84
|
-
this.router.register(path.substring(0, path.length - 1))[method] = this.router.register(path)[method];
|
|
85
|
-
else
|
|
86
|
-
this.router.register(`${path}/`)[method] =
|
|
87
|
-
this.router.register(path)[method];
|
|
88
|
-
}
|
|
89
|
-
onStart(handler) {
|
|
90
|
-
this.event.start.push(handler);
|
|
91
|
-
return this;
|
|
92
|
-
}
|
|
93
|
-
onRequest(handler) {
|
|
94
|
-
this.event.request.push(handler);
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
onParse(parser) {
|
|
98
|
-
this.event.parse.splice(this.event.parse.length - 1, 0, parser);
|
|
99
|
-
return this;
|
|
100
|
-
}
|
|
101
|
-
onTransform(handler) {
|
|
102
|
-
this.event.transform.push(handler);
|
|
103
|
-
return this;
|
|
104
|
-
}
|
|
105
|
-
onBeforeHandle(handler) {
|
|
106
|
-
this.event.beforeHandle.push(handler);
|
|
107
|
-
return this;
|
|
108
|
-
}
|
|
109
|
-
onAfterHandle(handler) {
|
|
110
|
-
this.event.afterHandle.push(handler);
|
|
111
|
-
return this;
|
|
112
|
-
}
|
|
113
|
-
onError(errorHandler) {
|
|
114
|
-
this.event.error.push(errorHandler);
|
|
115
|
-
return this;
|
|
116
|
-
}
|
|
117
|
-
onStop(handler) {
|
|
118
|
-
this.event.stop.push(handler);
|
|
119
|
-
return this;
|
|
120
|
-
}
|
|
121
|
-
on(type, handler) {
|
|
122
|
-
switch (type) {
|
|
123
|
-
case 'start':
|
|
124
|
-
this.event.start.push(handler);
|
|
125
|
-
break;
|
|
126
|
-
case 'request':
|
|
127
|
-
this.event.request.push(handler);
|
|
128
|
-
break;
|
|
129
|
-
case 'parse':
|
|
130
|
-
this.event.parse.push(handler);
|
|
131
|
-
break;
|
|
132
|
-
case 'transform':
|
|
133
|
-
this.event.transform.push(handler);
|
|
134
|
-
break;
|
|
135
|
-
case 'beforeHandle':
|
|
136
|
-
this.event.beforeHandle.push(handler);
|
|
137
|
-
break;
|
|
138
|
-
case 'afterHandle':
|
|
139
|
-
this.event.afterHandle.push(handler);
|
|
140
|
-
break;
|
|
141
|
-
case 'error':
|
|
142
|
-
this.event.error.push(handler);
|
|
143
|
-
break;
|
|
144
|
-
case 'stop':
|
|
145
|
-
this.event.stop.push(handler);
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
return this;
|
|
149
|
-
}
|
|
150
|
-
group(prefix, run) {
|
|
151
|
-
const instance = new Elysia();
|
|
152
|
-
instance.store = this.store;
|
|
153
|
-
const sandbox = run(instance);
|
|
154
|
-
if (sandbox.event.request.length)
|
|
155
|
-
this.event.request = [
|
|
156
|
-
...this.event.request,
|
|
157
|
-
...sandbox.event.request
|
|
158
|
-
];
|
|
159
|
-
Object.values(instance.routes).forEach(({ method, path, handler, hooks }) => {
|
|
160
|
-
this._addHandler(method, `${prefix}${path}`, handler, hooks);
|
|
161
|
-
});
|
|
162
|
-
return this;
|
|
163
|
-
}
|
|
164
|
-
guard(hook, run) {
|
|
165
|
-
const instance = new Elysia();
|
|
166
|
-
instance.store = this.store;
|
|
167
|
-
const sandbox = run(instance);
|
|
168
|
-
if (sandbox.event.request.length)
|
|
169
|
-
this.event.request = [
|
|
170
|
-
...this.event.request,
|
|
171
|
-
...sandbox.event.request
|
|
172
|
-
];
|
|
173
|
-
Object.values(instance.routes).forEach(({ method, path, handler, hooks: localHook }) => {
|
|
174
|
-
this._addHandler(method, path, handler, mergeHook(hook, localHook));
|
|
175
|
-
});
|
|
176
|
-
return this;
|
|
177
|
-
}
|
|
178
|
-
use(plugin) {
|
|
179
|
-
if (plugin instanceof Promise) {
|
|
180
|
-
this.lazyLoadModules.push(plugin.then((plugin) => {
|
|
181
|
-
if (typeof plugin === 'function')
|
|
182
|
-
return plugin(this);
|
|
183
|
-
return plugin.default(this);
|
|
184
|
-
}));
|
|
185
|
-
return this;
|
|
186
|
-
}
|
|
187
|
-
const instance = plugin(this);
|
|
188
|
-
if (instance instanceof Promise) {
|
|
189
|
-
this.lazyLoadModules.push(instance);
|
|
190
|
-
return this;
|
|
191
|
-
}
|
|
192
|
-
return instance;
|
|
193
|
-
}
|
|
194
|
-
get(path, handler, hook) {
|
|
195
|
-
this._addHandler('GET', path, handler, hook);
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
|
-
post(path, handler, hook) {
|
|
199
|
-
this._addHandler('POST', path, handler, hook);
|
|
200
|
-
return this;
|
|
201
|
-
}
|
|
202
|
-
put(path, handler, hook) {
|
|
203
|
-
this._addHandler('PUT', path, handler, hook);
|
|
204
|
-
return this;
|
|
205
|
-
}
|
|
206
|
-
patch(path, handler, hook) {
|
|
207
|
-
this._addHandler('PATCH', path, handler, hook);
|
|
208
|
-
return this;
|
|
209
|
-
}
|
|
210
|
-
delete(path, handler, hook) {
|
|
211
|
-
this._addHandler('DELETE', path, handler, hook);
|
|
212
|
-
return this;
|
|
213
|
-
}
|
|
214
|
-
options(path, handler, hook) {
|
|
215
|
-
this._addHandler('OPTIONS', path, handler, hook);
|
|
216
|
-
return this;
|
|
217
|
-
}
|
|
218
|
-
all(path, handler, hook) {
|
|
219
|
-
this._addHandler('ALL', path, handler, hook);
|
|
220
|
-
return this;
|
|
221
|
-
}
|
|
222
|
-
head(path, handler, hook) {
|
|
223
|
-
this._addHandler('HEAD', path, handler, hook);
|
|
224
|
-
return this;
|
|
225
|
-
}
|
|
226
|
-
trace(path, handler, hook) {
|
|
227
|
-
this._addHandler('TRACE', path, handler, hook);
|
|
228
|
-
return this;
|
|
229
|
-
}
|
|
230
|
-
connect(path, handler, hook) {
|
|
231
|
-
this._addHandler('CONNECT', path, handler, hook);
|
|
232
|
-
return this;
|
|
233
|
-
}
|
|
234
|
-
route(method, path, handler, hook) {
|
|
235
|
-
this._addHandler(method, path, handler, hook);
|
|
236
|
-
return this;
|
|
237
|
-
}
|
|
238
|
-
state(name, value) {
|
|
239
|
-
if (!(name in this.store)) {
|
|
240
|
-
;
|
|
241
|
-
this.store[name] = value;
|
|
242
|
-
}
|
|
243
|
-
return this;
|
|
244
|
-
}
|
|
245
|
-
decorate(name, value) {
|
|
246
|
-
if (!this.decorators)
|
|
247
|
-
this.decorators = {};
|
|
248
|
-
if (!(name in this.decorators))
|
|
249
|
-
this.decorators[name] = value;
|
|
250
|
-
return this;
|
|
251
|
-
}
|
|
252
|
-
derive(transform) {
|
|
253
|
-
this.store = mergeDeep(this.store, transform(() => this.store));
|
|
254
|
-
return this;
|
|
255
|
-
}
|
|
256
|
-
inject(transform) {
|
|
257
|
-
return this.onTransform((context) => {
|
|
258
|
-
Object.assign(context, transform(context));
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
schema(schema) {
|
|
262
|
-
const defs = this.store[DEFS];
|
|
263
|
-
this.$schema = {
|
|
264
|
-
body: getSchemaValidator(schema.body, defs),
|
|
265
|
-
headers: getSchemaValidator(schema?.headers, defs, true),
|
|
266
|
-
params: getSchemaValidator(schema?.params, defs),
|
|
267
|
-
query: getSchemaValidator(schema?.query, defs),
|
|
268
|
-
response: getSchemaValidator(schema?.response, defs)
|
|
269
|
-
};
|
|
270
|
-
return this;
|
|
271
|
-
}
|
|
272
|
-
async handle(request) {
|
|
273
|
-
const set = {
|
|
274
|
-
status: 200,
|
|
275
|
-
headers: {}
|
|
276
|
-
};
|
|
277
|
-
let context;
|
|
278
|
-
if (this.decorators) {
|
|
279
|
-
context = clone(this.decorators);
|
|
280
|
-
context.request = request;
|
|
281
|
-
context.set = set;
|
|
282
|
-
context.store = this.store;
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
context = {
|
|
286
|
-
set,
|
|
287
|
-
store: this.store,
|
|
288
|
-
request
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
try {
|
|
292
|
-
for (let i = 0; i < this.event.request.length; i++) {
|
|
293
|
-
const onRequest = this.event.request[i];
|
|
294
|
-
let response = onRequest(context);
|
|
295
|
-
if (response instanceof Promise)
|
|
296
|
-
response = await response;
|
|
297
|
-
response = mapEarlyResponse(response, set);
|
|
298
|
-
if (response)
|
|
299
|
-
return response;
|
|
300
|
-
}
|
|
301
|
-
const index = request.url.indexOf('?', 10);
|
|
302
|
-
const route = this.router.find(request.url, index);
|
|
303
|
-
if (!route)
|
|
304
|
-
throw new Error('NOT_FOUND');
|
|
305
|
-
const handler = route.store[request.method] ||
|
|
306
|
-
route.store.ALL ||
|
|
307
|
-
this.fallbackRoute[request.method];
|
|
308
|
-
if (!handler)
|
|
309
|
-
throw new Error('NOT_FOUND');
|
|
310
|
-
const hooks = handler.hooks;
|
|
311
|
-
let body;
|
|
312
|
-
if (request.method !== 'GET') {
|
|
313
|
-
let contentType = request.headers.get('content-type');
|
|
314
|
-
if (contentType) {
|
|
315
|
-
const index = contentType.indexOf(';');
|
|
316
|
-
if (index !== -1)
|
|
317
|
-
contentType = contentType.slice(0, index);
|
|
318
|
-
for (let i = 0; i < this.event.parse.length; i++) {
|
|
319
|
-
let temp = this.event.parse[i](context, contentType);
|
|
320
|
-
if (temp instanceof Promise)
|
|
321
|
-
temp = await temp;
|
|
322
|
-
if (temp) {
|
|
323
|
-
body = temp;
|
|
324
|
-
break;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
if (body === undefined) {
|
|
328
|
-
switch (contentType) {
|
|
329
|
-
case 'application/json':
|
|
330
|
-
body = await request.json();
|
|
331
|
-
break;
|
|
332
|
-
case 'text/plain':
|
|
333
|
-
body = await request.text();
|
|
334
|
-
break;
|
|
335
|
-
case 'application/x-www-form-urlencoded':
|
|
336
|
-
body = mapQuery(await request.text(), null);
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
context.body = body;
|
|
343
|
-
context.params = route?.params || {};
|
|
344
|
-
context.query = mapQuery(request.url, index);
|
|
345
|
-
for (let i = 0; i < hooks.transform.length; i++) {
|
|
346
|
-
const operation = hooks.transform[i](context);
|
|
347
|
-
if (operation instanceof Promise)
|
|
348
|
-
await operation;
|
|
349
|
-
}
|
|
350
|
-
if (handler.validator) {
|
|
351
|
-
const validator = handler.validator;
|
|
352
|
-
if (validator.headers) {
|
|
353
|
-
const _header = {};
|
|
354
|
-
for (const key in request.headers)
|
|
355
|
-
_header[key] = request.headers.get(key);
|
|
356
|
-
if (validator.headers.Check(_header) === false)
|
|
357
|
-
throw createValidationError('header', validator.headers, _header);
|
|
358
|
-
}
|
|
359
|
-
if (validator.params?.Check(context.params) === false)
|
|
360
|
-
throw createValidationError('params', validator.params, context.params);
|
|
361
|
-
if (validator.query?.Check(context.query) === false)
|
|
362
|
-
throw createValidationError('query', validator.query, context.query);
|
|
363
|
-
if (validator.body?.Check(body) === false)
|
|
364
|
-
throw createValidationError('body', validator.body, body);
|
|
365
|
-
}
|
|
366
|
-
for (let i = 0; i < hooks.beforeHandle.length; i++) {
|
|
367
|
-
let response = hooks.beforeHandle[i](context);
|
|
368
|
-
if (response instanceof Promise)
|
|
369
|
-
response = await response;
|
|
370
|
-
if (response !== null && response !== undefined) {
|
|
371
|
-
for (let i = 0; i < hooks.afterHandle.length; i++) {
|
|
372
|
-
let newResponse = hooks.afterHandle[i](context, response);
|
|
373
|
-
if (newResponse instanceof Promise)
|
|
374
|
-
newResponse = await newResponse;
|
|
375
|
-
if (newResponse)
|
|
376
|
-
response = newResponse;
|
|
377
|
-
}
|
|
378
|
-
const result = mapEarlyResponse(response, context.set);
|
|
379
|
-
if (result)
|
|
380
|
-
return result;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
let response = handler.handle(context);
|
|
384
|
-
if (response instanceof Promise)
|
|
385
|
-
response = await response;
|
|
386
|
-
if (handler.validator?.response?.Check(response) === false)
|
|
387
|
-
throw createValidationError('response', handler.validator.response, response);
|
|
388
|
-
for (let i = 0; i < hooks.afterHandle.length; i++) {
|
|
389
|
-
let newResponse = hooks.afterHandle[i](context, response);
|
|
390
|
-
if (newResponse instanceof Promise)
|
|
391
|
-
newResponse = await newResponse;
|
|
392
|
-
const result = mapEarlyResponse(newResponse, context.set);
|
|
393
|
-
if (result)
|
|
394
|
-
return result;
|
|
395
|
-
}
|
|
396
|
-
return mapResponse(response, context.set);
|
|
397
|
-
}
|
|
398
|
-
catch (error) {
|
|
399
|
-
return this.handleError(error, set);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
async handleError(error, set = {
|
|
403
|
-
headers: {},
|
|
404
|
-
status: undefined
|
|
405
|
-
}) {
|
|
406
|
-
for (let i = 0; i < this.event.error.length; i++) {
|
|
407
|
-
let response = this.event.error[i]({
|
|
408
|
-
code: mapErrorCode(error.message),
|
|
409
|
-
error,
|
|
410
|
-
set
|
|
411
|
-
});
|
|
412
|
-
if (response instanceof Promise)
|
|
413
|
-
response = await response;
|
|
414
|
-
if (response !== undefined && response !== null)
|
|
415
|
-
return mapResponse(response, set);
|
|
416
|
-
}
|
|
417
|
-
return new Response(typeof error.cause === 'string' ? error.cause : error.message, {
|
|
418
|
-
headers: set.headers,
|
|
419
|
-
status: mapErrorStatus(mapErrorCode(error.message))
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
listen(options, callback) {
|
|
423
|
-
if (!Bun)
|
|
424
|
-
throw new Error('Bun to run');
|
|
425
|
-
const fetch = this.handle.bind(this);
|
|
426
|
-
if (typeof options === 'string') {
|
|
427
|
-
options = +options;
|
|
428
|
-
if (Number.isNaN(options))
|
|
429
|
-
throw new Error('Port must be a numeric value');
|
|
430
|
-
}
|
|
431
|
-
const serve = typeof options === 'object'
|
|
432
|
-
? {
|
|
433
|
-
...this.config.serve,
|
|
434
|
-
...options,
|
|
435
|
-
fetch
|
|
436
|
-
}
|
|
437
|
-
: {
|
|
438
|
-
...this.config.serve,
|
|
439
|
-
port: options,
|
|
440
|
-
fetch
|
|
441
|
-
};
|
|
442
|
-
const key = `$$Elysia:${serve.port}`;
|
|
443
|
-
if (globalThis[key]) {
|
|
444
|
-
this.server = globalThis[key];
|
|
445
|
-
this.server.reload(serve);
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
globalThis[key] = this.server = Bun.serve(serve);
|
|
449
|
-
}
|
|
450
|
-
for (let i = 0; i < this.event.start.length; i++)
|
|
451
|
-
this.event.start[i](this);
|
|
452
|
-
if (callback)
|
|
453
|
-
callback(this.server);
|
|
454
|
-
Promise.all(this.lazyLoadModules).then(() => {
|
|
455
|
-
Bun.gc(true);
|
|
456
|
-
});
|
|
457
|
-
return this;
|
|
458
|
-
}
|
|
459
|
-
get modules() {
|
|
460
|
-
return Promise.all(this.lazyLoadModules);
|
|
461
|
-
}
|
|
462
|
-
setModel(record) {
|
|
463
|
-
Object.entries(record).forEach(([key, value]) => {
|
|
464
|
-
if (!(key in this.store[DEFS]))
|
|
465
|
-
this.store[DEFS][key] = value;
|
|
466
|
-
});
|
|
467
|
-
return this;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
export { Elysia, Router };
|
|
471
|
-
export { Type as t } from '@sinclair/typebox';
|
|
472
|
-
export { SCHEMA, DEFS, getPath, createValidationError, getSchemaValidator } from './utils';
|
package/dist/router.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { ComposedHandler } from '../src';
|
|
2
|
-
export interface FindResult {
|
|
3
|
-
store: Partial<{
|
|
4
|
-
[k in string]: ComposedHandler;
|
|
5
|
-
}> & Partial<{
|
|
6
|
-
wildcardStore?: Map<number, any> | null;
|
|
7
|
-
}>;
|
|
8
|
-
params: Record<string, any>;
|
|
9
|
-
}
|
|
10
|
-
export interface ParametricNode {
|
|
11
|
-
paramName: string;
|
|
12
|
-
store: Record<string, any> | null;
|
|
13
|
-
staticChild: Node | null;
|
|
14
|
-
}
|
|
15
|
-
export interface Node {
|
|
16
|
-
pathPart: string;
|
|
17
|
-
store: Record<string, any> | null;
|
|
18
|
-
staticChildren: Map<any, any> | null;
|
|
19
|
-
parametricChild: ParametricNode | null;
|
|
20
|
-
wildcardStore: Map<number, any> | null;
|
|
21
|
-
}
|
|
22
|
-
export declare class Router {
|
|
23
|
-
private _root;
|
|
24
|
-
register(path: string): FindResult['store'];
|
|
25
|
-
find(url: string, queryIndex: number): FindResult | null;
|
|
26
|
-
}
|
package/dist/router.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { getPath } from './utils';
|
|
2
|
-
function createNode(pathPart, staticChildren) {
|
|
3
|
-
return {
|
|
4
|
-
pathPart,
|
|
5
|
-
store: null,
|
|
6
|
-
staticChildren: staticChildren !== undefined
|
|
7
|
-
? new Map(staticChildren.map((child) => [
|
|
8
|
-
child.pathPart.charCodeAt(0),
|
|
9
|
-
child
|
|
10
|
-
]))
|
|
11
|
-
: null,
|
|
12
|
-
parametricChild: null,
|
|
13
|
-
wildcardStore: null
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function cloneNode(node, newPathPart) {
|
|
17
|
-
return {
|
|
18
|
-
pathPart: newPathPart,
|
|
19
|
-
store: node.store,
|
|
20
|
-
staticChildren: node.staticChildren,
|
|
21
|
-
parametricChild: node.parametricChild,
|
|
22
|
-
wildcardStore: node.wildcardStore
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function createParametricNode(paramName) {
|
|
26
|
-
return {
|
|
27
|
-
paramName,
|
|
28
|
-
store: null,
|
|
29
|
-
staticChild: null
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
export class Router {
|
|
33
|
-
constructor() {
|
|
34
|
-
this._root = createNode('/');
|
|
35
|
-
}
|
|
36
|
-
register(path) {
|
|
37
|
-
if (typeof path !== 'string')
|
|
38
|
-
throw new TypeError('Route path must be a string');
|
|
39
|
-
if (path === '' || path[0] !== '/')
|
|
40
|
-
throw new Error(`Invalid route: ${path}\nRoute path must begin with a "/"`);
|
|
41
|
-
const endsWithWildcard = path.endsWith('*');
|
|
42
|
-
if (endsWithWildcard)
|
|
43
|
-
path = path.slice(0, -1);
|
|
44
|
-
const staticParts = path.split(/:.+?(?=\/|$)/);
|
|
45
|
-
const paramParts = path.match(/:.+?(?=\/|$)/g) || [];
|
|
46
|
-
if (staticParts[staticParts.length - 1] === '')
|
|
47
|
-
staticParts.pop();
|
|
48
|
-
let node = this._root;
|
|
49
|
-
let paramPartsIndex = 0;
|
|
50
|
-
for (let i = 0; i < staticParts.length; ++i) {
|
|
51
|
-
let pathPart = staticParts[i];
|
|
52
|
-
if (i > 0) {
|
|
53
|
-
const paramName = paramParts[paramPartsIndex++].slice(1);
|
|
54
|
-
if (node.parametricChild === null)
|
|
55
|
-
node.parametricChild = createParametricNode(paramName);
|
|
56
|
-
else if (node.parametricChild.paramName !== paramName)
|
|
57
|
-
throw new Error(`Cannot create route "${path}" with parameter "${paramName}" ` +
|
|
58
|
-
'because a route already exists with a different parameter name ' +
|
|
59
|
-
`("${node.parametricChild.paramName}") in the same location`);
|
|
60
|
-
const { parametricChild } = node;
|
|
61
|
-
if (parametricChild.staticChild === null) {
|
|
62
|
-
node = parametricChild.staticChild = createNode(pathPart);
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
node = parametricChild.staticChild;
|
|
66
|
-
}
|
|
67
|
-
for (let j = 0;;) {
|
|
68
|
-
if (j === pathPart.length) {
|
|
69
|
-
if (j < node.pathPart.length) {
|
|
70
|
-
const childNode = cloneNode(node, node.pathPart.slice(j));
|
|
71
|
-
Object.assign(node, createNode(pathPart, [childNode]));
|
|
72
|
-
}
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
if (j === node.pathPart.length) {
|
|
76
|
-
if (node.staticChildren === null)
|
|
77
|
-
node.staticChildren = new Map();
|
|
78
|
-
else if (node.staticChildren.has(pathPart.charCodeAt(j))) {
|
|
79
|
-
node = node.staticChildren.get(pathPart.charCodeAt(j));
|
|
80
|
-
pathPart = pathPart.slice(j);
|
|
81
|
-
j = 0;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
const childNode = createNode(pathPart.slice(j));
|
|
85
|
-
node.staticChildren.set(pathPart.charCodeAt(j), childNode);
|
|
86
|
-
node = childNode;
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
if (pathPart[j] !== node.pathPart[j]) {
|
|
90
|
-
const existingChild = cloneNode(node, node.pathPart.slice(j));
|
|
91
|
-
const newChild = createNode(pathPart.slice(j));
|
|
92
|
-
Object.assign(node, createNode(node.pathPart.slice(0, j), [
|
|
93
|
-
existingChild,
|
|
94
|
-
newChild
|
|
95
|
-
]));
|
|
96
|
-
node = newChild;
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
++j;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (paramPartsIndex < paramParts.length) {
|
|
103
|
-
const param = paramParts[paramPartsIndex];
|
|
104
|
-
const paramName = param.slice(1);
|
|
105
|
-
if (node.parametricChild === null)
|
|
106
|
-
node.parametricChild = createParametricNode(paramName);
|
|
107
|
-
else if (node.parametricChild.paramName !== paramName)
|
|
108
|
-
throw new Error(`Cannot create route "${path}" with parameter "${paramName}" ` +
|
|
109
|
-
'because a route already exists with a different parameter name ' +
|
|
110
|
-
`("${node.parametricChild.paramName}") in the same location`);
|
|
111
|
-
if (node.parametricChild.store === null)
|
|
112
|
-
node.parametricChild.store = Object.create(null);
|
|
113
|
-
return node.parametricChild.store;
|
|
114
|
-
}
|
|
115
|
-
if (endsWithWildcard) {
|
|
116
|
-
if (node.wildcardStore === null)
|
|
117
|
-
node.wildcardStore = Object.create(null);
|
|
118
|
-
return node.wildcardStore;
|
|
119
|
-
}
|
|
120
|
-
if (node.store === null)
|
|
121
|
-
node.store = Object.create(null);
|
|
122
|
-
return node.store;
|
|
123
|
-
}
|
|
124
|
-
find(url, queryIndex) {
|
|
125
|
-
url = getPath(url, queryIndex);
|
|
126
|
-
return matchRoute(url, url.length, this._root, 0);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
function matchRoute(url, urlLength, node, startIndex) {
|
|
130
|
-
const pathPart = node.pathPart;
|
|
131
|
-
const pathPartEndIndex = startIndex + pathPart.length;
|
|
132
|
-
if (pathPart.length > 1) {
|
|
133
|
-
if (pathPartEndIndex > urlLength)
|
|
134
|
-
return null;
|
|
135
|
-
if (pathPart.length < 15)
|
|
136
|
-
for (let i = 1, j = startIndex + 1; i < pathPart.length; ++i, ++j) {
|
|
137
|
-
if (pathPart[i] !== url[j]) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else if (url.slice(startIndex, pathPartEndIndex) !== pathPart)
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
if (pathPartEndIndex === urlLength) {
|
|
145
|
-
if (node.store)
|
|
146
|
-
return {
|
|
147
|
-
store: node.store,
|
|
148
|
-
params: {}
|
|
149
|
-
};
|
|
150
|
-
if (node.wildcardStore)
|
|
151
|
-
return {
|
|
152
|
-
store: node.wildcardStore,
|
|
153
|
-
params: { '*': '' }
|
|
154
|
-
};
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
if (node.staticChildren) {
|
|
158
|
-
const staticChild = node.staticChildren.get(url.charCodeAt(pathPartEndIndex));
|
|
159
|
-
if (staticChild !== undefined) {
|
|
160
|
-
const route = matchRoute(url, urlLength, staticChild, pathPartEndIndex);
|
|
161
|
-
if (route)
|
|
162
|
-
return route;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (node.parametricChild) {
|
|
166
|
-
const slashIndex = url.indexOf('/', pathPartEndIndex);
|
|
167
|
-
if (slashIndex !== pathPartEndIndex) {
|
|
168
|
-
if (slashIndex === -1 || slashIndex >= urlLength) {
|
|
169
|
-
if (node.parametricChild.store) {
|
|
170
|
-
const params = {};
|
|
171
|
-
let paramData = url.slice(pathPartEndIndex, urlLength);
|
|
172
|
-
if (paramData.includes('%'))
|
|
173
|
-
paramData = decodeURI(paramData);
|
|
174
|
-
params[node.parametricChild.paramName] = paramData;
|
|
175
|
-
return {
|
|
176
|
-
store: node.parametricChild.store,
|
|
177
|
-
params
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
else if (node.parametricChild.staticChild) {
|
|
182
|
-
const route = matchRoute(url, urlLength, node.parametricChild.staticChild, slashIndex);
|
|
183
|
-
if (route) {
|
|
184
|
-
let paramData = url.slice(pathPartEndIndex, slashIndex);
|
|
185
|
-
if (paramData.includes('%'))
|
|
186
|
-
paramData = decodeURI(paramData);
|
|
187
|
-
route.params[node.parametricChild.paramName] = paramData;
|
|
188
|
-
return route;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (node.wildcardStore)
|
|
194
|
-
return {
|
|
195
|
-
store: node.wildcardStore,
|
|
196
|
-
params: {
|
|
197
|
-
'*': url.slice(pathPartEndIndex, urlLength)
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
return null;
|
|
201
|
-
}
|
package/dist/schema.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { Kind } from '@sinclair/typebox';
|
|
2
|
-
export const toOpenAPIPath = (path) => path
|
|
3
|
-
.split('/')
|
|
4
|
-
.map((x) => (x.startsWith(':') ? `{${x.slice(1, x.length)}}` : x))
|
|
5
|
-
.join('/');
|
|
6
|
-
export const mapProperties = (name, schema, models) => {
|
|
7
|
-
if (schema === undefined)
|
|
8
|
-
return [];
|
|
9
|
-
if (typeof schema === 'string')
|
|
10
|
-
if (schema in models)
|
|
11
|
-
schema = models[schema];
|
|
12
|
-
else
|
|
13
|
-
throw new Error(`Can't find model ${schema}`);
|
|
14
|
-
return Object.entries(schema?.properties ?? []).map(([key, value]) => ({
|
|
15
|
-
...value,
|
|
16
|
-
in: name,
|
|
17
|
-
name: key,
|
|
18
|
-
type: value?.type,
|
|
19
|
-
required: schema.required?.includes(key) ?? false
|
|
20
|
-
}));
|
|
21
|
-
};
|
|
22
|
-
export const registerSchemaPath = ({ schema, path, method, hook, models }) => {
|
|
23
|
-
path = toOpenAPIPath(path);
|
|
24
|
-
const bodySchema = hook?.schema?.body;
|
|
25
|
-
const paramsSchema = hook?.schema?.params;
|
|
26
|
-
const headerSchema = hook?.schema?.headers;
|
|
27
|
-
const querySchema = hook?.schema?.query;
|
|
28
|
-
let responseSchema = hook?.schema?.response;
|
|
29
|
-
if (typeof responseSchema === 'object') {
|
|
30
|
-
if (Kind in responseSchema) {
|
|
31
|
-
const { type, properties, required, ...rest } = responseSchema;
|
|
32
|
-
responseSchema = {
|
|
33
|
-
'200': {
|
|
34
|
-
...rest,
|
|
35
|
-
schema: {
|
|
36
|
-
type,
|
|
37
|
-
properties,
|
|
38
|
-
required
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
Object.entries(responseSchema).forEach(([key, value]) => {
|
|
45
|
-
if (typeof value === 'string') {
|
|
46
|
-
const { type, properties, required, ...rest } = models[value];
|
|
47
|
-
responseSchema[key] = {
|
|
48
|
-
...rest,
|
|
49
|
-
schema: {
|
|
50
|
-
$ref: `#/definitions/${value}`
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
const { type, properties, required, ...rest } = value;
|
|
56
|
-
responseSchema[key] = {
|
|
57
|
-
...rest,
|
|
58
|
-
schema: {
|
|
59
|
-
type,
|
|
60
|
-
properties,
|
|
61
|
-
required
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
else if (typeof responseSchema === 'string') {
|
|
69
|
-
const { type, properties, required, ...rest } = models[responseSchema];
|
|
70
|
-
responseSchema = {
|
|
71
|
-
'200': {
|
|
72
|
-
...rest,
|
|
73
|
-
schema: {
|
|
74
|
-
$ref: `#/definitions/${responseSchema}`
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
const parameters = [
|
|
80
|
-
...mapProperties('header', headerSchema, models),
|
|
81
|
-
...mapProperties('path', paramsSchema, models),
|
|
82
|
-
...mapProperties('query', querySchema, models)
|
|
83
|
-
];
|
|
84
|
-
if (bodySchema)
|
|
85
|
-
parameters.push({
|
|
86
|
-
in: 'body',
|
|
87
|
-
name: 'body',
|
|
88
|
-
required: true,
|
|
89
|
-
schema: typeof bodySchema === 'string'
|
|
90
|
-
? {
|
|
91
|
-
$ref: `#/definitions/${bodySchema}`
|
|
92
|
-
}
|
|
93
|
-
: bodySchema
|
|
94
|
-
});
|
|
95
|
-
schema[path] = {
|
|
96
|
-
...(schema[path] ? schema[path] : {}),
|
|
97
|
-
[method.toLowerCase()]: {
|
|
98
|
-
...(headerSchema || paramsSchema || querySchema || bodySchema
|
|
99
|
-
? { parameters }
|
|
100
|
-
: {}),
|
|
101
|
-
...(responseSchema
|
|
102
|
-
? {
|
|
103
|
-
responses: responseSchema
|
|
104
|
-
}
|
|
105
|
-
: {}),
|
|
106
|
-
...hook?.schema?.detail
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
};
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/utils.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { Kind, Type } from '@sinclair/typebox';
|
|
2
|
-
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
3
|
-
export const SCHEMA = Symbol('schema');
|
|
4
|
-
export const DEFS = Symbol('definitions');
|
|
5
|
-
export const mergeObjectArray = (a, b) => [
|
|
6
|
-
...(Array.isArray(a) ? a : [a]),
|
|
7
|
-
...(Array.isArray(b) ? b : [b])
|
|
8
|
-
];
|
|
9
|
-
export const mergeHook = (a, b) => {
|
|
10
|
-
const aSchema = 'schema' in a ? a.schema : null;
|
|
11
|
-
const bSchema = b && 'schema' in b ? b.schema : null;
|
|
12
|
-
return {
|
|
13
|
-
schema: aSchema || bSchema
|
|
14
|
-
? {
|
|
15
|
-
body: bSchema?.body ?? aSchema?.body,
|
|
16
|
-
header: bSchema?.headers ?? aSchema?.headers,
|
|
17
|
-
params: bSchema?.params ?? aSchema?.params,
|
|
18
|
-
query: bSchema?.query ?? aSchema?.query,
|
|
19
|
-
response: bSchema?.response ?? aSchema?.response
|
|
20
|
-
}
|
|
21
|
-
: undefined,
|
|
22
|
-
transform: mergeObjectArray(a.transform ?? [], b?.transform ?? []),
|
|
23
|
-
beforeHandle: mergeObjectArray(a.beforeHandle ?? [], b?.beforeHandle ?? []),
|
|
24
|
-
afterHandle: mergeObjectArray(a.afterHandle ?? [], b?.afterHandle ?? []),
|
|
25
|
-
error: mergeObjectArray(a.error ?? [], b?.error ?? [])
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
export const clone = (value) => [value][0];
|
|
29
|
-
export const getPath = (url, queryIndex = url.indexOf('?')) => {
|
|
30
|
-
if (queryIndex === -1) {
|
|
31
|
-
const fragmentIndex = url.indexOf('#');
|
|
32
|
-
if (fragmentIndex !== -1)
|
|
33
|
-
queryIndex = fragmentIndex;
|
|
34
|
-
else
|
|
35
|
-
queryIndex = url.length;
|
|
36
|
-
}
|
|
37
|
-
return url.substring(url.indexOf('/', 9), queryIndex);
|
|
38
|
-
};
|
|
39
|
-
export const mapQuery = (url, queryIndex = url.indexOf('?')) => {
|
|
40
|
-
if (queryIndex === -1)
|
|
41
|
-
return {};
|
|
42
|
-
const query = {};
|
|
43
|
-
if (queryIndex)
|
|
44
|
-
url = url.slice(queryIndex);
|
|
45
|
-
else
|
|
46
|
-
url = ';' + url;
|
|
47
|
-
while (true) {
|
|
48
|
-
const sep = url.indexOf('&', 4);
|
|
49
|
-
if (sep === -1) {
|
|
50
|
-
const equal = url.indexOf('=');
|
|
51
|
-
let value = url.slice(equal + 1);
|
|
52
|
-
const hashIndex = value.indexOf('#');
|
|
53
|
-
if (hashIndex !== -1)
|
|
54
|
-
value = value.slice(0, hashIndex);
|
|
55
|
-
if (value.includes('%'))
|
|
56
|
-
value = decodeURI(value);
|
|
57
|
-
query[url.slice(1, equal)] = value;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
const path = url.slice(0, sep);
|
|
61
|
-
const equal = path.indexOf('=');
|
|
62
|
-
let value = path.slice(equal + 1);
|
|
63
|
-
if (value.includes('%'))
|
|
64
|
-
value = decodeURI(value);
|
|
65
|
-
query[path.slice(1, equal)] = value;
|
|
66
|
-
url = url.slice(sep);
|
|
67
|
-
}
|
|
68
|
-
return query;
|
|
69
|
-
};
|
|
70
|
-
const isObject = (item) => item && typeof item === 'object' && !Array.isArray(item);
|
|
71
|
-
export const mergeDeep = (target, source) => {
|
|
72
|
-
const output = Object.assign({}, target);
|
|
73
|
-
if (isObject(target) && isObject(source)) {
|
|
74
|
-
Object.keys(source).forEach((key) => {
|
|
75
|
-
if (isObject(source[key])) {
|
|
76
|
-
if (!(key in target))
|
|
77
|
-
Object.assign(output, { [key]: source[key] });
|
|
78
|
-
else
|
|
79
|
-
output[key] = mergeDeep(target[key], source[key]);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
Object.assign(output, { [key]: source[key] });
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
return output;
|
|
87
|
-
};
|
|
88
|
-
export const createValidationError = (type, validator, value) => {
|
|
89
|
-
const error = validator.Errors(value).next().value;
|
|
90
|
-
return new Error('VALIDATION', {
|
|
91
|
-
cause: `Invalid ${type}: '${error?.path?.slice(1) || 'root'}'. ${error.message}`
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
export const getSchemaValidator = (s, models, additionalProperties = false) => {
|
|
95
|
-
if (!s)
|
|
96
|
-
return;
|
|
97
|
-
if (typeof s === 'string' && !(s in models))
|
|
98
|
-
return;
|
|
99
|
-
const schema = typeof s === 'string' ? models[s] : s;
|
|
100
|
-
if (schema.type === 'object' && 'additionalProperties' in schema === false)
|
|
101
|
-
schema.additionalProperties = additionalProperties;
|
|
102
|
-
return TypeCompiler.Compile(schema);
|
|
103
|
-
};
|
|
104
|
-
export const getResponseSchemaValidator = (s, models, additionalProperties = false) => {
|
|
105
|
-
if (!s)
|
|
106
|
-
return;
|
|
107
|
-
if (typeof s === 'string' && !(s in models))
|
|
108
|
-
return;
|
|
109
|
-
const maybeSchemaOrRecord = typeof s === 'string' ? models[s] : s;
|
|
110
|
-
const schema = Kind in maybeSchemaOrRecord
|
|
111
|
-
? maybeSchemaOrRecord
|
|
112
|
-
: Type.Union(Object.keys(maybeSchemaOrRecord)
|
|
113
|
-
.map((key) => {
|
|
114
|
-
const maybeNameOrSchema = maybeSchemaOrRecord[key];
|
|
115
|
-
if (typeof maybeNameOrSchema === 'string') {
|
|
116
|
-
if (maybeNameOrSchema in models) {
|
|
117
|
-
const schema = models[maybeNameOrSchema];
|
|
118
|
-
return schema;
|
|
119
|
-
}
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
return maybeNameOrSchema;
|
|
123
|
-
})
|
|
124
|
-
.filter((a) => a));
|
|
125
|
-
if (schema.type === 'object' && 'additionalProperties' in schema === false)
|
|
126
|
-
schema.additionalProperties = additionalProperties;
|
|
127
|
-
return TypeCompiler.Compile(schema);
|
|
128
|
-
};
|