@shware/http 2.2.2 → 2.2.3

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.
@@ -1,483 +0,0 @@
1
- "use strict";
2
-
3
- // src/hono/__tests__/authorizer.test.ts
4
- var import_hono = require("hono");
5
- var import_request_id = require("hono/request-id");
6
- var import_authorizer = require("../authorizer.cjs");
7
- var import_handler = require("../handler.cjs");
8
- describe("authorizer", () => {
9
- let app;
10
- beforeEach(() => {
11
- app = new import_hono.Hono();
12
- app.use((0, import_request_id.requestId)());
13
- app.onError(import_handler.errorHandler);
14
- });
15
- describe("Basic functionality", () => {
16
- it("should allow all requests when no rules are defined", async () => {
17
- const auth = {
18
- isAuthenticated: jest.fn().mockResolvedValue(true)
19
- };
20
- app.use((0, import_authorizer.authorizer)({ auth }));
21
- app.get("/test", (c) => c.text("OK"));
22
- const res = await app.request("/test");
23
- expect(res.status).toBe(200);
24
- expect(auth.isAuthenticated).not.toHaveBeenCalled();
25
- });
26
- it("should allow requests when rules match and authentication passes", async () => {
27
- const auth = {
28
- isAuthenticated: jest.fn().mockResolvedValue(true)
29
- };
30
- app.use((0, import_authorizer.authorizer)({ auth, rules: [{ path: "/protected", methods: ["GET"] }] }));
31
- app.get("/protected", (c) => c.text("Protected content"));
32
- const res = await app.request("/protected");
33
- expect(res.status).toBe(200);
34
- expect(await res.text()).toBe("Protected content");
35
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(1);
36
- });
37
- it("should reject requests when rules match but authentication fails", async () => {
38
- const auth = {
39
- isAuthenticated: jest.fn().mockResolvedValue(false)
40
- };
41
- app.use((0, import_authorizer.authorizer)({ auth, rules: [{ path: "/protected", methods: ["GET"] }] }));
42
- app.get("/protected", (c) => c.text("Protected content"));
43
- const res = await app.request("/protected");
44
- expect(res.status).toBe(401);
45
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(1);
46
- });
47
- it("should support custom error messages", async () => {
48
- const auth = {
49
- isAuthenticated: jest.fn().mockResolvedValue(false)
50
- };
51
- const customMessage = "Please login first";
52
- app.use(
53
- (0, import_authorizer.authorizer)({
54
- auth,
55
- errorMessage: customMessage,
56
- rules: [{ path: "/protected", methods: ["GET"] }]
57
- })
58
- );
59
- app.get("/protected", (c) => c.text("Protected content"));
60
- const res = await app.request("/protected");
61
- expect(res.status).toBe(401);
62
- });
63
- });
64
- describe("HTTP methods", () => {
65
- it("should only protect specified HTTP methods", async () => {
66
- const auth = {
67
- isAuthenticated: jest.fn().mockResolvedValue(false)
68
- };
69
- app.use(
70
- (0, import_authorizer.authorizer)({
71
- auth,
72
- rules: [{ path: "/api/users", methods: ["POST", "DELETE"] }]
73
- })
74
- );
75
- app.get("/api/users", (c) => c.text("GET allowed"));
76
- app.post("/api/users", (c) => c.text("POST protected"));
77
- app.delete("/api/users", (c) => c.text("DELETE protected"));
78
- app.put("/api/users", (c) => c.text("PUT allowed"));
79
- const getRes = await app.request("/api/users", { method: "GET" });
80
- expect(getRes.status).toBe(200);
81
- expect(await getRes.text()).toBe("GET allowed");
82
- const postRes = await app.request("/api/users", { method: "POST" });
83
- expect(postRes.status).toBe(401);
84
- const deleteRes = await app.request("/api/users", { method: "DELETE" });
85
- expect(deleteRes.status).toBe(401);
86
- const putRes = await app.request("/api/users", { method: "PUT" });
87
- expect(putRes.status).toBe(200);
88
- expect(await putRes.text()).toBe("PUT allowed");
89
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(2);
90
- });
91
- it("should protect all methods when methods not specified", async () => {
92
- const auth = {
93
- isAuthenticated: jest.fn().mockResolvedValue(false)
94
- };
95
- app.use(
96
- (0, import_authorizer.authorizer)({
97
- auth,
98
- rules: [{ path: "/api/admin" }]
99
- // methods not specified
100
- })
101
- );
102
- app.get("/api/admin", (c) => c.text("GET"));
103
- app.post("/api/admin", (c) => c.text("POST"));
104
- app.put("/api/admin", (c) => c.text("PUT"));
105
- app.delete("/api/admin", (c) => c.text("DELETE"));
106
- const methods = ["GET", "POST", "PUT", "DELETE"];
107
- for (const method of methods) {
108
- const res = await app.request("/api/admin", { method });
109
- expect(res.status).toBe(401);
110
- }
111
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(4);
112
- });
113
- it("should always allow OPTIONS requests", async () => {
114
- const auth = {
115
- isAuthenticated: jest.fn().mockResolvedValue(false)
116
- };
117
- app.use(
118
- (0, import_authorizer.authorizer)({
119
- auth,
120
- rules: [{ path: "/api/*" }]
121
- // protect all /api/* paths
122
- })
123
- );
124
- app.options("/api/test", (c) => c.text("OPTIONS OK"));
125
- const res = await app.request("/api/test", { method: "OPTIONS" });
126
- expect(res.status).toBe(200);
127
- expect(await res.text()).toBe("OPTIONS OK");
128
- expect(auth.isAuthenticated).not.toHaveBeenCalled();
129
- });
130
- });
131
- describe("Path matching", () => {
132
- it("should support exact path matching", async () => {
133
- const auth = {
134
- isAuthenticated: jest.fn().mockResolvedValue(false)
135
- };
136
- app.use(
137
- (0, import_authorizer.authorizer)({
138
- auth,
139
- rules: [{ path: "/api/users" }]
140
- })
141
- );
142
- app.get("/api/users", (c) => c.text("Exact"));
143
- app.get("/api/users/123", (c) => c.text("With ID"));
144
- app.get("/api", (c) => c.text("Parent"));
145
- const exactRes = await app.request("/api/users");
146
- expect(exactRes.status).toBe(401);
147
- const idRes = await app.request("/api/users/123");
148
- expect(idRes.status).toBe(200);
149
- expect(await idRes.text()).toBe("With ID");
150
- const parentRes = await app.request("/api");
151
- expect(parentRes.status).toBe(200);
152
- expect(await parentRes.text()).toBe("Parent");
153
- });
154
- it("should support wildcard path matching", async () => {
155
- const auth = {
156
- isAuthenticated: jest.fn().mockResolvedValue(false)
157
- };
158
- app.use(
159
- (0, import_authorizer.authorizer)({
160
- auth,
161
- rules: [{ path: "/api/*" }, { path: "/admin/:id" }]
162
- })
163
- );
164
- app.get("/api/users", (c) => c.text("API Users"));
165
- app.get("/api/posts/123", (c) => c.text("API Post"));
166
- app.get("/admin/123", (c) => c.text("Admin"));
167
- app.get("/public", (c) => c.text("Public"));
168
- const apiUsersRes = await app.request("/api/users");
169
- expect(apiUsersRes.status).toBe(401);
170
- const apiPostRes = await app.request("/api/posts/123");
171
- expect(apiPostRes.status).toBe(401);
172
- const adminRes = await app.request("/admin/123");
173
- expect(adminRes.status).toBe(401);
174
- const publicRes = await app.request("/public");
175
- expect(publicRes.status).toBe(200);
176
- expect(await publicRes.text()).toBe("Public");
177
- });
178
- it("should support pattern-like path matching", async () => {
179
- const auth = {
180
- isAuthenticated: jest.fn().mockResolvedValue(false)
181
- };
182
- app.use(
183
- (0, import_authorizer.authorizer)({
184
- auth,
185
- rules: [
186
- { path: "/api/v1/*" },
187
- { path: "/api/v2/*" },
188
- { path: "/data.json" },
189
- { path: "/config.json" }
190
- ]
191
- })
192
- );
193
- app.get("/api/v1/users", (c) => c.text("V1"));
194
- app.get("/api/v2/users", (c) => c.text("V2"));
195
- app.get("/api/v3/users", (c) => c.text("V3"));
196
- app.get("/data.json", (c) => c.text("JSON"));
197
- app.get("/config.json", (c) => c.text("Config JSON"));
198
- app.get("/data.xml", (c) => c.text("XML"));
199
- const v1Res = await app.request("/api/v1/users");
200
- expect(v1Res.status).toBe(401);
201
- const v2Res = await app.request("/api/v2/users");
202
- expect(v2Res.status).toBe(401);
203
- const v3Res = await app.request("/api/v3/users");
204
- expect(v3Res.status).toBe(200);
205
- const jsonRes = await app.request("/data.json");
206
- expect(jsonRes.status).toBe(401);
207
- const configJsonRes = await app.request("/config.json");
208
- expect(configJsonRes.status).toBe(401);
209
- const xmlRes = await app.request("/data.xml");
210
- expect(xmlRes.status).toBe(200);
211
- });
212
- });
213
- describe("Authentication function", () => {
214
- it("should pass Request object correctly to auth function", async () => {
215
- const auth = {
216
- isAuthenticated: jest.fn().mockImplementation(async (request) => {
217
- const authHeader = request.headers.get("Authorization");
218
- return authHeader === "Bearer valid-token";
219
- })
220
- };
221
- app.use(
222
- (0, import_authorizer.authorizer)({
223
- auth,
224
- rules: [{ path: "/protected" }]
225
- })
226
- );
227
- app.get("/protected", (c) => c.text("Protected"));
228
- const noTokenRes = await app.request("/protected");
229
- expect(noTokenRes.status).toBe(401);
230
- const invalidTokenRes = await app.request("/protected", {
231
- headers: { Authorization: "Bearer invalid-token" }
232
- });
233
- expect(invalidTokenRes.status).toBe(401);
234
- const validTokenRes = await app.request("/protected", {
235
- headers: { Authorization: "Bearer valid-token" }
236
- });
237
- expect(validTokenRes.status).toBe(200);
238
- expect(await validTokenRes.text()).toBe("Protected");
239
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(3);
240
- });
241
- it("should handle exceptions thrown by auth function", async () => {
242
- const auth = {
243
- isAuthenticated: jest.fn().mockRejectedValue(new Error("Auth service error"))
244
- };
245
- app.use(
246
- (0, import_authorizer.authorizer)({
247
- auth,
248
- rules: [{ path: "/protected" }]
249
- })
250
- );
251
- app.get("/protected", (c) => c.text("Protected"));
252
- const res = await app.request("/protected");
253
- expect(res.status).toBe(500);
254
- });
255
- it("should support cookie-based authentication", async () => {
256
- const auth = {
257
- isAuthenticated: jest.fn().mockImplementation(async (request) => {
258
- const cookie = request.headers.get("Cookie");
259
- return cookie?.includes("session=valid-session");
260
- })
261
- };
262
- app.use(
263
- (0, import_authorizer.authorizer)({
264
- auth,
265
- rules: [{ path: "/dashboard" }]
266
- })
267
- );
268
- app.get("/dashboard", (c) => c.text("Dashboard"));
269
- const noCookieRes = await app.request("/dashboard");
270
- expect(noCookieRes.status).toBe(401);
271
- const validCookieRes = await app.request("/dashboard", {
272
- headers: { Cookie: "session=valid-session; other=value" }
273
- });
274
- expect(validCookieRes.status).toBe(200);
275
- expect(await validCookieRes.text()).toBe("Dashboard");
276
- });
277
- it("should support query parameter authentication", async () => {
278
- const auth = {
279
- isAuthenticated: jest.fn().mockImplementation(async (request) => {
280
- const url = new URL(request.url);
281
- return url.searchParams.get("api_key") === "valid-key";
282
- })
283
- };
284
- app.use(
285
- (0, import_authorizer.authorizer)({
286
- auth,
287
- rules: [{ path: "/api/data" }]
288
- })
289
- );
290
- app.get("/api/data", (c) => c.text("Data"));
291
- const noKeyRes = await app.request("/api/data");
292
- expect(noKeyRes.status).toBe(401);
293
- const invalidKeyRes = await app.request("/api/data?api_key=invalid-key");
294
- expect(invalidKeyRes.status).toBe(401);
295
- const validKeyRes = await app.request("/api/data?api_key=valid-key");
296
- expect(validKeyRes.status).toBe(200);
297
- expect(await validKeyRes.text()).toBe("Data");
298
- });
299
- });
300
- describe("Multiple rules", () => {
301
- it("should support multiple rule combinations", async () => {
302
- const auth = {
303
- isAuthenticated: jest.fn().mockResolvedValue(false)
304
- };
305
- app.use(
306
- (0, import_authorizer.authorizer)({
307
- auth,
308
- rules: [
309
- { path: "/api/users", methods: ["POST", "PUT", "DELETE"] },
310
- { path: "/api/admin/*" },
311
- { path: "/api/reports", methods: ["GET"] },
312
- { path: "/webhook/*", methods: ["POST"] }
313
- ]
314
- })
315
- );
316
- app.get("/api/users", (c) => c.text("GET users"));
317
- app.post("/api/users", (c) => c.text("POST users"));
318
- app.get("/api/admin/settings", (c) => c.text("Admin settings"));
319
- app.get("/api/reports", (c) => c.text("Reports"));
320
- app.post("/webhook/github", (c) => c.text("Webhook"));
321
- app.get("/public", (c) => c.text("Public"));
322
- const getUsersRes = await app.request("/api/users");
323
- expect(getUsersRes.status).toBe(200);
324
- const postUsersRes = await app.request("/api/users", { method: "POST" });
325
- expect(postUsersRes.status).toBe(401);
326
- const adminRes = await app.request("/api/admin/settings");
327
- expect(adminRes.status).toBe(401);
328
- const reportsRes = await app.request("/api/reports");
329
- expect(reportsRes.status).toBe(401);
330
- const webhookRes = await app.request("/webhook/github", { method: "POST" });
331
- expect(webhookRes.status).toBe(401);
332
- const publicRes = await app.request("/public");
333
- expect(publicRes.status).toBe(200);
334
- });
335
- it("should handle overlapping rules correctly", async () => {
336
- const auth = {
337
- isAuthenticated: jest.fn().mockResolvedValue(true)
338
- };
339
- app.use(
340
- (0, import_authorizer.authorizer)({
341
- auth,
342
- rules: [
343
- { path: "/api/*" },
344
- // protect all /api/* paths
345
- { path: "/api/public", methods: ["GET"] }
346
- // also protect GET /api/public
347
- ]
348
- })
349
- );
350
- app.get("/api/public", (c) => c.text("Public API"));
351
- app.post("/api/public", (c) => c.text("POST Public API"));
352
- const getRes = await app.request("/api/public");
353
- expect(getRes.status).toBe(200);
354
- const postRes = await app.request("/api/public", { method: "POST" });
355
- expect(postRes.status).toBe(200);
356
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(2);
357
- });
358
- });
359
- describe("Edge cases", () => {
360
- it("should allow all requests with empty rules array", async () => {
361
- const auth = {
362
- isAuthenticated: jest.fn().mockResolvedValue(false)
363
- };
364
- app.use((0, import_authorizer.authorizer)({ auth, rules: [] }));
365
- app.get("/any/path", (c) => c.text("OK"));
366
- const res = await app.request("/any/path");
367
- expect(res.status).toBe(200);
368
- expect(auth.isAuthenticated).not.toHaveBeenCalled();
369
- });
370
- it("should handle special characters in paths", async () => {
371
- const auth = {
372
- isAuthenticated: jest.fn().mockResolvedValue(false)
373
- };
374
- app.use(
375
- (0, import_authorizer.authorizer)({
376
- auth,
377
- rules: [
378
- { path: "/api/user@email.com" },
379
- { path: "/files/*.pdf" },
380
- { path: "/path-with-dash" },
381
- { path: "/path_with_underscore" }
382
- ]
383
- })
384
- );
385
- app.get("/api/user@email.com", (c) => c.text("Email"));
386
- app.get("/files/document.pdf", (c) => c.text("PDF"));
387
- app.get("/path-with-dash", (c) => c.text("Dash"));
388
- app.get("/path_with_underscore", (c) => c.text("Underscore"));
389
- const emailRes = await app.request("/api/user@email.com");
390
- expect(emailRes.status).toBe(401);
391
- const pdfRes = await app.request("/files/document.pdf");
392
- expect(pdfRes.status).toBe(401);
393
- const dashRes = await app.request("/path-with-dash");
394
- expect(dashRes.status).toBe(401);
395
- const underscoreRes = await app.request("/path_with_underscore");
396
- expect(underscoreRes.status).toBe(401);
397
- });
398
- it("should handle URLs with query parameters and fragments", async () => {
399
- const auth = {
400
- isAuthenticated: jest.fn().mockResolvedValue(false)
401
- };
402
- app.use(
403
- (0, import_authorizer.authorizer)({
404
- auth,
405
- rules: [{ path: "/api/search" }]
406
- })
407
- );
408
- app.get("/api/search", (c) => c.text("Search"));
409
- const res = await app.request("/api/search?q=test&page=1#results");
410
- expect(res.status).toBe(401);
411
- expect(auth.isAuthenticated).toHaveBeenCalledTimes(1);
412
- });
413
- it("should handle root path correctly", async () => {
414
- const auth = {
415
- isAuthenticated: jest.fn().mockResolvedValue(false)
416
- };
417
- app.use(
418
- (0, import_authorizer.authorizer)({
419
- auth,
420
- rules: [{ path: "/" }]
421
- })
422
- );
423
- app.get("/", (c) => c.text("Home"));
424
- app.get("/other", (c) => c.text("Other"));
425
- const rootRes = await app.request("/");
426
- expect(rootRes.status).toBe(401);
427
- const otherRes = await app.request("/other");
428
- expect(otherRes.status).toBe(200);
429
- });
430
- it("should handle trailing slashes as different paths", async () => {
431
- const auth = {
432
- isAuthenticated: jest.fn().mockResolvedValue(false)
433
- };
434
- app.use(
435
- (0, import_authorizer.authorizer)({
436
- auth,
437
- rules: [{ path: "/api/users" }, { path: "/api/users/" }]
438
- })
439
- );
440
- app.get("/api/users", (c) => c.text("Users"));
441
- app.get("/api/users/", (c) => c.text("Users with slash"));
442
- const withoutSlash = await app.request("/api/users");
443
- expect(withoutSlash.status).toBe(401);
444
- const withSlash = await app.request("/api/users/");
445
- expect(withSlash.status).toBe(401);
446
- });
447
- });
448
- describe("Complex authentication scenarios", () => {
449
- it("should support role-based authentication", async () => {
450
- const auth = {
451
- isAuthenticated: jest.fn().mockImplementation(async (request) => {
452
- const authHeader = request.headers.get("Authorization");
453
- const url = new URL(request.url);
454
- if (url.pathname.startsWith("/admin")) {
455
- return authHeader === "Bearer admin-token";
456
- }
457
- return authHeader?.startsWith("Bearer ");
458
- })
459
- };
460
- app.use(
461
- (0, import_authorizer.authorizer)({
462
- auth,
463
- rules: [{ path: "/admin/*" }, { path: "/api/*" }]
464
- })
465
- );
466
- app.get("/admin/users", (c) => c.text("Admin Users"));
467
- app.get("/api/data", (c) => c.text("API Data"));
468
- const adminWithRegularToken = await app.request("/admin/users", {
469
- headers: { Authorization: "Bearer user-token" }
470
- });
471
- expect(adminWithRegularToken.status).toBe(401);
472
- const adminWithAdminToken = await app.request("/admin/users", {
473
- headers: { Authorization: "Bearer admin-token" }
474
- });
475
- expect(adminWithAdminToken.status).toBe(200);
476
- const apiWithUserToken = await app.request("/api/data", {
477
- headers: { Authorization: "Bearer user-token" }
478
- });
479
- expect(apiWithUserToken.status).toBe(200);
480
- });
481
- });
482
- });
483
- //# sourceMappingURL=authorizer.test.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/hono/__tests__/authorizer.test.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport { requestId } from 'hono/request-id';\nimport { type AuthorizerConfig, authorizer } from '../authorizer';\nimport { type Env, errorHandler } from '../handler';\n\ndescribe('authorizer', () => {\n let app: Hono<Env>;\n\n beforeEach(() => {\n app = new Hono<Env>();\n app.use(requestId());\n app.onError(errorHandler);\n });\n\n describe('Basic functionality', () => {\n it('should allow all requests when no rules are defined', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(true),\n };\n\n app.use(authorizer({ auth }));\n app.get('/test', (c) => c.text('OK'));\n\n const res = await app.request('/test');\n expect(res.status).toBe(200);\n expect(auth.isAuthenticated).not.toHaveBeenCalled();\n });\n\n it('should allow requests when rules match and authentication passes', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(true),\n };\n\n app.use(authorizer({ auth, rules: [{ path: '/protected', methods: ['GET'] }] }));\n app.get('/protected', (c) => c.text('Protected content'));\n\n const res = await app.request('/protected');\n expect(res.status).toBe(200);\n expect(await res.text()).toBe('Protected content');\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(1);\n });\n\n it('should reject requests when rules match but authentication fails', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(authorizer({ auth, rules: [{ path: '/protected', methods: ['GET'] }] }));\n app.get('/protected', (c) => c.text('Protected content'));\n\n const res = await app.request('/protected');\n expect(res.status).toBe(401);\n // StatusError wraps the message, just verify status\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(1);\n });\n\n it('should support custom error messages', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n const customMessage = 'Please login first';\n\n app.use(\n authorizer({\n auth,\n errorMessage: customMessage,\n rules: [{ path: '/protected', methods: ['GET'] }],\n })\n );\n app.get('/protected', (c) => c.text('Protected content'));\n\n const res = await app.request('/protected');\n expect(res.status).toBe(401);\n // Error message is wrapped in StatusError, just verify status\n });\n });\n\n describe('HTTP methods', () => {\n it('should only protect specified HTTP methods', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/users', methods: ['POST', 'DELETE'] }],\n })\n );\n app.get('/api/users', (c) => c.text('GET allowed'));\n app.post('/api/users', (c) => c.text('POST protected'));\n app.delete('/api/users', (c) => c.text('DELETE protected'));\n app.put('/api/users', (c) => c.text('PUT allowed'));\n\n // GET should pass (not protected)\n const getRes = await app.request('/api/users', { method: 'GET' });\n expect(getRes.status).toBe(200);\n expect(await getRes.text()).toBe('GET allowed');\n\n // POST should be rejected (protected and auth failed)\n const postRes = await app.request('/api/users', { method: 'POST' });\n expect(postRes.status).toBe(401);\n\n // DELETE should be rejected (protected and auth failed)\n const deleteRes = await app.request('/api/users', { method: 'DELETE' });\n expect(deleteRes.status).toBe(401);\n\n // PUT should pass (not protected)\n const putRes = await app.request('/api/users', { method: 'PUT' });\n expect(putRes.status).toBe(200);\n expect(await putRes.text()).toBe('PUT allowed');\n\n // auth.isAuthenticated should only be called for POST and DELETE\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(2);\n });\n\n it('should protect all methods when methods not specified', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/admin' }], // methods not specified\n })\n );\n app.get('/api/admin', (c) => c.text('GET'));\n app.post('/api/admin', (c) => c.text('POST'));\n app.put('/api/admin', (c) => c.text('PUT'));\n app.delete('/api/admin', (c) => c.text('DELETE'));\n\n // All methods should be rejected\n const methods = ['GET', 'POST', 'PUT', 'DELETE'];\n for (const method of methods) {\n const res = await app.request('/api/admin', { method });\n expect(res.status).toBe(401);\n }\n\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(4);\n });\n\n it('should always allow OPTIONS requests', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/*' }], // protect all /api/* paths\n })\n );\n app.options('/api/test', (c) => c.text('OPTIONS OK'));\n\n const res = await app.request('/api/test', { method: 'OPTIONS' });\n expect(res.status).toBe(200);\n expect(await res.text()).toBe('OPTIONS OK');\n expect(auth.isAuthenticated).not.toHaveBeenCalled();\n });\n });\n\n describe('Path matching', () => {\n it('should support exact path matching', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/users' }],\n })\n );\n app.get('/api/users', (c) => c.text('Exact'));\n app.get('/api/users/123', (c) => c.text('With ID'));\n app.get('/api', (c) => c.text('Parent'));\n\n // Exact match path should be protected\n const exactRes = await app.request('/api/users');\n expect(exactRes.status).toBe(401);\n\n // Other paths should pass\n const idRes = await app.request('/api/users/123');\n expect(idRes.status).toBe(200);\n expect(await idRes.text()).toBe('With ID');\n\n const parentRes = await app.request('/api');\n expect(parentRes.status).toBe(200);\n expect(await parentRes.text()).toBe('Parent');\n });\n\n it('should support wildcard path matching', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/*' }, { path: '/admin/:id' }],\n })\n );\n app.get('/api/users', (c) => c.text('API Users'));\n app.get('/api/posts/123', (c) => c.text('API Post'));\n app.get('/admin/123', (c) => c.text('Admin'));\n app.get('/public', (c) => c.text('Public'));\n\n // All paths under /api/* should be protected\n const apiUsersRes = await app.request('/api/users');\n expect(apiUsersRes.status).toBe(401);\n\n const apiPostRes = await app.request('/api/posts/123');\n expect(apiPostRes.status).toBe(401);\n\n // /admin/:id should be protected\n const adminRes = await app.request('/admin/123');\n expect(adminRes.status).toBe(401);\n\n // /public should pass\n const publicRes = await app.request('/public');\n expect(publicRes.status).toBe(200);\n expect(await publicRes.text()).toBe('Public');\n });\n\n it('should support pattern-like path matching', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [\n { path: '/api/v1/*' },\n { path: '/api/v2/*' },\n { path: '/data.json' },\n { path: '/config.json' },\n ],\n })\n );\n app.get('/api/v1/users', (c) => c.text('V1'));\n app.get('/api/v2/users', (c) => c.text('V2'));\n app.get('/api/v3/users', (c) => c.text('V3'));\n app.get('/data.json', (c) => c.text('JSON'));\n app.get('/config.json', (c) => c.text('Config JSON'));\n app.get('/data.xml', (c) => c.text('XML'));\n\n // v1 and v2 should be protected\n const v1Res = await app.request('/api/v1/users');\n expect(v1Res.status).toBe(401);\n\n const v2Res = await app.request('/api/v2/users');\n expect(v2Res.status).toBe(401);\n\n // v3 should pass\n const v3Res = await app.request('/api/v3/users');\n expect(v3Res.status).toBe(200);\n\n // .json files should be protected\n const jsonRes = await app.request('/data.json');\n expect(jsonRes.status).toBe(401);\n\n const configJsonRes = await app.request('/config.json');\n expect(configJsonRes.status).toBe(401);\n\n // .xml files should pass\n const xmlRes = await app.request('/data.xml');\n expect(xmlRes.status).toBe(200);\n });\n });\n\n describe('Authentication function', () => {\n it('should pass Request object correctly to auth function', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockImplementation(async (request: Request) => {\n const authHeader = request.headers.get('Authorization');\n return authHeader === 'Bearer valid-token';\n }),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/protected' }],\n })\n );\n app.get('/protected', (c) => c.text('Protected'));\n\n // No token should fail\n const noTokenRes = await app.request('/protected');\n expect(noTokenRes.status).toBe(401);\n\n // Invalid token should fail\n const invalidTokenRes = await app.request('/protected', {\n headers: { Authorization: 'Bearer invalid-token' },\n });\n expect(invalidTokenRes.status).toBe(401);\n\n // Valid token should succeed\n const validTokenRes = await app.request('/protected', {\n headers: { Authorization: 'Bearer valid-token' },\n });\n expect(validTokenRes.status).toBe(200);\n expect(await validTokenRes.text()).toBe('Protected');\n\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(3);\n });\n\n it('should handle exceptions thrown by auth function', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockRejectedValue(new Error('Auth service error')),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/protected' }],\n })\n );\n app.get('/protected', (c) => c.text('Protected'));\n\n const res = await app.request('/protected');\n expect(res.status).toBe(500);\n // Error details are wrapped, just verify status\n });\n\n it('should support cookie-based authentication', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockImplementation(async (request: Request) => {\n const cookie = request.headers.get('Cookie');\n return cookie?.includes('session=valid-session');\n }),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/dashboard' }],\n })\n );\n app.get('/dashboard', (c) => c.text('Dashboard'));\n\n // No cookie should fail\n const noCookieRes = await app.request('/dashboard');\n expect(noCookieRes.status).toBe(401);\n\n // Valid cookie should succeed\n const validCookieRes = await app.request('/dashboard', {\n headers: { Cookie: 'session=valid-session; other=value' },\n });\n expect(validCookieRes.status).toBe(200);\n expect(await validCookieRes.text()).toBe('Dashboard');\n });\n\n it('should support query parameter authentication', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockImplementation(async (request: Request) => {\n const url = new URL(request.url);\n return url.searchParams.get('api_key') === 'valid-key';\n }),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/data' }],\n })\n );\n app.get('/api/data', (c) => c.text('Data'));\n\n // No API key should fail\n const noKeyRes = await app.request('/api/data');\n expect(noKeyRes.status).toBe(401);\n\n // Invalid API key should fail\n const invalidKeyRes = await app.request('/api/data?api_key=invalid-key');\n expect(invalidKeyRes.status).toBe(401);\n\n // Valid API key should succeed\n const validKeyRes = await app.request('/api/data?api_key=valid-key');\n expect(validKeyRes.status).toBe(200);\n expect(await validKeyRes.text()).toBe('Data');\n });\n });\n\n describe('Multiple rules', () => {\n it('should support multiple rule combinations', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [\n { path: '/api/users', methods: ['POST', 'PUT', 'DELETE'] },\n { path: '/api/admin/*' },\n { path: '/api/reports', methods: ['GET'] },\n { path: '/webhook/*', methods: ['POST'] },\n ],\n })\n );\n\n // Setup routes\n app.get('/api/users', (c) => c.text('GET users'));\n app.post('/api/users', (c) => c.text('POST users'));\n app.get('/api/admin/settings', (c) => c.text('Admin settings'));\n app.get('/api/reports', (c) => c.text('Reports'));\n app.post('/webhook/github', (c) => c.text('Webhook'));\n app.get('/public', (c) => c.text('Public'));\n\n // GET /api/users should pass (not protected)\n const getUsersRes = await app.request('/api/users');\n expect(getUsersRes.status).toBe(200);\n\n // POST /api/users should be rejected (protected)\n const postUsersRes = await app.request('/api/users', { method: 'POST' });\n expect(postUsersRes.status).toBe(401);\n\n // GET /api/admin/settings should be rejected (all methods protected)\n const adminRes = await app.request('/api/admin/settings');\n expect(adminRes.status).toBe(401);\n\n // GET /api/reports should be rejected (GET method protected)\n const reportsRes = await app.request('/api/reports');\n expect(reportsRes.status).toBe(401);\n\n // POST /webhook/github should be rejected (POST method protected)\n const webhookRes = await app.request('/webhook/github', { method: 'POST' });\n expect(webhookRes.status).toBe(401);\n\n // GET /public should pass (not protected)\n const publicRes = await app.request('/public');\n expect(publicRes.status).toBe(200);\n });\n\n it('should handle overlapping rules correctly', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(true),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [\n { path: '/api/*' }, // protect all /api/* paths\n { path: '/api/public', methods: ['GET'] }, // also protect GET /api/public\n ],\n })\n );\n app.get('/api/public', (c) => c.text('Public API'));\n app.post('/api/public', (c) => c.text('POST Public API'));\n\n // Both rules match, but auth passes, so should succeed\n const getRes = await app.request('/api/public');\n expect(getRes.status).toBe(200);\n\n const postRes = await app.request('/api/public', { method: 'POST' });\n expect(postRes.status).toBe(200);\n\n // Auth function should be called twice\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(2);\n });\n });\n\n describe('Edge cases', () => {\n it('should allow all requests with empty rules array', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(authorizer({ auth, rules: [] }));\n app.get('/any/path', (c) => c.text('OK'));\n\n const res = await app.request('/any/path');\n expect(res.status).toBe(200);\n expect(auth.isAuthenticated).not.toHaveBeenCalled();\n });\n\n it('should handle special characters in paths', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [\n { path: '/api/user@email.com' },\n { path: '/files/*.pdf' },\n { path: '/path-with-dash' },\n { path: '/path_with_underscore' },\n ],\n })\n );\n\n app.get('/api/user@email.com', (c) => c.text('Email'));\n app.get('/files/document.pdf', (c) => c.text('PDF'));\n app.get('/path-with-dash', (c) => c.text('Dash'));\n app.get('/path_with_underscore', (c) => c.text('Underscore'));\n\n // All special character paths should be matched and protected correctly\n const emailRes = await app.request('/api/user@email.com');\n expect(emailRes.status).toBe(401);\n\n const pdfRes = await app.request('/files/document.pdf');\n expect(pdfRes.status).toBe(401);\n\n const dashRes = await app.request('/path-with-dash');\n expect(dashRes.status).toBe(401);\n\n const underscoreRes = await app.request('/path_with_underscore');\n expect(underscoreRes.status).toBe(401);\n });\n\n it('should handle URLs with query parameters and fragments', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/search' }],\n })\n );\n app.get('/api/search', (c) => c.text('Search'));\n\n // Requests with query parameters should be matched correctly\n const res = await app.request('/api/search?q=test&page=1#results');\n expect(res.status).toBe(401);\n expect(auth.isAuthenticated).toHaveBeenCalledTimes(1);\n });\n\n it('should handle root path correctly', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/' }],\n })\n );\n app.get('/', (c) => c.text('Home'));\n app.get('/other', (c) => c.text('Other'));\n\n // Root path should be protected\n const rootRes = await app.request('/');\n expect(rootRes.status).toBe(401);\n\n // Other paths should pass\n const otherRes = await app.request('/other');\n expect(otherRes.status).toBe(200);\n });\n\n it('should handle trailing slashes as different paths', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockResolvedValue(false),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/api/users' }, { path: '/api/users/' }],\n })\n );\n app.get('/api/users', (c) => c.text('Users'));\n app.get('/api/users/', (c) => c.text('Users with slash'));\n\n // Both paths should be protected when explicitly defined\n const withoutSlash = await app.request('/api/users');\n expect(withoutSlash.status).toBe(401);\n\n const withSlash = await app.request('/api/users/');\n expect(withSlash.status).toBe(401);\n });\n });\n\n describe('Complex authentication scenarios', () => {\n it('should support role-based authentication', async () => {\n const auth: AuthorizerConfig['auth'] = {\n isAuthenticated: jest.fn().mockImplementation(async (request: Request) => {\n const authHeader = request.headers.get('Authorization');\n const url = new URL(request.url);\n\n // Admin endpoints require admin token\n if (url.pathname.startsWith('/admin')) {\n return authHeader === 'Bearer admin-token';\n }\n\n // Regular endpoints accept any valid token\n return authHeader?.startsWith('Bearer ');\n }),\n };\n\n app.use(\n authorizer({\n auth,\n rules: [{ path: '/admin/*' }, { path: '/api/*' }],\n })\n );\n\n app.get('/admin/users', (c) => c.text('Admin Users'));\n app.get('/api/data', (c) => c.text('API Data'));\n\n // Admin endpoint with regular token should fail\n const adminWithRegularToken = await app.request('/admin/users', {\n headers: { Authorization: 'Bearer user-token' },\n });\n expect(adminWithRegularToken.status).toBe(401);\n\n // Admin endpoint with admin token should succeed\n const adminWithAdminToken = await app.request('/admin/users', {\n headers: { Authorization: 'Bearer admin-token' },\n });\n expect(adminWithAdminToken.status).toBe(200);\n\n // API endpoint with any token should succeed\n const apiWithUserToken = await app.request('/api/data', {\n headers: { Authorization: 'Bearer user-token' },\n });\n expect(apiWithUserToken.status).toBe(200);\n });\n });\n});\n"],"mappings":"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","names":[]}
@@ -1,2 +0,0 @@
1
-
2
- export { }
@@ -1,2 +0,0 @@
1
-
2
- export { }