Skip to content

Commit 830590a

Browse files
authored
Merge pull request #128 from ozeanjs/release/v0.11.0
chore(release): bump version to v0.11.0
2 parents 6e17245 + 218eb40 commit 830590a

File tree

7 files changed

+178
-9
lines changed

7 files changed

+178
-9
lines changed

.husky/pre-commit

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env sh
22
. "$(dirname -- "$0")/_/husky.sh"
33

4-
bun lint-staged
4+
bun lint-staged
5+
bun run test

packages/ozean-cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ozean-cli",
3-
"version": "0.10.0",
3+
"version": "0.11.0",
44
"description": "This is the official Command-Line Interface (CLI) for the OzeanJs Framework. It helps you kickstart new projects.",
55
"keywords": [
66
"ozean",

packages/ozean/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ozean",
3-
"version": "0.10.0",
3+
"version": "0.11.0",
44
"description": "A modern, simple, and high-performance web framework for Bun, inspired by Angular's architecture.",
55
"keywords": [
66
"ozean",

packages/ozean/src/core/app.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,17 @@ export class App {
375375
const meta = executionPlan!.paramMeta[i];
376376
let val: any;
377377
if (meta) {
378-
if (meta.type === 'file') val = (req as any).file;
379-
else if (meta.type === 'query')
378+
if (meta.type === 'req') {
379+
val = req;
380+
} else if (meta.type === 'file') {
381+
val = (req as any).file;
382+
} else if (meta.type === 'query') {
380383
val = Object.fromEntries(url.searchParams)[meta.key];
381-
else if (meta.type === 'param') val = matched.params[meta.key];
382-
else if (meta.type === 'body') val = meta.key ? body[meta.key] : body;
384+
} else if (meta.type === 'param') {
385+
val = matched.params[meta.key];
386+
} else if (meta.type === 'body') {
387+
val = meta.key ? body[meta.key] : body;
388+
}
383389
}
384390
const argMeta: ArgumentMetadata = {
385391
type: meta?.type,

packages/ozean/src/decorators/parameters.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
function createParameterDecorator(
2-
type: 'query' | 'param' | 'body',
2+
type: 'req' | 'query' | 'param' | 'body',
33
key?: string
44
): ParameterDecorator {
55
return (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => {
@@ -13,6 +13,7 @@ function createParameterDecorator(
1313
Reflect.defineMetadata('custom:param', existingParams, target, propertyKey);
1414
};
1515
}
16+
export const Req = () => createParameterDecorator('req');
1617
export const Query = (key: string) => createParameterDecorator('query', key);
1718
export const Param = (key: string) => createParameterDecorator('param', key);
1819
export const Body = (key?: string) => createParameterDecorator('body', key);

packages/ozean/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export { Module } from './decorators/module';
55
export { Controller } from './decorators/controller';
66
export { Get, Post, Put, Delete, Patch } from './decorators/http-methods';
77
export { Injectable, Inject } from './decorators/injectable';
8-
export { Query, Param, Body } from './decorators/parameters';
8+
export { Req, Query, Param, Body } from './decorators/parameters';
99
export { UseMiddleware } from './decorators/use-middleware.decorator';
1010
export { UsePipes } from './decorators/use-pipes.decorator';
1111
export { UseFilters } from './decorators/use-filters.decorator';
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { describe, test, expect, beforeAll, afterAll, beforeEach } from 'bun:test';
2+
import type { Server } from 'bun';
3+
import 'reflect-metadata';
4+
5+
import {
6+
App,
7+
Module,
8+
Controller,
9+
Get,
10+
Injectable,
11+
type Middleware,
12+
type NextFunction,
13+
UseMiddleware,
14+
} from '../../src';
15+
16+
const executionOrder: string[] = [];
17+
18+
@Injectable()
19+
class GlobalMiddleware1 implements Middleware {
20+
async use(req: Request, next: NextFunction) {
21+
executionOrder.push('GlobalMiddleware1');
22+
return await next();
23+
}
24+
}
25+
26+
@Injectable()
27+
class GlobalMiddleware2 implements Middleware {
28+
async use(req: Request, next: NextFunction) {
29+
executionOrder.push('GlobalMiddleware2');
30+
return await next();
31+
}
32+
}
33+
34+
@Injectable()
35+
class ControllerMiddleware implements Middleware {
36+
async use(req: Request, next: NextFunction) {
37+
executionOrder.push('ControllerMiddleware');
38+
return await next();
39+
}
40+
}
41+
42+
@Injectable()
43+
class RouteMiddleware implements Middleware {
44+
async use(req: Request, next: NextFunction) {
45+
executionOrder.push('RouteMiddleware');
46+
return await next();
47+
}
48+
}
49+
50+
@Injectable()
51+
class ShortCircuitMiddleware implements Middleware {
52+
async use(req: Request, next: NextFunction) {
53+
return new Response('Request was short-circuited by middleware', { status: 200 });
54+
}
55+
}
56+
57+
@Controller('/middleware-test')
58+
@UseMiddleware(ControllerMiddleware)
59+
class TestController {
60+
@Get('/all')
61+
@UseMiddleware(RouteMiddleware)
62+
getWithAllMiddlewares() {
63+
executionOrder.push('Handler');
64+
return { success: true };
65+
}
66+
67+
@Get('/no-route-mw')
68+
getWithNoRouteMiddleware() {
69+
executionOrder.push('Handler');
70+
return { success: true };
71+
}
72+
73+
@Get('/short-circuit')
74+
@UseMiddleware(ShortCircuitMiddleware)
75+
getShortCircuited() {
76+
executionOrder.push('Handler');
77+
return { message: 'This should not be returned' };
78+
}
79+
}
80+
81+
@Module({
82+
controllers: [TestController],
83+
providers: [
84+
GlobalMiddleware1,
85+
GlobalMiddleware2,
86+
ControllerMiddleware,
87+
RouteMiddleware,
88+
ShortCircuitMiddleware,
89+
],
90+
})
91+
class TestAppModule {}
92+
93+
describe('Middlewares (E2E)', () => {
94+
let app: App;
95+
let server: Server;
96+
97+
beforeAll(() => {
98+
app = new App(TestAppModule);
99+
100+
app.use(GlobalMiddleware1, GlobalMiddleware2);
101+
102+
server = app.listen(0);
103+
});
104+
105+
afterAll(() => {
106+
server.stop(true);
107+
});
108+
109+
beforeEach(() => {
110+
executionOrder.length = 0;
111+
});
112+
113+
test('should execute global, controller, and route middlewares in correct order', async () => {
114+
const response = await fetch(new URL('/middleware-test/all', server.url));
115+
116+
expect(response.status).toBe(200);
117+
118+
expect(executionOrder).toEqual([
119+
'GlobalMiddleware1',
120+
'GlobalMiddleware2',
121+
'ControllerMiddleware',
122+
'RouteMiddleware',
123+
'Handler',
124+
]);
125+
});
126+
127+
test('should execute only global and controller middlewares when no route middleware is present', async () => {
128+
const response = await fetch(new URL('/middleware-test/no-route-mw', server.url));
129+
130+
expect(response.status).toBe(200);
131+
132+
expect(executionOrder).toEqual([
133+
'GlobalMiddleware1',
134+
'GlobalMiddleware2',
135+
'ControllerMiddleware',
136+
'Handler',
137+
]);
138+
});
139+
140+
test('should allow a middleware to short-circuit the request chain', async () => {
141+
const response = await fetch(new URL('/middleware-test/short-circuit', server.url));
142+
143+
expect(response.status).toBe(200);
144+
expect(await response.text()).toBe('Request was short-circuited by middleware');
145+
146+
expect(executionOrder).not.toContain('Handler');
147+
expect(executionOrder).toEqual([
148+
'GlobalMiddleware1',
149+
'GlobalMiddleware2',
150+
'ControllerMiddleware',
151+
]);
152+
});
153+
154+
test('should not apply middlewares to a non-existent route', async () => {
155+
const response = await fetch(new URL('/not-found', server.url));
156+
157+
expect(response.status).toBe(404);
158+
159+
expect(executionOrder).toEqual([]);
160+
});
161+
});

0 commit comments

Comments
 (0)