@buenojs/bueno 0.8.0 → 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
- bueno: "^0.1.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"
@@ -1368,7 +1373,7 @@ function getTsConfigTemplate() {
1368
1373
  allowSyntheticDefaultImports: true,
1369
1374
  jsx: "react-jsx",
1370
1375
  paths: {
1371
- bueno: ["./node_modules/bueno/dist/index.d.ts"]
1376
+ "@buenojs/bueno": ["./node_modules/@buenojs/bueno/dist/index.d.ts"]
1372
1377
  }
1373
1378
  },
1374
1379
  include: ["server/**/*", "client/**/*"],
@@ -1377,7 +1382,7 @@ function getTsConfigTemplate() {
1377
1382
  }
1378
1383
  function getMainTemplate(config) {
1379
1384
  if (config.template === "minimal") {
1380
- return `import { createServer } from 'bueno';
1385
+ return `import { createServer } from '@buenojs/bueno';
1381
1386
 
1382
1387
  const app = createServer();
1383
1388
 
@@ -1388,8 +1393,8 @@ app.router.get('/', () => {
1388
1393
  await app.listen(3000);
1389
1394
  `;
1390
1395
  }
1391
- return `import { createApp, Module, Controller, Get, Injectable } from 'bueno';
1392
- import type { Context } from 'bueno';
1396
+ return `import { createApp, Module, Controller, Get, Injectable } from '@buenojs/bueno';
1397
+ import type { Context } from '@buenojs/bueno';
1393
1398
 
1394
1399
  // Services
1395
1400
  @Injectable()
@@ -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')
@@ -1429,7 +1470,7 @@ await app.listen(3000);
1429
1470
  }
1430
1471
  function getConfigTemplate(config) {
1431
1472
  const dbConfig = config.database === "sqlite" ? `{ url: 'sqlite:./data.db' }` : `{ url: process.env.DATABASE_URL ?? '${config.database}://localhost/${kebabCase(config.name)}' }`;
1432
- return `import { defineConfig } from 'bueno';
1473
+ return `import { defineConfig } from '@buenojs/bueno';
1433
1474
 
1434
1475
  export default defineConfig({
1435
1476
  server: {
@@ -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
 
@@ -1879,8 +1949,8 @@ var GENERATOR_ALIASES = {
1879
1949
  };
1880
1950
  function getTemplate(type) {
1881
1951
  const templates = {
1882
- controller: `import { Controller, Get, Post, Put, Delete{{#if path}} } from 'bueno'{{/if}}{{#if service}}, { {{pascalCase service}}Service } from './{{kebabCase service}}.service'{{/if}};
1883
- import type { Context } from 'bueno';
1952
+ controller: `import { Controller, Get, Post, Put, Delete{{#if path}} } from '@buenojs/bueno'{{/if}}{{#if service}}, { {{pascalCase service}}Service } from './{{kebabCase service}}.service'{{/if}};
1953
+ import type { Context } from '@buenojs/bueno';
1884
1954
 
1885
1955
  @Controller('{{path}}')
1886
1956
  export class {{pascalCase name}}Controller {
@@ -1919,7 +1989,7 @@ export class {{pascalCase name}}Controller {
1919
1989
  }
1920
1990
  }
1921
1991
  `,
1922
- service: `import { Injectable } from 'bueno';
1992
+ service: `import { Injectable } from '@buenojs/bueno';
1923
1993
 
1924
1994
  @Injectable()
1925
1995
  export class {{pascalCase name}}Service {
@@ -1949,7 +2019,7 @@ export class {{pascalCase name}}Service {
1949
2019
  }
1950
2020
  }
1951
2021
  `,
1952
- module: `import { Module } from 'bueno';
2022
+ module: `import { Module } from '@buenojs/bueno';
1953
2023
  import { {{pascalCase name}}Controller } from './{{kebabCase name}}.controller';
1954
2024
  import { {{pascalCase name}}Service } from './{{kebabCase name}}.service';
1955
2025
 
@@ -1960,7 +2030,7 @@ import { {{pascalCase name}}Service } from './{{kebabCase name}}.service';
1960
2030
  })
1961
2031
  export class {{pascalCase name}}Module {}
1962
2032
  `,
1963
- guard: `import { Injectable, type CanActivate, type Context } from 'bueno';
2033
+ guard: `import { Injectable, type CanActivate, type Context } from '@buenojs/bueno';
1964
2034
 
1965
2035
  @Injectable()
1966
2036
  export class {{pascalCase name}}Guard implements CanActivate {
@@ -1971,7 +2041,7 @@ export class {{pascalCase name}}Guard implements CanActivate {
1971
2041
  }
1972
2042
  }
1973
2043
  `,
1974
- interceptor: `import { Injectable, type NestInterceptor, type CallHandler, type Context } from 'bueno';
2044
+ interceptor: `import { Injectable, type NestInterceptor, type CallHandler, type Context } from '@buenojs/bueno';
1975
2045
  import type { Observable } from 'rxjs';
1976
2046
 
1977
2047
  @Injectable()
@@ -1990,7 +2060,7 @@ export class {{pascalCase name}}Interceptor implements NestInterceptor {
1990
2060
  }
1991
2061
  }
1992
2062
  `,
1993
- pipe: `import { Injectable, type PipeTransform, type Context } from 'bueno';
2063
+ pipe: `import { Injectable, type PipeTransform, type Context } from '@buenojs/bueno';
1994
2064
 
1995
2065
  @Injectable()
1996
2066
  export class {{pascalCase name}}Pipe implements PipeTransform {
@@ -2001,8 +2071,8 @@ export class {{pascalCase name}}Pipe implements PipeTransform {
2001
2071
  }
2002
2072
  }
2003
2073
  `,
2004
- filter: `import { Injectable, type ExceptionFilter, type Context } from 'bueno';
2005
- import type { Response } from 'bueno';
2074
+ filter: `import { Injectable, type ExceptionFilter, type Context } from '@buenojs/bueno';
2075
+ import type { Response } from '@buenojs/bueno';
2006
2076
 
2007
2077
  @Injectable()
2008
2078
  export class {{pascalCase name}}Filter implements ExceptionFilter {
@@ -2048,7 +2118,7 @@ export interface Update{{pascalCase name}}Dto extends Partial<Create{{pascalCase
2048
2118
  // TODO: Define optional properties for update
2049
2119
  }
2050
2120
  `,
2051
- middleware: `import type { Middleware, Context, Handler } from 'bueno';
2121
+ middleware: `import type { Middleware, Context, Handler } from '@buenojs/bueno';
2052
2122
 
2053
2123
  /**
2054
2124
  * {{pascalCase name}} Middleware
@@ -2069,7 +2139,7 @@ export const {{camelCase name}}Middleware: Middleware = async (
2069
2139
  return result;
2070
2140
  };
2071
2141
  `,
2072
- migration: `import { createMigration, type MigrationRunner } from 'bueno';
2142
+ migration: `import { createMigration, type MigrationRunner } from '@buenojs/bueno';
2073
2143
 
2074
2144
  export default createMigration('{{migrationId}}', '{{migrationName}}')
2075
2145
  .up(async (db: MigrationRunner) => {
@@ -2325,7 +2395,7 @@ async function createMigration(name, dryRun) {
2325
2395
  const kebabName = name.toLowerCase().replace(/\s+/g, "-");
2326
2396
  const fileName = `${id}_${kebabName}.ts`;
2327
2397
  const filePath = joinPaths(migrationsDir, fileName);
2328
- const template = `import { createMigration, type MigrationRunner } from 'bueno';
2398
+ const template = `import { createMigration, type MigrationRunner } from '@buenojs/bueno';
2329
2399
 
2330
2400
  export default createMigration('${id}', '${kebabName}')
2331
2401
  .up(async (db: MigrationRunner) => {
@@ -2421,7 +2491,7 @@ async function handleMigration(args) {
2421
2491
  cliConsole.log("");
2422
2492
  cliConsole.log("Example:");
2423
2493
  cliConsole.log(colors.cyan(`
2424
- import { createMigrationRunner, loadMigrations } from 'bueno';
2494
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
2425
2495
  import { db } from './database';
2426
2496
 
2427
2497
  const runner = createMigrationRunner(db);
@@ -2437,7 +2507,7 @@ await runner.migrate(migrations);
2437
2507
  cliConsole.log("");
2438
2508
  cliConsole.log("Example:");
2439
2509
  cliConsole.log(colors.cyan(`
2440
- import { createMigrationRunner, loadMigrations } from 'bueno';
2510
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
2441
2511
  import { db } from './database';
2442
2512
 
2443
2513
  const runner = createMigrationRunner(db);
@@ -2453,7 +2523,7 @@ await runner.rollback(migrations, ${steps});
2453
2523
  cliConsole.log("");
2454
2524
  cliConsole.log("Example:");
2455
2525
  cliConsole.log(colors.cyan(`
2456
- import { createMigrationRunner, loadMigrations } from 'bueno';
2526
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
2457
2527
  import { db } from './database';
2458
2528
 
2459
2529
  const runner = createMigrationRunner(db);
@@ -2469,7 +2539,7 @@ await runner.reset(migrations);
2469
2539
  cliConsole.log("");
2470
2540
  cliConsole.log("Example:");
2471
2541
  cliConsole.log(colors.cyan(`
2472
- import { createMigrationRunner, loadMigrations } from 'bueno';
2542
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
2473
2543
  import { db } from './database';
2474
2544
 
2475
2545
  const runner = createMigrationRunner(db);
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.0",
3
+ "version": "0.8.2",
4
4
  "description": "A Bun-Native Full-Stack Framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -69,8 +69,8 @@ interface GeneratorConfig {
69
69
  */
70
70
  function getTemplate(type: GeneratorType): string {
71
71
  const templates: Record<GeneratorType, string> = {
72
- controller: `import { Controller, Get, Post, Put, Delete{{#if path}} } from 'bueno'{{/if}}{{#if service}}, { {{pascalCase service}}Service } from './{{kebabCase service}}.service'{{/if}};
73
- import type { Context } from 'bueno';
72
+ controller: `import { Controller, Get, Post, Put, Delete{{#if path}} } from '@buenojs/bueno'{{/if}}{{#if service}}, { {{pascalCase service}}Service } from './{{kebabCase service}}.service'{{/if}};
73
+ import type { Context } from '@buenojs/bueno';
74
74
 
75
75
  @Controller('{{path}}')
76
76
  export class {{pascalCase name}}Controller {
@@ -109,7 +109,7 @@ export class {{pascalCase name}}Controller {
109
109
  }
110
110
  }
111
111
  `,
112
- service: `import { Injectable } from 'bueno';
112
+ service: `import { Injectable } from '@buenojs/bueno';
113
113
 
114
114
  @Injectable()
115
115
  export class {{pascalCase name}}Service {
@@ -139,7 +139,7 @@ export class {{pascalCase name}}Service {
139
139
  }
140
140
  }
141
141
  `,
142
- module: `import { Module } from 'bueno';
142
+ module: `import { Module } from '@buenojs/bueno';
143
143
  import { {{pascalCase name}}Controller } from './{{kebabCase name}}.controller';
144
144
  import { {{pascalCase name}}Service } from './{{kebabCase name}}.service';
145
145
 
@@ -150,7 +150,7 @@ import { {{pascalCase name}}Service } from './{{kebabCase name}}.service';
150
150
  })
151
151
  export class {{pascalCase name}}Module {}
152
152
  `,
153
- guard: `import { Injectable, type CanActivate, type Context } from 'bueno';
153
+ guard: `import { Injectable, type CanActivate, type Context } from '@buenojs/bueno';
154
154
 
155
155
  @Injectable()
156
156
  export class {{pascalCase name}}Guard implements CanActivate {
@@ -161,7 +161,7 @@ export class {{pascalCase name}}Guard implements CanActivate {
161
161
  }
162
162
  }
163
163
  `,
164
- interceptor: `import { Injectable, type NestInterceptor, type CallHandler, type Context } from 'bueno';
164
+ interceptor: `import { Injectable, type NestInterceptor, type CallHandler, type Context } from '@buenojs/bueno';
165
165
  import type { Observable } from 'rxjs';
166
166
 
167
167
  @Injectable()
@@ -180,7 +180,7 @@ export class {{pascalCase name}}Interceptor implements NestInterceptor {
180
180
  }
181
181
  }
182
182
  `,
183
- pipe: `import { Injectable, type PipeTransform, type Context } from 'bueno';
183
+ pipe: `import { Injectable, type PipeTransform, type Context } from '@buenojs/bueno';
184
184
 
185
185
  @Injectable()
186
186
  export class {{pascalCase name}}Pipe implements PipeTransform {
@@ -191,8 +191,8 @@ export class {{pascalCase name}}Pipe implements PipeTransform {
191
191
  }
192
192
  }
193
193
  `,
194
- filter: `import { Injectable, type ExceptionFilter, type Context } from 'bueno';
195
- import type { Response } from 'bueno';
194
+ filter: `import { Injectable, type ExceptionFilter, type Context } from '@buenojs/bueno';
195
+ import type { Response } from '@buenojs/bueno';
196
196
 
197
197
  @Injectable()
198
198
  export class {{pascalCase name}}Filter implements ExceptionFilter {
@@ -238,7 +238,7 @@ export interface Update{{pascalCase name}}Dto extends Partial<Create{{pascalCase
238
238
  // TODO: Define optional properties for update
239
239
  }
240
240
  `,
241
- middleware: `import type { Middleware, Context, Handler } from 'bueno';
241
+ middleware: `import type { Middleware, Context, Handler } from '@buenojs/bueno';
242
242
 
243
243
  /**
244
244
  * {{pascalCase name}} Middleware
@@ -259,7 +259,7 @@ export const {{camelCase name}}Middleware: Middleware = async (
259
259
  return result;
260
260
  };
261
261
  `,
262
- migration: `import { createMigration, type MigrationRunner } from 'bueno';
262
+ migration: `import { createMigration, type MigrationRunner } from '@buenojs/bueno';
263
263
 
264
264
  export default createMigration('{{migrationId}}', '{{migrationName}}')
265
265
  .up(async (db: MigrationRunner) => {
@@ -104,7 +104,7 @@ async function createMigration(name: string, dryRun: boolean): Promise<string> {
104
104
  const fileName = `${id}_${kebabName}.ts`;
105
105
  const filePath = joinPaths(migrationsDir, fileName);
106
106
 
107
- const template = `import { createMigration, type MigrationRunner } from 'bueno';
107
+ const template = `import { createMigration, type MigrationRunner } from '@buenojs/bueno';
108
108
 
109
109
  export default createMigration('${id}', '${kebabName}')
110
110
  .up(async (db: MigrationRunner) => {
@@ -236,7 +236,7 @@ async function handleMigration(args: ParsedArgs): Promise<void> {
236
236
  cliConsole.log('');
237
237
  cliConsole.log('Example:');
238
238
  cliConsole.log(colors.cyan(`
239
- import { createMigrationRunner, loadMigrations } from 'bueno';
239
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
240
240
  import { db } from './database';
241
241
 
242
242
  const runner = createMigrationRunner(db);
@@ -255,7 +255,7 @@ await runner.migrate(migrations);
255
255
  cliConsole.log('');
256
256
  cliConsole.log('Example:');
257
257
  cliConsole.log(colors.cyan(`
258
- import { createMigrationRunner, loadMigrations } from 'bueno';
258
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
259
259
  import { db } from './database';
260
260
 
261
261
  const runner = createMigrationRunner(db);
@@ -274,7 +274,7 @@ await runner.rollback(migrations, ${steps});
274
274
  cliConsole.log('');
275
275
  cliConsole.log('Example:');
276
276
  cliConsole.log(colors.cyan(`
277
- import { createMigrationRunner, loadMigrations } from 'bueno';
277
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
278
278
  import { db } from './database';
279
279
 
280
280
  const runner = createMigrationRunner(db);
@@ -293,7 +293,7 @@ await runner.reset(migrations);
293
293
  cliConsole.log('');
294
294
  cliConsole.log('Example:');
295
295
  cliConsole.log(colors.cyan(`
296
- import { createMigrationRunner, loadMigrations } from 'bueno';
296
+ import { createMigrationRunner, loadMigrations } from '@buenojs/bueno';
297
297
  import { db } from './database';
298
298
 
299
299
  const runner = createMigrationRunner(db);
@@ -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
- bueno: '^0.1.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',
@@ -141,8 +146,8 @@ function getTsConfigTemplate(): string {
141
146
  allowSyntheticDefaultImports: true,
142
147
  jsx: 'react-jsx',
143
148
  paths: {
144
- bueno: ['./node_modules/bueno/dist/index.d.ts'],
145
- },
149
+ '@buenojs/bueno': ['./node_modules/@buenojs/bueno/dist/index.d.ts'],
150
+ },
146
151
  },
147
152
  include: ['server/**/*', 'client/**/*'],
148
153
  exclude: ['node_modules', 'dist'],
@@ -157,7 +162,7 @@ function getTsConfigTemplate(): string {
157
162
  */
158
163
  function getMainTemplate(config: ProjectConfig): string {
159
164
  if (config.template === 'minimal') {
160
- return `import { createServer } from 'bueno';
165
+ return `import { createServer } from '@buenojs/bueno';
161
166
 
162
167
  const app = createServer();
163
168
 
@@ -169,8 +174,8 @@ await app.listen(3000);
169
174
  `;
170
175
  }
171
176
 
172
- return `import { createApp, Module, Controller, Get, Injectable } from 'bueno';
173
- import type { Context } from 'bueno';
177
+ return `import { createApp, Module, Controller, Get, Injectable } from '@buenojs/bueno';
178
+ import type { Context } from '@buenojs/bueno';
174
179
 
175
180
  // Services
176
181
  @Injectable()
@@ -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')
@@ -217,7 +258,7 @@ function getConfigTemplate(config: ProjectConfig): string {
217
258
  ? `{ url: 'sqlite:./data.db' }`
218
259
  : `{ url: process.env.DATABASE_URL ?? '${config.database}://localhost/${kebabCase(config.name)}' }`;
219
260
 
220
- return `import { defineConfig } from 'bueno';
261
+ return `import { defineConfig } from '@buenojs/bueno';
221
262
 
222
263
  export default defineConfig({
223
264
  server: {
@@ -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"]