@elysiumjs/core 0.4.3 → 0.5.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 +26 -17
- package/dist/app.d.ts +180 -0
- package/dist/cache.d.ts +114 -0
- package/dist/command.d.ts +273 -0
- package/dist/console.d.ts +167 -0
- package/dist/database.d.ts +113 -0
- package/dist/env.d.ts +30 -0
- package/dist/event.d.ts +94 -0
- package/dist/http.d.ts +242 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +24 -0
- package/dist/job.d.ts +106 -0
- package/dist/macros.d.ts +2 -0
- package/dist/middleware.d.ts +70 -0
- package/dist/model.d.ts +4803 -0
- package/dist/module.d.ts +45 -0
- package/dist/redis.d.ts +134 -0
- package/dist/repository.d.ts +164 -0
- package/dist/service.d.ts +132 -0
- package/dist/utils.d.ts +26 -0
- package/dist/wamp.d.ts +273 -0
- package/dist/websocket.d.ts +92 -0
- package/dist/worker.d.ts +220 -0
- package/package.json +15 -8
- package/tsconfig.json +34 -33
- package/index.ts +0 -54
- package/macros.ts +0 -16
- package/src/app.ts +0 -647
- package/src/cache.ts +0 -218
- package/src/command.ts +0 -908
- package/src/console.ts +0 -493
- package/src/database.ts +0 -257
- package/src/env.ts +0 -62
- package/src/event.ts +0 -227
- package/src/http.ts +0 -736
- package/src/job.ts +0 -196
- package/src/middleware.ts +0 -164
- package/src/model.ts +0 -386
- package/src/module.ts +0 -108
- package/src/redis.ts +0 -408
- package/src/repository.ts +0 -295
- package/src/service.ts +0 -351
- package/src/utils.ts +0 -95
- package/src/wamp.ts +0 -569
- package/src/websocket.ts +0 -191
- package/src/worker.ts +0 -849
- package/types.d.ts +0 -35
package/src/http.ts
DELETED
|
@@ -1,736 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import type { AppHttpContext } from '@elysiumjs/core';
|
|
16
|
-
import type { Context as ElysiaContext, Handler, HTTPMethod, PreContext, TSchema } from 'elysia';
|
|
17
|
-
import type { Class, MergeDeep } from 'type-fest';
|
|
18
|
-
import type { Middleware } from './middleware';
|
|
19
|
-
import type { Module } from './module';
|
|
20
|
-
|
|
21
|
-
import { Elysia, t } from 'elysia';
|
|
22
|
-
import { assign, isEmpty, objectify } from 'radash';
|
|
23
|
-
|
|
24
|
-
import { Application } from './app';
|
|
25
|
-
import { Database } from './database';
|
|
26
|
-
import { applyMiddlewares, executeMiddlewareChain } from './middleware';
|
|
27
|
-
import { Service } from './service';
|
|
28
|
-
import { nextTick, Symbols } from './utils';
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A route is a string that starts with a forward slash.
|
|
32
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
33
|
-
*/
|
|
34
|
-
export type Route = `/${string}`;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* A class for validating data against a schema.
|
|
38
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
39
|
-
*/
|
|
40
|
-
export type ValidatorClass<T extends TSchema = TSchema> = {
|
|
41
|
-
/**
|
|
42
|
-
* The validation schema. This schema is automatically checked against the input data during
|
|
43
|
-
* the validation stage of the HTTP request.
|
|
44
|
-
*/
|
|
45
|
-
readonly schema: T;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Whether the request should be authorized before validation. If the request is not authorized,
|
|
49
|
-
* the validation will be skipped.
|
|
50
|
-
*/
|
|
51
|
-
authorize(ctx: Context<T['static']>): Promise<boolean>;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Processes custom validation logic. This method is called after the validation schema is checked
|
|
55
|
-
* against the input data. So it's safe to assume that the schema is valid.
|
|
56
|
-
* @param data The input data to validate.
|
|
57
|
-
* @returns Whether the input data is valid.
|
|
58
|
-
*/
|
|
59
|
-
validate(ctx: Context<T['static']>): Promise<boolean>;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* A function that handles an HTTP request.
|
|
64
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
65
|
-
*/
|
|
66
|
-
type HttpRequestHandler = (...args: unknown[]) => unknown;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Stores metadata for an HTTP request handler.
|
|
70
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
71
|
-
*/
|
|
72
|
-
type HttpRequestHandlerMetadata = {
|
|
73
|
-
/**
|
|
74
|
-
* The path of the HTTP route.
|
|
75
|
-
*/
|
|
76
|
-
path: Route;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* The HTTP method of the handler.
|
|
80
|
-
*/
|
|
81
|
-
method: HTTPMethod;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* The request handler function.
|
|
85
|
-
*/
|
|
86
|
-
handler: HttpRequestHandler;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* The response schema.
|
|
90
|
-
*/
|
|
91
|
-
response?: TSchema | Record<number, TSchema>;
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* The request body schema.
|
|
95
|
-
*/
|
|
96
|
-
body?: { schema?: TSchema; validator?: ValidatorClass; index: number };
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* The request query schema.
|
|
100
|
-
*/
|
|
101
|
-
query?: { schema?: TSchema; index: number };
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* The request parameters.
|
|
105
|
-
*/
|
|
106
|
-
params: Array<{ slug: string; schema: TSchema; index: number }>;
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* The raw context for the handler.
|
|
110
|
-
*/
|
|
111
|
-
rawContext?: { index: number };
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Custom decorators for the handler.
|
|
115
|
-
*/
|
|
116
|
-
customDecorators: Array<{ handler: Handler; index: number }>;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* The middlewares for the handler.
|
|
120
|
-
*/
|
|
121
|
-
middlewares: Array<Class<Middleware>>;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* The OpenAPI's operationId for the handler.
|
|
125
|
-
*/
|
|
126
|
-
operationId?: string;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* The OpenAPI's description for the handler.
|
|
130
|
-
*/
|
|
131
|
-
description?: string;
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* The list of services injected in the handler.
|
|
135
|
-
*/
|
|
136
|
-
services: Array<{ name: string; index: number }>;
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Whether the request handler is transactional.
|
|
140
|
-
*
|
|
141
|
-
* If set to `true`, a new transaction will be created and all the database
|
|
142
|
-
* queries running for that handler will be wrapped in that transaction.
|
|
143
|
-
*/
|
|
144
|
-
transactional?: boolean;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Parameters for registering an HTTP request handler.
|
|
149
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
150
|
-
*/
|
|
151
|
-
type HttpRequestHandlerRegistrationProps = Pick<
|
|
152
|
-
HttpRequestHandlerMetadata,
|
|
153
|
-
'path' | 'method' | 'handler' | 'response' | 'operationId' | 'description' | 'transactional'
|
|
154
|
-
> & {
|
|
155
|
-
target: Object;
|
|
156
|
-
propertyKey: string | symbol;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Metadata for the HTTP context.
|
|
161
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
162
|
-
*/
|
|
163
|
-
export type Singleton<TController = unknown, TModule extends Module = Module> = MergeDeep<
|
|
164
|
-
AppHttpContext,
|
|
165
|
-
{
|
|
166
|
-
decorator: {
|
|
167
|
-
[key: string]: unknown;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* The controller instance.
|
|
171
|
-
*/
|
|
172
|
-
controller: () => TController;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* The module instance.
|
|
176
|
-
*/
|
|
177
|
-
module: TModule;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
resolve: {
|
|
181
|
-
/**
|
|
182
|
-
* The tenant ID.
|
|
183
|
-
*/
|
|
184
|
-
readonly tenant: string;
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
>;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* The Elysia context with the controller injected.
|
|
191
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
192
|
-
*/
|
|
193
|
-
export type Context<
|
|
194
|
-
TBody = unknown,
|
|
195
|
-
TController = unknown,
|
|
196
|
-
TModule extends Module = Module
|
|
197
|
-
> = ElysiaContext<
|
|
198
|
-
{
|
|
199
|
-
body: TBody;
|
|
200
|
-
},
|
|
201
|
-
Singleton<TController, TModule>
|
|
202
|
-
>;
|
|
203
|
-
|
|
204
|
-
export type ElysiaApp = Elysia<Route, Singleton>;
|
|
205
|
-
|
|
206
|
-
const registerHttpRequestHandler = (props: HttpRequestHandlerRegistrationProps) => {
|
|
207
|
-
const body = Reflect.getMetadata('http:body', props.target, props.propertyKey);
|
|
208
|
-
const params = Reflect.getMetadata('http:params', props.target, props.propertyKey) ?? [];
|
|
209
|
-
const query = Reflect.getMetadata('http:query', props.target, props.propertyKey);
|
|
210
|
-
const rawContext = Reflect.getMetadata('http:rawContext', props.target, props.propertyKey);
|
|
211
|
-
const customDecorators =
|
|
212
|
-
Reflect.getMetadata('http:customDecorators', props.target, props.propertyKey) ?? [];
|
|
213
|
-
const middlewares =
|
|
214
|
-
Reflect.getMetadata(Symbols.middlewares, props.target, props.propertyKey) ?? [];
|
|
215
|
-
const services = Reflect.getMetadata(Symbols.services, props.target, props.propertyKey) ?? [];
|
|
216
|
-
|
|
217
|
-
const { path, method, handler, target, response, operationId, description, transactional } =
|
|
218
|
-
props;
|
|
219
|
-
|
|
220
|
-
const metadata: HttpRequestHandlerMetadata[] =
|
|
221
|
-
Reflect.getMetadata(Symbols.http, target.constructor) ?? [];
|
|
222
|
-
|
|
223
|
-
metadata.push({
|
|
224
|
-
path,
|
|
225
|
-
method,
|
|
226
|
-
body,
|
|
227
|
-
params,
|
|
228
|
-
query,
|
|
229
|
-
customDecorators,
|
|
230
|
-
rawContext,
|
|
231
|
-
handler,
|
|
232
|
-
middlewares,
|
|
233
|
-
response,
|
|
234
|
-
operationId,
|
|
235
|
-
description,
|
|
236
|
-
services,
|
|
237
|
-
transactional
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
Reflect.defineMetadata(Symbols.http, metadata, target.constructor);
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* The scope of an HTTP controller.
|
|
245
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
246
|
-
*/
|
|
247
|
-
export enum HttpControllerScope {
|
|
248
|
-
/**
|
|
249
|
-
* The controller is instantiated once in the server and used for every request.
|
|
250
|
-
*/
|
|
251
|
-
SERVER,
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* A new instance of the controller is created for each request.
|
|
255
|
-
*/
|
|
256
|
-
REQUEST
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Properties required when declaring an HTTP controller using the `@http()` decorator.
|
|
261
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
262
|
-
*/
|
|
263
|
-
export type HttpControllerProps = {
|
|
264
|
-
/**
|
|
265
|
-
* The path of the HTTP route.
|
|
266
|
-
*/
|
|
267
|
-
path: Route;
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* The scope of the HTTP controller.
|
|
271
|
-
* @default HttpControllerScope.SERVER
|
|
272
|
-
*/
|
|
273
|
-
scope?: HttpControllerScope;
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* The list of tags for the controller.
|
|
277
|
-
* Used in Swagger documentation.
|
|
278
|
-
*/
|
|
279
|
-
tags?: Array<string>;
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Whether to create a database transaction for all the queries executed
|
|
283
|
-
* for all the request handlers in this controller.
|
|
284
|
-
*/
|
|
285
|
-
transactional?: boolean;
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Properties required when declaring an HTTP request handler.
|
|
290
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
291
|
-
*/
|
|
292
|
-
export type RequestHandlerDecoratorProps = {
|
|
293
|
-
/**
|
|
294
|
-
* The HTTP method of the handler.
|
|
295
|
-
*/
|
|
296
|
-
method?: HTTPMethod;
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* The path of the HTTP route.
|
|
300
|
-
*/
|
|
301
|
-
path?: Route;
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* The schema of the response body.
|
|
305
|
-
*/
|
|
306
|
-
response?: TSchema | Record<number, TSchema>;
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* The operation ID for the handler.
|
|
310
|
-
* Used in Swagger documentation.
|
|
311
|
-
*/
|
|
312
|
-
operationId?: string;
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* The description for the handler.
|
|
316
|
-
* Used in Swagger documentation.
|
|
317
|
-
*/
|
|
318
|
-
description?: string;
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Whether to create a database transaction for all the queries executed
|
|
322
|
-
* for this request handler.
|
|
323
|
-
*/
|
|
324
|
-
transactional?: boolean;
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
export namespace Http {
|
|
328
|
-
/**
|
|
329
|
-
* Marks a class as an HTTP controller.
|
|
330
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
331
|
-
* @param props The decorator options.
|
|
332
|
-
*/
|
|
333
|
-
export const controller = (props: HttpControllerProps = { path: '/' }) => {
|
|
334
|
-
return function (target: Class<any>) {
|
|
335
|
-
async function handleHttp(): Promise<ElysiaApp> {
|
|
336
|
-
// TODO: Use the logger service here
|
|
337
|
-
console.log(`Registering HTTP controller for ${props.path} using ${target.name}`);
|
|
338
|
-
await nextTick();
|
|
339
|
-
|
|
340
|
-
props = assign({ path: '/', scope: HttpControllerScope.SERVER, tags: [] }, props);
|
|
341
|
-
|
|
342
|
-
const app: ElysiaApp = new Elysia({
|
|
343
|
-
prefix: props.path,
|
|
344
|
-
name: target.name
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
if (props.scope === HttpControllerScope.SERVER) {
|
|
348
|
-
const controller = Service.make(target);
|
|
349
|
-
app.resolve({ as: 'local' }, () => ({ controller: () => controller }));
|
|
350
|
-
} else if (props.scope === HttpControllerScope.REQUEST) {
|
|
351
|
-
app.resolve({ as: 'local' }, () => ({ controller: () => Service.make(target) }));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const onRequest = Reflect.getMetadata('http:onRequest', target) ?? {};
|
|
355
|
-
if (onRequest.handler) {
|
|
356
|
-
app.onRequest((c: PreContext<Singleton>) => {
|
|
357
|
-
const controller = c.controller();
|
|
358
|
-
return onRequest.handler.call(controller, c);
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const middlewares = Reflect.getMetadata(Symbols.middlewares, target) ?? [];
|
|
363
|
-
applyMiddlewares(middlewares, app);
|
|
364
|
-
|
|
365
|
-
const metadata: HttpRequestHandlerMetadata[] =
|
|
366
|
-
Reflect.getMetadata(Symbols.http, target) ?? [];
|
|
367
|
-
|
|
368
|
-
for (const route of metadata) {
|
|
369
|
-
const getParameters = async (c: Context) => {
|
|
370
|
-
const parameters: any[] = [];
|
|
371
|
-
|
|
372
|
-
if (route.rawContext) {
|
|
373
|
-
parameters[route.rawContext.index] = c;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (route.body) {
|
|
377
|
-
parameters[route.body.index] = c.body;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if (route.query) {
|
|
381
|
-
parameters[route.query.index] = c.query;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (!isEmpty(route.params)) {
|
|
385
|
-
for (const param of route.params) {
|
|
386
|
-
parameters[param.index] = c.params[param.slug];
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (!isEmpty(route.customDecorators)) {
|
|
391
|
-
for (const customDecorator of route.customDecorators) {
|
|
392
|
-
parameters[customDecorator.index] = await customDecorator.handler(c);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (!isEmpty(route.services)) {
|
|
397
|
-
for (const service of route.services) {
|
|
398
|
-
parameters[service.index] = Service.get(service.name);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
return parameters;
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
const isGenerator = route.handler.constructor.name.includes('GeneratorFunction');
|
|
406
|
-
const isSSE = route.method === 'elysium:SSE';
|
|
407
|
-
const isTransactional = route.transactional ?? props.transactional ?? false;
|
|
408
|
-
const isValidator =
|
|
409
|
-
route.body && route.body.schema === undefined && route.body.validator !== undefined;
|
|
410
|
-
|
|
411
|
-
route.method = isSSE ? 'GET' : route.method;
|
|
412
|
-
|
|
413
|
-
const getHandler = () => {
|
|
414
|
-
const initTransactedHandler = (c: Context) => {
|
|
415
|
-
if (isTransactional) {
|
|
416
|
-
return function (...args: unknown[]) {
|
|
417
|
-
return Database.getDefaultConnection().transaction((tx) => {
|
|
418
|
-
return Application.context.run(
|
|
419
|
-
new Map([
|
|
420
|
-
['tenant', c.tenant as unknown],
|
|
421
|
-
['http:context', c],
|
|
422
|
-
['db:tx', tx]
|
|
423
|
-
]),
|
|
424
|
-
() => {
|
|
425
|
-
try {
|
|
426
|
-
return route.handler.call(c.controller(), ...args) as Promise<unknown>;
|
|
427
|
-
} catch (e) {
|
|
428
|
-
tx.rollback();
|
|
429
|
-
throw e;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
);
|
|
433
|
-
});
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return function (...args: unknown[]) {
|
|
438
|
-
return Application.context.run(
|
|
439
|
-
new Map([
|
|
440
|
-
['tenant', c.tenant as unknown],
|
|
441
|
-
['http:context', c]
|
|
442
|
-
]),
|
|
443
|
-
() => route.handler.call(c.controller(), ...args) as Promise<unknown>
|
|
444
|
-
);
|
|
445
|
-
};
|
|
446
|
-
};
|
|
447
|
-
|
|
448
|
-
if (isGenerator) {
|
|
449
|
-
return async function* (c: Context) {
|
|
450
|
-
const handler = initTransactedHandler(c);
|
|
451
|
-
|
|
452
|
-
try {
|
|
453
|
-
for await (const eachValue of handler(...(await getParameters(c))) as any)
|
|
454
|
-
yield eachValue;
|
|
455
|
-
} catch (error: any) {
|
|
456
|
-
yield error;
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (isSSE) {
|
|
462
|
-
return async function* (c: Context) {
|
|
463
|
-
const handler = initTransactedHandler(c);
|
|
464
|
-
|
|
465
|
-
c.set.headers['Content-Type'] = 'text/event-stream';
|
|
466
|
-
c.set.headers['Cache-Control'] = 'no-cache';
|
|
467
|
-
c.set.headers['Connection'] = 'keep-alive';
|
|
468
|
-
|
|
469
|
-
while (true) {
|
|
470
|
-
yield `data: ${await handler(...(await getParameters(c)))}\n\n`;
|
|
471
|
-
await Bun.sleep(1);
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
if (isValidator) {
|
|
477
|
-
return async function (c: Context) {
|
|
478
|
-
if (await route.body!.validator!.validate(c)) {
|
|
479
|
-
const handler = initTransactedHandler(c);
|
|
480
|
-
return await handler(...(await getParameters(c)));
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
throw c.status(400, 'Invalid request body');
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return async function (c: Context) {
|
|
488
|
-
const handler = initTransactedHandler(c);
|
|
489
|
-
return await handler(...(await getParameters(c)));
|
|
490
|
-
};
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
const params = objectify(
|
|
494
|
-
route.params ?? [],
|
|
495
|
-
(p) => p.slug,
|
|
496
|
-
(p) => p.schema
|
|
497
|
-
);
|
|
498
|
-
|
|
499
|
-
const mi = route.middlewares.map((middleware) => Service.make<Middleware>(middleware));
|
|
500
|
-
|
|
501
|
-
app.route(route.method, route.path, getHandler(), {
|
|
502
|
-
// @ts-ignore
|
|
503
|
-
config: {},
|
|
504
|
-
async transform(c) {
|
|
505
|
-
if (isValidator && !(await route.body!.validator!.authorize(c as Context))) {
|
|
506
|
-
throw c.status(401, 'Unauthorized');
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
return executeMiddlewareChain(mi, c, 'onTransform');
|
|
510
|
-
},
|
|
511
|
-
beforeHandle(c) {
|
|
512
|
-
return executeMiddlewareChain(mi, c, 'onBeforeHandle');
|
|
513
|
-
},
|
|
514
|
-
afterHandle(c) {
|
|
515
|
-
return executeMiddlewareChain(mi, c, 'onAfterHandle');
|
|
516
|
-
},
|
|
517
|
-
afterResponse(c) {
|
|
518
|
-
return executeMiddlewareChain(mi, c, 'onAfterResponse');
|
|
519
|
-
},
|
|
520
|
-
detail: {
|
|
521
|
-
tags: props.tags,
|
|
522
|
-
description: route.description,
|
|
523
|
-
operationId: route.operationId
|
|
524
|
-
},
|
|
525
|
-
body: isValidator ? route.body?.validator?.schema : route.body?.schema,
|
|
526
|
-
response: route.response,
|
|
527
|
-
params: isEmpty(params) ? undefined : t.Object(params)
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
return app;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
Reflect.defineMetadata(Symbols.elysiaPlugin, handleHttp, target);
|
|
535
|
-
};
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
/**
|
|
539
|
-
* Marks a method as an HTTP "server-sent events" request handler.
|
|
540
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
541
|
-
* @param props The request handler properties.
|
|
542
|
-
*/
|
|
543
|
-
export const sse = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
544
|
-
const { path = '/', ...rest } = props;
|
|
545
|
-
return custom({ method: 'elysium:SSE', path, ...rest });
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
/**
|
|
549
|
-
* Marks a method as an HTTP "get" request handler.
|
|
550
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
551
|
-
* @param props The request handler properties.
|
|
552
|
-
*/
|
|
553
|
-
export const get = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
554
|
-
const { path = '/', ...rest } = props;
|
|
555
|
-
return custom({ method: 'GET', path, ...rest });
|
|
556
|
-
};
|
|
557
|
-
|
|
558
|
-
/**
|
|
559
|
-
* Marks a method as an HTTP "post" request handler.
|
|
560
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
561
|
-
* @param props The request handler properties.
|
|
562
|
-
*/
|
|
563
|
-
export const post = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
564
|
-
const { path = '/', ...rest } = props;
|
|
565
|
-
return custom({ method: 'POST', path, ...rest });
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Marks a method as an HTTP "put" request handler.
|
|
570
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
571
|
-
* @param props The request handler properties.
|
|
572
|
-
*/
|
|
573
|
-
export const put = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
574
|
-
const { path = '/', ...rest } = props;
|
|
575
|
-
return custom({ method: 'PUT', path, ...rest });
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
/**
|
|
579
|
-
* Marks a method as an HTTP "delete" request handler.
|
|
580
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
581
|
-
* @param props The request handler properties.
|
|
582
|
-
*/
|
|
583
|
-
export const del = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
584
|
-
const { path = '/', ...rest } = props;
|
|
585
|
-
return custom({ method: 'DELETE', path, ...rest });
|
|
586
|
-
};
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* Marks a method as an HTTP "patch" request handler.
|
|
590
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
591
|
-
* @param props The request handler properties.
|
|
592
|
-
*/
|
|
593
|
-
export const patch = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
594
|
-
const { path = '/', ...rest } = props;
|
|
595
|
-
return custom({ method: 'PATCH', path, ...rest });
|
|
596
|
-
};
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Marks a method as an HTTP "head" request handler.
|
|
600
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
601
|
-
* @param props The request handler properties.
|
|
602
|
-
*/
|
|
603
|
-
export const head = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
604
|
-
const { path = '/', ...rest } = props ?? {};
|
|
605
|
-
return custom({ method: 'HEAD', path, ...rest });
|
|
606
|
-
};
|
|
607
|
-
|
|
608
|
-
/**
|
|
609
|
-
* Marks a method as an HTTP "options" request handler.
|
|
610
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
611
|
-
* @param props The request handler properties.
|
|
612
|
-
*/
|
|
613
|
-
export const options = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
614
|
-
const { path = '/', ...rest } = props;
|
|
615
|
-
return custom({ method: 'OPTIONS', path, ...rest });
|
|
616
|
-
};
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* Marks a method as an HTTP "trace" request handler.
|
|
620
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
621
|
-
* @param props The request handler properties.
|
|
622
|
-
*/
|
|
623
|
-
export const trace = (props: RequestHandlerDecoratorProps = {}): MethodDecorator => {
|
|
624
|
-
const { path = '/', ...rest } = props;
|
|
625
|
-
return custom({ method: 'TRACE', path, ...rest });
|
|
626
|
-
};
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Marks a method as an HTTP request handler with a custom method.
|
|
630
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
631
|
-
* @param props The request handler properties.
|
|
632
|
-
*/
|
|
633
|
-
export const custom = ({
|
|
634
|
-
path = '/',
|
|
635
|
-
...rest
|
|
636
|
-
}: RequestHandlerDecoratorProps & { method: HTTPMethod }): MethodDecorator => {
|
|
637
|
-
return function (target, propertyKey, descriptor) {
|
|
638
|
-
process.nextTick(() => {
|
|
639
|
-
registerHttpRequestHandler({
|
|
640
|
-
path,
|
|
641
|
-
handler: descriptor.value as HttpRequestHandler,
|
|
642
|
-
target,
|
|
643
|
-
propertyKey,
|
|
644
|
-
...rest
|
|
645
|
-
});
|
|
646
|
-
});
|
|
647
|
-
};
|
|
648
|
-
};
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* Marks a method as the callback for the request handler.
|
|
652
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
653
|
-
*/
|
|
654
|
-
export const onRequest = (): MethodDecorator => {
|
|
655
|
-
return function (target, propertyKey, descriptor) {
|
|
656
|
-
const metadata = Reflect.getMetadata('http:onRequest', target.constructor) ?? {};
|
|
657
|
-
metadata.handler = descriptor.value;
|
|
658
|
-
Reflect.defineMetadata('http:onRequest', metadata, target.constructor);
|
|
659
|
-
};
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
/**
|
|
663
|
-
* Resolves the context for the current request in the annotated parameter.
|
|
664
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
665
|
-
*/
|
|
666
|
-
export const context = (): ParameterDecorator => {
|
|
667
|
-
return function (target, propertyKey, parameterIndex) {
|
|
668
|
-
Reflect.defineMetadata('http:rawContext', { index: parameterIndex }, target, propertyKey!);
|
|
669
|
-
};
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* Resolves the value of a URL parameter in the annotated parameter.
|
|
674
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
675
|
-
* @param slug The slug of the parameter.
|
|
676
|
-
* @param schema The schema of the parameter.
|
|
677
|
-
*/
|
|
678
|
-
export const param = (slug: string, schema?: TSchema): ParameterDecorator => {
|
|
679
|
-
return function (target, propertyKey, parameterIndex) {
|
|
680
|
-
const params = Reflect.getMetadata('http:params', target, propertyKey!) ?? [];
|
|
681
|
-
params.push({ slug, schema: schema ?? t.String(), index: parameterIndex });
|
|
682
|
-
Reflect.defineMetadata('http:params', params, target, propertyKey!);
|
|
683
|
-
};
|
|
684
|
-
};
|
|
685
|
-
|
|
686
|
-
/**
|
|
687
|
-
* Resolves the value of a query parameter in the annotated parameter.
|
|
688
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
689
|
-
* @param schema The schema of the query parameter.
|
|
690
|
-
*/
|
|
691
|
-
export const query = (schema?: TSchema): ParameterDecorator => {
|
|
692
|
-
return function (target, propertyKey, parameterIndex) {
|
|
693
|
-
Reflect.defineMetadata('http:query', { schema, index: parameterIndex }, target, propertyKey!);
|
|
694
|
-
};
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
/**
|
|
698
|
-
* Resolves the value of the request body in the annotated parameter.
|
|
699
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
700
|
-
* @param schema The schema of the request body.
|
|
701
|
-
*/
|
|
702
|
-
export const body = (schema?: TSchema | ValidatorClass): ParameterDecorator => {
|
|
703
|
-
return function (target, propertyKey, parameterIndex) {
|
|
704
|
-
if (typeof schema === 'function') {
|
|
705
|
-
Reflect.defineMetadata(
|
|
706
|
-
'http:body',
|
|
707
|
-
{ validator: schema, index: parameterIndex },
|
|
708
|
-
target,
|
|
709
|
-
propertyKey!
|
|
710
|
-
);
|
|
711
|
-
} else {
|
|
712
|
-
Reflect.defineMetadata(
|
|
713
|
-
'http:body',
|
|
714
|
-
{ schema, index: parameterIndex },
|
|
715
|
-
target,
|
|
716
|
-
propertyKey!
|
|
717
|
-
);
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
};
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Executes a custom function to resolve the value of the parameter from the context.
|
|
724
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
725
|
-
* @param handler The custom function that will return the value for the parameter.
|
|
726
|
-
*/
|
|
727
|
-
export const decorate = (handler: Handler): (() => ParameterDecorator) => {
|
|
728
|
-
return () => {
|
|
729
|
-
return function (target, propertyKey, parameterIndex) {
|
|
730
|
-
const decorators = Reflect.getMetadata('http:customDecorators', target, propertyKey!) ?? [];
|
|
731
|
-
decorators.push({ handler, index: parameterIndex });
|
|
732
|
-
Reflect.defineMetadata('http:customDecorators', decorators, target, propertyKey!);
|
|
733
|
-
};
|
|
734
|
-
};
|
|
735
|
-
};
|
|
736
|
-
}
|