@buenojs/bueno 0.8.0
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/.env.example +109 -0
- package/.github/workflows/ci.yml +31 -0
- package/LICENSE +21 -0
- package/README.md +892 -0
- package/architecture.md +652 -0
- package/bun.lock +70 -0
- package/dist/cli/index.js +3233 -0
- package/dist/index.js +9014 -0
- package/package.json +77 -0
- package/src/cache/index.ts +795 -0
- package/src/cli/ARCHITECTURE.md +837 -0
- package/src/cli/bin.ts +10 -0
- package/src/cli/commands/build.ts +425 -0
- package/src/cli/commands/dev.ts +248 -0
- package/src/cli/commands/generate.ts +541 -0
- package/src/cli/commands/help.ts +55 -0
- package/src/cli/commands/index.ts +112 -0
- package/src/cli/commands/migration.ts +355 -0
- package/src/cli/commands/new.ts +804 -0
- package/src/cli/commands/start.ts +208 -0
- package/src/cli/core/args.ts +283 -0
- package/src/cli/core/console.ts +349 -0
- package/src/cli/core/index.ts +60 -0
- package/src/cli/core/prompt.ts +424 -0
- package/src/cli/core/spinner.ts +265 -0
- package/src/cli/index.ts +135 -0
- package/src/cli/templates/deploy.ts +295 -0
- package/src/cli/templates/docker.ts +307 -0
- package/src/cli/templates/index.ts +24 -0
- package/src/cli/utils/fs.ts +428 -0
- package/src/cli/utils/index.ts +8 -0
- package/src/cli/utils/strings.ts +197 -0
- package/src/config/env.ts +408 -0
- package/src/config/index.ts +506 -0
- package/src/config/loader.ts +329 -0
- package/src/config/merge.ts +285 -0
- package/src/config/types.ts +320 -0
- package/src/config/validation.ts +441 -0
- package/src/container/forward-ref.ts +143 -0
- package/src/container/index.ts +386 -0
- package/src/context/index.ts +360 -0
- package/src/database/index.ts +1142 -0
- package/src/database/migrations/index.ts +371 -0
- package/src/database/schema/index.ts +619 -0
- package/src/frontend/api-routes.ts +640 -0
- package/src/frontend/bundler.ts +643 -0
- package/src/frontend/console-client.ts +419 -0
- package/src/frontend/console-stream.ts +587 -0
- package/src/frontend/dev-server.ts +846 -0
- package/src/frontend/file-router.ts +611 -0
- package/src/frontend/frameworks/index.ts +106 -0
- package/src/frontend/frameworks/react.ts +85 -0
- package/src/frontend/frameworks/solid.ts +104 -0
- package/src/frontend/frameworks/svelte.ts +110 -0
- package/src/frontend/frameworks/vue.ts +92 -0
- package/src/frontend/hmr-client.ts +663 -0
- package/src/frontend/hmr.ts +728 -0
- package/src/frontend/index.ts +342 -0
- package/src/frontend/islands.ts +552 -0
- package/src/frontend/isr.ts +555 -0
- package/src/frontend/layout.ts +475 -0
- package/src/frontend/ssr/react.ts +446 -0
- package/src/frontend/ssr/solid.ts +523 -0
- package/src/frontend/ssr/svelte.ts +546 -0
- package/src/frontend/ssr/vue.ts +504 -0
- package/src/frontend/ssr.ts +699 -0
- package/src/frontend/types.ts +2274 -0
- package/src/health/index.ts +604 -0
- package/src/index.ts +410 -0
- package/src/lock/index.ts +587 -0
- package/src/logger/index.ts +444 -0
- package/src/logger/transports/index.ts +969 -0
- package/src/metrics/index.ts +494 -0
- package/src/middleware/built-in.ts +360 -0
- package/src/middleware/index.ts +94 -0
- package/src/modules/filters.ts +458 -0
- package/src/modules/guards.ts +405 -0
- package/src/modules/index.ts +1256 -0
- package/src/modules/interceptors.ts +574 -0
- package/src/modules/lazy.ts +418 -0
- package/src/modules/lifecycle.ts +478 -0
- package/src/modules/metadata.ts +90 -0
- package/src/modules/pipes.ts +626 -0
- package/src/router/index.ts +339 -0
- package/src/router/linear.ts +371 -0
- package/src/router/regex.ts +292 -0
- package/src/router/tree.ts +562 -0
- package/src/rpc/index.ts +1263 -0
- package/src/security/index.ts +436 -0
- package/src/ssg/index.ts +631 -0
- package/src/storage/index.ts +456 -0
- package/src/telemetry/index.ts +1097 -0
- package/src/testing/index.ts +1586 -0
- package/src/types/index.ts +236 -0
- package/src/types/optional-deps.d.ts +219 -0
- package/src/validation/index.ts +276 -0
- package/src/websocket/index.ts +1004 -0
- package/tests/integration/cli.test.ts +1016 -0
- package/tests/integration/fullstack.test.ts +234 -0
- package/tests/unit/cache.test.ts +174 -0
- package/tests/unit/cli-commands.test.ts +892 -0
- package/tests/unit/cli.test.ts +1258 -0
- package/tests/unit/container.test.ts +279 -0
- package/tests/unit/context.test.ts +221 -0
- package/tests/unit/database.test.ts +183 -0
- package/tests/unit/linear-router.test.ts +280 -0
- package/tests/unit/lock.test.ts +336 -0
- package/tests/unit/middleware.test.ts +184 -0
- package/tests/unit/modules.test.ts +142 -0
- package/tests/unit/pubsub.test.ts +257 -0
- package/tests/unit/regex-router.test.ts +265 -0
- package/tests/unit/router.test.ts +373 -0
- package/tests/unit/rpc.test.ts +1248 -0
- package/tests/unit/security.test.ts +174 -0
- package/tests/unit/telemetry.test.ts +371 -0
- package/tests/unit/test-cache.test.ts +110 -0
- package/tests/unit/test-database.test.ts +282 -0
- package/tests/unit/tree-router.test.ts +325 -0
- package/tests/unit/validation.test.ts +794 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards System
|
|
3
|
+
*
|
|
4
|
+
* Guards determine whether a request should be allowed to proceed to the handler.
|
|
5
|
+
* They run before interceptors and pipes in the request pipeline.
|
|
6
|
+
*
|
|
7
|
+
* Execution Order:
|
|
8
|
+
* Incoming Request → Guards → Interceptors → Pipes → Handler
|
|
9
|
+
*
|
|
10
|
+
* If any guard returns false, the request is rejected with 403 Forbidden.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Context } from "../context";
|
|
14
|
+
import type { Token } from "../container";
|
|
15
|
+
|
|
16
|
+
// ============= Types =============
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Guard interface for authorization checks
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* @Injectable()
|
|
24
|
+
* class AuthGuard implements CanActivate {
|
|
25
|
+
* canActivate(context: Context): boolean {
|
|
26
|
+
* return !!context.request.headers.get('Authorization');
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export interface CanActivate {
|
|
32
|
+
canActivate(context: Context): boolean | Promise<boolean>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Guard function type (for functional guards)
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const authGuard: GuardFn = (context) => {
|
|
41
|
+
* return !!context.request.headers.get('Authorization');
|
|
42
|
+
* };
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export type GuardFn = (context: Context) => boolean | Promise<boolean>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Guard type - can be:
|
|
49
|
+
* - A token for a guard class registered in the container
|
|
50
|
+
* - A guard class instance
|
|
51
|
+
* - A guard function
|
|
52
|
+
*/
|
|
53
|
+
export type Guard = Token<CanActivate> | CanActivate | GuardFn;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Metadata key for storing guards on classes and methods
|
|
57
|
+
*/
|
|
58
|
+
const GUARDS_METADATA_KEY = "guards";
|
|
59
|
+
|
|
60
|
+
// ============= Metadata Storage =============
|
|
61
|
+
|
|
62
|
+
// Type alias for class constructors
|
|
63
|
+
type Constructor = new (...args: unknown[]) => unknown;
|
|
64
|
+
|
|
65
|
+
// WeakMap for storing guards metadata on classes
|
|
66
|
+
const guardsClassMetadata = new WeakMap<Constructor, Guard[]>();
|
|
67
|
+
|
|
68
|
+
// WeakMap for storing guards metadata on method prototypes
|
|
69
|
+
const guardsMethodMetadata = new WeakMap<object, Map<string | symbol, Guard[]>>();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Set guards on a class constructor
|
|
73
|
+
*/
|
|
74
|
+
function setClassGuards(target: Constructor, guards: Guard[]): void {
|
|
75
|
+
guardsClassMetadata.set(target, guards);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get guards from a class constructor
|
|
80
|
+
*/
|
|
81
|
+
export function getClassGuards(target: Constructor): Guard[] | undefined {
|
|
82
|
+
return guardsClassMetadata.get(target);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Set guards on a method
|
|
87
|
+
*/
|
|
88
|
+
function setMethodGuards(
|
|
89
|
+
target: object,
|
|
90
|
+
propertyKey: string | symbol,
|
|
91
|
+
guards: Guard[],
|
|
92
|
+
): void {
|
|
93
|
+
if (!guardsMethodMetadata.has(target)) {
|
|
94
|
+
guardsMethodMetadata.set(target, new Map());
|
|
95
|
+
}
|
|
96
|
+
guardsMethodMetadata.get(target)?.set(propertyKey, guards);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get guards from a method
|
|
101
|
+
*/
|
|
102
|
+
export function getMethodGuards(
|
|
103
|
+
target: object,
|
|
104
|
+
propertyKey: string | symbol,
|
|
105
|
+
): Guard[] | undefined {
|
|
106
|
+
return guardsMethodMetadata.get(target)?.get(propertyKey);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ============= Decorators =============
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Decorator to apply guards to a controller class or method.
|
|
113
|
+
* Guards are executed in the order they are provided.
|
|
114
|
+
*
|
|
115
|
+
* @param guards - Guards to apply
|
|
116
|
+
* @returns ClassDecorator & MethodDecorator
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* // Apply to all methods in controller
|
|
121
|
+
* @Controller('users')
|
|
122
|
+
* @UseGuards(AuthGuard)
|
|
123
|
+
* class UsersController {
|
|
124
|
+
* @Get()
|
|
125
|
+
* getUsers() {} // Protected by AuthGuard
|
|
126
|
+
*
|
|
127
|
+
* @Get(':id')
|
|
128
|
+
* @UseGuards(RolesGuard) // Additional guard
|
|
129
|
+
* getUser() {} // Protected by AuthGuard AND RolesGuard
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function UseGuards(...guards: Guard[]): MethodDecorator & ClassDecorator {
|
|
134
|
+
const decorator = (
|
|
135
|
+
target: unknown,
|
|
136
|
+
propertyKey?: string | symbol,
|
|
137
|
+
descriptor?: PropertyDescriptor,
|
|
138
|
+
): PropertyDescriptor | void => {
|
|
139
|
+
if (propertyKey !== undefined && descriptor !== undefined) {
|
|
140
|
+
// Method decorator
|
|
141
|
+
const targetObj = target as object;
|
|
142
|
+
const existingGuards = getMethodGuards(targetObj, propertyKey) ?? [];
|
|
143
|
+
setMethodGuards(targetObj, propertyKey, [...existingGuards, ...guards]);
|
|
144
|
+
return descriptor;
|
|
145
|
+
} else {
|
|
146
|
+
// Class decorator
|
|
147
|
+
const targetClass = target as Constructor;
|
|
148
|
+
const existingGuards = getClassGuards(targetClass) ?? [];
|
|
149
|
+
setClassGuards(targetClass, [...existingGuards, ...guards]);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
return decorator as MethodDecorator & ClassDecorator;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ============= Built-in Guards =============
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* AuthGuard - Checks for Authorization header
|
|
159
|
+
*
|
|
160
|
+
* This guard verifies that the request has an Authorization header.
|
|
161
|
+
* It does not validate the token - that should be done by a custom guard.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* @Controller('api')
|
|
166
|
+
* @UseGuards(AuthGuard)
|
|
167
|
+
* class ApiController {
|
|
168
|
+
* @Get('protected')
|
|
169
|
+
* protectedRoute() {} // Requires Authorization header
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export class AuthGuard implements CanActivate {
|
|
174
|
+
canActivate(context: Context): boolean {
|
|
175
|
+
const authHeader = context.req.headers.get("Authorization");
|
|
176
|
+
return authHeader !== null && authHeader.length > 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Role metadata key for storing required roles on methods
|
|
182
|
+
*/
|
|
183
|
+
const ROLES_METADATA_KEY = "roles";
|
|
184
|
+
|
|
185
|
+
// WeakMap for storing roles metadata on method prototypes
|
|
186
|
+
const rolesMethodMetadata = new WeakMap<object, Map<string | symbol, string[]>>();
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Set required roles on a method
|
|
190
|
+
*/
|
|
191
|
+
function setMethodRoles(
|
|
192
|
+
target: object,
|
|
193
|
+
propertyKey: string | symbol,
|
|
194
|
+
roles: string[],
|
|
195
|
+
): void {
|
|
196
|
+
if (!rolesMethodMetadata.has(target)) {
|
|
197
|
+
rolesMethodMetadata.set(target, new Map());
|
|
198
|
+
}
|
|
199
|
+
rolesMethodMetadata.get(target)?.set(propertyKey, roles);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get required roles from a method
|
|
204
|
+
*/
|
|
205
|
+
export function getMethodRoles(
|
|
206
|
+
target: object,
|
|
207
|
+
propertyKey: string | symbol,
|
|
208
|
+
): string[] | undefined {
|
|
209
|
+
return rolesMethodMetadata.get(target)?.get(propertyKey);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Decorator to specify required roles for a route
|
|
214
|
+
* Must be used in conjunction with RolesGuard
|
|
215
|
+
*
|
|
216
|
+
* @param roles - Required roles
|
|
217
|
+
* @returns MethodDecorator
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* @Controller('admin')
|
|
222
|
+
* @UseGuards(AuthGuard, RolesGuard)
|
|
223
|
+
* class AdminController {
|
|
224
|
+
* @Get('users')
|
|
225
|
+
* @Roles('admin', 'moderator')
|
|
226
|
+
* getUsers() {} // Requires 'admin' or 'moderator' role
|
|
227
|
+
* }
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
export function Roles(...roles: string[]): MethodDecorator {
|
|
231
|
+
return (
|
|
232
|
+
target: unknown,
|
|
233
|
+
propertyKey: string | symbol,
|
|
234
|
+
descriptor: PropertyDescriptor,
|
|
235
|
+
): PropertyDescriptor => {
|
|
236
|
+
const targetObj = target as object;
|
|
237
|
+
setMethodRoles(targetObj, propertyKey, roles);
|
|
238
|
+
return descriptor;
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* User interface for type safety
|
|
244
|
+
* Applications should extend this interface with their user type
|
|
245
|
+
*/
|
|
246
|
+
export interface User {
|
|
247
|
+
id: string | number;
|
|
248
|
+
roles?: string[];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Context extension for user data
|
|
253
|
+
* This extends the Context type to include user information
|
|
254
|
+
*/
|
|
255
|
+
declare module "../context" {
|
|
256
|
+
interface Context {
|
|
257
|
+
user?: User;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* RolesGuard - Checks user roles
|
|
263
|
+
*
|
|
264
|
+
* This guard checks if the authenticated user has the required roles.
|
|
265
|
+
* It should be used after AuthGuard in the guard chain.
|
|
266
|
+
*
|
|
267
|
+
* The user object must be set on the context before this guard runs.
|
|
268
|
+
* This is typically done by an authentication middleware or a previous guard.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* @Controller('admin')
|
|
273
|
+
* @UseGuards(AuthGuard, RolesGuard)
|
|
274
|
+
* class AdminController {
|
|
275
|
+
* @Get('dashboard')
|
|
276
|
+
* @Roles('admin')
|
|
277
|
+
* getDashboard() {} // Requires 'admin' role
|
|
278
|
+
* }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export class RolesGuard implements CanActivate {
|
|
282
|
+
canActivate(context: Context): boolean {
|
|
283
|
+
// Get required roles from context (set by the framework during route matching)
|
|
284
|
+
const requiredRoles = (context as unknown as { requiredRoles?: string[] }).requiredRoles;
|
|
285
|
+
|
|
286
|
+
// If no roles are required, allow access
|
|
287
|
+
if (!requiredRoles || requiredRoles.length === 0) {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Check if user exists and has at least one required role
|
|
292
|
+
const user = (context as unknown as { user?: User }).user;
|
|
293
|
+
if (!user || !user.roles) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return requiredRoles.some((role) => user.roles?.includes(role));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ============= Guard Executor =============
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Guard executor options
|
|
305
|
+
*/
|
|
306
|
+
export interface GuardExecutorOptions {
|
|
307
|
+
/** Global guards applied to all routes */
|
|
308
|
+
globalGuards?: Guard[];
|
|
309
|
+
/** Guards from controller class */
|
|
310
|
+
classGuards?: Guard[];
|
|
311
|
+
/** Guards from method */
|
|
312
|
+
methodGuards?: Guard[];
|
|
313
|
+
/** Container for resolving guard instances */
|
|
314
|
+
resolveGuard?: (guard: Guard) => CanActivate | GuardFn | null;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Execute guards in order and return whether the request should proceed
|
|
319
|
+
*
|
|
320
|
+
* @param context - Request context
|
|
321
|
+
* @param options - Guard executor options
|
|
322
|
+
* @returns true if all guards pass, false otherwise
|
|
323
|
+
*/
|
|
324
|
+
export async function executeGuards(
|
|
325
|
+
context: Context,
|
|
326
|
+
options: GuardExecutorOptions,
|
|
327
|
+
): Promise<boolean> {
|
|
328
|
+
const { globalGuards = [], classGuards = [], methodGuards = [], resolveGuard } = options;
|
|
329
|
+
|
|
330
|
+
// Combine all guards in execution order
|
|
331
|
+
const allGuards = [...globalGuards, ...classGuards, ...methodGuards];
|
|
332
|
+
|
|
333
|
+
// Execute each guard in order
|
|
334
|
+
for (const guard of allGuards) {
|
|
335
|
+
let guardInstance: CanActivate | GuardFn | null = null;
|
|
336
|
+
|
|
337
|
+
// Resolve the guard
|
|
338
|
+
if (typeof guard === "function") {
|
|
339
|
+
// Check if it's a guard function or a class constructor
|
|
340
|
+
const funcGuard = guard as { prototype?: unknown; canActivate?: unknown };
|
|
341
|
+
if (funcGuard.prototype && typeof funcGuard.prototype === "object" &&
|
|
342
|
+
"canActivate" in (funcGuard.prototype as object)) {
|
|
343
|
+
// It's a class constructor - try to resolve from container or create instance
|
|
344
|
+
guardInstance = resolveGuard ? resolveGuard(guard) : null;
|
|
345
|
+
if (!guardInstance) {
|
|
346
|
+
// Create a new instance if not in container
|
|
347
|
+
// Use unknown first to safely convert
|
|
348
|
+
const GuardClass = guard as unknown as new () => CanActivate;
|
|
349
|
+
guardInstance = new GuardClass();
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
// It's a guard function
|
|
353
|
+
guardInstance = guard as GuardFn;
|
|
354
|
+
}
|
|
355
|
+
} else if (typeof guard === "object" && guard !== null) {
|
|
356
|
+
// It's a token or already an instance
|
|
357
|
+
const objGuard = guard as { canActivate?: unknown };
|
|
358
|
+
if ("canActivate" in objGuard && typeof objGuard.canActivate === "function") {
|
|
359
|
+
// It's already a CanActivate instance
|
|
360
|
+
guardInstance = guard as CanActivate;
|
|
361
|
+
} else {
|
|
362
|
+
// It's a token - try to resolve
|
|
363
|
+
guardInstance = resolveGuard ? resolveGuard(guard) : null;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (!guardInstance) {
|
|
368
|
+
console.warn("Guard could not be resolved:", guard);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Execute the guard
|
|
373
|
+
let result: boolean;
|
|
374
|
+
if (typeof guardInstance === "function") {
|
|
375
|
+
// Guard function
|
|
376
|
+
result = await guardInstance(context);
|
|
377
|
+
} else {
|
|
378
|
+
// CanActivate instance
|
|
379
|
+
result = await guardInstance.canActivate(context);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// If any guard returns false, stop and return false
|
|
383
|
+
if (!result) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Create a 403 Forbidden response
|
|
393
|
+
*/
|
|
394
|
+
export function createForbiddenResponse(): Response {
|
|
395
|
+
return new Response(JSON.stringify({
|
|
396
|
+
statusCode: 403,
|
|
397
|
+
error: "Forbidden",
|
|
398
|
+
message: "Access denied",
|
|
399
|
+
}), {
|
|
400
|
+
status: 403,
|
|
401
|
+
headers: {
|
|
402
|
+
"Content-Type": "application/json",
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
}
|