@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.
Files changed (120) hide show
  1. package/.env.example +109 -0
  2. package/.github/workflows/ci.yml +31 -0
  3. package/LICENSE +21 -0
  4. package/README.md +892 -0
  5. package/architecture.md +652 -0
  6. package/bun.lock +70 -0
  7. package/dist/cli/index.js +3233 -0
  8. package/dist/index.js +9014 -0
  9. package/package.json +77 -0
  10. package/src/cache/index.ts +795 -0
  11. package/src/cli/ARCHITECTURE.md +837 -0
  12. package/src/cli/bin.ts +10 -0
  13. package/src/cli/commands/build.ts +425 -0
  14. package/src/cli/commands/dev.ts +248 -0
  15. package/src/cli/commands/generate.ts +541 -0
  16. package/src/cli/commands/help.ts +55 -0
  17. package/src/cli/commands/index.ts +112 -0
  18. package/src/cli/commands/migration.ts +355 -0
  19. package/src/cli/commands/new.ts +804 -0
  20. package/src/cli/commands/start.ts +208 -0
  21. package/src/cli/core/args.ts +283 -0
  22. package/src/cli/core/console.ts +349 -0
  23. package/src/cli/core/index.ts +60 -0
  24. package/src/cli/core/prompt.ts +424 -0
  25. package/src/cli/core/spinner.ts +265 -0
  26. package/src/cli/index.ts +135 -0
  27. package/src/cli/templates/deploy.ts +295 -0
  28. package/src/cli/templates/docker.ts +307 -0
  29. package/src/cli/templates/index.ts +24 -0
  30. package/src/cli/utils/fs.ts +428 -0
  31. package/src/cli/utils/index.ts +8 -0
  32. package/src/cli/utils/strings.ts +197 -0
  33. package/src/config/env.ts +408 -0
  34. package/src/config/index.ts +506 -0
  35. package/src/config/loader.ts +329 -0
  36. package/src/config/merge.ts +285 -0
  37. package/src/config/types.ts +320 -0
  38. package/src/config/validation.ts +441 -0
  39. package/src/container/forward-ref.ts +143 -0
  40. package/src/container/index.ts +386 -0
  41. package/src/context/index.ts +360 -0
  42. package/src/database/index.ts +1142 -0
  43. package/src/database/migrations/index.ts +371 -0
  44. package/src/database/schema/index.ts +619 -0
  45. package/src/frontend/api-routes.ts +640 -0
  46. package/src/frontend/bundler.ts +643 -0
  47. package/src/frontend/console-client.ts +419 -0
  48. package/src/frontend/console-stream.ts +587 -0
  49. package/src/frontend/dev-server.ts +846 -0
  50. package/src/frontend/file-router.ts +611 -0
  51. package/src/frontend/frameworks/index.ts +106 -0
  52. package/src/frontend/frameworks/react.ts +85 -0
  53. package/src/frontend/frameworks/solid.ts +104 -0
  54. package/src/frontend/frameworks/svelte.ts +110 -0
  55. package/src/frontend/frameworks/vue.ts +92 -0
  56. package/src/frontend/hmr-client.ts +663 -0
  57. package/src/frontend/hmr.ts +728 -0
  58. package/src/frontend/index.ts +342 -0
  59. package/src/frontend/islands.ts +552 -0
  60. package/src/frontend/isr.ts +555 -0
  61. package/src/frontend/layout.ts +475 -0
  62. package/src/frontend/ssr/react.ts +446 -0
  63. package/src/frontend/ssr/solid.ts +523 -0
  64. package/src/frontend/ssr/svelte.ts +546 -0
  65. package/src/frontend/ssr/vue.ts +504 -0
  66. package/src/frontend/ssr.ts +699 -0
  67. package/src/frontend/types.ts +2274 -0
  68. package/src/health/index.ts +604 -0
  69. package/src/index.ts +410 -0
  70. package/src/lock/index.ts +587 -0
  71. package/src/logger/index.ts +444 -0
  72. package/src/logger/transports/index.ts +969 -0
  73. package/src/metrics/index.ts +494 -0
  74. package/src/middleware/built-in.ts +360 -0
  75. package/src/middleware/index.ts +94 -0
  76. package/src/modules/filters.ts +458 -0
  77. package/src/modules/guards.ts +405 -0
  78. package/src/modules/index.ts +1256 -0
  79. package/src/modules/interceptors.ts +574 -0
  80. package/src/modules/lazy.ts +418 -0
  81. package/src/modules/lifecycle.ts +478 -0
  82. package/src/modules/metadata.ts +90 -0
  83. package/src/modules/pipes.ts +626 -0
  84. package/src/router/index.ts +339 -0
  85. package/src/router/linear.ts +371 -0
  86. package/src/router/regex.ts +292 -0
  87. package/src/router/tree.ts +562 -0
  88. package/src/rpc/index.ts +1263 -0
  89. package/src/security/index.ts +436 -0
  90. package/src/ssg/index.ts +631 -0
  91. package/src/storage/index.ts +456 -0
  92. package/src/telemetry/index.ts +1097 -0
  93. package/src/testing/index.ts +1586 -0
  94. package/src/types/index.ts +236 -0
  95. package/src/types/optional-deps.d.ts +219 -0
  96. package/src/validation/index.ts +276 -0
  97. package/src/websocket/index.ts +1004 -0
  98. package/tests/integration/cli.test.ts +1016 -0
  99. package/tests/integration/fullstack.test.ts +234 -0
  100. package/tests/unit/cache.test.ts +174 -0
  101. package/tests/unit/cli-commands.test.ts +892 -0
  102. package/tests/unit/cli.test.ts +1258 -0
  103. package/tests/unit/container.test.ts +279 -0
  104. package/tests/unit/context.test.ts +221 -0
  105. package/tests/unit/database.test.ts +183 -0
  106. package/tests/unit/linear-router.test.ts +280 -0
  107. package/tests/unit/lock.test.ts +336 -0
  108. package/tests/unit/middleware.test.ts +184 -0
  109. package/tests/unit/modules.test.ts +142 -0
  110. package/tests/unit/pubsub.test.ts +257 -0
  111. package/tests/unit/regex-router.test.ts +265 -0
  112. package/tests/unit/router.test.ts +373 -0
  113. package/tests/unit/rpc.test.ts +1248 -0
  114. package/tests/unit/security.test.ts +174 -0
  115. package/tests/unit/telemetry.test.ts +371 -0
  116. package/tests/unit/test-cache.test.ts +110 -0
  117. package/tests/unit/test-database.test.ts +282 -0
  118. package/tests/unit/tree-router.test.ts +325 -0
  119. package/tests/unit/validation.test.ts +794 -0
  120. package/tsconfig.json +27 -0
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Lazy Loading System
3
+ *
4
+ * Provides on-demand module loading for improved startup time
5
+ * and reduced memory usage for large applications.
6
+ */
7
+
8
+ import type { Container, Token, Provider } from "../container";
9
+ import { Injectable } from "./metadata";
10
+ import { Inject } from "./index";
11
+
12
+ // ============= Types =============
13
+
14
+ /**
15
+ * Constructor type for module classes
16
+ */
17
+ export type Constructor = new (...args: unknown[]) => unknown;
18
+
19
+ /**
20
+ * Lazy module loader interface
21
+ */
22
+ export interface LazyModuleLoader {
23
+ /**
24
+ * Load the lazy module
25
+ */
26
+ load(): Promise<void>;
27
+
28
+ /**
29
+ * Check if the module is already loaded
30
+ */
31
+ isLoaded(): boolean;
32
+ }
33
+
34
+ /**
35
+ * Module loader function type for dynamic imports
36
+ */
37
+ export type ModuleLoaderFn = () => Promise<Constructor>;
38
+
39
+ /**
40
+ * Metadata for lazy modules
41
+ */
42
+ export interface LazyModuleMetadata {
43
+ loader: ModuleLoaderFn;
44
+ loaded: boolean;
45
+ loadedModule?: Constructor;
46
+ }
47
+
48
+ // ============= Metadata Storage =============
49
+
50
+ /**
51
+ * WeakMap storage for lazy module metadata
52
+ */
53
+ const lazyModuleMetadata = new WeakMap<Constructor, LazyModuleMetadata>();
54
+
55
+ /**
56
+ * Set lazy module metadata
57
+ */
58
+ function setLazyMetadata(
59
+ target: Constructor,
60
+ metadata: LazyModuleMetadata,
61
+ ): void {
62
+ lazyModuleMetadata.set(target, metadata);
63
+ }
64
+
65
+ /**
66
+ * Get lazy module metadata
67
+ */
68
+ export function getLazyMetadata(
69
+ target: Constructor,
70
+ ): LazyModuleMetadata | undefined {
71
+ return lazyModuleMetadata.get(target);
72
+ }
73
+
74
+ /**
75
+ * Check if a module is a lazy module
76
+ */
77
+ export function isLazyModule(target: Constructor): boolean {
78
+ return lazyModuleMetadata.has(target);
79
+ }
80
+
81
+ // ============= Lazy Module Loader Implementation =============
82
+
83
+ /**
84
+ * Implementation of LazyModuleLoader
85
+ */
86
+ export class LazyModuleLoaderImpl implements LazyModuleLoader {
87
+ private loaded = false;
88
+ private loadingPromise: Promise<void> | null = null;
89
+ private loader: ModuleLoaderFn;
90
+ private onModuleLoaded?: (moduleClass: Constructor) => Promise<void>;
91
+
92
+ constructor(
93
+ loader: ModuleLoaderFn,
94
+ onModuleLoaded?: (moduleClass: Constructor) => Promise<void>,
95
+ ) {
96
+ this.loader = loader;
97
+ this.onModuleLoaded = onModuleLoaded;
98
+ }
99
+
100
+ async load(): Promise<void> {
101
+ // Return existing promise if already loading
102
+ if (this.loadingPromise) {
103
+ return this.loadingPromise;
104
+ }
105
+
106
+ // Already loaded
107
+ if (this.loaded) {
108
+ return;
109
+ }
110
+
111
+ // Start loading
112
+ this.loadingPromise = this.doLoad();
113
+ await this.loadingPromise;
114
+ this.loadingPromise = null;
115
+ }
116
+
117
+ private async doLoad(): Promise<void> {
118
+ try {
119
+ const moduleClass = await this.loader();
120
+ this.loaded = true;
121
+
122
+ // Notify callback if provided
123
+ if (this.onModuleLoaded) {
124
+ await this.onModuleLoaded(moduleClass);
125
+ }
126
+ } catch (error) {
127
+ this.loadingPromise = null;
128
+ throw new Error(
129
+ `Failed to load lazy module: ${error instanceof Error ? error.message : String(error)}`,
130
+ );
131
+ }
132
+ }
133
+
134
+ isLoaded(): boolean {
135
+ return this.loaded;
136
+ }
137
+ }
138
+
139
+ // ============= Lazy Module Decorator =============
140
+
141
+ /**
142
+ * Decorator to mark a module as lazy-loaded
143
+ *
144
+ * @param loader - Function that returns a Promise resolving to the module class
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * @LazyModule(() => import('./users.module').then(m => m.UsersModule))
149
+ * export class LazyUsersModule {}
150
+ * ```
151
+ */
152
+ export function LazyModule(loader: ModuleLoaderFn): ClassDecorator {
153
+ return <TFunction extends Function>(target: TFunction): TFunction => {
154
+ // Store metadata about the lazy module
155
+ setLazyMetadata(target as unknown as Constructor, {
156
+ loader,
157
+ loaded: false,
158
+ });
159
+
160
+ return target;
161
+ };
162
+ }
163
+
164
+ // ============= Module Loader Service =============
165
+
166
+ /**
167
+ * Token for the ModuleLoader service
168
+ */
169
+ export const MODULE_LOADER_TOKEN = Symbol.for("ModuleLoader") as Token<ModuleLoader>;
170
+
171
+ /**
172
+ * Options for loading lazy modules
173
+ */
174
+ export interface LoadModuleOptions {
175
+ /**
176
+ * Skip lifecycle hooks when loading
177
+ */
178
+ skipLifecycle?: boolean;
179
+ }
180
+
181
+ /**
182
+ * Module loader service for programmatically loading lazy modules
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * @Controller('admin')
187
+ * class AdminController {
188
+ * constructor(private moduleLoader: ModuleLoader) {}
189
+ *
190
+ * @Post('load-users-module')
191
+ * async loadUsersModule() {
192
+ * await this.moduleLoader.load(LazyUsersModule);
193
+ * return { message: 'Users module loaded' };
194
+ * }
195
+ * }
196
+ * ```
197
+ */
198
+ @Injectable()
199
+ export class ModuleLoader {
200
+ private container: Container;
201
+ private loadedModules = new Set<Constructor>();
202
+ private moduleLoaders = new Map<Constructor, LazyModuleLoaderImpl>();
203
+ private onModuleLoadCallback?: (
204
+ moduleClass: Constructor,
205
+ ) => Promise<void>;
206
+
207
+ constructor(container: Container) {
208
+ this.container = container;
209
+ }
210
+
211
+ /**
212
+ * Set callback to be called when a module is loaded
213
+ * Used by Application to register controllers and providers
214
+ */
215
+ setOnModuleLoadCallback(
216
+ callback: (moduleClass: Constructor) => Promise<void>,
217
+ ): void {
218
+ this.onModuleLoadCallback = callback;
219
+ }
220
+
221
+ /**
222
+ * Load a lazy module by its token/class
223
+ *
224
+ * @param moduleToken - The module class or token to load
225
+ * @param options - Options for loading
226
+ */
227
+ async load(
228
+ moduleToken: Token | Constructor,
229
+ options: LoadModuleOptions = {},
230
+ ): Promise<void> {
231
+ // Normalize to Constructor if it's a token
232
+ const moduleClass =
233
+ typeof moduleToken === "function"
234
+ ? (moduleToken as Constructor)
235
+ : null;
236
+
237
+ if (!moduleClass) {
238
+ throw new Error("Module token must be a class constructor");
239
+ }
240
+
241
+ // Check if already loaded
242
+ if (this.isLoaded(moduleClass)) {
243
+ return;
244
+ }
245
+
246
+ // Check if it's a lazy module
247
+ const metadata = getLazyMetadata(moduleClass);
248
+ if (!metadata) {
249
+ throw new Error(
250
+ `Module ${moduleClass.name} is not a lazy module. Use @LazyModule decorator.`,
251
+ );
252
+ }
253
+
254
+ // Get or create loader
255
+ let loader = this.moduleLoaders.get(moduleClass);
256
+ if (!loader) {
257
+ loader = new LazyModuleLoaderImpl(
258
+ metadata.loader,
259
+ async (loadedModule) => {
260
+ // Update metadata
261
+ metadata.loaded = true;
262
+ metadata.loadedModule = loadedModule;
263
+
264
+ // Call the callback if set
265
+ if (this.onModuleLoadCallback && !options.skipLifecycle) {
266
+ await this.onModuleLoadCallback(loadedModule);
267
+ }
268
+ },
269
+ );
270
+ this.moduleLoaders.set(moduleClass, loader);
271
+ }
272
+
273
+ await loader.load();
274
+ this.loadedModules.add(moduleClass);
275
+ }
276
+
277
+ /**
278
+ * Check if a module is loaded
279
+ *
280
+ * @param moduleToken - The module class or token to check
281
+ */
282
+ isLoaded(moduleToken: Token | Constructor): boolean {
283
+ if (typeof moduleToken === "function") {
284
+ const metadata = getLazyMetadata(moduleToken as Constructor);
285
+ if (metadata) {
286
+ return metadata.loaded;
287
+ }
288
+ return this.loadedModules.has(moduleToken as unknown as Constructor);
289
+ }
290
+ return this.loadedModules.has(moduleToken as unknown as Constructor);
291
+ }
292
+
293
+ /**
294
+ * Get all loaded module classes
295
+ */
296
+ getLoadedModules(): Constructor[] {
297
+ return Array.from(this.loadedModules);
298
+ }
299
+
300
+ /**
301
+ * Preload multiple lazy modules
302
+ *
303
+ * @param moduleTokens - Array of module tokens to preload
304
+ */
305
+ async preload(moduleTokens: Array<Token | Constructor>): Promise<void> {
306
+ await Promise.all(moduleTokens.map((token) => this.load(token)));
307
+ }
308
+ }
309
+
310
+ // ============= Lazy Module Registry =============
311
+
312
+ /**
313
+ * Registry for tracking lazy modules across the application
314
+ */
315
+ export class LazyModuleRegistry {
316
+ private static instance: LazyModuleRegistry;
317
+ private lazyModules = new Map<Token, LazyModuleMetadata>();
318
+
319
+ private constructor() {}
320
+
321
+ static getInstance(): LazyModuleRegistry {
322
+ if (!LazyModuleRegistry.instance) {
323
+ LazyModuleRegistry.instance = new LazyModuleRegistry();
324
+ }
325
+ return LazyModuleRegistry.instance;
326
+ }
327
+
328
+ /**
329
+ * Register a lazy module
330
+ */
331
+ register(token: Token, metadata: LazyModuleMetadata): void {
332
+ this.lazyModules.set(token, metadata);
333
+ }
334
+
335
+ /**
336
+ * Get lazy module metadata
337
+ */
338
+ get(token: Token): LazyModuleMetadata | undefined {
339
+ return this.lazyModules.get(token);
340
+ }
341
+
342
+ /**
343
+ * Check if a token is a registered lazy module
344
+ */
345
+ has(token: Token): boolean {
346
+ return this.lazyModules.has(token);
347
+ }
348
+
349
+ /**
350
+ * Get all registered lazy module tokens
351
+ */
352
+ getAllTokens(): Token[] {
353
+ return Array.from(this.lazyModules.keys());
354
+ }
355
+
356
+ /**
357
+ * Clear the registry
358
+ */
359
+ clear(): void {
360
+ this.lazyModules.clear();
361
+ }
362
+ }
363
+
364
+ // ============= Helper Functions =============
365
+
366
+ /**
367
+ * Create a lazy module loader for dynamic imports
368
+ *
369
+ * @param importFn - Dynamic import function
370
+ * @param exportName - Name of the exported module class (default: 'default')
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * const loadUsersModule = createLazyLoader(
375
+ * () => import('./users.module'),
376
+ * 'UsersModule'
377
+ * );
378
+ * ```
379
+ */
380
+ export function createLazyLoader(
381
+ importFn: () => Promise<Record<string, unknown>>,
382
+ exportName = "default",
383
+ ): ModuleLoaderFn {
384
+ return async () => {
385
+ const module = await importFn();
386
+ const moduleClass = module[exportName] as Constructor;
387
+ if (!moduleClass) {
388
+ throw new Error(
389
+ `Export "${exportName}" not found in lazy loaded module`,
390
+ );
391
+ }
392
+ return moduleClass;
393
+ };
394
+ }
395
+
396
+ /**
397
+ * Check if all lazy modules in a list are loaded
398
+ */
399
+ export function areAllLazyModulesLoaded(
400
+ modules: Constructor[],
401
+ ): boolean {
402
+ return modules.every((module) => {
403
+ const metadata = getLazyMetadata(module);
404
+ return !metadata || metadata.loaded;
405
+ });
406
+ }
407
+
408
+ /**
409
+ * Get list of unloaded lazy modules
410
+ */
411
+ export function getUnloadedLazyModules(
412
+ modules: Constructor[],
413
+ ): Constructor[] {
414
+ return modules.filter((module) => {
415
+ const metadata = getLazyMetadata(module);
416
+ return metadata && !metadata.loaded;
417
+ });
418
+ }