bxo 0.0.5-dev.15 → 0.0.5-dev.17

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/index.ts CHANGED
@@ -37,8 +37,6 @@ export type Context<TConfig extends RouteConfig = {}> = {
37
37
  status?: number;
38
38
  headers?: Record<string, string>;
39
39
  };
40
- // Extended properties that can be added by plugins
41
- user?: any;
42
40
  [key: string]: any;
43
41
  };
44
42
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bxo",
3
3
  "module": "index.ts",
4
- "version": "0.0.5-dev.15",
4
+ "version": "0.0.5-dev.17",
5
5
  "description": "A simple and lightweight web framework for Bun",
6
6
  "type": "module",
7
7
  "devDependencies": {
package/plugins/auth.ts DELETED
@@ -1,119 +0,0 @@
1
- import BXO from '../index';
2
-
3
- interface AuthOptions {
4
- type: 'jwt' | 'bearer' | 'apikey';
5
- secret?: string;
6
- header?: string;
7
- verify?: (token: string, ctx: any) => Promise<any> | any;
8
- exclude?: string[];
9
- }
10
-
11
- export function auth(options: AuthOptions): BXO {
12
- const {
13
- type,
14
- secret,
15
- header = 'authorization',
16
- verify,
17
- exclude = []
18
- } = options;
19
-
20
- const authInstance = new BXO();
21
-
22
- authInstance.onRequest(async (ctx: any) => {
23
- const url = new URL(ctx.request.url);
24
- const pathname = url.pathname;
25
-
26
- // Skip auth for excluded paths
27
- if (exclude.some(path => {
28
- if (path.includes('*')) {
29
- const regex = new RegExp(path.replace(/\*/g, '.*'));
30
- return regex.test(pathname);
31
- }
32
- return pathname === path || pathname.startsWith(path);
33
- })) {
34
- return;
35
- }
36
-
37
- const authHeader = ctx.request.headers.get(header.toLowerCase());
38
-
39
- if (!authHeader) {
40
- throw new Response(JSON.stringify({ error: 'Authorization header required' }), {
41
- status: 401,
42
- headers: { 'Content-Type': 'application/json' }
43
- });
44
- }
45
-
46
- let token: string;
47
-
48
- if (type === 'jwt' || type === 'bearer') {
49
- if (!authHeader.startsWith('Bearer ')) {
50
- throw new Response(JSON.stringify({ error: 'Invalid authorization format. Use Bearer <token>' }), {
51
- status: 401,
52
- headers: { 'Content-Type': 'application/json' }
53
- });
54
- }
55
- token = authHeader.slice(7);
56
- } else if (type === 'apikey') {
57
- token = authHeader;
58
- } else {
59
- token = authHeader;
60
- }
61
-
62
- try {
63
- let user: any;
64
-
65
- if (verify) {
66
- user = await verify(token, ctx);
67
- } else if (type === 'jwt' && secret) {
68
- // Simple JWT verification (in production, use a proper JWT library)
69
- const [headerB64, payloadB64, signature] = token.split('.');
70
- if (!headerB64 || !payloadB64 || !signature) {
71
- throw new Error('Invalid JWT format');
72
- }
73
-
74
- const payload = JSON.parse(atob(payloadB64));
75
-
76
- // Check expiration
77
- if (payload.exp && Date.now() >= payload.exp * 1000) {
78
- throw new Error('Token expired');
79
- }
80
-
81
- user = payload;
82
- } else {
83
- user = { token };
84
- }
85
-
86
- // Attach user to context
87
- ctx.user = user;
88
-
89
- } catch (error) {
90
- const message = error instanceof Error ? error.message : 'Invalid token';
91
- throw new Response(JSON.stringify({ error: message }), {
92
- status: 401,
93
- headers: { 'Content-Type': 'application/json' }
94
- });
95
- }
96
- });
97
-
98
- return authInstance;
99
- }
100
-
101
- // Helper function for creating JWT tokens (simple implementation)
102
- export function createJWT(payload: any, secret: string, expiresIn: number = 3600): string {
103
- const header = { alg: 'HS256', typ: 'JWT' };
104
- const now = Math.floor(Date.now() / 1000);
105
-
106
- const jwtPayload = {
107
- ...payload,
108
- iat: now,
109
- exp: now + expiresIn
110
- };
111
-
112
- const headerB64 = btoa(JSON.stringify(header));
113
- const payloadB64 = btoa(JSON.stringify(jwtPayload));
114
-
115
- // Simple signature (in production, use proper HMAC-SHA256)
116
- const signature = btoa(`${headerB64}.${payloadB64}.${secret}`);
117
-
118
- return `${headerB64}.${payloadB64}.${signature}`;
119
- }
package/plugins/logger.ts DELETED
@@ -1,109 +0,0 @@
1
- import BXO from '../index';
2
-
3
- interface LoggerOptions {
4
- format?: 'simple' | 'detailed' | 'json';
5
- includeBody?: boolean;
6
- includeHeaders?: boolean;
7
- }
8
-
9
- export function logger(options: LoggerOptions = {}): BXO {
10
- const {
11
- format = 'simple',
12
- includeBody = false,
13
- includeHeaders = false
14
- } = options;
15
-
16
- const loggerInstance = new BXO();
17
-
18
- loggerInstance.onRequest(async (ctx: any) => {
19
- ctx._startTime = Date.now();
20
-
21
- if (format === 'json') {
22
- const logData: any = {
23
- timestamp: new Date().toISOString(),
24
- method: ctx.request.method,
25
- url: ctx.request.url,
26
- type: 'request'
27
- };
28
-
29
- if (includeHeaders) {
30
- logData.headers = Object.fromEntries(ctx.request.headers.entries());
31
- }
32
-
33
- if (includeBody && ctx.body) {
34
- logData.body = ctx.body;
35
- }
36
-
37
- console.log(JSON.stringify(logData));
38
- } else if (format === 'detailed') {
39
- console.log(`→ ${ctx.request.method} ${ctx.request.url}`);
40
- if (includeHeaders) {
41
- console.log(' Headers:', Object.fromEntries(ctx.request.headers.entries()));
42
- }
43
- if (includeBody && ctx.body) {
44
- console.log(' Body:', ctx.body);
45
- }
46
- } else {
47
- console.log(`→ ${ctx.request.method} ${ctx.request.url}`);
48
- }
49
- });
50
-
51
- loggerInstance.onResponse(async (ctx: any, response: any) => {
52
- const duration = Date.now() - (ctx._startTime || 0);
53
- const status = ctx.set.status || 200;
54
-
55
- if (format === 'json') {
56
- const logData: any = {
57
- timestamp: new Date().toISOString(),
58
- method: ctx.request.method,
59
- url: ctx.request.url,
60
- status,
61
- duration: `${duration}ms`,
62
- type: 'response'
63
- };
64
-
65
- if (includeHeaders && ctx.set.headers) {
66
- logData.responseHeaders = ctx.set.headers;
67
- }
68
-
69
- if (includeBody && response) {
70
- logData.response = response;
71
- }
72
-
73
- console.log(JSON.stringify(logData));
74
- } else if (format === 'detailed') {
75
- console.log(`← ${ctx.request.method} ${ctx.request.url} ${status} ${duration}ms`);
76
- if (includeHeaders && ctx.set.headers) {
77
- console.log(' Response Headers:', ctx.set.headers);
78
- }
79
- if (includeBody && response) {
80
- console.log(' Response:', response);
81
- }
82
- } else {
83
- const statusColor = status >= 400 ? '\x1b[31m' : status >= 300 ? '\x1b[33m' : '\x1b[32m';
84
- const resetColor = '\x1b[0m';
85
- console.log(`← ${ctx.request.method} ${ctx.request.url} ${statusColor}${status}${resetColor} ${duration}ms`);
86
- }
87
-
88
- return response;
89
- });
90
-
91
- loggerInstance.onError(async (ctx: any, error: Error) => {
92
- const duration = Date.now() - (ctx._startTime || 0);
93
-
94
- if (format === 'json') {
95
- console.log(JSON.stringify({
96
- timestamp: new Date().toISOString(),
97
- method: ctx.request.method,
98
- url: ctx.request.url,
99
- error: error.message,
100
- duration: `${duration}ms`,
101
- type: 'error'
102
- }));
103
- } else {
104
- console.log(`✗ ${ctx.request.method} ${ctx.request.url} \x1b[31mERROR\x1b[0m ${duration}ms: ${error.message}`);
105
- }
106
- });
107
-
108
- return loggerInstance;
109
- }