bxo 0.0.5-dev.16 → 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/package.json +1 -1
- package/plugins/auth.ts +0 -119
- package/plugins/logger.ts +0 -109
package/package.json
CHANGED
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
|
-
}
|