@buenojs/bueno 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -20,6 +20,10 @@ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
20
20
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
21
  return c > 3 && r && Object.defineProperty(target, key, r), r;
22
22
  };
23
+ var __legacyMetadataTS = (k, v) => {
24
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
25
+ return Reflect.metadata(k, v);
26
+ };
23
27
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
24
28
  var __require = import.meta.require;
25
29
 
@@ -1328,9 +1332,10 @@ function validateProjectName(name) {
1328
1332
  return true;
1329
1333
  }
1330
1334
  function getPackageJsonTemplate(config) {
1331
- const dependencies = {
1332
- "@buenojs/bueno": "^0.8.0"
1333
- };
1335
+ const dependencies = {};
1336
+ if (!config.link) {
1337
+ dependencies["@buenojs/bueno"] = "^0.8.0";
1338
+ }
1334
1339
  const devDependencies = {
1335
1340
  "@types/bun": "latest",
1336
1341
  typescript: "^5.3.0"
@@ -1405,8 +1410,44 @@ export class AppController {
1405
1410
  constructor(private readonly appService: AppService) {}
1406
1411
 
1407
1412
  @Get()
1408
- findAll(ctx: Context) {
1409
- return this.appService.findAll();
1413
+ hello() {
1414
+ return new Response(\`<html>
1415
+ <head>
1416
+ <title>Welcome to Bueno</title>
1417
+ <style>
1418
+ body { font-family: system-ui, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
1419
+ h1 { color: #2563eb; }
1420
+ code { background: #f3f4f6; padding: 2px 6px; border-radius: 4px; }
1421
+ pre { background: #f3f4f6; padding: 16px; border-radius: 8px; overflow-x: auto; }
1422
+ a { color: #2563eb; }
1423
+ </style>
1424
+ </head>
1425
+ <body>
1426
+ <h1>\uD83C\uDF89 Welcome to Bueno Framework!</h1>
1427
+ <p>Your Bun-native full-stack framework is running successfully.</p>
1428
+
1429
+ <h2>Getting Started</h2>
1430
+ <ul>
1431
+ <li>Edit <code>server/main.ts</code> to modify this app</li>
1432
+ <li>Add routes using the <code>@Get()</code>, <code>@Post()</code> decorators</li>
1433
+ <li>Create services with <code>@Injectable()</code> and inject them in controllers</li>
1434
+ </ul>
1435
+
1436
+ <h2>Documentation</h2>
1437
+ <p>Visit <a href="https://buenojs.dev">https://buenojs.dev</a> for full documentation.</p>
1438
+
1439
+ <h2>Quick Example</h2>
1440
+ <pre><code>@Controller('/api')
1441
+ class MyController {
1442
+ @Get('/users')
1443
+ getUsers() {
1444
+ return { users: [] };
1445
+ }
1446
+ }</code></pre>
1447
+ </body>
1448
+ </html>\`, {
1449
+ headers: { 'Content-Type': 'text/html; charset=utf-8' }
1450
+ });
1410
1451
  }
1411
1452
 
1412
1453
  @Get('health')
@@ -1669,6 +1710,7 @@ async function handleNew(args) {
1669
1710
  const skipInstall = hasFlag(args, "skip-install");
1670
1711
  const skipGit = hasFlag(args, "skip-git");
1671
1712
  const docker = hasFlag(args, "docker");
1713
+ const link = hasFlag(args, "link");
1672
1714
  const deployPlatforms = getOptionValues(args, "deploy");
1673
1715
  const validPlatforms = ["render", "fly", "railway"];
1674
1716
  const deploy = [];
@@ -1717,7 +1759,8 @@ async function handleNew(args) {
1717
1759
  skipInstall,
1718
1760
  skipGit,
1719
1761
  docker,
1720
- deploy
1762
+ deploy,
1763
+ link
1721
1764
  };
1722
1765
  const projectPath = joinPaths(process.cwd(), kebabCase(name));
1723
1766
  if (await fileExists(projectPath)) {
@@ -1731,6 +1774,7 @@ async function handleNew(args) {
1731
1774
  ["Docker", docker ? colors.green("Yes") : colors.red("No")],
1732
1775
  ["Deploy", deploy.length > 0 ? colors.green(deploy.map(getDeployPlatformName).join(", ")) : colors.red("None")],
1733
1776
  ["Install dependencies", skipInstall ? colors.red("No") : colors.green("Yes")],
1777
+ ["Use local package", link ? colors.green("Yes (bun link)") : colors.red("No")],
1734
1778
  ["Initialize git", skipGit ? colors.red("No") : colors.green("Yes")]
1735
1779
  ];
1736
1780
  printTable(["Setting", "Value"], rows);
@@ -1755,6 +1799,25 @@ async function handleNew(args) {
1755
1799
  } catch {
1756
1800
  installSpinner.warn("Failed to install dependencies. Run `bun install` manually.");
1757
1801
  }
1802
+ if (link) {
1803
+ cliConsole.subheader("Linking local @buenojs/bueno...");
1804
+ const linkSpinner = spinner("Running bun link @buenojs/bueno...");
1805
+ try {
1806
+ const proc = Bun.spawn(["bun", "link", "@buenojs/bueno"], {
1807
+ cwd: projectPath,
1808
+ stdout: "pipe",
1809
+ stderr: "pipe"
1810
+ });
1811
+ const exitCode = await proc.exited;
1812
+ if (exitCode === 0) {
1813
+ linkSpinner.success("Local @buenojs/bueno linked successfully");
1814
+ } else {
1815
+ linkSpinner.warn("Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.");
1816
+ }
1817
+ } catch {
1818
+ linkSpinner.warn("Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.");
1819
+ }
1820
+ }
1758
1821
  }
1759
1822
  if (!skipGit) {
1760
1823
  cliConsole.subheader("Initializing git repository...");
@@ -1835,6 +1898,12 @@ defineCommand({
1835
1898
  default: false,
1836
1899
  description: "Include Docker configuration (Dockerfile, docker-compose.yml)"
1837
1900
  },
1901
+ {
1902
+ name: "link",
1903
+ type: "boolean",
1904
+ default: false,
1905
+ description: "Use local @buenojs/bueno via bun link (for development)"
1906
+ },
1838
1907
  {
1839
1908
  name: "deploy",
1840
1909
  type: "string",
@@ -1860,7 +1929,8 @@ defineCommand({
1860
1929
  "bueno new my-app --deploy render --deploy fly",
1861
1930
  "bueno new my-app --docker --deploy render",
1862
1931
  "bueno new my-app --docker --database postgresql --deploy render",
1863
- "bueno new my-app -y"
1932
+ "bueno new my-app -y",
1933
+ "bueno new my-app --link"
1864
1934
  ]
1865
1935
  }, handleNew);
1866
1936
 
package/dist/index.js CHANGED
@@ -19,6 +19,10 @@ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
19
19
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
20
20
  return c > 3 && r && Object.defineProperty(target, key, r), r;
21
21
  };
22
+ var __legacyMetadataTS = (k, v) => {
23
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
24
+ return Reflect.metadata(k, v);
25
+ };
22
26
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
23
27
  var __require = import.meta.require;
24
28
 
@@ -564,7 +568,7 @@ class ResolutionStack {
564
568
  }
565
569
  }
566
570
 
567
- class Container {
571
+ class Container2 {
568
572
  providers = new Map;
569
573
  resolutionStack = new ResolutionStack;
570
574
  register(provider) {
@@ -684,7 +688,7 @@ class Container {
684
688
  return Array.from(this.providers.keys());
685
689
  }
686
690
  createChild() {
687
- const child = new Container;
691
+ const child = new Container2;
688
692
  for (const [token, resolved] of this.providers) {
689
693
  if (resolved.provider.scope === "singleton") {
690
694
  child.providers.set(token, resolved);
@@ -1901,7 +1905,10 @@ class ModuleLoader {
1901
1905
  }
1902
1906
  }
1903
1907
  ModuleLoader = __legacyDecorateClassTS([
1904
- Injectable2()
1908
+ Injectable2(),
1909
+ __legacyMetadataTS("design:paramtypes", [
1910
+ typeof Container === "undefined" ? Object : Container
1911
+ ])
1905
1912
  ], ModuleLoader);
1906
1913
 
1907
1914
  class LazyModuleRegistry {
@@ -2692,9 +2699,9 @@ function createInternalErrorResponse(exception) {
2692
2699
  function Inject2(token) {
2693
2700
  return (target, propertyKey, parameterIndex) => {
2694
2701
  const targetObj = target;
2695
- const existingTokens = getMetadata(targetObj, "inject:tokens") ?? [];
2702
+ const existingTokens = getContainerMetadata(targetObj, "inject:tokens") ?? [];
2696
2703
  existingTokens[parameterIndex] = token;
2697
- setMetadata(targetObj, "inject:tokens", existingTokens);
2704
+ setContainerMetadata(targetObj, "inject:tokens", existingTokens);
2698
2705
  };
2699
2706
  }
2700
2707
  function createMethodDecorator(method) {
@@ -2748,7 +2755,13 @@ class AppModule {
2748
2755
  }
2749
2756
  }
2750
2757
  if (metadata.providers) {
2751
- this.providers.push(...metadata.providers);
2758
+ const normalizedProviders = metadata.providers.map((p) => {
2759
+ if (typeof p === "function" && !p.token) {
2760
+ return { token: p, useClass: p };
2761
+ }
2762
+ return p;
2763
+ });
2764
+ this.providers.push(...normalizedProviders);
2752
2765
  }
2753
2766
  if (metadata.controllers) {
2754
2767
  this.controllers.push(...metadata.controllers);
@@ -2787,7 +2800,7 @@ class Application {
2787
2800
  moduleLoader;
2788
2801
  loadedLazyModules = new Set;
2789
2802
  constructor(moduleClass) {
2790
- this.container = new Container;
2803
+ this.container = new Container2;
2791
2804
  this.router = new Router;
2792
2805
  this.appModule = new AppModule(moduleClass);
2793
2806
  this.lifecycleManager = new LifecycleHookManager;
@@ -2834,7 +2847,13 @@ class Application {
2834
2847
  registerController(controllerClass) {
2835
2848
  const basePath = getMetadata(controllerClass, "path") ?? "";
2836
2849
  const routes = getPrototypeMetadata(controllerClass.prototype, "routes") ?? [];
2837
- const injectTokens = getContainerMetadata(controllerClass, "inject:tokens") ?? [];
2850
+ let injectTokens = getContainerMetadata(controllerClass, "inject:tokens") ?? [];
2851
+ if (injectTokens.length === 0 && typeof Reflect !== "undefined" && typeof Reflect.getMetadata === "function") {
2852
+ const paramTypes = Reflect.getMetadata("design:paramtypes", controllerClass);
2853
+ if (paramTypes) {
2854
+ injectTokens = paramTypes.map((paramType) => paramType);
2855
+ }
2856
+ }
2838
2857
  const deps = injectTokens.map((tokenOrRef) => {
2839
2858
  const token = isForwardRef(tokenOrRef) ? resolveForwardRef(tokenOrRef) : tokenOrRef;
2840
2859
  return this.container.resolve(token);
@@ -9004,7 +9023,7 @@ export {
9004
9023
  Database,
9005
9024
  Controller,
9006
9025
  Context,
9007
- Container,
9026
+ Container2 as Container,
9008
9027
  ConfigManager,
9009
9028
  Cache,
9010
9029
  CSRF,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buenojs/bueno",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "A Bun-Native Full-Stack Framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -58,6 +58,7 @@ interface ProjectConfig {
58
58
  skipGit: boolean;
59
59
  docker: boolean;
60
60
  deploy: DeployPlatform[];
61
+ link: boolean;
61
62
  }
62
63
 
63
64
  /**
@@ -87,9 +88,13 @@ function validateProjectName(name: string): boolean | string {
87
88
  * Get package.json template
88
89
  */
89
90
  function getPackageJsonTemplate(config: ProjectConfig): string {
90
- const dependencies: Record<string, string> = {
91
- '@buenojs/bueno': '^0.8.0',
92
- };
91
+ const dependencies: Record<string, string> = {};
92
+
93
+ // If using link, don't add @buenojs/bueno to dependencies
94
+ // It will be linked from the local version
95
+ if (!config.link) {
96
+ dependencies['@buenojs/bueno'] = '^0.8.0';
97
+ }
93
98
 
94
99
  const devDependencies: Record<string, string> = {
95
100
  '@types/bun': 'latest',
@@ -186,8 +191,44 @@ export class AppController {
186
191
  constructor(private readonly appService: AppService) {}
187
192
 
188
193
  @Get()
189
- findAll(ctx: Context) {
190
- return this.appService.findAll();
194
+ hello() {
195
+ return new Response(\`<html>
196
+ <head>
197
+ <title>Welcome to Bueno</title>
198
+ <style>
199
+ body { font-family: system-ui, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
200
+ h1 { color: #2563eb; }
201
+ code { background: #f3f4f6; padding: 2px 6px; border-radius: 4px; }
202
+ pre { background: #f3f4f6; padding: 16px; border-radius: 8px; overflow-x: auto; }
203
+ a { color: #2563eb; }
204
+ </style>
205
+ </head>
206
+ <body>
207
+ <h1>🎉 Welcome to Bueno Framework!</h1>
208
+ <p>Your Bun-native full-stack framework is running successfully.</p>
209
+
210
+ <h2>Getting Started</h2>
211
+ <ul>
212
+ <li>Edit <code>server/main.ts</code> to modify this app</li>
213
+ <li>Add routes using the <code>@Get()</code>, <code>@Post()</code> decorators</li>
214
+ <li>Create services with <code>@Injectable()</code> and inject them in controllers</li>
215
+ </ul>
216
+
217
+ <h2>Documentation</h2>
218
+ <p>Visit <a href="https://buenojs.dev">https://buenojs.dev</a> for full documentation.</p>
219
+
220
+ <h2>Quick Example</h2>
221
+ <pre><code>@Controller('/api')
222
+ class MyController {
223
+ @Get('/users')
224
+ getUsers() {
225
+ return { users: [] };
226
+ }
227
+ }</code></pre>
228
+ </body>
229
+ </html>\`, {
230
+ headers: { 'Content-Type': 'text/html; charset=utf-8' }
231
+ });
191
232
  }
192
233
 
193
234
  @Get('health')
@@ -554,6 +595,7 @@ async function handleNew(args: ParsedArgs): Promise<void> {
554
595
  const skipInstall = hasFlag(args, 'skip-install');
555
596
  const skipGit = hasFlag(args, 'skip-git');
556
597
  const docker = hasFlag(args, 'docker');
598
+ const link = hasFlag(args, 'link');
557
599
 
558
600
  // Get deployment platforms (can be specified multiple times)
559
601
  const deployPlatforms = getOptionValues(args, 'deploy');
@@ -628,6 +670,7 @@ async function handleNew(args: ParsedArgs): Promise<void> {
628
670
  skipGit,
629
671
  docker,
630
672
  deploy,
673
+ link,
631
674
  };
632
675
 
633
676
  // Check if directory exists
@@ -649,6 +692,7 @@ async function handleNew(args: ParsedArgs): Promise<void> {
649
692
  ['Docker', docker ? colors.green('Yes') : colors.red('No')],
650
693
  ['Deploy', deploy.length > 0 ? colors.green(deploy.map(getDeployPlatformName).join(', ')) : colors.red('None')],
651
694
  ['Install dependencies', skipInstall ? colors.red('No') : colors.green('Yes')],
695
+ ['Use local package', link ? colors.green('Yes (bun link)') : colors.red('No')],
652
696
  ['Initialize git', skipGit ? colors.red('No') : colors.green('Yes')],
653
697
  ];
654
698
 
@@ -681,6 +725,30 @@ async function handleNew(args: ParsedArgs): Promise<void> {
681
725
  } catch {
682
726
  installSpinner.warn('Failed to install dependencies. Run `bun install` manually.');
683
727
  }
728
+
729
+ // Link local @buenojs/bueno if --link flag is set
730
+ if (link) {
731
+ cliConsole.subheader('Linking local @buenojs/bueno...');
732
+ const linkSpinner = spinner('Running bun link @buenojs/bueno...');
733
+
734
+ try {
735
+ const proc = Bun.spawn(['bun', 'link', '@buenojs/bueno'], {
736
+ cwd: projectPath,
737
+ stdout: 'pipe',
738
+ stderr: 'pipe',
739
+ });
740
+
741
+ const exitCode = await proc.exited;
742
+
743
+ if (exitCode === 0) {
744
+ linkSpinner.success('Local @buenojs/bueno linked successfully');
745
+ } else {
746
+ linkSpinner.warn('Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.');
747
+ }
748
+ } catch {
749
+ linkSpinner.warn('Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.');
750
+ }
751
+ }
684
752
  }
685
753
 
686
754
  // Initialize git
@@ -772,6 +840,12 @@ defineCommand(
772
840
  default: false,
773
841
  description: 'Include Docker configuration (Dockerfile, docker-compose.yml)',
774
842
  },
843
+ {
844
+ name: 'link',
845
+ type: 'boolean',
846
+ default: false,
847
+ description: 'Use local @buenojs/bueno via bun link (for development)',
848
+ },
775
849
  {
776
850
  name: 'deploy',
777
851
  type: 'string',
@@ -798,6 +872,7 @@ defineCommand(
798
872
  'bueno new my-app --docker --deploy render',
799
873
  'bueno new my-app --docker --database postgresql --deploy render',
800
874
  'bueno new my-app -y',
875
+ 'bueno new my-app --link',
801
876
  ],
802
877
  },
803
878
  handleNew,
@@ -382,5 +382,5 @@ export function Inject(token: Token | ForwardRef<Token>): ParameterDecorator {
382
382
  };
383
383
  }
384
384
 
385
- // Export getter for use by modules
386
- export { getContainerMetadata as getInjectTokens };
385
+ // Export getter and setter for use by modules
386
+ export { getContainerMetadata as getInjectTokens, setContainerMetadata, getContainerMetadata };
@@ -14,6 +14,8 @@ import {
14
14
  isForwardRef,
15
15
  resolveForwardRef,
16
16
  getInjectTokens,
17
+ setContainerMetadata,
18
+ getContainerMetadata,
17
19
  } from "../container";
18
20
  import {
19
21
  type LazyModuleLoader,
@@ -162,11 +164,11 @@ export function Inject(token: Token | ForwardRef<Token>): ParameterDecorator {
162
164
  propertyKey: string | symbol | undefined,
163
165
  parameterIndex: number,
164
166
  ) => {
165
- const targetObj = target as Constructor;
167
+ const targetObj = target as object;
166
168
  const existingTokens: Array<Token | ForwardRef<Token>> =
167
- getMetadata(targetObj, "inject:tokens") ?? [];
169
+ getContainerMetadata<Array<Token | ForwardRef<Token>>>(targetObj, "inject:tokens") ?? [];
168
170
  existingTokens[parameterIndex] = token;
169
- setMetadata(targetObj, "inject:tokens", existingTokens);
171
+ setContainerMetadata(targetObj, "inject:tokens", existingTokens);
170
172
  };
171
173
  }
172
174
 
@@ -246,9 +248,16 @@ export class AppModule {
246
248
  }
247
249
  }
248
250
 
249
- // Add providers
251
+ // Add providers (normalize class references to provider objects)
250
252
  if (metadata.providers) {
251
- this.providers.push(...metadata.providers);
253
+ const normalizedProviders = metadata.providers.map(p => {
254
+ // If it's a class constructor (function) without token, normalize it
255
+ if (typeof p === 'function' && !p.token) {
256
+ return { token: p, useClass: p };
257
+ }
258
+ return p;
259
+ });
260
+ this.providers.push(...normalizedProviders);
252
261
  }
253
262
 
254
263
  // Add controllers
@@ -475,8 +484,20 @@ export class Application {
475
484
  >(controllerClass.prototype, "routes") ?? [];
476
485
 
477
486
  // Create controller instance
478
- const injectTokens =
487
+ // First, check for explicit injection tokens from @Inject decorator
488
+ let injectTokens =
479
489
  getInjectTokens<Array<Token | ForwardRef<Token>>>(controllerClass, "inject:tokens") ?? [];
490
+
491
+ // If no explicit tokens, try to use TypeScript's design:paramtypes metadata
492
+ // This requires the reflect-metadata polyfill to be imported by the user
493
+ if (injectTokens.length === 0 && typeof Reflect !== 'undefined' && typeof Reflect.getMetadata === 'function') {
494
+ const paramTypes = Reflect.getMetadata('design:paramtypes', controllerClass) as Array<new (...args: unknown[]) => unknown> | undefined;
495
+ if (paramTypes) {
496
+ // Use the constructor parameter types as injection tokens
497
+ injectTokens = paramTypes.map((paramType) => paramType as unknown as Token);
498
+ }
499
+ }
500
+
480
501
  const deps = injectTokens.map((tokenOrRef) => {
481
502
  // Resolve forward reference if needed
482
503
  const token = isForwardRef(tokenOrRef) ? resolveForwardRef(tokenOrRef) : tokenOrRef;
package/tsconfig.json CHANGED
@@ -20,7 +20,9 @@
20
20
  "paths": {
21
21
  "@/*": ["./src/*"]
22
22
  },
23
- "types": ["bun-types"]
23
+ "types": ["bun-types"],
24
+ "experimentalDecorators": true,
25
+ "emitDecoratorMetadata": true
24
26
  },
25
27
  "include": ["src/**/*"],
26
28
  "exclude": ["node_modules", "dist", "tests"]