ts-typed-api 0.2.12 → 0.2.13
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/dist/handler.js +48 -0
- package/dist/hono-cloudflare-workers.js +48 -2
- package/package.json +1 -1
- package/src/handler.ts +59 -0
- package/src/hono-cloudflare-workers.ts +56 -2
- package/tests/middleware.test.ts +24 -0
- package/tests/setup.ts +91 -90
package/dist/handler.js
CHANGED
|
@@ -55,6 +55,50 @@ function preprocessQueryParams(query, querySchema) {
|
|
|
55
55
|
}
|
|
56
56
|
return processedQuery;
|
|
57
57
|
}
|
|
58
|
+
// Helper function to create respond method for middleware compatibility
|
|
59
|
+
function createRespondFunction(routeDefinition, responseSetter) {
|
|
60
|
+
return (status, data) => {
|
|
61
|
+
const responseSchema = routeDefinition.responses[status];
|
|
62
|
+
if (!responseSchema) {
|
|
63
|
+
console.error(`No response schema defined for status ${status}`);
|
|
64
|
+
responseSetter(500, {
|
|
65
|
+
data: null,
|
|
66
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Undefined response schema for status." }]
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
let responseBody;
|
|
71
|
+
if (status === 422) {
|
|
72
|
+
responseBody = {
|
|
73
|
+
data: null,
|
|
74
|
+
error: data
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
responseBody = {
|
|
79
|
+
data: data,
|
|
80
|
+
error: null
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const validationResult = responseSchema.safeParse(responseBody);
|
|
84
|
+
if (validationResult.success) {
|
|
85
|
+
// Handle 204 responses specially - they must not have a body
|
|
86
|
+
if (status === 204) {
|
|
87
|
+
responseSetter(status, null);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
responseSetter(status, validationResult.data);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.error(`FATAL: Constructed response body failed Zod validation for status ${status}.`, validationResult.error.issues, 'Provided data:', data, 'Constructed response body:', responseBody);
|
|
95
|
+
responseSetter(500, {
|
|
96
|
+
data: null,
|
|
97
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Constructed response failed validation." }]
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
58
102
|
// Helper function to create multer middleware based on file upload configuration
|
|
59
103
|
function createFileUploadMiddleware(config) {
|
|
60
104
|
// Default multer configuration
|
|
@@ -367,6 +411,10 @@ middlewares) {
|
|
|
367
411
|
middlewares.forEach(middleware => {
|
|
368
412
|
const wrappedMiddleware = async (req, res, next) => {
|
|
369
413
|
try {
|
|
414
|
+
// Add respond method to res for middleware compatibility
|
|
415
|
+
res.respond = createRespondFunction(routeDefinition, (status, data) => {
|
|
416
|
+
res.status(status).json(data);
|
|
417
|
+
});
|
|
370
418
|
await middleware(req, res, next, { domain: currentDomain, routeKey: currentRouteKey });
|
|
371
419
|
}
|
|
372
420
|
catch (error) {
|
|
@@ -415,10 +415,56 @@ function registerHonoRouteHandlers(app, apiDefinition, routeHandlers, middleware
|
|
|
415
415
|
path: c.req.path,
|
|
416
416
|
originalUrl: c.req.url
|
|
417
417
|
};
|
|
418
|
-
// Create minimal res object
|
|
419
|
-
const fakeRes = {
|
|
418
|
+
// Create minimal res object with respond method for middleware compatibility
|
|
419
|
+
const fakeRes = {
|
|
420
|
+
respond: (status, data) => {
|
|
421
|
+
const responseSchema = routeDefinition.responses[status];
|
|
422
|
+
if (!responseSchema) {
|
|
423
|
+
console.error(`No response schema defined for status ${status}`);
|
|
424
|
+
c.json({
|
|
425
|
+
data: null,
|
|
426
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Undefined response schema for status." }]
|
|
427
|
+
}, 500);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
let responseBody;
|
|
431
|
+
if (status === 422) {
|
|
432
|
+
responseBody = {
|
|
433
|
+
data: null,
|
|
434
|
+
error: data
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
responseBody = {
|
|
439
|
+
data: data,
|
|
440
|
+
error: null
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
const validationResult = responseSchema.safeParse(responseBody);
|
|
444
|
+
if (validationResult.success) {
|
|
445
|
+
// Handle 204 responses specially - they must not have a body
|
|
446
|
+
if (status === 204) {
|
|
447
|
+
c.__response = new Response(null, { status: status });
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
c.__response = c.json(validationResult.data, status);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
console.error(`FATAL: Constructed response body failed Zod validation for status ${status}.`, validationResult.error.issues, 'Provided data:', data, 'Constructed response body:', responseBody);
|
|
455
|
+
c.__response = c.json({
|
|
456
|
+
data: null,
|
|
457
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Constructed response failed validation." }]
|
|
458
|
+
}, 500);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
};
|
|
420
462
|
// Call Express-style middleware
|
|
421
463
|
await middleware(fakeReq, fakeRes, next, { domain: currentDomain, routeKey: currentRouteKey });
|
|
464
|
+
// Check if middleware responded directly
|
|
465
|
+
if (c.__response) {
|
|
466
|
+
return c.__response;
|
|
467
|
+
}
|
|
422
468
|
}
|
|
423
469
|
catch (error) {
|
|
424
470
|
console.error('Middleware error:', error);
|
package/package.json
CHANGED
package/src/handler.ts
CHANGED
|
@@ -79,6 +79,61 @@ function preprocessQueryParams(query: any, querySchema?: z.ZodTypeAny): any {
|
|
|
79
79
|
return processedQuery;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Helper function to create respond method for middleware compatibility
|
|
83
|
+
function createRespondFunction(
|
|
84
|
+
routeDefinition: RouteSchema,
|
|
85
|
+
responseSetter: (status: number, data: any) => void
|
|
86
|
+
) {
|
|
87
|
+
return (status: number, data: any) => {
|
|
88
|
+
const responseSchema = routeDefinition.responses[status];
|
|
89
|
+
|
|
90
|
+
if (!responseSchema) {
|
|
91
|
+
console.error(`No response schema defined for status ${status}`);
|
|
92
|
+
responseSetter(500, {
|
|
93
|
+
data: null,
|
|
94
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Undefined response schema for status." }]
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let responseBody: any;
|
|
100
|
+
|
|
101
|
+
if (status === 422) {
|
|
102
|
+
responseBody = {
|
|
103
|
+
data: null,
|
|
104
|
+
error: data
|
|
105
|
+
};
|
|
106
|
+
} else {
|
|
107
|
+
responseBody = {
|
|
108
|
+
data: data,
|
|
109
|
+
error: null
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const validationResult = responseSchema.safeParse(responseBody);
|
|
114
|
+
|
|
115
|
+
if (validationResult.success) {
|
|
116
|
+
// Handle 204 responses specially - they must not have a body
|
|
117
|
+
if (status === 204) {
|
|
118
|
+
responseSetter(status, null);
|
|
119
|
+
} else {
|
|
120
|
+
responseSetter(status, validationResult.data);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
console.error(
|
|
124
|
+
`FATAL: Constructed response body failed Zod validation for status ${status}.`,
|
|
125
|
+
validationResult.error.issues,
|
|
126
|
+
'Provided data:', data,
|
|
127
|
+
'Constructed response body:', responseBody
|
|
128
|
+
);
|
|
129
|
+
responseSetter(500, {
|
|
130
|
+
data: null,
|
|
131
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Constructed response failed validation." }]
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
82
137
|
// Helper function to create multer middleware based on file upload configuration
|
|
83
138
|
function createFileUploadMiddleware(config: FileUploadConfig): express.RequestHandler {
|
|
84
139
|
// Default multer configuration
|
|
@@ -418,6 +473,10 @@ export function registerRouteHandlers<TDef extends ApiDefinitionSchema>(
|
|
|
418
473
|
middlewares.forEach(middleware => {
|
|
419
474
|
const wrappedMiddleware: express.RequestHandler = async (req, res, next) => {
|
|
420
475
|
try {
|
|
476
|
+
// Add respond method to res for middleware compatibility
|
|
477
|
+
(res as any).respond = createRespondFunction(routeDefinition, (status, data) => {
|
|
478
|
+
res.status(status).json(data);
|
|
479
|
+
});
|
|
421
480
|
await middleware(req, res, next, { domain: currentDomain, routeKey: currentRouteKey } as any);
|
|
422
481
|
} catch (error) {
|
|
423
482
|
next(error);
|
|
@@ -497,12 +497,66 @@ export function registerHonoRouteHandlers<
|
|
|
497
497
|
originalUrl: c.req.url
|
|
498
498
|
};
|
|
499
499
|
|
|
500
|
-
// Create minimal res object
|
|
501
|
-
const fakeRes = {
|
|
500
|
+
// Create minimal res object with respond method for middleware compatibility
|
|
501
|
+
const fakeRes = {
|
|
502
|
+
respond: (status: number, data: any) => {
|
|
503
|
+
const responseSchema = routeDefinition.responses[status];
|
|
504
|
+
|
|
505
|
+
if (!responseSchema) {
|
|
506
|
+
console.error(`No response schema defined for status ${status}`);
|
|
507
|
+
c.json({
|
|
508
|
+
data: null,
|
|
509
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Undefined response schema for status." }]
|
|
510
|
+
}, 500);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
let responseBody: any;
|
|
515
|
+
|
|
516
|
+
if (status === 422) {
|
|
517
|
+
responseBody = {
|
|
518
|
+
data: null,
|
|
519
|
+
error: data
|
|
520
|
+
};
|
|
521
|
+
} else {
|
|
522
|
+
responseBody = {
|
|
523
|
+
data: data,
|
|
524
|
+
error: null
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const validationResult = responseSchema.safeParse(responseBody);
|
|
529
|
+
|
|
530
|
+
if (validationResult.success) {
|
|
531
|
+
// Handle 204 responses specially - they must not have a body
|
|
532
|
+
if (status === 204) {
|
|
533
|
+
(c as any).__response = new Response(null, { status: status as any });
|
|
534
|
+
} else {
|
|
535
|
+
(c as any).__response = c.json(validationResult.data, status as any);
|
|
536
|
+
}
|
|
537
|
+
} else {
|
|
538
|
+
console.error(
|
|
539
|
+
`FATAL: Constructed response body failed Zod validation for status ${status}.`,
|
|
540
|
+
validationResult.error.issues,
|
|
541
|
+
'Provided data:', data,
|
|
542
|
+
'Constructed response body:', responseBody
|
|
543
|
+
);
|
|
544
|
+
(c as any).__response = c.json({
|
|
545
|
+
data: null,
|
|
546
|
+
error: [{ field: "general", type: "general", message: "Internal server error: Constructed response failed validation." }]
|
|
547
|
+
}, 500);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
};
|
|
502
551
|
|
|
503
552
|
// Call Express-style middleware
|
|
504
553
|
await middleware(fakeReq as any, fakeRes as any, next, { domain: currentDomain, routeKey: currentRouteKey });
|
|
505
554
|
|
|
555
|
+
// Check if middleware responded directly
|
|
556
|
+
if ((c as any).__response) {
|
|
557
|
+
return (c as any).__response;
|
|
558
|
+
}
|
|
559
|
+
|
|
506
560
|
} catch (error) {
|
|
507
561
|
console.error('Middleware error:', error);
|
|
508
562
|
await next();
|
package/tests/middleware.test.ts
CHANGED
|
@@ -58,6 +58,9 @@ describe.each([
|
|
|
58
58
|
401: ({ data }) => {
|
|
59
59
|
throw new Error(`Authentication failed: ${data.error}`);
|
|
60
60
|
},
|
|
61
|
+
403: ({ data }) => {
|
|
62
|
+
throw new Error(`Forbidden: ${data.error}`);
|
|
63
|
+
},
|
|
61
64
|
422: ({ error }) => {
|
|
62
65
|
throw new Error(`Validation error: ${JSON.stringify(error)}`);
|
|
63
66
|
}
|
|
@@ -74,11 +77,32 @@ describe.each([
|
|
|
74
77
|
expect(data.error).toBe('No authorization header');
|
|
75
78
|
throw new Error('Authentication failed as expected');
|
|
76
79
|
},
|
|
80
|
+
403: ({ data }) => {
|
|
81
|
+
throw new Error(`Unexpected forbidden: ${data.error}`);
|
|
82
|
+
},
|
|
77
83
|
422: ({ error }) => {
|
|
78
84
|
throw new Error(`Validation error: ${JSON.stringify(error)}`);
|
|
79
85
|
}
|
|
80
86
|
})
|
|
81
87
|
).rejects.toThrow('Authentication failed as expected');
|
|
82
88
|
});
|
|
89
|
+
|
|
90
|
+
test('should deny access with invalid auth header', async () => {
|
|
91
|
+
await expect(
|
|
92
|
+
client.callApi('public', 'protected', { headers: { Authorization: 'Bearer invalid-token' } }, {
|
|
93
|
+
200: ({ data }) => data,
|
|
94
|
+
401: ({ data }) => {
|
|
95
|
+
throw new Error(`Unexpected auth failed: ${data.error}`);
|
|
96
|
+
},
|
|
97
|
+
403: ({ data }) => {
|
|
98
|
+
expect(data.error).toBe('Forbidden');
|
|
99
|
+
throw new Error('Forbidden as expected');
|
|
100
|
+
},
|
|
101
|
+
422: ({ error }) => {
|
|
102
|
+
throw new Error(`Validation error: ${JSON.stringify(error)}`);
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
).rejects.toThrow('Forbidden as expected');
|
|
106
|
+
});
|
|
83
107
|
});
|
|
84
108
|
});
|
package/tests/setup.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { PublicApiDefinition as SimplePublicApiDefinition, PrivateApiDefinition
|
|
|
7
7
|
import { PublicApiDefinition as AdvancedPublicApiDefinition, PrivateApiDefinition as AdvancedPrivateApiDefinition } from '../examples/advanced/definitions';
|
|
8
8
|
import { RegisterHandlers, RegisterHonoHandlers, CreateApiDefinition, CreateResponses, CreateTypedHonoHandlerWithContext } from '../src';
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
-
import { EndpointMiddlewareCtx } from '../src/object-handlers';
|
|
11
10
|
|
|
12
11
|
// Shared handler definitions for simple API
|
|
13
12
|
const simplePublicHandlers = {
|
|
@@ -219,7 +218,8 @@ export const MiddlewareTestApiDefinition = CreateApiDefinition({
|
|
|
219
218
|
path: '/protected',
|
|
220
219
|
responses: CreateResponses({
|
|
221
220
|
200: z.object({ message: z.string(), user: z.string() }),
|
|
222
|
-
401: z.object({ error: z.string() })
|
|
221
|
+
401: z.object({ error: z.string() }),
|
|
222
|
+
403: z.object({ error: z.string() })
|
|
223
223
|
})
|
|
224
224
|
},
|
|
225
225
|
context: {
|
|
@@ -444,62 +444,111 @@ async function startHonoServer(): Promise<void> {
|
|
|
444
444
|
});
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
-
type Ctx = { user
|
|
447
|
+
type Ctx = { user?: string; noAuth?: boolean; forbidden?: boolean }
|
|
448
448
|
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
449
|
+
// Shared handlers for middleware tests
|
|
450
|
+
const middlewareTestHandlers = {
|
|
451
|
+
public: {
|
|
452
|
+
ping: async (req: any, res: any) => {
|
|
453
|
+
res.respond(200, { message: "pong" });
|
|
454
|
+
},
|
|
455
|
+
protected: async (req: any, res: any) => {
|
|
456
|
+
// Middleware has already validated auth, so we only handle success case
|
|
457
|
+
res.respond(200, {
|
|
458
|
+
message: "protected content",
|
|
459
|
+
user: req.ctx?.user || "unknown"
|
|
460
|
+
});
|
|
461
|
+
},
|
|
462
|
+
context: async (req: any, res: any) => {
|
|
463
|
+
res.respond(200, {
|
|
464
|
+
message: "context test",
|
|
465
|
+
contextData: req.ctx?.middlewareData || "default"
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
};
|
|
454
470
|
|
|
455
|
-
|
|
456
|
-
|
|
471
|
+
// Generic middleware setup function
|
|
472
|
+
function setupMiddlewareApp(app: any, isHono: boolean) {
|
|
473
|
+
// Define middleware functions
|
|
474
|
+
const loggingMiddleware = isHono ?
|
|
475
|
+
async (req: any, res: any, next: any, endpointInfo: any) => {
|
|
476
|
+
console.log(`[Test Hono] ${req.method} ${req.path} - Domain: ${endpointInfo.domain}, Route: ${endpointInfo.routeKey}`);
|
|
477
|
+
await next();
|
|
478
|
+
} :
|
|
479
|
+
(req: express.Request, res: express.Response, next: express.NextFunction, endpointInfo: any) => {
|
|
457
480
|
console.log(`[Test] ${req.method} ${req.path} - Domain: ${endpointInfo.domain}, Route: ${endpointInfo.routeKey}`);
|
|
458
481
|
next();
|
|
459
482
|
};
|
|
460
483
|
|
|
461
|
-
|
|
484
|
+
const contextMiddleware = isHono ?
|
|
485
|
+
async (req: any, res: any, next: any) => {
|
|
486
|
+
req.ctx = { ...req.ctx, middlewareData: "middleware-added-data" };
|
|
487
|
+
await next();
|
|
488
|
+
} :
|
|
489
|
+
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
462
490
|
(req as any).ctx = { middlewareData: "middleware-added-data" };
|
|
463
491
|
next();
|
|
464
492
|
};
|
|
465
493
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
494
|
+
const authMiddleware = isHono ?
|
|
495
|
+
async (req: any, res: any, next: any, endpointInfo: any) => {
|
|
496
|
+
// Only apply auth checks to protected routes
|
|
497
|
+
if (endpointInfo.domain === 'public' && endpointInfo.routeKey === 'protected') {
|
|
498
|
+
const authHeader = req.headers?.authorization;
|
|
499
|
+
if (!authHeader) {
|
|
500
|
+
(res as any).respond(401, { error: "No authorization header" });
|
|
501
|
+
} else if (authHeader === 'Bearer valid-token') {
|
|
502
|
+
req.ctx = { ...req.ctx, user: 'testuser' };
|
|
503
|
+
await next();
|
|
504
|
+
} else {
|
|
505
|
+
(res as any).respond(403, { error: "Forbidden" });
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
await next();
|
|
470
509
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
res.respond(200, {
|
|
484
|
-
message: "protected content",
|
|
485
|
-
user: req.ctx.user
|
|
486
|
-
});
|
|
487
|
-
} else {
|
|
488
|
-
res.respond(401, { error: "No authorization header" });
|
|
489
|
-
}
|
|
490
|
-
},
|
|
491
|
-
context: async (req: any, res: any) => {
|
|
492
|
-
res.respond(200, {
|
|
493
|
-
message: "context test",
|
|
494
|
-
contextData: req.ctx?.middlewareData || "default"
|
|
495
|
-
});
|
|
510
|
+
} :
|
|
511
|
+
(req: any, res: any, next: any, endpointInfo: any) => {
|
|
512
|
+
// Only apply auth checks to protected routes
|
|
513
|
+
if (endpointInfo.domain === 'public' && endpointInfo.routeKey === 'protected') {
|
|
514
|
+
const authHeader = req.headers?.authorization;
|
|
515
|
+
if (!authHeader) {
|
|
516
|
+
(res as any).respond(401, { error: "No authorization header" });
|
|
517
|
+
} else if (authHeader === 'Bearer valid-token') {
|
|
518
|
+
req.ctx = { ...req.ctx, user: 'testuser' };
|
|
519
|
+
next();
|
|
520
|
+
} else {
|
|
521
|
+
(res as any).respond(403, { error: "Forbidden" });
|
|
496
522
|
}
|
|
523
|
+
} else {
|
|
524
|
+
next();
|
|
497
525
|
}
|
|
498
|
-
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// Register handlers with middleware
|
|
529
|
+
if (isHono) {
|
|
530
|
+
const hndl = CreateTypedHonoHandlerWithContext<Ctx>();
|
|
531
|
+
hndl(app, MiddlewareTestApiDefinition, middlewareTestHandlers, [
|
|
532
|
+
loggingMiddleware,
|
|
533
|
+
contextMiddleware,
|
|
534
|
+
authMiddleware
|
|
535
|
+
]);
|
|
536
|
+
} else {
|
|
537
|
+
RegisterHandlers(app, MiddlewareTestApiDefinition, middlewareTestHandlers, [
|
|
499
538
|
loggingMiddleware,
|
|
500
539
|
contextMiddleware,
|
|
501
540
|
authMiddleware
|
|
502
541
|
]);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Middleware test servers
|
|
546
|
+
async function startMiddlewareExpressServer(): Promise<void> {
|
|
547
|
+
return new Promise((resolve) => {
|
|
548
|
+
const app = express();
|
|
549
|
+
app.use(express.json());
|
|
550
|
+
|
|
551
|
+
setupMiddlewareApp(app, false);
|
|
503
552
|
|
|
504
553
|
middlewareExpressServer = app.listen(MIDDLEWARE_EXPRESS_PORT, () => {
|
|
505
554
|
resolve();
|
|
@@ -511,55 +560,7 @@ async function startMiddlewareHonoServer(): Promise<void> {
|
|
|
511
560
|
return new Promise((resolve) => {
|
|
512
561
|
const app = new Hono();
|
|
513
562
|
|
|
514
|
-
|
|
515
|
-
const loggingMiddleware = async (req: any, res: any, next: any, endpointInfo: any) => {
|
|
516
|
-
console.log(`[Test Hono] ${req.method} ${req.path} - Domain: ${endpointInfo.domain}, Route: ${endpointInfo.routeKey}`);
|
|
517
|
-
await next();
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
const contextMiddleware = async (req: any, res: any, next: any) => {
|
|
521
|
-
req.ctx = { ...req.ctx, middlewareData: "middleware-added-data" };
|
|
522
|
-
await next();
|
|
523
|
-
};
|
|
524
|
-
|
|
525
|
-
const authMiddleware: EndpointMiddlewareCtx<Ctx> = async (req, res, next) => {
|
|
526
|
-
const authHeader = req.headers?.authorization;
|
|
527
|
-
if (authHeader === 'Bearer valid-token') {
|
|
528
|
-
req.ctx = { ...req.ctx, user: 'testuser' };
|
|
529
|
-
}
|
|
530
|
-
await next();
|
|
531
|
-
};
|
|
532
|
-
|
|
533
|
-
const hdnl = CreateTypedHonoHandlerWithContext<Ctx>()
|
|
534
|
-
// Register handlers with middleware
|
|
535
|
-
hdnl(app, MiddlewareTestApiDefinition, {
|
|
536
|
-
public: {
|
|
537
|
-
ping: async (req: any, res: any) => {
|
|
538
|
-
res.respond(200, { message: "pong" });
|
|
539
|
-
},
|
|
540
|
-
protected: async (req, res) => {
|
|
541
|
-
// Check if user is authenticated via context
|
|
542
|
-
if (req.ctx && req.ctx.user) {
|
|
543
|
-
res.respond(200, {
|
|
544
|
-
message: "protected content",
|
|
545
|
-
user: req.ctx.user
|
|
546
|
-
});
|
|
547
|
-
} else {
|
|
548
|
-
res.respond(401, { error: "No authorization header" });
|
|
549
|
-
}
|
|
550
|
-
},
|
|
551
|
-
context: async (req: any, res: any) => {
|
|
552
|
-
res.respond(200, {
|
|
553
|
-
message: "context test",
|
|
554
|
-
contextData: req.ctx?.middlewareData || "default"
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}, [
|
|
559
|
-
loggingMiddleware,
|
|
560
|
-
contextMiddleware,
|
|
561
|
-
authMiddleware
|
|
562
|
-
]);
|
|
563
|
+
setupMiddlewareApp(app, true);
|
|
563
564
|
|
|
564
565
|
// Create HTTP server from Hono app
|
|
565
566
|
const server = app.fetch;
|