@buenojs/bueno 0.8.3 → 0.8.5
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/README.md +136 -16
- package/dist/cli/{index.js → bin.js} +3036 -1421
- package/dist/container/index.js +250 -0
- package/dist/context/index.js +219 -0
- package/dist/database/index.js +493 -0
- package/dist/frontend/index.js +7697 -0
- package/dist/health/index.js +364 -0
- package/dist/i18n/index.js +345 -0
- package/dist/index.js +11043 -6482
- package/dist/jobs/index.js +819 -0
- package/dist/lock/index.js +367 -0
- package/dist/logger/index.js +281 -0
- package/dist/metrics/index.js +289 -0
- package/dist/middleware/index.js +77 -0
- package/dist/migrations/index.js +571 -0
- package/dist/modules/index.js +3346 -0
- package/dist/notification/index.js +484 -0
- package/dist/observability/index.js +331 -0
- package/dist/openapi/index.js +776 -0
- package/dist/orm/index.js +1356 -0
- package/dist/router/index.js +886 -0
- package/dist/rpc/index.js +691 -0
- package/dist/schema/index.js +400 -0
- package/dist/telemetry/index.js +595 -0
- package/dist/template/index.js +640 -0
- package/dist/templates/index.js +640 -0
- package/dist/testing/index.js +1111 -0
- package/dist/types/index.js +60 -0
- package/package.json +121 -27
- package/src/cache/index.ts +2 -1
- package/src/cli/bin.ts +2 -2
- package/src/cli/commands/build.ts +183 -165
- package/src/cli/commands/dev.ts +96 -89
- package/src/cli/commands/generate.ts +142 -111
- package/src/cli/commands/help.ts +20 -16
- package/src/cli/commands/index.ts +3 -6
- package/src/cli/commands/migration.ts +124 -105
- package/src/cli/commands/new.ts +392 -438
- package/src/cli/commands/start.ts +81 -79
- package/src/cli/core/args.ts +68 -50
- package/src/cli/core/console.ts +89 -95
- package/src/cli/core/index.ts +4 -4
- package/src/cli/core/prompt.ts +65 -62
- package/src/cli/core/spinner.ts +23 -20
- package/src/cli/index.ts +46 -38
- package/src/cli/templates/database/index.ts +61 -0
- package/src/cli/templates/database/mysql.ts +14 -0
- package/src/cli/templates/database/none.ts +16 -0
- package/src/cli/templates/database/postgresql.ts +14 -0
- package/src/cli/templates/database/sqlite.ts +14 -0
- package/src/cli/templates/deploy.ts +29 -26
- package/src/cli/templates/docker.ts +41 -30
- package/src/cli/templates/frontend/index.ts +63 -0
- package/src/cli/templates/frontend/none.ts +17 -0
- package/src/cli/templates/frontend/react.ts +140 -0
- package/src/cli/templates/frontend/solid.ts +134 -0
- package/src/cli/templates/frontend/svelte.ts +131 -0
- package/src/cli/templates/frontend/vue.ts +130 -0
- package/src/cli/templates/generators/index.ts +339 -0
- package/src/cli/templates/generators/types.ts +56 -0
- package/src/cli/templates/index.ts +35 -2
- package/src/cli/templates/project/api.ts +81 -0
- package/src/cli/templates/project/default.ts +140 -0
- package/src/cli/templates/project/fullstack.ts +111 -0
- package/src/cli/templates/project/index.ts +95 -0
- package/src/cli/templates/project/minimal.ts +45 -0
- package/src/cli/templates/project/types.ts +94 -0
- package/src/cli/templates/project/website.ts +263 -0
- package/src/cli/utils/fs.ts +55 -41
- package/src/cli/utils/index.ts +3 -2
- package/src/cli/utils/strings.ts +47 -33
- package/src/cli/utils/version.ts +47 -0
- package/src/config/env-validation.ts +100 -0
- package/src/config/env.ts +169 -41
- package/src/config/index.ts +28 -20
- package/src/config/loader.ts +25 -16
- package/src/config/merge.ts +21 -10
- package/src/config/types.ts +545 -25
- package/src/config/validation.ts +215 -7
- package/src/container/forward-ref.ts +22 -22
- package/src/container/index.ts +34 -12
- package/src/context/index.ts +11 -1
- package/src/database/index.ts +7 -190
- package/src/database/orm/builder.ts +457 -0
- package/src/database/orm/casts/index.ts +130 -0
- package/src/database/orm/casts/types.ts +25 -0
- package/src/database/orm/compiler.ts +304 -0
- package/src/database/orm/hooks/index.ts +114 -0
- package/src/database/orm/index.ts +61 -0
- package/src/database/orm/model-registry.ts +59 -0
- package/src/database/orm/model.ts +821 -0
- package/src/database/orm/relationships/base.ts +146 -0
- package/src/database/orm/relationships/belongs-to-many.ts +179 -0
- package/src/database/orm/relationships/belongs-to.ts +56 -0
- package/src/database/orm/relationships/has-many.ts +45 -0
- package/src/database/orm/relationships/has-one.ts +41 -0
- package/src/database/orm/relationships/index.ts +11 -0
- package/src/database/orm/scopes/index.ts +55 -0
- package/src/events/__tests__/event-system.test.ts +235 -0
- package/src/events/config.ts +238 -0
- package/src/events/example-usage.ts +185 -0
- package/src/events/index.ts +278 -0
- package/src/events/manager.ts +385 -0
- package/src/events/registry.ts +182 -0
- package/src/events/types.ts +124 -0
- package/src/frontend/api-routes.ts +65 -23
- package/src/frontend/bundler.ts +76 -34
- package/src/frontend/console-client.ts +2 -2
- package/src/frontend/console-stream.ts +94 -38
- package/src/frontend/dev-server.ts +94 -46
- package/src/frontend/file-router.ts +61 -19
- package/src/frontend/frameworks/index.ts +37 -10
- package/src/frontend/frameworks/react.ts +10 -8
- package/src/frontend/frameworks/solid.ts +11 -9
- package/src/frontend/frameworks/svelte.ts +15 -9
- package/src/frontend/frameworks/vue.ts +13 -11
- package/src/frontend/hmr-client.ts +12 -10
- package/src/frontend/hmr.ts +146 -103
- package/src/frontend/index.ts +14 -5
- package/src/frontend/islands.ts +41 -22
- package/src/frontend/isr.ts +59 -37
- package/src/frontend/layout.ts +36 -21
- package/src/frontend/ssr/react.ts +74 -27
- package/src/frontend/ssr/solid.ts +54 -20
- package/src/frontend/ssr/svelte.ts +48 -14
- package/src/frontend/ssr/vue.ts +50 -18
- package/src/frontend/ssr.ts +83 -39
- package/src/frontend/types.ts +91 -56
- package/src/health/index.ts +21 -9
- package/src/i18n/engine.ts +305 -0
- package/src/i18n/index.ts +38 -0
- package/src/i18n/loader.ts +218 -0
- package/src/i18n/middleware.ts +164 -0
- package/src/i18n/negotiator.ts +162 -0
- package/src/i18n/types.ts +158 -0
- package/src/index.ts +179 -27
- package/src/jobs/drivers/memory.ts +315 -0
- package/src/jobs/drivers/redis.ts +459 -0
- package/src/jobs/index.ts +30 -0
- package/src/jobs/queue.ts +281 -0
- package/src/jobs/types.ts +295 -0
- package/src/jobs/worker.ts +380 -0
- package/src/logger/index.ts +1 -3
- package/src/logger/transports/index.ts +62 -22
- package/src/metrics/index.ts +25 -16
- package/src/migrations/index.ts +9 -0
- package/src/modules/filters.ts +13 -17
- package/src/modules/guards.ts +49 -26
- package/src/modules/index.ts +409 -298
- package/src/modules/interceptors.ts +58 -20
- package/src/modules/lazy.ts +11 -19
- package/src/modules/lifecycle.ts +15 -7
- package/src/modules/metadata.ts +15 -5
- package/src/modules/pipes.ts +94 -72
- package/src/notification/channels/base.ts +68 -0
- package/src/notification/channels/email.ts +105 -0
- package/src/notification/channels/push.ts +104 -0
- package/src/notification/channels/sms.ts +105 -0
- package/src/notification/channels/whatsapp.ts +104 -0
- package/src/notification/index.ts +48 -0
- package/src/notification/service.ts +354 -0
- package/src/notification/types.ts +344 -0
- package/src/observability/__tests__/observability.test.ts +483 -0
- package/src/observability/breadcrumbs.ts +114 -0
- package/src/observability/index.ts +136 -0
- package/src/observability/interceptor.ts +85 -0
- package/src/observability/service.ts +303 -0
- package/src/observability/trace.ts +37 -0
- package/src/observability/types.ts +196 -0
- package/src/openapi/__tests__/decorators.test.ts +335 -0
- package/src/openapi/__tests__/document-builder.test.ts +285 -0
- package/src/openapi/__tests__/route-scanner.test.ts +334 -0
- package/src/openapi/__tests__/schema-generator.test.ts +275 -0
- package/src/openapi/decorators.ts +328 -0
- package/src/openapi/document-builder.ts +274 -0
- package/src/openapi/index.ts +112 -0
- package/src/openapi/metadata.ts +112 -0
- package/src/openapi/route-scanner.ts +289 -0
- package/src/openapi/schema-generator.ts +256 -0
- package/src/openapi/swagger-module.ts +166 -0
- package/src/openapi/types.ts +398 -0
- package/src/orm/index.ts +10 -0
- package/src/rpc/index.ts +3 -1
- package/src/schema/index.ts +9 -0
- package/src/security/index.ts +15 -6
- package/src/ssg/index.ts +9 -8
- package/src/telemetry/index.ts +76 -22
- package/src/template/index.ts +7 -0
- package/src/templates/engine.ts +224 -0
- package/src/templates/index.ts +9 -0
- package/src/templates/loader.ts +331 -0
- package/src/templates/renderers/markdown.ts +212 -0
- package/src/templates/renderers/simple.ts +269 -0
- package/src/templates/types.ts +154 -0
- package/src/testing/index.ts +100 -27
- package/src/types/optional-deps.d.ts +347 -187
- package/src/validation/index.ts +92 -2
- package/src/validation/schemas.ts +536 -0
- package/tests/integration/fullstack.test.ts +4 -4
- package/tests/unit/database.test.ts +2 -72
- package/tests/unit/env-validation.test.ts +166 -0
- package/tests/unit/events.test.ts +910 -0
- package/tests/unit/i18n.test.ts +455 -0
- package/tests/unit/jobs.test.ts +493 -0
- package/tests/unit/notification.test.ts +988 -0
- package/tests/unit/observability.test.ts +453 -0
- package/tests/unit/orm/builder.test.ts +323 -0
- package/tests/unit/orm/casts.test.ts +179 -0
- package/tests/unit/orm/compiler.test.ts +220 -0
- package/tests/unit/orm/eager-loading.test.ts +285 -0
- package/tests/unit/orm/hooks.test.ts +191 -0
- package/tests/unit/orm/model.test.ts +373 -0
- package/tests/unit/orm/relationships.test.ts +303 -0
- package/tests/unit/orm/scopes.test.ts +74 -0
- package/tests/unit/templates-simple.test.ts +53 -0
- package/tests/unit/templates.test.ts +454 -0
- package/tests/unit/validation.test.ts +18 -24
- package/tsconfig.json +11 -3
package/src/modules/filters.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import type { Context } from "../context";
|
|
13
13
|
import type { Token } from "../types";
|
|
14
|
-
import { BuenoError,
|
|
14
|
+
import { BuenoError, NotFoundError, ValidationError } from "../types";
|
|
15
15
|
|
|
16
16
|
// ============= Types =============
|
|
17
17
|
|
|
@@ -69,10 +69,7 @@ function setFilterMetadata(
|
|
|
69
69
|
filterMetadataStore.get(target)?.set(key, value);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
function getFilterMetadata<T>(
|
|
73
|
-
target: Constructor,
|
|
74
|
-
key: string,
|
|
75
|
-
): T | undefined {
|
|
72
|
+
function getFilterMetadata<T>(target: Constructor, key: string): T | undefined {
|
|
76
73
|
return filterMetadataStore.get(target)?.get(key) as T | undefined;
|
|
77
74
|
}
|
|
78
75
|
|
|
@@ -114,7 +111,9 @@ function getFilterPrototypeMetadata<T>(
|
|
|
114
111
|
* }
|
|
115
112
|
* ```
|
|
116
113
|
*/
|
|
117
|
-
export function UseFilters(
|
|
114
|
+
export function UseFilters(
|
|
115
|
+
...filters: Filter[]
|
|
116
|
+
): MethodDecorator & ClassDecorator {
|
|
118
117
|
const decorator = (
|
|
119
118
|
target: unknown,
|
|
120
119
|
propertyKey?: string | symbol,
|
|
@@ -168,7 +167,11 @@ export function Catch<T extends Error>(
|
|
|
168
167
|
exceptionType: new (...args: never[]) => T,
|
|
169
168
|
): ClassDecorator {
|
|
170
169
|
const decorator = (target: Constructor): void => {
|
|
171
|
-
catchMetadataStore.set(target, {
|
|
170
|
+
catchMetadataStore.set(target, {
|
|
171
|
+
exceptionType: exceptionType as unknown as new (
|
|
172
|
+
...args: unknown[]
|
|
173
|
+
) => Error,
|
|
174
|
+
});
|
|
172
175
|
};
|
|
173
176
|
return decorator as ClassDecorator;
|
|
174
177
|
}
|
|
@@ -224,10 +227,7 @@ export function getCatchType(
|
|
|
224
227
|
/**
|
|
225
228
|
* Check if a filter can handle a specific exception
|
|
226
229
|
*/
|
|
227
|
-
export function canHandleException(
|
|
228
|
-
filter: Filter,
|
|
229
|
-
exception: Error,
|
|
230
|
-
): boolean {
|
|
230
|
+
export function canHandleException(filter: Filter, exception: Error): boolean {
|
|
231
231
|
const catchType = getCatchType(filter);
|
|
232
232
|
if (!catchType) {
|
|
233
233
|
// No specific catch type means it handles all exceptions
|
|
@@ -327,11 +327,7 @@ export async function findAndExecuteFilter(
|
|
|
327
327
|
const { globalFilters, classFilters, methodFilters, resolveFilter } = options;
|
|
328
328
|
|
|
329
329
|
// Combine all filters in execution order (method first, then class, then global)
|
|
330
|
-
const allFilters = [
|
|
331
|
-
...methodFilters,
|
|
332
|
-
...classFilters,
|
|
333
|
-
...globalFilters,
|
|
334
|
-
];
|
|
330
|
+
const allFilters = [...methodFilters, ...classFilters, ...globalFilters];
|
|
335
331
|
|
|
336
332
|
// Find the first filter that can handle this exception type
|
|
337
333
|
for (const filter of allFilters) {
|
|
@@ -455,4 +451,4 @@ export function createInternalErrorResponse(exception: Error): Response {
|
|
|
455
451
|
},
|
|
456
452
|
},
|
|
457
453
|
);
|
|
458
|
-
}
|
|
454
|
+
}
|
package/src/modules/guards.ts
CHANGED
|
@@ -3,21 +3,21 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Guards determine whether a request should be allowed to proceed to the handler.
|
|
5
5
|
* They run before interceptors and pipes in the request pipeline.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Execution Order:
|
|
8
8
|
* Incoming Request → Guards → Interceptors → Pipes → Handler
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* If any guard returns false, the request is rejected with 403 Forbidden.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type { Context } from "../context";
|
|
14
13
|
import type { Token } from "../container";
|
|
14
|
+
import type { Context } from "../context";
|
|
15
15
|
|
|
16
16
|
// ============= Types =============
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Guard interface for authorization checks
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```typescript
|
|
23
23
|
* @Injectable()
|
|
@@ -34,7 +34,7 @@ export interface CanActivate {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Guard function type (for functional guards)
|
|
37
|
-
*
|
|
37
|
+
*
|
|
38
38
|
* @example
|
|
39
39
|
* ```typescript
|
|
40
40
|
* const authGuard: GuardFn = (context) => {
|
|
@@ -66,7 +66,10 @@ type Constructor = new (...args: unknown[]) => unknown;
|
|
|
66
66
|
const guardsClassMetadata = new WeakMap<Constructor, Guard[]>();
|
|
67
67
|
|
|
68
68
|
// WeakMap for storing guards metadata on method prototypes
|
|
69
|
-
const guardsMethodMetadata = new WeakMap<
|
|
69
|
+
const guardsMethodMetadata = new WeakMap<
|
|
70
|
+
object,
|
|
71
|
+
Map<string | symbol, Guard[]>
|
|
72
|
+
>();
|
|
70
73
|
|
|
71
74
|
/**
|
|
72
75
|
* Set guards on a class constructor
|
|
@@ -130,7 +133,9 @@ export function getMethodGuards(
|
|
|
130
133
|
* }
|
|
131
134
|
* ```
|
|
132
135
|
*/
|
|
133
|
-
export function UseGuards(
|
|
136
|
+
export function UseGuards(
|
|
137
|
+
...guards: Guard[]
|
|
138
|
+
): MethodDecorator & ClassDecorator {
|
|
134
139
|
const decorator = (
|
|
135
140
|
target: unknown,
|
|
136
141
|
propertyKey?: string | symbol,
|
|
@@ -183,7 +188,10 @@ export class AuthGuard implements CanActivate {
|
|
|
183
188
|
const ROLES_METADATA_KEY = "roles";
|
|
184
189
|
|
|
185
190
|
// WeakMap for storing roles metadata on method prototypes
|
|
186
|
-
const rolesMethodMetadata = new WeakMap<
|
|
191
|
+
const rolesMethodMetadata = new WeakMap<
|
|
192
|
+
object,
|
|
193
|
+
Map<string | symbol, string[]>
|
|
194
|
+
>();
|
|
187
195
|
|
|
188
196
|
/**
|
|
189
197
|
* Set required roles on a method
|
|
@@ -212,10 +220,10 @@ export function getMethodRoles(
|
|
|
212
220
|
/**
|
|
213
221
|
* Decorator to specify required roles for a route
|
|
214
222
|
* Must be used in conjunction with RolesGuard
|
|
215
|
-
*
|
|
223
|
+
*
|
|
216
224
|
* @param roles - Required roles
|
|
217
225
|
* @returns MethodDecorator
|
|
218
|
-
*
|
|
226
|
+
*
|
|
219
227
|
* @example
|
|
220
228
|
* ```typescript
|
|
221
229
|
* @Controller('admin')
|
|
@@ -281,7 +289,8 @@ declare module "../context" {
|
|
|
281
289
|
export class RolesGuard implements CanActivate {
|
|
282
290
|
canActivate(context: Context): boolean {
|
|
283
291
|
// Get required roles from context (set by the framework during route matching)
|
|
284
|
-
const requiredRoles = (context as unknown as { requiredRoles?: string[] })
|
|
292
|
+
const requiredRoles = (context as unknown as { requiredRoles?: string[] })
|
|
293
|
+
.requiredRoles;
|
|
285
294
|
|
|
286
295
|
// If no roles are required, allow access
|
|
287
296
|
if (!requiredRoles || requiredRoles.length === 0) {
|
|
@@ -316,7 +325,7 @@ export interface GuardExecutorOptions {
|
|
|
316
325
|
|
|
317
326
|
/**
|
|
318
327
|
* Execute guards in order and return whether the request should proceed
|
|
319
|
-
*
|
|
328
|
+
*
|
|
320
329
|
* @param context - Request context
|
|
321
330
|
* @param options - Guard executor options
|
|
322
331
|
* @returns true if all guards pass, false otherwise
|
|
@@ -325,7 +334,12 @@ export async function executeGuards(
|
|
|
325
334
|
context: Context,
|
|
326
335
|
options: GuardExecutorOptions,
|
|
327
336
|
): Promise<boolean> {
|
|
328
|
-
const {
|
|
337
|
+
const {
|
|
338
|
+
globalGuards = [],
|
|
339
|
+
classGuards = [],
|
|
340
|
+
methodGuards = [],
|
|
341
|
+
resolveGuard,
|
|
342
|
+
} = options;
|
|
329
343
|
|
|
330
344
|
// Combine all guards in execution order
|
|
331
345
|
const allGuards = [...globalGuards, ...classGuards, ...methodGuards];
|
|
@@ -338,8 +352,11 @@ export async function executeGuards(
|
|
|
338
352
|
if (typeof guard === "function") {
|
|
339
353
|
// Check if it's a guard function or a class constructor
|
|
340
354
|
const funcGuard = guard as { prototype?: unknown; canActivate?: unknown };
|
|
341
|
-
if (
|
|
342
|
-
|
|
355
|
+
if (
|
|
356
|
+
funcGuard.prototype &&
|
|
357
|
+
typeof funcGuard.prototype === "object" &&
|
|
358
|
+
"canActivate" in (funcGuard.prototype as object)
|
|
359
|
+
) {
|
|
343
360
|
// It's a class constructor - try to resolve from container or create instance
|
|
344
361
|
guardInstance = resolveGuard ? resolveGuard(guard) : null;
|
|
345
362
|
if (!guardInstance) {
|
|
@@ -355,7 +372,10 @@ export async function executeGuards(
|
|
|
355
372
|
} else if (typeof guard === "object" && guard !== null) {
|
|
356
373
|
// It's a token or already an instance
|
|
357
374
|
const objGuard = guard as { canActivate?: unknown };
|
|
358
|
-
if (
|
|
375
|
+
if (
|
|
376
|
+
"canActivate" in objGuard &&
|
|
377
|
+
typeof objGuard.canActivate === "function"
|
|
378
|
+
) {
|
|
359
379
|
// It's already a CanActivate instance
|
|
360
380
|
guardInstance = guard as CanActivate;
|
|
361
381
|
} else {
|
|
@@ -392,14 +412,17 @@ export async function executeGuards(
|
|
|
392
412
|
* Create a 403 Forbidden response
|
|
393
413
|
*/
|
|
394
414
|
export function createForbiddenResponse(): Response {
|
|
395
|
-
return new Response(
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
415
|
+
return new Response(
|
|
416
|
+
JSON.stringify({
|
|
417
|
+
statusCode: 403,
|
|
418
|
+
error: "Forbidden",
|
|
419
|
+
message: "Access denied",
|
|
420
|
+
}),
|
|
421
|
+
{
|
|
422
|
+
status: 403,
|
|
423
|
+
headers: {
|
|
424
|
+
"Content-Type": "application/json",
|
|
425
|
+
},
|
|
403
426
|
},
|
|
404
|
-
|
|
405
|
-
}
|
|
427
|
+
);
|
|
428
|
+
}
|