create-buntok 0.1.3 → 0.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-buntok",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "CLI tool to create new Buntok projects",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -1,15 +1,9 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
3
  import {
4
- cpSync,
5
4
  existsSync,
6
- mkdirSync,
7
- readFileSync,
8
- readdirSync,
9
- statSync,
10
- unlinkSync,
11
- writeFileSync,
12
5
  } from "node:fs";
6
+ import fs from "node:fs/promises";
13
7
  import { join, resolve } from "node:path";
14
8
  import { createInterface } from "node:readline";
15
9
 
@@ -49,22 +43,6 @@ function validateProjectName(name: string): boolean {
49
43
  return true;
50
44
  }
51
45
 
52
- function copyDirSync(src: string, dest: string) {
53
- mkdirSync(dest, { recursive: true });
54
- const entries = readdirSync(src);
55
-
56
- for (const entry of entries) {
57
- const srcPath = join(src, entry);
58
- const destPath = join(dest, entry);
59
-
60
- if (statSync(srcPath).isDirectory()) {
61
- copyDirSync(srcPath, destPath);
62
- } else {
63
- cpSync(srcPath, destPath);
64
- }
65
- }
66
- }
67
-
68
46
  function replaceTemplate(content: string, projectName: string): string {
69
47
  return content.replace(/{PROJECT_NAME}/g, projectName);
70
48
  }
@@ -115,12 +93,12 @@ async function main() {
115
93
  "\x1b[36mDo you want to include Docker support? (Y/n): \x1b[0m",
116
94
  );
117
95
 
118
- // Create project directory
119
- mkdirSync(projectPath, { recursive: true });
120
-
121
- // Copy templates
96
+ // Create project directory and copy templates asynchronously
122
97
  console.log("\n\x1b[90m Copying template files...\x1b[0m");
123
- copyDirSync(TEMPLATES_DIR, projectPath);
98
+ await fs.mkdir(projectPath, { recursive: true });
99
+
100
+ // Use native recursive copy for maximum performance
101
+ await fs.cp(TEMPLATES_DIR, projectPath, { recursive: true });
124
102
 
125
103
  // Handle Docker files based on user choice
126
104
  const dockerFiles = ["Dockerfile", ".dockerignore", "docker-compose.yml"];
@@ -129,7 +107,7 @@ async function main() {
129
107
  for (const file of dockerFiles) {
130
108
  const filePath = join(projectPath, file);
131
109
  if (existsSync(filePath)) {
132
- unlinkSync(filePath);
110
+ await fs.unlink(filePath);
133
111
  }
134
112
  }
135
113
  console.log("\x1b[90m Skipped Docker files\x1b[0m");
@@ -137,18 +115,18 @@ async function main() {
137
115
  console.log("\x1b[90m Included Docker support\x1b[0m");
138
116
  }
139
117
 
140
- // Process template files (replace placeholders)
141
- const packageJsonPath = join(projectPath, "package.json");
142
- if (existsSync(packageJsonPath)) {
143
- const content = readFileSync(packageJsonPath, "utf-8");
144
- writeFileSync(packageJsonPath, replaceTemplate(content, projectName));
145
- }
146
-
147
- const tsConfigPath = join(projectPath, "tsconfig.json");
148
- if (existsSync(tsConfigPath)) {
149
- const content = readFileSync(tsConfigPath, "utf-8");
150
- writeFileSync(tsConfigPath, replaceTemplate(content, projectName));
151
- }
118
+ // Process template files (replace placeholders) concurrently
119
+ const filesToProcess = ["package.json", "tsconfig.json"];
120
+
121
+ await Promise.all(
122
+ filesToProcess.map(async (file) => {
123
+ const filePath = join(projectPath, file);
124
+ if (existsSync(filePath)) {
125
+ const content = await fs.readFile(filePath, "utf-8");
126
+ await fs.writeFile(filePath, replaceTemplate(content, projectName));
127
+ }
128
+ })
129
+ );
152
130
 
153
131
  // Run bun install
154
132
  console.log("\n\x1b[90m Installing dependencies...\x1b[0m\n");
@@ -163,6 +141,18 @@ async function main() {
163
141
  process.exit(1);
164
142
  }
165
143
 
144
+ // Initialize Git repository
145
+ console.log("\n\x1b[90m Initializing git repository...\x1b[0m");
146
+ const gitProc = Bun.spawnSync(["git", "init"], {
147
+ cwd: projectPath,
148
+ stdio: ["ignore", "ignore", "ignore"], // Hide git output for cleaner terminal
149
+ });
150
+
151
+ if (gitProc.exitCode === 0) {
152
+ // Add all files to initial commit staging to be ready
153
+ Bun.spawnSync(["git", "add", "."], { cwd: projectPath, stdio: ["ignore", "ignore", "ignore"] });
154
+ }
155
+
166
156
  // Success message
167
157
  console.log(`
168
158
  \x1b[32m✓ Project "${projectName}" created successfully!\x1b[0m
@@ -2,6 +2,7 @@
2
2
  "editor.formatOnSave": true,
3
3
  "editor.defaultFormatter": "biomejs.biome",
4
4
  "editor.codeActionsOnSave": {
5
+ "source.removeUnusedImports": "explicit",
5
6
  "source.organizeImports.biome": "explicit",
6
7
  "quickfix.biome": "explicit"
7
8
  },
@@ -27,6 +27,14 @@ src/
27
27
  └── index.ts # Entry point
28
28
  ```
29
29
 
30
+ | Feature | Description |
31
+ |------|-------------|
32
+ | 📦 **Code Generation** | CLI tool for generating schema, repo, service, controller |
33
+ | 🧠 **Cache System** | Built-in driver-based Cache manager |
34
+ | 🔄 **Queue System** | Built-in driver-based background Queues |
35
+ | ⏱️ **Task Scheduler** | Native CRON job support via `@CronJob` |
36
+ | 🛡️ **Auth Guards** | Granular access control via `@UseGuard` |
37
+
30
38
  ## Code Generation
31
39
 
32
40
  Generate CRUD files for an entity:
@@ -133,6 +141,74 @@ api.get("/users", getUsers);
133
141
  api.post("/users", createUser);
134
142
  ```
135
143
 
144
+ ### Controllers (Decorators)
145
+
146
+ ```ts
147
+ import { Controller, Get } from "buntok";
148
+
149
+ @Controller("/users")
150
+ export class UserController {
151
+ @Get("/")
152
+ getAll(ctx: Context) {
153
+ return ctx.json([{ id: 1 }]);
154
+ }
155
+ }
156
+
157
+ app.registerController(UserController);
158
+ ```
159
+
160
+ ### WebSockets
161
+
162
+ ```ts
163
+ app.ws("/chat", {
164
+ open: (ws) => {
165
+ // Treat user ID as a room
166
+ ws.subscribe("user_123");
167
+ },
168
+ message: (ws, msg) => {
169
+ // Parse JSON for events
170
+ const payload = JSON.parse(String(msg));
171
+ if (payload.event === "typing") { /* ... */ }
172
+ }
173
+ });
174
+ ```
175
+
176
+ **Note on Frontend Clients:**
177
+ Buntok uses **Raw WebSockets (RFC 6455)** natively.
178
+ ⚠️ **Do NOT use `socket.io-client`** to connect to Buntok.
179
+ ✅ **Recommended clients for React/Next.js:** `react-use-websocket`, `partysocket`, or native `WebSocket`.
180
+
181
+ **Broadcasting Events from API/Jobs:**
182
+ You can access the Bun Server instance natively via `app.server` to publish messages from anywhere in your backend!
183
+
184
+ ```typescript
185
+ // Broadcast to a specific user
186
+ app.post("/api/checkout", (ctx) => {
187
+ app.server?.publish("user_123", JSON.stringify({
188
+ event: "order_done", data: {}
189
+ }));
190
+ return ctx.success();
191
+ });
192
+ ```
193
+
194
+ ### Server-Sent Events (SSE)
195
+
196
+ Lightweight alternative to WebSockets for Server-to-Client one-way streams.
197
+
198
+ ```ts
199
+ app.get("/stream", (ctx) => {
200
+ return ctx.sse((stream) => {
201
+ stream.sendEvent("connected", { status: "ok" });
202
+
203
+ const timer = setInterval(() => {
204
+ stream.sendEvent("ping", { time: Date.now() });
205
+ }, 1000);
206
+
207
+ stream.onClose(() => clearInterval(timer));
208
+ });
209
+ });
210
+ ```
211
+
136
212
  ### Middleware
137
213
 
138
214
  ```ts
@@ -6,23 +6,29 @@
6
6
  "useIgnoreFile": true
7
7
  },
8
8
  "files": {
9
- "ignoreUnknown": false
9
+ "ignoreUnknown": true,
10
+ "ignore": ["node_modules", "dist", ".buntok", "coverage"]
10
11
  },
11
12
  "formatter": {
12
13
  "enabled": true,
13
14
  "indentStyle": "tab",
14
15
  "indentWidth": 2,
15
- "lineWidth": 80
16
+ "lineWidth": 100,
17
+ "lineEnding": "lf"
16
18
  },
17
19
  "linter": {
18
20
  "enabled": true,
19
21
  "rules": {
20
- "preset": "recommended"
22
+ "preset": "recommended",
23
+ "suspicious": {
24
+ "noExplicitAny": "off"
25
+ }
21
26
  }
22
27
  },
23
28
  "javascript": {
24
29
  "formatter": {
25
- "quoteStyle": "double"
30
+ "quoteStyle": "double",
31
+ "trailingCommas": "all"
26
32
  }
27
33
  }
28
34
  }
@@ -15,7 +15,8 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "buntok": "latest",
18
- "drizzle-orm": "^0.45.2"
18
+ "drizzle-orm": "^0.45.2",
19
+ "postgres": "^3.4.5"
19
20
  },
20
21
  "devDependencies": {
21
22
  "@biomejs/biome": "2.5.3",
@@ -0,0 +1,9 @@
1
+ import { Controller, Get, type Context } from "buntok";
2
+
3
+ @Controller("/")
4
+ export class HomeController {
5
+ @Get("/")
6
+ async index(ctx: Context) {
7
+ return ctx.json({ message: "Welcome to BUNTOK Enterprise!" });
8
+ }
9
+ }
@@ -1,7 +1,25 @@
1
- import { App } from "buntok";
1
+ import {
2
+ App,
3
+ Cache,
4
+ MemoryCacheDriver,
5
+ Queue,
6
+ MemoryQueueDriver,
7
+ setDefaultSchedulerDriver,
8
+ MemorySchedulerDriver
9
+ } from "buntok";
10
+
11
+ import { HomeController } from "./controllers/home.controller";
12
+
13
+ // 1. Set global default scheduler driver
14
+ setDefaultSchedulerDriver(new MemorySchedulerDriver());
2
15
 
3
16
  const app = new App();
4
17
 
5
- app.get("/", (ctx) => {
6
- return ctx.json({ message: "Welcome to BUNTOK!" });
7
- });
18
+ // 2. Register Cache and Queue into DI
19
+ app.set("cache", new Cache(new MemoryCacheDriver()));
20
+ app.set("queue", new Queue(new MemoryQueueDriver("main")));
21
+
22
+ // 3. Register Controllers
23
+ app.registerController(HomeController);
24
+
25
+ export default app;
@@ -6,17 +6,28 @@
6
6
  "moduleDetection": "force",
7
7
  "jsx": "react-jsx",
8
8
  "allowJs": true,
9
- "types": ["bun"],
9
+ "types": ["bun", "node"],
10
10
  "moduleResolution": "bundler",
11
11
  "allowImportingTsExtensions": true,
12
12
  "verbatimModuleSyntax": true,
13
13
  "noEmit": true,
14
+
15
+ /* Strictness Options for TS 7+ */
14
16
  "strict": true,
17
+ "noUncheckedIndexedAccess": true,
18
+ "exactOptionalPropertyTypes": true,
19
+ "noImplicitOverride": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "isolatedModules": true,
15
22
  "skipLibCheck": true,
16
- "baseUrl": ".",
23
+
24
+ /* Buntok Decorator Config */
25
+ "experimentalDecorators": true,
26
+ "emitDecoratorMetadata": true,
17
27
  "paths": {
18
28
  "@/*": ["./src/*"]
19
29
  }
20
30
  },
21
- "include": ["src/**/*"]
31
+ "include": ["src/**/*", "drizzle.config.ts"],
32
+ "exclude": ["node_modules", "dist"]
22
33
  }