@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/src/job.ts DELETED
@@ -1,196 +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 'reflect-metadata';
16
-
17
- import type { Class } from 'type-fest';
18
-
19
- import { assign, uid } from 'radash';
20
-
21
- import { InteractsWithConsole } from './console';
22
- import { Service } from './service';
23
- import { Symbols } from './utils';
24
-
25
- /**
26
- * Properties required when declaring a job using the `@job()` decorator.
27
- * @author Axel Nana <axel.nana@workbud.com>
28
- */
29
- export type JobProps = {
30
- /**
31
- * The name of the job.
32
- */
33
- name?: string;
34
-
35
- /**
36
- * The queue on which the job should be processed.
37
- */
38
- queue?: string;
39
- };
40
-
41
- /**
42
- * Base class for background jobs.
43
- *
44
- * Jobs are classes that can be executed in the background. They provide
45
- * an abstract execute method that serves as the entry point for the job.
46
- *
47
- * @author Axel Nana <axel.nana@workbud.com>
48
- */
49
- export abstract class Job extends InteractsWithConsole {
50
- #startedAt?: Date;
51
- #completedAt?: Date;
52
- #status: JobStatus = JobStatus.PENDING;
53
- #err?: Error;
54
-
55
- /**
56
- * Marks a class as a job.
57
- * @author Axel Nana <axel.nana@workbud.com>
58
- * @param options The decorator options.
59
- */
60
- public static register(options: JobProps = {}) {
61
- return function (target: Class<Job>) {
62
- options = assign({ name: target.name, queue: 'default' }, options);
63
-
64
- const name = `job.${options.name}`;
65
-
66
- Service.instance(name, target);
67
-
68
- Reflect.defineMetadata(Symbols.job, { name, queue: options.queue }, target);
69
- };
70
- }
71
-
72
- /**
73
- * Unique identifier for the job.
74
- */
75
- public readonly id: string;
76
-
77
- /**
78
- * The timestamp when the job was created.
79
- */
80
- public readonly createdAt: Date;
81
-
82
- /**
83
- * The timestamp when the job started execution.
84
- */
85
- public get startedAt(): Date | undefined {
86
- return this.#startedAt;
87
- }
88
-
89
- /**
90
- * The timestamp when the job completed execution.
91
- */
92
- public get completedAt(): Date | undefined {
93
- return this.#completedAt;
94
- }
95
-
96
- /**
97
- * The current status of the job.
98
- */
99
- public get status(): JobStatus {
100
- return this.#status;
101
- }
102
-
103
- /**
104
- * Creates a new job instance.
105
- *
106
- * @param id Optional job ID. If not provided, a random ID will be generated.
107
- */
108
- constructor(id?: string) {
109
- super();
110
- this.id = id || this.generateJobId();
111
- this.createdAt = new Date();
112
- }
113
-
114
- /**
115
- * Run the job.
116
- * This method handles the job lifecycle and calls the execute method.
117
- */
118
- public async run(): Promise<void> {
119
- try {
120
- this.#status = JobStatus.RUNNING;
121
- this.#startedAt = new Date();
122
-
123
- this.debug(`Job ${this.id} started at ${this.#startedAt.toISOString()}`);
124
-
125
- // Execute the job implementation
126
- await this.execute();
127
-
128
- this.#status = JobStatus.COMPLETED;
129
- this.#completedAt = new Date();
130
-
131
- this.debug(`Job ${this.id} completed at ${this.#completedAt.toISOString()}`);
132
- } catch (err) {
133
- this.#err = err instanceof Error ? err : new Error(String(err));
134
-
135
- if (this.#status !== JobStatus.CANCELLED) {
136
- this.#status = JobStatus.FAILED;
137
- }
138
-
139
- this.#completedAt = new Date();
140
-
141
- this.trace(this.#err);
142
- }
143
- }
144
-
145
- /**
146
- * Cancels the job.
147
- */
148
- public cancel(): void {
149
- this.#status = JobStatus.CANCELLED;
150
- }
151
-
152
- /**
153
- * The main execution method for the job.
154
- * This must be implemented by all job classes.
155
- */
156
- protected abstract execute(): Promise<void>;
157
-
158
- /**
159
- * Generate a random job ID.
160
- * @returns A random job ID.
161
- */
162
- private generateJobId(): string {
163
- return `job_${Date.now()}_${uid(8)}`;
164
- }
165
- }
166
-
167
- /**
168
- * Possible statuses for a job.
169
- * @author Axel Nana <axel.nana@workbud.com>
170
- */
171
- export enum JobStatus {
172
- /**
173
- * The job is in pending state, meaning it has been added to the queue but has not yet been processed.
174
- */
175
- PENDING = 'pending',
176
-
177
- /**
178
- * The job is in running state, meaning it is currently being processed.
179
- */
180
- RUNNING = 'running',
181
-
182
- /**
183
- * The job has completed successfully.
184
- */
185
- COMPLETED = 'completed',
186
-
187
- /**
188
- * The job has failed to complete successfully. If there are enough retries left, the job will be restarted.
189
- */
190
- FAILED = 'failed',
191
-
192
- /**
193
- * The job has been cancelled by the user or another job.
194
- */
195
- CANCELLED = 'cancelled'
196
- }
package/src/middleware.ts DELETED
@@ -1,164 +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 { AnyElysia } from 'elysia';
16
- import type { Class } from 'type-fest';
17
- import type { Context } from './http';
18
-
19
- import { Application } from './app';
20
- import { Service } from './service';
21
- import { Symbols } from './utils';
22
-
23
- /**
24
- * Execute a chain of middlewares, stopping on the first return or throw.
25
- * @author Axel Nana <axel.nana@workbud.com>
26
- * @param middlewares The list of middleware instances to execute.
27
- * @param context The context to pass to each middleware.
28
- * @param method The method to call on each middleware.
29
- */
30
- export const executeMiddlewareChain = (
31
- middlewares: Middleware[],
32
- context: any,
33
- method: Exclude<keyof Middleware, 'guards'>
34
- ): Promise<any> => {
35
- return Application.context.run(
36
- new Map([
37
- ['tenant', context.tenant],
38
- ['http:context', context]
39
- ]),
40
- async () => {
41
- for (const middleware of middlewares) {
42
- try {
43
- const result = await middleware[method](context);
44
- if (result !== undefined) {
45
- return result; // Stop the chain if middleware returns a value
46
- }
47
- } catch (error) {
48
- throw error; // Stop the chain and propagate the error
49
- }
50
- }
51
- }
52
- );
53
- };
54
-
55
- /**
56
- * Apply a list of middlewares to an Elysia plugin.
57
- * @author Axel Nana <axel.nana@workbud.com>
58
- * @param middlewares The list of middlewares to apply.
59
- * @param plugin The Elysia plugin instance.
60
- */
61
- export const applyMiddlewares = (middlewares: Class<Middleware>[], plugin: AnyElysia) => {
62
- const mi = middlewares.map((middleware) => Service.make<Middleware>(middleware));
63
-
64
- plugin.onRequest((c) => {
65
- return executeMiddlewareChain(mi, c, 'onRequest');
66
- });
67
-
68
- plugin.onTransform((c) => {
69
- return executeMiddlewareChain(mi, c, 'onTransform');
70
- });
71
-
72
- plugin.onBeforeHandle((c) => {
73
- return executeMiddlewareChain(mi, c, 'onBeforeHandle');
74
- });
75
-
76
- plugin.onAfterHandle((c) => {
77
- return executeMiddlewareChain(mi, c, 'onAfterHandle');
78
- });
79
-
80
- plugin.onAfterResponse((c) => {
81
- return executeMiddlewareChain(mi, c, 'onAfterResponse');
82
- });
83
- };
84
-
85
- /**
86
- * Base class for middleware.
87
- * @author Axel Nana <axel.nana@workbud.com>
88
- * @template TGuards The list of guards for the middleware.
89
- */
90
- export abstract class Middleware<TGuards extends string[] = []> {
91
- /**
92
- * Registers a list of middlewares to be applied on a controller or endpoint.
93
- * @author Axel Nana <axel.nana@workbud.com>
94
- * @param middlewares The list of middlewares to apply.
95
- */
96
- public static register(...middlewares: Class<Middleware>[]): ClassDecorator & MethodDecorator {
97
- return function (
98
- target: Object,
99
- propertyKey?: string | symbol,
100
- descriptor?: PropertyDescriptor
101
- ) {
102
- if (propertyKey === undefined && descriptor === undefined) {
103
- const m = Reflect.getMetadata(Symbols.middlewares, target) ?? [];
104
- m.push(...middlewares);
105
- Reflect.defineMetadata(Symbols.middlewares, m, target);
106
- } else {
107
- const m = Reflect.getMetadata(Symbols.middlewares, target, propertyKey!) ?? [];
108
- m.push(...middlewares);
109
- Reflect.defineMetadata(Symbols.middlewares, m, target, propertyKey!);
110
- }
111
- };
112
- }
113
-
114
- /**
115
- * Creates a guarded version of the middleware.
116
- * @author Axel Nana <axel.nana@workbud.com>
117
- * @param guards The list of guards for the middleware.
118
- * @returns A middleware class decorated with guards.
119
- */
120
- public static guards(guards: string[]): Class<Middleware> {
121
- class GuardedMiddleware extends this {}
122
- Reflect.defineMetadata(Symbols.middlewareGuards, guards, GuardedMiddleware);
123
- return GuardedMiddleware;
124
- }
125
-
126
- /**
127
- * Gets the list of guards for the middleware.
128
- */
129
- public get guards(): TGuards {
130
- return Reflect.getMetadata(Symbols.middlewareGuards, this.constructor) ?? [];
131
- }
132
-
133
- /**
134
- * Called first before everything else. This middleware hook works only when used on
135
- * a controller, a module, or the application.
136
- * @param ctx The request context.
137
- */
138
- public onRequest(ctx: Context): any {}
139
-
140
- /**
141
- * Called before validation, but after the request has been parsed.
142
- * Use this method to modify the request inputs before validation.
143
- * @param ctx The request context.
144
- */
145
- public onTransform(ctx: Context): any {}
146
-
147
- /**
148
- * Called after the request has been handled, but before the response is sent.
149
- * @param ctx The request context.
150
- */
151
- public onAfterHandle(ctx: Context): any {}
152
-
153
- /**
154
- * Called before the request is handled.
155
- * @param ctx The request context.
156
- */
157
- public onBeforeHandle(ctx: Context): any {}
158
-
159
- /**
160
- * Called after the response has been sent.
161
- * @param ctx The request context.
162
- */
163
- public onAfterResponse(ctx: Context): any {}
164
- }