speexjs 0.2.2 โ 0.2.3
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 +47 -472
- package/dist/cli/index.js +17 -17
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,152 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SpeexJS
|
|
2
2
|
|
|
3
|
-
**Fullstack
|
|
4
|
-
**๐ฎ๐ฉ Indonesia First, Built for the World**
|
|
3
|
+
**Fullstack TypeScript Framework โ zero dependencies.**
|
|
5
4
|
|
|
6
5
|
```bash
|
|
7
6
|
npm install speexjs
|
|
8
7
|
```
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## ๐ฆ Kenapa speexjs?
|
|
15
|
-
|
|
16
|
-
| Masalah | Solusi speexjs |
|
|
17
|
-
|---------|---------------|
|
|
18
|
-
| Next.js terlalu berat & vendor lock-in | speexjs ringan, zero-dep, engine-swappable |
|
|
19
|
-
| Express terlalu minimalis | speexjs Laravel-like: routing, middleware, controller, DI, ORM |
|
|
20
|
-
| Laravel pakai PHP | speexjs TypeScript native, end-to-end type safe |
|
|
21
|
-
| Fetch API ribet | SuperRequest/SuperResponse wrapper sendiri โ lebih mudah |
|
|
22
|
-
| Framework asing untuk Indonesia | ๐ฎ๐ฉ NIK, NPWP, Phone, Rupiah, terbilang built-in |
|
|
23
|
-
| React/Vue dependency berat | Signal-based VDOM sendiri โ ringan, cepat |
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## โจ Fitur Lengkap
|
|
28
|
-
|
|
29
|
-
### ๐ด Server (Laravel-like, TypeScript Native)
|
|
30
|
-
|
|
31
|
-
| Modul | Fitur |
|
|
32
|
-
|-------|-------|
|
|
33
|
-
| **Routing** | `get()`, `post()`, `put()`, `patch()`, `delete()`, `resource()`, `group()`, named routes |
|
|
34
|
-
| **Middleware** | CORS, CSRF, Auth, Throttle, Session, Helmet, Logger, Body Parser, Compress, Static Files |
|
|
35
|
-
| **Controller** | Base class + `@controller`/`@get`/`@post` decorators |
|
|
36
|
-
| **Container (DI)** | `bind()`, `singleton()`, `instance()`, `resolve()` |
|
|
37
|
-
| **HTTP** | SuperRequest + SuperResponse **(BUKAN Fetch API)** โ `.json()`, `.html()`, `.redirect()`, `.stream()`, `.file()` |
|
|
38
|
-
| **Engine** | Node.js default, bisa ganti ke Bun/Deno via `app.setEngine()` |
|
|
39
|
-
| **Validation** | 25+ schema types + ๐ฎ๐ฉ NIK, NPWP, Phone, Kodepos, Rekening |
|
|
40
|
-
| **Error Handling** | `TypedError`, HTTP status codes, exception handler |
|
|
41
|
-
| **Logging** | Structured logger โ WIB/WITA/WIT timezone |
|
|
42
|
-
|
|
43
|
-
### ๐ก Auth & Security
|
|
44
|
-
|
|
45
|
-
| Modul | Fitur |
|
|
46
|
-
|-------|-------|
|
|
47
|
-
| **Session Guard** | Login/logout via encrypted cookies (AES-256-GCM) |
|
|
48
|
-
| **Token Guard** | Bearer token authentication, abilities/permissions |
|
|
49
|
-
| **Gate** | Authorization policies โ `Gate.define()`, `Gate.allows()` |
|
|
50
|
-
| **Middleware** | `authMiddleware()`, `guestMiddleware()`, `authorize()` |
|
|
51
|
-
| **Encryption** | AES-256-GCM encrypt/decrypt โ Node.js `crypto` native |
|
|
52
|
-
| **Hashing** | scrypt (OWASP recommended) + PBKDF2 |
|
|
53
|
-
|
|
54
|
-
### ๐ก Database
|
|
55
|
-
|
|
56
|
-
| Modul | Fitur |
|
|
57
|
-
|-------|-------|
|
|
58
|
-
| **Query Builder** | Laravel-like chain: `.select()`, `.where()`, `.join()`, `.orderBy()` |
|
|
59
|
-
| **Pagination** | `.paginate(perPage)` โ built-in di Query Builder |
|
|
60
|
-
| **Migrations** | `SchemaBuilder`, `TableBlueprint` (30+ column types) |
|
|
61
|
-
| **Seeding** | `Seeder` class โ insert/truncate data awal |
|
|
62
|
-
| **Drivers** | MySQL (default), SQLite, PostgreSQL โ runtime dynamic import |
|
|
63
|
-
|
|
64
|
-
### ๐จ Client (Signal-Based VDOM)
|
|
65
|
-
|
|
66
|
-
| Modul | Fitur |
|
|
67
|
-
|-------|-------|
|
|
68
|
-
| **Signals** | `signal()`, `computed()`, `effect()`, `batch()`, `untracked()` |
|
|
69
|
-
| **VDOM** | `h()`, `render()`, `patch()`, `hydrate()` โ Virtual DOM sendiri |
|
|
70
|
-
| **SSR** | `renderToString()`, `renderToStream()`, `ServerRenderer` |
|
|
71
|
-
| **JSX** | Full JSX support via `jsxImportSource: \"@SpeexJS/vdom\"` |
|
|
72
|
-
| **Router** | File-based routing, guards, reactive current/params/query |
|
|
73
|
-
| **Adapters** | `FrameworkAdapter` interface โ React/Vue integration |
|
|
74
|
-
|
|
75
|
-
### ๐ RPC (Type-Safe)
|
|
76
|
-
|
|
77
|
-
| Modul | Fitur |
|
|
78
|
-
|-------|-------|
|
|
79
|
-
| **Server** | `rpc.create()` โ definisi procedure + schema validation |
|
|
80
|
-
| **Client** | `createClient()` โ auto-typed queries & mutations |
|
|
81
|
-
| **Batch** | Multiple procedures in one request |
|
|
82
|
-
|
|
83
|
-
### ๐ ๏ธ CLI (Zero Dependencies)
|
|
84
|
-
|
|
85
|
-
| Perintah | Fungsi |
|
|
86
|
-
|----------|--------|
|
|
87
|
-
| `speexjs init [name]` | Scaffold project baru (blank/fullstack/api-only) |
|
|
88
|
-
| `speexjs make:controller <name>` | Generate controller |
|
|
89
|
-
| `speexjs make:middleware <name>` | Generate middleware |
|
|
90
|
-
| `speexjs make:schema <name>` | Generate schema |
|
|
91
|
-
| `speexjs list-routes` | Lihat semua route yang terdaftar |
|
|
92
|
-
| `speexjs serve` | Jalankan development server |
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## ๐ Quickstart
|
|
97
|
-
|
|
98
|
-
### 1. Install
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
npm install speexjs
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### 2. Buat File Server
|
|
9
|
+
## Quick Start
|
|
105
10
|
|
|
106
11
|
```typescript
|
|
107
|
-
// src/index.ts
|
|
108
12
|
import { speexjs } from 'speexjs/server'
|
|
109
13
|
|
|
110
14
|
const app = speexjs()
|
|
111
15
|
|
|
112
16
|
app.get('/', async ({ response }) => {
|
|
113
|
-
return response.html('<h1>
|
|
17
|
+
return response.html('<h1>SpeexJS ๐</h1>')
|
|
114
18
|
})
|
|
115
19
|
|
|
116
|
-
app.
|
|
117
|
-
return response.json({ message: 'Halo Dunia!' })
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
app.listen(3000, () => console.log('speexjs running on http://localhost:3000'))
|
|
20
|
+
app.listen(3000)
|
|
121
21
|
```
|
|
122
22
|
|
|
123
|
-
### 3. Jalankan
|
|
124
|
-
|
|
125
23
|
```bash
|
|
126
24
|
npx speexjs serve
|
|
127
|
-
# atau
|
|
128
|
-
node --loader ts-node src/index.ts
|
|
129
25
|
```
|
|
130
26
|
|
|
131
|
-
|
|
27
|
+
## Feature Overview
|
|
28
|
+
|
|
29
|
+
| Category | Features |
|
|
30
|
+
|----------|----------|
|
|
31
|
+
| **Server** | Router, Middleware (10 built-in), Controller, DI Container, Laravel-like API |
|
|
32
|
+
| **Database** | Query Builder, Migrations, Pagination, MySQL/SQLite/PostgreSQL |
|
|
33
|
+
| **Auth** | Session Guard, Token Guard, Gate Authorization, Encryption, Hashing |
|
|
34
|
+
| **Validation** | 25+ schema types, NIK/NPWP/Phone/Kodepos/Rupiah |
|
|
35
|
+
| **Client** | Signals, VDOM, JSX, SSR โ no React dependency |
|
|
36
|
+
| **RPC** | Type-safe server-client communication |
|
|
37
|
+
| **CLI** | `speexjs init`, `serve`, `make:*`, `list-routes` |
|
|
38
|
+
| **Zero Dep** | 100% native Node.js โ zero external dependencies |
|
|
132
39
|
|
|
133
|
-
##
|
|
40
|
+
## Examples
|
|
134
41
|
|
|
135
|
-
###
|
|
42
|
+
### Routing
|
|
136
43
|
|
|
137
44
|
```typescript
|
|
138
|
-
import { speexjs } from 'speexjs/server'
|
|
45
|
+
import { speexjs, Controller, get, post, controller } from 'speexjs/server'
|
|
139
46
|
|
|
140
47
|
const app = speexjs()
|
|
141
48
|
|
|
142
|
-
//
|
|
143
|
-
app.get('/users', handler)
|
|
144
|
-
app.post('/users', handler)
|
|
145
|
-
app.put('/users/:id', handler)
|
|
146
|
-
app.delete('/users/:id', handler)
|
|
147
|
-
app.patch('/users/:id', handler)
|
|
148
|
-
|
|
149
|
-
// Route groups
|
|
49
|
+
// Route groups with middleware
|
|
150
50
|
app.group('/api', (router) => {
|
|
151
51
|
router.get('/users', [UserController, 'index'])
|
|
152
52
|
router.post('/users', [UserController, 'store'])
|
|
@@ -154,402 +54,77 @@ app.group('/api', (router) => {
|
|
|
154
54
|
|
|
155
55
|
// Resource routes
|
|
156
56
|
app.router.resource('/posts', PostController)
|
|
157
|
-
// GET
|
|
158
|
-
// GET /posts/create โ create
|
|
159
|
-
// POST /posts โ store
|
|
160
|
-
// GET /posts/:id โ show
|
|
161
|
-
// GET /posts/:id/edit โ edit
|
|
162
|
-
// PUT /posts/:id โ update
|
|
163
|
-
// DELETE /posts/:id โ destroy
|
|
164
|
-
|
|
165
|
-
// Named routes
|
|
166
|
-
app.get('/users/:id', handler).name('users.show')
|
|
167
|
-
// app.router.route('users.show', { id: 5 }) โ '/users/5'
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Controller
|
|
171
|
-
|
|
172
|
-
```typescript
|
|
173
|
-
import { Controller, get, post, put, del } from 'speexjs/server'
|
|
174
|
-
|
|
175
|
-
@controller('/api/users')
|
|
176
|
-
export class UserController extends Controller {
|
|
177
|
-
@get('/')
|
|
178
|
-
async index({ response }) {
|
|
179
|
-
const users = await UserService.all()
|
|
180
|
-
return response.json(users)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
@post('/')
|
|
184
|
-
async store({ request, response }) {
|
|
185
|
-
const data = await request.validate(CreateUserSchema)
|
|
186
|
-
const user = await UserService.create(data)
|
|
187
|
-
return response.json(user, 201)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
@get('/:id')
|
|
191
|
-
async show({ params, response }) {
|
|
192
|
-
const user = await UserService.findOrFail(params.id)
|
|
193
|
-
return response.json(user)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
@put('/:id')
|
|
197
|
-
async update({ params, request, response }) {
|
|
198
|
-
const data = await request.validate(UpdateUserSchema)
|
|
199
|
-
const user = await UserService.update(params.id, data)
|
|
200
|
-
return response.json(user)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
@del('/:id')
|
|
204
|
-
async destroy({ params, response }) {
|
|
205
|
-
await UserService.delete(params.id)
|
|
206
|
-
return response.noContent()
|
|
207
|
-
}
|
|
208
|
-
}
|
|
57
|
+
// GET /posts, POST /posts, GET /posts/:id, PUT /posts/:id, DELETE /posts/:id
|
|
209
58
|
```
|
|
210
59
|
|
|
211
|
-
###
|
|
60
|
+
### Validation
|
|
212
61
|
|
|
213
62
|
```typescript
|
|
214
63
|
import { s } from 'speexjs/schema'
|
|
215
64
|
|
|
216
|
-
// Buat schema
|
|
217
65
|
const UserSchema = s.object({
|
|
218
|
-
id: s.number(),
|
|
219
66
|
name: s.string().min(3).max(100),
|
|
220
67
|
email: s.string().email(),
|
|
221
68
|
age: s.number().min(17).max(120).optional(),
|
|
222
|
-
phone: s.phone(),
|
|
223
|
-
nik: s.nik().optional(),
|
|
224
|
-
npwp: s.npwp().optional(), // ๐ฎ๐ฉ NPWP
|
|
69
|
+
phone: s.phone(), // Nomor Indonesia
|
|
70
|
+
nik: s.nik().optional(), // NIK 16 digit
|
|
225
71
|
})
|
|
226
72
|
|
|
227
|
-
// Type inference
|
|
228
73
|
type User = s.Infer<typeof UserSchema>
|
|
229
|
-
|
|
230
|
-
// Parse & validate
|
|
231
|
-
const result = UserSchema.safeParse(input)
|
|
232
|
-
if (!result.success) {
|
|
233
|
-
console.log(result.error) // Pesan error Bahasa Indonesia
|
|
234
|
-
}
|
|
235
74
|
```
|
|
236
75
|
|
|
237
|
-
### Database
|
|
76
|
+
### Database
|
|
238
77
|
|
|
239
78
|
```typescript
|
|
240
79
|
import { DatabaseConnection } from 'speexjs/server/database'
|
|
241
80
|
|
|
242
|
-
const db = new DatabaseConnection({
|
|
243
|
-
driver: 'mysql', // mysql | sqlite | postgresql
|
|
244
|
-
host: 'localhost',
|
|
245
|
-
database: 'myapp',
|
|
246
|
-
username: 'root',
|
|
247
|
-
password: 'secret',
|
|
248
|
-
})
|
|
249
|
-
|
|
81
|
+
const db = new DatabaseConnection({ driver: 'mysql', database: 'myapp' })
|
|
250
82
|
await db.connect()
|
|
251
83
|
|
|
252
|
-
// Query dengan chaining
|
|
253
84
|
const users = await db.table('users')
|
|
254
85
|
.select('id', 'name', 'email')
|
|
255
86
|
.where('age', '>', 18)
|
|
256
|
-
.whereLike('name', '%john%')
|
|
257
87
|
.orderByDesc('created_at')
|
|
258
|
-
.
|
|
259
|
-
.get()
|
|
260
|
-
|
|
261
|
-
// Pagination
|
|
262
|
-
const result = await db.table('posts')
|
|
263
|
-
.where('published', true)
|
|
264
|
-
.paginate(15, 1)
|
|
265
|
-
// result.data, result.total, result.lastPage, ...
|
|
266
|
-
|
|
267
|
-
// Insert
|
|
268
|
-
const id = await db.table('users').insert({
|
|
269
|
-
name: 'John',
|
|
270
|
-
email: 'john@test.com',
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
// Update
|
|
274
|
-
await db.table('users')
|
|
275
|
-
.where('id', 1)
|
|
276
|
-
.update({ name: 'John Doe' })
|
|
277
|
-
|
|
278
|
-
// Raw SQL
|
|
279
|
-
const result = await db.raw('SELECT * FROM users WHERE age > ?', [18])
|
|
88
|
+
.paginate(10, 1)
|
|
280
89
|
```
|
|
281
90
|
|
|
282
|
-
###
|
|
91
|
+
### Auth
|
|
283
92
|
|
|
284
93
|
```typescript
|
|
285
|
-
import { speexjs } from 'speexjs/server'
|
|
286
94
|
import { AuthManager, SessionGuard } from 'speexjs/server/auth'
|
|
287
95
|
|
|
288
|
-
const app = speexjs()
|
|
289
|
-
|
|
290
|
-
// Setup auth
|
|
291
96
|
const auth = new AuthManager()
|
|
292
|
-
auth.guard('session', new SessionGuard({
|
|
293
|
-
table: 'users',
|
|
294
|
-
cookieName: 'speexjs_session',
|
|
295
|
-
}))
|
|
97
|
+
auth.guard('session', new SessionGuard({ table: 'users' }))
|
|
296
98
|
|
|
297
|
-
// Login route
|
|
298
99
|
app.post('/login', async ({ request, response }) => {
|
|
299
100
|
const { email, password } = await request.json()
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
if (!authenticated) {
|
|
303
|
-
return response.json({ error: 'Login gagal' }, 401)
|
|
304
|
-
}
|
|
101
|
+
const ok = await auth.guard('session').attempt({ email, password })
|
|
102
|
+
if (!ok) return response.json({ error: 'Login gagal' }, 401)
|
|
305
103
|
return response.json({ message: 'Login berhasil' })
|
|
306
104
|
})
|
|
307
|
-
|
|
308
|
-
// Protected route
|
|
309
|
-
app.get('/profile', async ({ response }, next) => {
|
|
310
|
-
const user = await auth.guard('session').user()
|
|
311
|
-
return response.json(user)
|
|
312
|
-
}).middleware(['auth'])
|
|
313
|
-
|
|
314
|
-
// Authorization Gate
|
|
315
|
-
import { Gate } from 'speexjs/server/gate'
|
|
316
|
-
|
|
317
|
-
const gate = new Gate()
|
|
318
|
-
gate.define('update-post', (user, post) => user.id === post.user_id)
|
|
319
|
-
|
|
320
|
-
app.put('/posts/:id', async ({ params, response }) => {
|
|
321
|
-
const post = await Post.find(params.id)
|
|
322
|
-
await gate.authorize('update-post', currentUser, post)
|
|
323
|
-
// ...
|
|
324
|
-
})
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Client โ Signals + VDOM
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
import { signal, computed, effect, h, render } from 'speexjs/client'
|
|
331
|
-
|
|
332
|
-
function Counter() {
|
|
333
|
-
const count = signal(0)
|
|
334
|
-
const doubled = computed(() => count.value * 2)
|
|
335
|
-
|
|
336
|
-
effect(() => console.log('Count:', count.value))
|
|
337
|
-
|
|
338
|
-
return h('div', { class: 'counter' },
|
|
339
|
-
h('p', {}, `Count: ${count.value}`),
|
|
340
|
-
h('p', {}, `Doubled: ${doubled.value}`),
|
|
341
|
-
h('button', { onClick: () => count.value++ }, '+'),
|
|
342
|
-
h('button', { onClick: () => count.value-- }, '-'),
|
|
343
|
-
)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Mount ke DOM
|
|
347
|
-
render(h(Counter), document.getElementById('root')!)
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
Dengan JSX (`tsconfig.json`):
|
|
351
|
-
```json
|
|
352
|
-
{
|
|
353
|
-
"compilerOptions": {
|
|
354
|
-
"jsx": "react-jsx",
|
|
355
|
-
"jsxImportSource": "@SpeexJS/vdom"
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
```tsx
|
|
361
|
-
function Counter() {
|
|
362
|
-
const count = signal(0)
|
|
363
|
-
return (
|
|
364
|
-
<div class="counter">
|
|
365
|
-
<p>Count: {count}</p>
|
|
366
|
-
<button onClick={() => count.value++}>+</button>
|
|
367
|
-
</div>
|
|
368
|
-
)
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Cache
|
|
373
|
-
|
|
374
|
-
```typescript
|
|
375
|
-
import { Cache } from 'speexjs/server/cache'
|
|
376
|
-
|
|
377
|
-
const cache = new Cache({ store: 'memory', ttl: 3600 })
|
|
378
|
-
|
|
379
|
-
// Set & Get
|
|
380
|
-
await cache.set('user:1', { name: 'John' })
|
|
381
|
-
const user = await cache.get('user:1') // { name: 'John' }
|
|
382
|
-
|
|
383
|
-
// Remember (get or set)
|
|
384
|
-
const data = await cache.remember('expensive:data', 300, async () => {
|
|
385
|
-
return await fetchExpensiveData()
|
|
386
|
-
})
|
|
387
|
-
|
|
388
|
-
// Increment/Decrement
|
|
389
|
-
await cache.increment('visits')
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### File Storage
|
|
393
|
-
|
|
394
|
-
```typescript
|
|
395
|
-
import { createStorage } from 'speexjs/server/storage'
|
|
396
|
-
|
|
397
|
-
const storage = createStorage({
|
|
398
|
-
defaultDisk: 'local',
|
|
399
|
-
disks: {
|
|
400
|
-
local: { driver: 'local', root: './storage' },
|
|
401
|
-
public: { driver: 'local', root: './public/uploads', url: '/uploads' },
|
|
402
|
-
},
|
|
403
|
-
})
|
|
404
|
-
|
|
405
|
-
// Upload file
|
|
406
|
-
await storage.disk('public').put('images/photo.jpg', buffer)
|
|
407
|
-
|
|
408
|
-
// Get file URL
|
|
409
|
-
const url = storage.disk('public').url('images/photo.jpg')
|
|
410
|
-
|
|
411
|
-
// Check exists
|
|
412
|
-
const exists = await storage.exists('images/photo.jpg')
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### Events
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
import { event } from 'speexjs/server/events'
|
|
419
|
-
|
|
420
|
-
// Listen
|
|
421
|
-
event.on('user.registered', async (user) => {
|
|
422
|
-
await sendWelcomeEmail(user)
|
|
423
|
-
})
|
|
424
|
-
|
|
425
|
-
// Wildcard pattern
|
|
426
|
-
event.onPattern('user.*', async (eventName, data) => {
|
|
427
|
-
console.log(`User event: ${eventName}`, data)
|
|
428
|
-
})
|
|
429
|
-
|
|
430
|
-
// Emit
|
|
431
|
-
await event.emit('user.registered', { id: 1, email: 'john@test.com' })
|
|
432
105
|
```
|
|
433
106
|
|
|
434
|
-
###
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
// === SERVER ===
|
|
438
|
-
import { speexjs } from 'speexjs/server'
|
|
439
|
-
import { rpc } from 'speexjs/rpc'
|
|
440
|
-
import { s } from 'speexjs/schema'
|
|
441
|
-
|
|
442
|
-
const api = rpc.create({
|
|
443
|
-
procedures: {
|
|
444
|
-
'users.list': {
|
|
445
|
-
input: s.object({ page: s.number().default(1) }),
|
|
446
|
-
output: s.array(s.object({ id: s.number(), name: s.string() })),
|
|
447
|
-
handler: async ({ page }, ctx) => {
|
|
448
|
-
return await db.table('users').paginate(10, page).data
|
|
449
|
-
},
|
|
450
|
-
},
|
|
451
|
-
'echo': {
|
|
452
|
-
input: s.object({ message: s.string() }),
|
|
453
|
-
output: s.object({ reply: s.string() }),
|
|
454
|
-
handler: async ({ message }) => ({ reply: `You said: ${message}` }),
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
})
|
|
458
|
-
|
|
459
|
-
const app = speexjs()
|
|
460
|
-
app.post('/api/rpc', api.toHandler())
|
|
461
|
-
app.listen(3000)
|
|
462
|
-
|
|
463
|
-
// === CLIENT ===
|
|
464
|
-
import { createClient } from 'speexjs/rpc'
|
|
107
|
+
### CLI
|
|
465
108
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
109
|
+
```bash
|
|
110
|
+
speexjs init my-app # Buat project baru
|
|
111
|
+
speexjs serve # Jalankan dev server
|
|
112
|
+
speexjs make:controller User # Generate controller
|
|
113
|
+
speexjs make:middleware Auth # Generate middleware
|
|
114
|
+
speexjs list-routes # Lihat semua route
|
|
469
115
|
```
|
|
470
116
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
## ๐ฎ๐ฉ Fitur Indonesia
|
|
474
|
-
|
|
475
|
-
| Fitur | Keterangan |
|
|
476
|
-
|-------|-----------|
|
|
477
|
-
| `s.nik()` | Validasi NIK 16 digit + tanggal lahir |
|
|
478
|
-
| `s.npwp()` | Validasi NPWP + checksum |
|
|
479
|
-
| `s.phone()` | Validasi nomor telepon Indonesia (+62, 08xx) |
|
|
480
|
-
| `s.kodepos()` | Validasi kode pos 5 digit |
|
|
481
|
-
| `s.rekening()` | Validasi nomor rekening bank |
|
|
482
|
-
| `s.alamat()` | Validasi alamat Indonesia |
|
|
483
|
-
| `Number.formatRupiah()` | Format mata uang Rupiah |
|
|
484
|
-
| `Number.terbilang()` | Angka ke kata Bahasa Indonesia |
|
|
485
|
-
| **Logger** | Timezone WIB/WITA/WIT |
|
|
486
|
-
| **Error messages** | Bahasa Indonesia default |
|
|
487
|
-
| **CLI** | Output dengan Bahasa Indonesia |
|
|
488
|
-
|
|
489
|
-
---
|
|
490
|
-
|
|
491
|
-
## ๐๏ธ Arsitektur
|
|
117
|
+
## Architecture
|
|
492
118
|
|
|
493
119
|
```
|
|
494
120
|
speexjs/
|
|
495
|
-
โโโ
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
โ โ โโโ http/ # SuperRequest/SuperResponse
|
|
501
|
-
โ โ โโโ router/ # Routing engine
|
|
502
|
-
โ โ โโโ middleware/ # 10 built-in middleware
|
|
503
|
-
โ โ โโโ controller/ # Base controller
|
|
504
|
-
โ โ โโโ container/ # Dependency injection
|
|
505
|
-
โ โ โโโ engine/ # Swappable engine
|
|
506
|
-
โ โ โโโ auth/ # Session + Token guards
|
|
507
|
-
โ โ โโโ gate/ # Authorization
|
|
508
|
-
โ โ โโโ cache/ # Caching system
|
|
509
|
-
โ โ โโโ storage/ # File storage
|
|
510
|
-
โ โ โโโ events/ # Event system
|
|
511
|
-
โ โ โโโ database/ # Query Builder + Migrations
|
|
512
|
-
โ โโโ client/ # Signals + VDOM + SSR
|
|
513
|
-
โ โโโ rpc/ # Type-safe RPC
|
|
514
|
-
โ โโโ cli/ # Native CLI (zero dep)
|
|
515
|
-
โโโ tests/
|
|
121
|
+
โโโ server/ (HTTP, Router, Middleware, Auth, Database, Cache, Storage, Events)
|
|
122
|
+
โโโ client/ (Signals, VDOM, SSR, JSX)
|
|
123
|
+
โโโ schema/ (25+ validation types)
|
|
124
|
+
โโโ rpc/ (Type-safe RPC)
|
|
125
|
+
โโโ cli/ (speexjs init, serve, make:*)
|
|
516
126
|
```
|
|
517
127
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
## ๐ Perbandingan dengan Framework Lain
|
|
521
|
-
|
|
522
|
-
| Fitur | speexjs | Next.js | Express | AdonisJS | Laravel |
|
|
523
|
-
|-------|---------|---------|---------|----------|---------|
|
|
524
|
-
| Bahasa | TS/JS | TS/JS | JS | TS/JS | PHP |
|
|
525
|
-
| Dependencies | **0** | Ratusan | Puluhan | Puluhan | Ratusan |
|
|
526
|
-
| File size | ~175KB | >50MB | ~500KB | >10MB | >20MB |
|
|
527
|
-
| Routing | โ
Laravel-like | โ
File-based | โ Manual | โ
Programmatic | โ
Laravel |
|
|
528
|
-
| Database | โ
Query Builder | โ Prisma | โ None | โ
Lucid ORM | โ
Eloquent |
|
|
529
|
-
| Auth | โ
Session+Token | โ
NextAuth | โ Manual | โ
Built-in | โ
Built-in |
|
|
530
|
-
| Validation | โ
Schema (25+) | โ
Zod | โ Manual | โ
Vine | โ
Form Request |
|
|
531
|
-
| VDOM/Signals | โ
Built-in | โ
React | โ | โ Edge | โ Blade |
|
|
532
|
-
| RPC | โ
Type-safe | โ Server Actions | โ | โ
Tuyau | โ |
|
|
533
|
-
| ๐ฎ๐ฉ Indonesia | โ
Built-in | โ | โ | โ | โ |
|
|
534
|
-
|
|
535
|
-
---
|
|
536
|
-
|
|
537
|
-
## ๐บ๏ธ Roadmap
|
|
538
|
-
|
|
539
|
-
| Version | Fitur |
|
|
540
|
-
|---------|-------|
|
|
541
|
-
| **v0.1.0** | โ
Schema, Server (HTTP+Router+Middleware+Controller), Client (Signals+VDOM), RPC, CLI (commander) |
|
|
542
|
-
| **v0.2.0** | โ
Zero dependencies, Native CLI, Auth (Session+Token), Gate, Database (Query Builder+Migrations+Pagination), Cache, Storage, Events, Encryption, Hashing, Helpers |
|
|
543
|
-
| **v0.3.0** | ๐ File-based routing, Server Components, ORM, Queues |
|
|
544
|
-
| **v1.0.0** | ๐ Adapter React/Vue, Dokumentasi lengkap, Publikasi global |
|
|
545
|
-
|
|
546
|
-
---
|
|
547
|
-
|
|
548
|
-
## โ๏ธ License
|
|
549
|
-
|
|
550
|
-
MIT โ bebas digunakan, dimodifikasi, dan didistribusikan.
|
|
551
|
-
|
|
552
|
-
---
|
|
128
|
+
## License
|
|
553
129
|
|
|
554
|
-
|
|
555
|
-
**๐ฎ๐ฉ Dibuat oleh developer Indonesia, untuk developer dunia.**
|
|
130
|
+
MIT
|
package/dist/cli/index.js
CHANGED
|
@@ -133,12 +133,12 @@ var TEMPLATES = {
|
|
|
133
133
|
type: "module",
|
|
134
134
|
private: true,
|
|
135
135
|
scripts: {
|
|
136
|
-
dev: "
|
|
137
|
-
build: "
|
|
136
|
+
dev: "speexjs serve",
|
|
137
|
+
build: "speexjs build",
|
|
138
138
|
start: "node dist/index.js"
|
|
139
139
|
},
|
|
140
140
|
dependencies: {
|
|
141
|
-
|
|
141
|
+
speexjs: "latest"
|
|
142
142
|
},
|
|
143
143
|
devDependencies: {
|
|
144
144
|
"@types/node": "^26.0.1",
|
|
@@ -169,9 +169,9 @@ var TEMPLATES = {
|
|
|
169
169
|
null,
|
|
170
170
|
2
|
|
171
171
|
),
|
|
172
|
-
"src/index.ts": `import {
|
|
172
|
+
"src/index.ts": `import { speexjs } from 'speexjs/server'
|
|
173
173
|
|
|
174
|
-
const app =
|
|
174
|
+
const app = speexjs()
|
|
175
175
|
|
|
176
176
|
const PORT = Number(process.env.PORT) || 3000
|
|
177
177
|
|
|
@@ -183,10 +183,10 @@ app.listen(PORT, () => {
|
|
|
183
183
|
console.log(\`SpeexJS running on http://localhost:\${PORT}\`)
|
|
184
184
|
})
|
|
185
185
|
`,
|
|
186
|
-
"src/app.ts": `import {
|
|
186
|
+
"src/app.ts": `import { speexjs } from 'speexjs/server'
|
|
187
187
|
|
|
188
188
|
export function createApp() {
|
|
189
|
-
const app =
|
|
189
|
+
const app = speexjs()
|
|
190
190
|
return app
|
|
191
191
|
}
|
|
192
192
|
`,
|
|
@@ -219,12 +219,12 @@ dist/
|
|
|
219
219
|
type: "module",
|
|
220
220
|
private: true,
|
|
221
221
|
scripts: {
|
|
222
|
-
dev: "
|
|
222
|
+
dev: "speexjs serve",
|
|
223
223
|
build: "tsc",
|
|
224
224
|
start: "node dist/server/index.js"
|
|
225
225
|
},
|
|
226
226
|
dependencies: {
|
|
227
|
-
|
|
227
|
+
speexjs: "latest"
|
|
228
228
|
},
|
|
229
229
|
devDependencies: {
|
|
230
230
|
"@types/node": "^26.0.1",
|
|
@@ -247,7 +247,7 @@ dist/
|
|
|
247
247
|
isolatedModules: true,
|
|
248
248
|
resolveJsonModule: true,
|
|
249
249
|
jsx: "react-jsx",
|
|
250
|
-
jsxImportSource: "@
|
|
250
|
+
jsxImportSource: "@speexjs/vdom",
|
|
251
251
|
outDir: "./dist",
|
|
252
252
|
rootDir: "./src"
|
|
253
253
|
},
|
|
@@ -257,12 +257,12 @@ dist/
|
|
|
257
257
|
null,
|
|
258
258
|
2
|
|
259
259
|
),
|
|
260
|
-
"src/server/index.ts": `import {
|
|
260
|
+
"src/server/index.ts": `import { speexjs } from 'speexjs/server'
|
|
261
261
|
import { UserController } from './controllers/user.controller.js'
|
|
262
262
|
|
|
263
263
|
const PORT = Number(process.env.PORT) || 3000
|
|
264
264
|
|
|
265
|
-
const app =
|
|
265
|
+
const app = speexjs()
|
|
266
266
|
|
|
267
267
|
app.controller(UserController)
|
|
268
268
|
|
|
@@ -372,12 +372,12 @@ dist/
|
|
|
372
372
|
type: "module",
|
|
373
373
|
private: true,
|
|
374
374
|
scripts: {
|
|
375
|
-
dev: "
|
|
375
|
+
dev: "speexjs serve",
|
|
376
376
|
build: "tsc",
|
|
377
377
|
start: "node dist/index.js"
|
|
378
378
|
},
|
|
379
379
|
dependencies: {
|
|
380
|
-
|
|
380
|
+
speexjs: "latest"
|
|
381
381
|
},
|
|
382
382
|
devDependencies: {
|
|
383
383
|
"@types/node": "^26.0.1",
|
|
@@ -408,11 +408,11 @@ dist/
|
|
|
408
408
|
null,
|
|
409
409
|
2
|
|
410
410
|
),
|
|
411
|
-
"src/index.ts": `import {
|
|
411
|
+
"src/index.ts": `import { speexjs } from 'speexjs/server'
|
|
412
412
|
|
|
413
413
|
const PORT = Number(process.env.PORT) || 3000
|
|
414
414
|
|
|
415
|
-
const app =
|
|
415
|
+
const app = speexjs()
|
|
416
416
|
|
|
417
417
|
app.get('/api/health', async ({ response }) => {
|
|
418
418
|
return response.json({ status: 'ok', timestamp: new Date().toISOString() })
|
|
@@ -521,7 +521,7 @@ async function initProject(name, options) {
|
|
|
521
521
|
const packageManager = String(options["package-manager"] || options.packageManager || "npm");
|
|
522
522
|
console.log();
|
|
523
523
|
console.log(`${colors.bold("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")}`);
|
|
524
|
-
console.log(`${colors.bold("\u2551")} ${colors.green("
|
|
524
|
+
console.log(`${colors.bold("\u2551")} ${colors.green("speexjs \u{1F680} Project Created")}${colors.bold(" \u2551")}`);
|
|
525
525
|
console.log(`${colors.bold("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")}`);
|
|
526
526
|
console.log();
|
|
527
527
|
console.log(` ${colors.bold("Name:")} ${toPascalCase(name)}`);
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/native/args.ts","../../src/native/colors.ts","../../src/cli/commands/init.ts","../../src/cli/commands/make-controller.ts","../../src/cli/commands/make-middleware.ts","../../src/cli/commands/make-schema.ts","../../src/cli/commands/list-routes.ts","../../src/cli/commands/serve.ts","../../src/native/logger.ts","../../src/cli/index.ts"],"sourcesContent":["export interface ParsedArgs {\n command: string\n subcommand?: string\n args: string[]\n options: Record<string, string | boolean | string[]>\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const args = argv.slice(2)\n const result: ParsedArgs = {\n command: '',\n args: [],\n options: {},\n }\n\n if (args.length === 0) return result\n\n const first = args[0]!\n\n if (first.includes(':')) {\n result.command = first\n parseOptions(args.slice(1), result)\n return result\n }\n\n result.command = first\n\n if (args.length > 1) {\n const second = args[1]!\n if (!second.startsWith('-')) {\n result.subcommand = second\n result.args.push(second)\n parseOptions(args.slice(2), result)\n return result\n }\n }\n\n parseOptions(args.slice(1), result)\n return result\n}\n\nfunction parseOptions(argv: string[], result: ParsedArgs): void {\n let i = 0\n while (i < argv.length) {\n const arg = argv[i]!\n\n if (arg === '--') {\n for (let j = i + 1; j < argv.length; j++) {\n result.args.push(argv[j]!)\n }\n break\n }\n\n if (arg.startsWith('--no-')) {\n const key = arg.slice(5)\n if (key) {\n result.options[key] = false\n }\n i++\n continue\n }\n\n if (arg.startsWith('--')) {\n const key = arg.slice(2)\n if (i + 1 < argv.length && !argv[i + 1]!.startsWith('-')) {\n const val = argv[i + 1]!\n const existing = result.options[key]\n if (existing !== undefined) {\n result.options[key] = Array.isArray(existing)\n ? ([...existing, val] as string[])\n : [existing as string, val]\n } else {\n result.options[key] = val\n }\n i += 2\n } else {\n result.options[key] = true\n i++\n }\n continue\n }\n\n if (arg.startsWith('-') && arg.length === 2) {\n const key = arg.slice(1)\n if (i + 1 < argv.length && !argv[i + 1]!.startsWith('-')) {\n const val = argv[i + 1]!\n result.options[key] = val\n i += 2\n } else {\n result.options[key] = true\n i++\n }\n continue\n }\n\n result.args.push(arg)\n i++\n }\n}\n\nexport function toCommandName(argv: string[]): string {\n const args = argv.slice(2)\n if (args.length === 0) return ''\n\n const first = args[0]!\n\n if (first.includes(':')) return first\n\n if (args.length > 1 && !args[1]!.startsWith('-')) {\n return `${first}:${args[1]}`\n }\n\n return first\n}\n","const RESET = '\\x1b[0m'\n\nconst codes: Record<string, string> = {\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n italic: '\\x1b[3m',\n underline: '\\x1b[4m',\n}\n\nexport const colors = {\n red: (s: string): string => `${codes.red}${s}${RESET}`,\n green: (s: string): string => `${codes.green}${s}${RESET}`,\n yellow: (s: string): string => `${codes.yellow}${s}${RESET}`,\n blue: (s: string): string => `${codes.blue}${s}${RESET}`,\n magenta: (s: string): string => `${codes.magenta}${s}${RESET}`,\n cyan: (s: string): string => `${codes.cyan}${s}${RESET}`,\n gray: (s: string): string => `${codes.gray}${s}${RESET}`,\n white: (s: string): string => `${codes.white}${s}${RESET}`,\n bold: (s: string): string => `${codes.bold}${s}${RESET}`,\n dim: (s: string): string => `${codes.dim}${s}${RESET}`,\n italic: (s: string): string => `${codes.italic}${s}${RESET}`,\n underline: (s: string): string => `${codes.underline}${s}${RESET}`,\n}\n\nexport function stripColors(s: string): string {\n const ansi = String.fromCharCode(27)\n const re = new RegExp(`${ansi}\\\\[\\\\d+m`, 'g')\n return s.replace(re, '')\n}\n\nexport function isColorSupported(): boolean {\n if (typeof process === 'undefined') return false\n if (process.env.NO_COLOR) return false\n if (process.env.FORCE_COLOR) return true\n if (!process.stdout) return false\n if (!process.stdout.isTTY) return false\n return true\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\ninterface TemplateContent {\n dirs: string[]\n files: Record<string, string | ((name: string) => string)>\n}\n\nconst TEMPLATES: Record<string, TemplateContent> = {\n blank: {\n dirs: ['src'],\n files: {\n 'package.json': (name: string) =>\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n private: true,\n scripts: {\n dev: 'SpeexJS serve',\n build: 'SpeexJS build',\n start: 'node dist/index.js',\n },\n dependencies: {\n SpeexJS: 'latest',\n },\n devDependencies: {\n '@types/node': '^26.0.1',\n typescript: '^5.7.0',\n },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n sourceMap: true,\n esModuleInterop: true,\n isolatedModules: true,\n resolveJsonModule: true,\n outDir: './dist',\n rootDir: './src',\n },\n include: ['src/**/*.ts'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n ),\n 'src/index.ts': `import { SpeexJS } from 'speexjs/server'\n\nconst app = SpeexJS()\n\nconst PORT = Number(process.env.PORT) || 3000\n\napp.get('/', async ({ response }) => {\n return response.html('<h1>SpeexJS ๐</h1>')\n})\n\napp.listen(PORT, () => {\n console.log(\\`SpeexJS running on http://localhost:\\${PORT}\\`)\n})\n`,\n 'src/app.ts': `import { SpeexJS } from 'speexjs/server'\n\nexport function createApp() {\n const app = SpeexJS()\n return app\n}\n`,\n '.env.example': `PORT=3000\nNODE_ENV=development\n`,\n '.gitignore': `node_modules/\ndist/\n.env\n*.log\n`,\n },\n },\n\n fullstack: {\n dirs: [\n 'src/server',\n 'src/server/controllers',\n 'src/server/middleware',\n 'src/client',\n 'src/client/components',\n 'src/client/pages',\n 'src/shared',\n 'public',\n ],\n files: {\n 'package.json': (name: string) =>\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n private: true,\n scripts: {\n dev: 'SpeexJS serve',\n build: 'tsc',\n start: 'node dist/server/index.js',\n },\n dependencies: {\n SpeexJS: 'latest',\n },\n devDependencies: {\n '@types/node': '^26.0.1',\n typescript: '^5.7.0',\n },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n sourceMap: true,\n esModuleInterop: true,\n isolatedModules: true,\n resolveJsonModule: true,\n jsx: 'react-jsx',\n jsxImportSource: '@SpeexJS/vdom',\n outDir: './dist',\n rootDir: './src',\n },\n include: ['src/**/*.ts', 'src/**/*.tsx'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n ),\n 'src/server/index.ts': `import { SpeexJS } from 'speexjs/server'\nimport { UserController } from './controllers/user.controller.js'\n\nconst PORT = Number(process.env.PORT) || 3000\n\nconst app = SpeexJS()\n\napp.controller(UserController)\n\napp.get('/', async ({ response }) => {\n return response.html(\\`\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>SpeexJS Fullstack</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/client/index.js\"></script>\n </body>\n </html>\n \\`)\n})\n\napp.listen(PORT, () => {\n console.log(\\`SpeexJS running on http://localhost:\\${PORT}\\`)\n})\n`,\n 'src/server/controllers/user.controller.ts': `import { Controller, get, post } from 'speexjs/server'\n\nexport class UserController extends Controller {\n @get('/users')\n async index({ response }) {\n return response.json({ data: [] })\n }\n\n @post('/users')\n async store({ request, response }) {\n const body = await request.body()\n return response.json({ data: body }, 201)\n }\n}\n`,\n 'src/client/index.ts': `import { createApp } from './app.js'\n\ndocument.addEventListener('DOMContentLoaded', () => {\n createApp().mount('#root')\n})\n`,\n 'src/client/app.ts': `export function createApp() {\n function mount(selector: string) {\n const root = document.querySelector(selector)\n if (!root) {\n console.error('Root element not found:', selector)\n return\n }\n root.innerHTML = \\`\n <div style=\"text-align:center;padding:2rem\">\n <h1>SpeexJS Fullstack</h1>\n <p>Welcome to SpeexJS!</p>\n </div>\n \\`\n }\n\n return { mount }\n}\n`,\n 'public/style.css': `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0f172a;\n color: #e2e8f0;\n min-height: 100vh;\n}\n\n#root {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n}\n`,\n 'src/shared/types.ts': `export interface ApiResponse<T = unknown> {\n success: boolean\n data: T\n message?: string\n}\n`,\n '.env.example': `PORT=3000\nNODE_ENV=development\n`,\n '.gitignore': `node_modules/\ndist/\n.env\n*.log\n`,\n },\n },\n\n 'api-only': {\n dirs: ['src', 'src/controllers', 'src/middleware'],\n files: {\n 'package.json': (name: string) =>\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n private: true,\n scripts: {\n dev: 'SpeexJS serve',\n build: 'tsc',\n start: 'node dist/index.js',\n },\n dependencies: {\n SpeexJS: 'latest',\n },\n devDependencies: {\n '@types/node': '^26.0.1',\n typescript: '^5.7.0',\n },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n sourceMap: true,\n esModuleInterop: true,\n isolatedModules: true,\n resolveJsonModule: true,\n outDir: './dist',\n rootDir: './src',\n },\n include: ['src/**/*.ts'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n ),\n 'src/index.ts': `import { SpeexJS } from 'speexjs/server'\n\nconst PORT = Number(process.env.PORT) || 3000\n\nconst app = SpeexJS()\n\napp.get('/api/health', async ({ response }) => {\n return response.json({ status: 'ok', timestamp: new Date().toISOString() })\n})\n\napp.listen(PORT, () => {\n console.log(\\`SpeexJS API running on http://localhost:\\${PORT}\\`)\n})\n`,\n 'src/controllers/health.controller.ts': `import { Controller, get } from 'speexjs/server'\n\nexport class HealthController extends Controller {\n @get('/health')\n async check({ response }) {\n return response.json({\n status: 'ok',\n uptime: process.uptime(),\n })\n }\n}\n`,\n 'src/middleware/auth.ts': `import type { RouteContext } from 'speexjs/server/router'\n\nexport function auth() {\n return async (ctx: RouteContext, next: () => Promise<void>) => {\n const token = ctx.request.headers.get('authorization')\n\n if (!token) {\n ctx.response.status(401).json({\n error: 'Unauthorized',\n message: 'Missing authorization header',\n })\n return\n }\n\n await next()\n }\n}\n`,\n '.env.example': `PORT=3000\nNODE_ENV=development\n`,\n '.gitignore': `node_modules/\ndist/\n.env\n*.log\n`,\n },\n },\n}\n\nconst TEMPLATE_ALIASES: Record<string, string> = {\n api: 'api-only',\n full: 'fullstack',\n}\n\nfunction getTemplate(name: string): string {\n return TEMPLATE_ALIASES[name] ?? name\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nexport async function initProject(\n name: string,\n options: Record<string, any>,\n): Promise<void> {\n const targetDir = resolve(process.cwd(), name)\n\n if (existsSync(targetDir)) {\n console.error(colors.red(`Directory '${name}' sudah ada!`))\n process.exit(1)\n }\n\n const templateName = getTemplate(String(options.template || 'blank'))\n const template = TEMPLATES[templateName]\n\n if (!template) {\n console.error(\n colors.red(\n `Template '${options.template}' tidak dikenal. Gunakan: blank, fullstack, api-only`,\n ),\n )\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n for (const dir of template.dirs) {\n mkdirSync(resolve(targetDir, dir), { recursive: true })\n }\n\n for (const [filePath, content] of Object.entries(template.files)) {\n const fullPath = resolve(targetDir, filePath)\n mkdirSync(dirname(fullPath), { recursive: true })\n\n const resolvedContent =\n typeof content === 'function' ? content(name) : content\n\n writeFileSync(fullPath, resolvedContent, 'utf-8')\n }\n\n if (options.git !== false) {\n try {\n const { execSync } = await import('child_process')\n execSync('git init', { cwd: targetDir, stdio: 'ignore' })\n } catch {\n // git not available\n }\n }\n\n if (options.install !== false) {\n const pm = String(options['package-manager'] || options.packageManager || 'npm')\n try {\n const { execSync } = await import('child_process')\n console.log(` ${colors.cyan('โ')} Installing dependencies with ${pm}...`)\n execSync(`${pm} install`, { cwd: targetDir, stdio: 'inherit' })\n } catch {\n console.log(\n ` ${colors.yellow('!')} Dependency install skipped. Run '${pm} install' manually.`,\n )\n }\n }\n\n const packageManager = String(options['package-manager'] || options.packageManager || 'npm')\n\n console.log()\n console.log(`${colors.bold('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ')}`)\n console.log(`${colors.bold('โ')} ${colors.green('SpeexJS ๐ Project Created')}${colors.bold(' โ')}`)\n console.log(`${colors.bold('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ')}`)\n console.log()\n console.log(` ${colors.bold('Name:')} ${toPascalCase(name)}`)\n console.log(` ${colors.bold('Template:')} ${templateName}`)\n console.log(` ${colors.bold('Dir:')} ${targetDir}`)\n console.log()\n console.log(` ${colors.cyan('$')} cd ${name}`)\n console.log(` ${colors.cyan('$')} ${packageManager} run dev`)\n console.log()\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nfunction toCamelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toLowerCase())\n}\n\nexport function makeController(name: string): void {\n const className = `${toPascalCase(name)}Controller`\n const fileName = `${toKebabCase(name)}.controller.ts`\n const targetDir = resolve(process.cwd(), 'src/server/controllers')\n const fullPath = resolve(targetDir, fileName)\n const varName = toCamelCase(name)\n\n if (existsSync(fullPath)) {\n console.error(colors.red(`File ${fileName} sudah ada!`))\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n const content = `import { Controller, get, post, put, del } from 'speexjs/server'\nimport type { RouteContext } from 'speexjs/server/router'\n\nexport class ${className} extends Controller {\n @get('/')\n async index({ response }: RouteContext) {\n return response.json({ data: [] })\n }\n\n @get('/:id')\n async show({ response, params }: RouteContext) {\n return response.json({ data: { id: params.id } })\n }\n\n @post('/')\n async store({ request, response }: RouteContext) {\n const body = await request.body()\n return response.json({ data: body }, 201)\n }\n\n @put('/:id')\n async update({ request, response, params }: RouteContext) {\n const body = await request.body()\n return response.json({ data: { id: params.id, ...body } })\n }\n\n @del('/:id')\n async destroy({ response, params }: RouteContext) {\n return response.json({ message: \\`${className} deleted \\${params.id}\\` })\n }\n}\n\nexport const ${varName}Controller = ${className}\n`\n\n writeFileSync(fullPath, content, 'utf-8')\n console.log(\n `${colors.green('โ
')} Controller ${colors.bold(className)} dibuat di ${colors.cyan(fileName)}`,\n )\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nfunction toCamelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toLowerCase())\n}\n\nexport function makeMiddleware(name: string): void {\n const functionName = toCamelCase(name)\n const className = toPascalCase(name)\n const fileName = `${toKebabCase(name)}.middleware.ts`\n const targetDir = resolve(process.cwd(), 'src/server/middleware')\n const fullPath = resolve(targetDir, fileName)\n\n if (existsSync(fullPath)) {\n console.error(colors.red(`File ${fileName} sudah ada!`))\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n const content = `import type { RouteContext } from 'speexjs/server/router'\n\nexport function ${functionName}(options?: Record<string, unknown>) {\n return async (ctx: RouteContext, next: () => Promise<void>) => {\n const start = Date.now()\n\n await next()\n\n const duration = Date.now() - start\n console.log(\\`[${className}Middleware] \\${ctx.request.method} \\${ctx.request.url} \\${duration}ms\\`)\n }\n}\n`\n\n writeFileSync(fullPath, content, 'utf-8')\n console.log(\n `${colors.green('โ
')} Middleware ${colors.bold(functionName)} dibuat di ${colors.cyan(fileName)}`,\n )\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nexport function makeSchema(name: string): void {\n const schemaName = `${toPascalCase(name)}Schema`\n const typeName = toPascalCase(name)\n const fileName = `${toKebabCase(name)}.schema.ts`\n const targetDir = resolve(process.cwd(), 'src/schemas')\n const fullPath = resolve(targetDir, fileName)\n\n if (existsSync(fullPath)) {\n console.error(colors.red(`File ${fileName} sudah ada!`))\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n const content = `import { s, type Infer } from 'speexjs/schema'\n\nexport const ${schemaName} = s.object({\n id: s.string().uuid(),\n name: s.string().min(1).max(255),\n createdAt: s.string().datetime(),\n updatedAt: s.string().datetime().optional(),\n})\n\nexport type ${typeName} = Infer<typeof ${schemaName}>\n\nexport const create${typeName}Schema = s.object({\n name: s.string().min(1).max(255),\n})\n\nexport type Create${typeName} = Infer<typeof create${typeName}Schema>\n`\n\n writeFileSync(fullPath, content, 'utf-8')\n console.log(\n `${colors.green('โ
')} Schema ${colors.bold(schemaName)} dibuat di ${colors.cyan(fileName)}`,\n )\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\ninterface RouteInfo {\n method: string\n path: string\n}\n\nfunction extractDecorators(content: string): RouteInfo[] {\n const pattern = /@(get|post|put|patch|del|delete)\\s*\\(\\s*'([^']+)'\\s*\\)/g\n const results: RouteInfo[] = []\n\n let match: RegExpExecArray | null = pattern.exec(content)\n while (match !== null) {\n const method =\n match[1] === 'del' ? 'DELETE' : (match[1] as string).toUpperCase()\n const path = match[2] as string\n results.push({ method, path })\n match = pattern.exec(content)\n }\n\n return results\n}\n\nexport function listRoutes(): void {\n const routesDir = resolve(process.cwd(), 'src/server/controllers')\n\n if (!existsSync(routesDir)) {\n console.log(\n ` ${colors.yellow('!')} Tidak ada route terdaftar. Buat controller dulu:`,\n )\n console.log(` ${colors.cyan('speexjs make:controller <name>')}`)\n return\n }\n\n const files = readdirSync(routesDir).filter(f => f.endsWith('.ts'))\n\n if (files.length === 0) {\n console.log(\n ` ${colors.yellow('!')} Tidak ada route terdaftar. Buat controller dulu:`,\n )\n console.log(` ${colors.cyan('speexjs make:controller <name>')}`)\n return\n }\n\n let total = 0\n\n console.log()\n console.log(` ${colors.bold('๐ Daftar Route:')}`)\n console.log()\n\n for (const file of files) {\n const content = readFileSync(resolve(routesDir, file), 'utf-8')\n const routes = extractDecorators(content)\n\n if (routes.length > 0) {\n console.log(` ${colors.cyan('โโ')} ${colors.bold(file.replace('.controller.ts', ''))} ${colors.cyan('โโ')}`)\n\n for (const { method, path } of routes) {\n const coloredMethod = method === 'GET'\n ? colors.green(method.padEnd(8))\n : method === 'POST'\n ? colors.blue(method.padEnd(8))\n : method === 'PUT' || method === 'PATCH'\n ? colors.yellow(method.padEnd(8))\n : colors.red(method.padEnd(8))\n\n console.log(` ${coloredMethod} ${path}`)\n total++\n }\n\n console.log()\n }\n }\n\n console.log(` ${colors.dim(`${total} route${total !== 1 ? 's' : ''} ditemukan`)}`)\n console.log()\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\nimport { logger } from '../../native/logger.js'\n\ninterface ServeOptions {\n port?: string | number\n host?: string\n dev?: string | boolean\n}\n\nexport async function serve(options: Record<string, any>): Promise<void> {\n const opts: ServeOptions = {\n port: options.port || options.p || 3000,\n host: options.host || options.H || 'localhost',\n dev: options.dev !== false,\n }\n\n const port = parseInt(String(opts.port), 10)\n const host = String(opts.host)\n\n const serverEntry = resolve(process.cwd(), 'src/app.ts')\n const serverEntryAlt = resolve(process.cwd(), 'src/server/index.ts')\n const serverEntryIndex = resolve(process.cwd(), 'src/index.ts')\n\n let entryPath: string | null = null\n if (existsSync(serverEntry)) entryPath = serverEntry\n else if (existsSync(serverEntryAlt)) entryPath = serverEntryAlt\n else if (existsSync(serverEntryIndex)) entryPath = serverEntryIndex\n\n if (!entryPath) {\n console.error(\n colors.red(\n 'Tidak ditemukan file entry point. Buat src/app.ts atau src/index.ts',\n ),\n )\n process.exit(1)\n }\n\n if (opts.dev) {\n logger.info(\n `Development server starting at ${colors.cyan(`http://${host}:${port}`)}`,\n )\n\n try {\n const { app } = await import(entryPath)\n\n if (!app || typeof app.listen !== 'function') {\n console.error(\n colors.red(\n 'Entry point harus export { app } dengan method .listen()',\n ),\n )\n process.exit(1)\n }\n\n app.listen(port, host, () => {\n console.log()\n console.log(` ${colors.bold('SpeexJS')} ${colors.green('running')}`)\n console.log(` ${colors.dim('โ')} ${colors.cyan(`http://${host}:${port}`)}`)\n console.log()\n })\n } catch (err: any) {\n console.error(colors.red(`Gagal menjalankan server: ${err.message}`))\n process.exit(1)\n }\n } else {\n try {\n const { app } = await import(entryPath)\n\n if (!app || typeof app.listen !== 'function') {\n console.error(\n colors.red(\n 'Entry point harus export { app } dengan method .listen()',\n ),\n )\n process.exit(1)\n }\n\n app.listen(port, host, () => {\n console.log()\n console.log(` ${colors.bold('SpeexJS')} ${colors.green('running')}`)\n console.log(` ${colors.dim('โ')} ${colors.cyan(`http://${host}:${port}`)}`)\n console.log()\n })\n } catch (err: any) {\n console.error(colors.red(`Gagal menjalankan server: ${err.message}`))\n process.exit(1)\n }\n }\n}\n","import { colors, isColorSupported } from './colors.js'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nexport interface LoggerOptions {\n level?: LogLevel\n name?: string\n colors?: boolean\n timestamps?: boolean\n timezone?: 'WIB' | 'WITA' | 'WIT' | 'UTC'\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n}\n\nconst TIMEZONE_OFFSETS: Record<string, number> = {\n WIB: 7,\n WITA: 8,\n WIT: 9,\n UTC: 0,\n}\n\nfunction pad(n: number): string {\n return n.toString().padStart(2, '0')\n}\n\nexport function formatTimestamp(tz?: string): string {\n const offset = TIMEZONE_OFFSETS[tz ?? ''] ?? 7\n const now = new Date()\n const utc = now.getTime() + now.getTimezoneOffset() * 60000\n const local = new Date(utc + offset * 3600000)\n\n const y = local.getFullYear()\n const M = pad(local.getMonth() + 1)\n const d = pad(local.getDate())\n const h = pad(local.getHours())\n const m = pad(local.getMinutes())\n const s = pad(local.getSeconds())\n\n return `${y}-${M}-${d} ${h}:${m}:${s} ${tz ?? 'WIB'}`\n}\n\nconst LEVEL_PREFIX: Record<LogLevel, string> = {\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n}\n\nconst LEVEL_COLOR: Record<LogLevel, (s: string) => string> = {\n debug: colors.gray,\n info: colors.cyan,\n warn: colors.yellow,\n error: colors.red,\n}\n\nexport class Logger {\n private _level: LogLevel\n private _name: string\n private _useColors: boolean\n private _useTimestamps: boolean\n private _timezone: string\n\n constructor(options?: LoggerOptions) {\n this._level = options?.level ?? 'info'\n this._name = options?.name ?? ''\n this._useColors = options?.colors ?? isColorSupported()\n this._useTimestamps = options?.timestamps ?? true\n this._timezone = options?.timezone ?? 'WIB'\n }\n\n private _format(level: LogLevel, msg: string, meta?: Record<string, unknown>): string {\n const parts: string[] = []\n\n if (this._useTimestamps) {\n parts.push(formatTimestamp(this._timezone))\n }\n\n if (this._useColors) {\n parts.push(LEVEL_COLOR[level](LEVEL_PREFIX[level]))\n } else {\n parts.push(LEVEL_PREFIX[level])\n }\n\n if (this._name) {\n parts.push(this._useColors ? colors.dim(`[${this._name}]`) : `[${this._name}]`)\n }\n\n if (this._useColors) {\n parts.push(LEVEL_COLOR[level](msg))\n } else {\n parts.push(msg)\n }\n\n if (meta && Object.keys(meta).length > 0) {\n parts.push(JSON.stringify(meta))\n }\n\n return parts.join(' ')\n }\n\n debug(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.debug) return\n console.debug(this._format('debug', msg, meta))\n }\n\n info(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.info) return\n console.info(this._format('info', msg, meta))\n }\n\n warn(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.warn) return\n console.warn(this._format('warn', msg, meta))\n }\n\n error(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.error) return\n console.error(this._format('error', msg, meta))\n }\n\n child(name: string): Logger {\n const childName = this._name ? `${this._name}:${name}` : name\n return new Logger({\n level: this._level,\n name: childName,\n colors: this._useColors,\n timestamps: this._useTimestamps,\n timezone: this._timezone as LoggerOptions['timezone'],\n })\n }\n\n setLevel(level: LogLevel): void {\n this._level = level\n }\n}\n\nexport const logger = new Logger()\n","#!/usr/bin/env node\nimport { parseArgs } from '../native/args.js'\nimport { colors } from '../native/colors.js'\nimport { initProject } from './commands/init.js'\nimport { makeController } from './commands/make-controller.js'\nimport { makeMiddleware } from './commands/make-middleware.js'\nimport { makeSchema } from './commands/make-schema.js'\nimport { listRoutes } from './commands/list-routes.js'\nimport { serve } from './commands/serve.js'\n\nfunction showHelp(): void {\n console.log(`${colors.bold('SpeexJS')} ${colors.cyan('v0.2.0')}`)\n console.log('Fullstack JavaScript/TypeScript Framework')\n console.log()\n console.log(`${colors.bold('Usage:')}`)\n console.log(' SpeexJS init [name] [options] Buat project baru')\n console.log(' SpeexJS make:controller <name> Generate controller')\n console.log(' SpeexJS make:middleware <name> Generate middleware')\n console.log(' SpeexJS make:schema <name> Generate schema')\n console.log(' SpeexJS list-routes Lihat semua route')\n console.log(' SpeexJS serve [options] Jalankan server')\n console.log(' SpeexJS --help Bantuan ini')\n console.log()\n console.log(`${colors.bold('Aliases:')}`)\n console.log(' SpeexJS -v, --version Lihat versi')\n console.log()\n console.log(`${colors.bold('Options:')}`)\n console.log(' --template <type> blank, fullstack, api-only')\n console.log(' --frontend <fe> super, react, vue')\n console.log(' --port <number> Port server (default: 3000)')\n console.log(' --host <string> Host address (default: localhost)')\n}\n\nasync function main(): Promise<void> {\n const parsed = parseArgs(process.argv)\n const command = parsed.command\n\n switch (command) {\n case 'init': {\n await initProject(parsed.args[0] || 'my-app', parsed.options)\n break\n }\n case 'make:controller': {\n if (!parsed.args[0]) {\n console.error(colors.red('Nama controller diperlukan'))\n console.log(` ${colors.cyan('SpeexJS make:controller <name>')}`)\n process.exit(1)\n }\n await makeController(parsed.args[0])\n break\n }\n case 'make:middleware': {\n if (!parsed.args[0]) {\n console.error(colors.red('Nama middleware diperlukan'))\n console.log(` ${colors.cyan('SpeexJS make:middleware <name>')}`)\n process.exit(1)\n }\n await makeMiddleware(parsed.args[0])\n break\n }\n case 'make:schema': {\n if (!parsed.args[0]) {\n console.error(colors.red('Nama schema diperlukan'))\n console.log(` ${colors.cyan('SpeexJS make:schema <name>')}`)\n process.exit(1)\n }\n await makeSchema(parsed.args[0])\n break\n }\n case 'list-routes':\n case 'routes':\n case 'lr': {\n await listRoutes()\n break\n }\n case 'serve':\n case 'dev': {\n await serve(parsed.options)\n break\n }\n case 'help':\n case '--help':\n case '-h': {\n showHelp()\n break\n }\n case 'version':\n case '--version':\n case '-v': {\n console.log('SpeexJS v0.2.0')\n break\n }\n default: {\n if (command) {\n console.error(`${colors.red(`Command '${command}' tidak dikenal`)}`)\n console.log()\n }\n showHelp()\n if (command) process.exit(1)\n }\n }\n}\n\nmain().catch(err => {\n console.error(colors.red(`Error: ${err.message}`))\n process.exit(1)\n})\n"],"mappings":"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","names":["existsSync","mkdirSync","writeFileSync","resolve","toPascalCase","resolve","existsSync","mkdirSync","writeFileSync","existsSync","mkdirSync","writeFileSync","resolve","toPascalCase","toKebabCase","toCamelCase","resolve","existsSync","mkdirSync","writeFileSync","existsSync","mkdirSync","writeFileSync","resolve","toPascalCase","toKebabCase","resolve","existsSync","mkdirSync","writeFileSync","existsSync","resolve","resolve","existsSync","existsSync","resolve","resolve","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../../src/native/args.ts","../../src/native/colors.ts","../../src/cli/commands/init.ts","../../src/cli/commands/make-controller.ts","../../src/cli/commands/make-middleware.ts","../../src/cli/commands/make-schema.ts","../../src/cli/commands/list-routes.ts","../../src/cli/commands/serve.ts","../../src/native/logger.ts","../../src/cli/index.ts"],"sourcesContent":["export interface ParsedArgs {\n command: string\n subcommand?: string\n args: string[]\n options: Record<string, string | boolean | string[]>\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const args = argv.slice(2)\n const result: ParsedArgs = {\n command: '',\n args: [],\n options: {},\n }\n\n if (args.length === 0) return result\n\n const first = args[0]!\n\n if (first.includes(':')) {\n result.command = first\n parseOptions(args.slice(1), result)\n return result\n }\n\n result.command = first\n\n if (args.length > 1) {\n const second = args[1]!\n if (!second.startsWith('-')) {\n result.subcommand = second\n result.args.push(second)\n parseOptions(args.slice(2), result)\n return result\n }\n }\n\n parseOptions(args.slice(1), result)\n return result\n}\n\nfunction parseOptions(argv: string[], result: ParsedArgs): void {\n let i = 0\n while (i < argv.length) {\n const arg = argv[i]!\n\n if (arg === '--') {\n for (let j = i + 1; j < argv.length; j++) {\n result.args.push(argv[j]!)\n }\n break\n }\n\n if (arg.startsWith('--no-')) {\n const key = arg.slice(5)\n if (key) {\n result.options[key] = false\n }\n i++\n continue\n }\n\n if (arg.startsWith('--')) {\n const key = arg.slice(2)\n if (i + 1 < argv.length && !argv[i + 1]!.startsWith('-')) {\n const val = argv[i + 1]!\n const existing = result.options[key]\n if (existing !== undefined) {\n result.options[key] = Array.isArray(existing)\n ? ([...existing, val] as string[])\n : [existing as string, val]\n } else {\n result.options[key] = val\n }\n i += 2\n } else {\n result.options[key] = true\n i++\n }\n continue\n }\n\n if (arg.startsWith('-') && arg.length === 2) {\n const key = arg.slice(1)\n if (i + 1 < argv.length && !argv[i + 1]!.startsWith('-')) {\n const val = argv[i + 1]!\n result.options[key] = val\n i += 2\n } else {\n result.options[key] = true\n i++\n }\n continue\n }\n\n result.args.push(arg)\n i++\n }\n}\n\nexport function toCommandName(argv: string[]): string {\n const args = argv.slice(2)\n if (args.length === 0) return ''\n\n const first = args[0]!\n\n if (first.includes(':')) return first\n\n if (args.length > 1 && !args[1]!.startsWith('-')) {\n return `${first}:${args[1]}`\n }\n\n return first\n}\n","const RESET = '\\x1b[0m'\n\nconst codes: Record<string, string> = {\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n italic: '\\x1b[3m',\n underline: '\\x1b[4m',\n}\n\nexport const colors = {\n red: (s: string): string => `${codes.red}${s}${RESET}`,\n green: (s: string): string => `${codes.green}${s}${RESET}`,\n yellow: (s: string): string => `${codes.yellow}${s}${RESET}`,\n blue: (s: string): string => `${codes.blue}${s}${RESET}`,\n magenta: (s: string): string => `${codes.magenta}${s}${RESET}`,\n cyan: (s: string): string => `${codes.cyan}${s}${RESET}`,\n gray: (s: string): string => `${codes.gray}${s}${RESET}`,\n white: (s: string): string => `${codes.white}${s}${RESET}`,\n bold: (s: string): string => `${codes.bold}${s}${RESET}`,\n dim: (s: string): string => `${codes.dim}${s}${RESET}`,\n italic: (s: string): string => `${codes.italic}${s}${RESET}`,\n underline: (s: string): string => `${codes.underline}${s}${RESET}`,\n}\n\nexport function stripColors(s: string): string {\n const ansi = String.fromCharCode(27)\n const re = new RegExp(`${ansi}\\\\[\\\\d+m`, 'g')\n return s.replace(re, '')\n}\n\nexport function isColorSupported(): boolean {\n if (typeof process === 'undefined') return false\n if (process.env.NO_COLOR) return false\n if (process.env.FORCE_COLOR) return true\n if (!process.stdout) return false\n if (!process.stdout.isTTY) return false\n return true\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\ninterface TemplateContent {\n dirs: string[]\n files: Record<string, string | ((name: string) => string)>\n}\n\nconst TEMPLATES: Record<string, TemplateContent> = {\n blank: {\n dirs: ['src'],\n files: {\n 'package.json': (name: string) =>\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n private: true,\n scripts: {\n dev: 'speexjs serve',\n build: 'speexjs build',\n start: 'node dist/index.js',\n },\n dependencies: {\n speexjs: 'latest',\n },\n devDependencies: {\n '@types/node': '^26.0.1',\n typescript: '^5.7.0',\n },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n sourceMap: true,\n esModuleInterop: true,\n isolatedModules: true,\n resolveJsonModule: true,\n outDir: './dist',\n rootDir: './src',\n },\n include: ['src/**/*.ts'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n ),\n 'src/index.ts': `import { speexjs } from 'speexjs/server'\n\nconst app = speexjs()\n\nconst PORT = Number(process.env.PORT) || 3000\n\napp.get('/', async ({ response }) => {\n return response.html('<h1>SpeexJS ๐</h1>')\n})\n\napp.listen(PORT, () => {\n console.log(\\`SpeexJS running on http://localhost:\\${PORT}\\`)\n})\n`,\n 'src/app.ts': `import { speexjs } from 'speexjs/server'\n\nexport function createApp() {\n const app = speexjs()\n return app\n}\n`,\n '.env.example': `PORT=3000\nNODE_ENV=development\n`,\n '.gitignore': `node_modules/\ndist/\n.env\n*.log\n`,\n },\n },\n\n fullstack: {\n dirs: [\n 'src/server',\n 'src/server/controllers',\n 'src/server/middleware',\n 'src/client',\n 'src/client/components',\n 'src/client/pages',\n 'src/shared',\n 'public',\n ],\n files: {\n 'package.json': (name: string) =>\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n private: true,\n scripts: {\n dev: 'speexjs serve',\n build: 'tsc',\n start: 'node dist/server/index.js',\n },\n dependencies: {\n speexjs: 'latest',\n },\n devDependencies: {\n '@types/node': '^26.0.1',\n typescript: '^5.7.0',\n },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n sourceMap: true,\n esModuleInterop: true,\n isolatedModules: true,\n resolveJsonModule: true,\n jsx: 'react-jsx',\n jsxImportSource: '@speexjs/vdom',\n outDir: './dist',\n rootDir: './src',\n },\n include: ['src/**/*.ts', 'src/**/*.tsx'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n ),\n 'src/server/index.ts': `import { speexjs } from 'speexjs/server'\nimport { UserController } from './controllers/user.controller.js'\n\nconst PORT = Number(process.env.PORT) || 3000\n\nconst app = speexjs()\n\napp.controller(UserController)\n\napp.get('/', async ({ response }) => {\n return response.html(\\`\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>SpeexJS Fullstack</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/client/index.js\"></script>\n </body>\n </html>\n \\`)\n})\n\napp.listen(PORT, () => {\n console.log(\\`SpeexJS running on http://localhost:\\${PORT}\\`)\n})\n`,\n 'src/server/controllers/user.controller.ts': `import { Controller, get, post } from 'speexjs/server'\n\nexport class UserController extends Controller {\n @get('/users')\n async index({ response }) {\n return response.json({ data: [] })\n }\n\n @post('/users')\n async store({ request, response }) {\n const body = await request.body()\n return response.json({ data: body }, 201)\n }\n}\n`,\n 'src/client/index.ts': `import { createApp } from './app.js'\n\ndocument.addEventListener('DOMContentLoaded', () => {\n createApp().mount('#root')\n})\n`,\n 'src/client/app.ts': `export function createApp() {\n function mount(selector: string) {\n const root = document.querySelector(selector)\n if (!root) {\n console.error('Root element not found:', selector)\n return\n }\n root.innerHTML = \\`\n <div style=\"text-align:center;padding:2rem\">\n <h1>SpeexJS Fullstack</h1>\n <p>Welcome to SpeexJS!</p>\n </div>\n \\`\n }\n\n return { mount }\n}\n`,\n 'public/style.css': `* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #0f172a;\n color: #e2e8f0;\n min-height: 100vh;\n}\n\n#root {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n}\n`,\n 'src/shared/types.ts': `export interface ApiResponse<T = unknown> {\n success: boolean\n data: T\n message?: string\n}\n`,\n '.env.example': `PORT=3000\nNODE_ENV=development\n`,\n '.gitignore': `node_modules/\ndist/\n.env\n*.log\n`,\n },\n },\n\n 'api-only': {\n dirs: ['src', 'src/controllers', 'src/middleware'],\n files: {\n 'package.json': (name: string) =>\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n private: true,\n scripts: {\n dev: 'speexjs serve',\n build: 'tsc',\n start: 'node dist/index.js',\n },\n dependencies: {\n speexjs: 'latest',\n },\n devDependencies: {\n '@types/node': '^26.0.1',\n typescript: '^5.7.0',\n },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n declaration: true,\n sourceMap: true,\n esModuleInterop: true,\n isolatedModules: true,\n resolveJsonModule: true,\n outDir: './dist',\n rootDir: './src',\n },\n include: ['src/**/*.ts'],\n exclude: ['node_modules', 'dist'],\n },\n null,\n 2,\n ),\n 'src/index.ts': `import { speexjs } from 'speexjs/server'\n\nconst PORT = Number(process.env.PORT) || 3000\n\nconst app = speexjs()\n\napp.get('/api/health', async ({ response }) => {\n return response.json({ status: 'ok', timestamp: new Date().toISOString() })\n})\n\napp.listen(PORT, () => {\n console.log(\\`SpeexJS API running on http://localhost:\\${PORT}\\`)\n})\n`,\n 'src/controllers/health.controller.ts': `import { Controller, get } from 'speexjs/server'\n\nexport class HealthController extends Controller {\n @get('/health')\n async check({ response }) {\n return response.json({\n status: 'ok',\n uptime: process.uptime(),\n })\n }\n}\n`,\n 'src/middleware/auth.ts': `import type { RouteContext } from 'speexjs/server/router'\n\nexport function auth() {\n return async (ctx: RouteContext, next: () => Promise<void>) => {\n const token = ctx.request.headers.get('authorization')\n\n if (!token) {\n ctx.response.status(401).json({\n error: 'Unauthorized',\n message: 'Missing authorization header',\n })\n return\n }\n\n await next()\n }\n}\n`,\n '.env.example': `PORT=3000\nNODE_ENV=development\n`,\n '.gitignore': `node_modules/\ndist/\n.env\n*.log\n`,\n },\n },\n}\n\nconst TEMPLATE_ALIASES: Record<string, string> = {\n api: 'api-only',\n full: 'fullstack',\n}\n\nfunction getTemplate(name: string): string {\n return TEMPLATE_ALIASES[name] ?? name\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nexport async function initProject(\n name: string,\n options: Record<string, any>,\n): Promise<void> {\n const targetDir = resolve(process.cwd(), name)\n\n if (existsSync(targetDir)) {\n console.error(colors.red(`Directory '${name}' sudah ada!`))\n process.exit(1)\n }\n\n const templateName = getTemplate(String(options.template || 'blank'))\n const template = TEMPLATES[templateName]\n\n if (!template) {\n console.error(\n colors.red(\n `Template '${options.template}' tidak dikenal. Gunakan: blank, fullstack, api-only`,\n ),\n )\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n for (const dir of template.dirs) {\n mkdirSync(resolve(targetDir, dir), { recursive: true })\n }\n\n for (const [filePath, content] of Object.entries(template.files)) {\n const fullPath = resolve(targetDir, filePath)\n mkdirSync(dirname(fullPath), { recursive: true })\n\n const resolvedContent =\n typeof content === 'function' ? content(name) : content\n\n writeFileSync(fullPath, resolvedContent, 'utf-8')\n }\n\n if (options.git !== false) {\n try {\n const { execSync } = await import('child_process')\n execSync('git init', { cwd: targetDir, stdio: 'ignore' })\n } catch {\n // git not available\n }\n }\n\n if (options.install !== false) {\n const pm = String(options['package-manager'] || options.packageManager || 'npm')\n try {\n const { execSync } = await import('child_process')\n console.log(` ${colors.cyan('โ')} Installing dependencies with ${pm}...`)\n execSync(`${pm} install`, { cwd: targetDir, stdio: 'inherit' })\n } catch {\n console.log(\n ` ${colors.yellow('!')} Dependency install skipped. Run '${pm} install' manually.`,\n )\n }\n }\n\n const packageManager = String(options['package-manager'] || options.packageManager || 'npm')\n\n console.log()\n console.log(`${colors.bold('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ')}`)\n console.log(`${colors.bold('โ')} ${colors.green('speexjs ๐ Project Created')}${colors.bold(' โ')}`)\n console.log(`${colors.bold('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ')}`)\n console.log()\n console.log(` ${colors.bold('Name:')} ${toPascalCase(name)}`)\n console.log(` ${colors.bold('Template:')} ${templateName}`)\n console.log(` ${colors.bold('Dir:')} ${targetDir}`)\n console.log()\n console.log(` ${colors.cyan('$')} cd ${name}`)\n console.log(` ${colors.cyan('$')} ${packageManager} run dev`)\n console.log()\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nfunction toCamelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toLowerCase())\n}\n\nexport function makeController(name: string): void {\n const className = `${toPascalCase(name)}Controller`\n const fileName = `${toKebabCase(name)}.controller.ts`\n const targetDir = resolve(process.cwd(), 'src/server/controllers')\n const fullPath = resolve(targetDir, fileName)\n const varName = toCamelCase(name)\n\n if (existsSync(fullPath)) {\n console.error(colors.red(`File ${fileName} sudah ada!`))\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n const content = `import { Controller, get, post, put, del } from 'speexjs/server'\nimport type { RouteContext } from 'speexjs/server/router'\n\nexport class ${className} extends Controller {\n @get('/')\n async index({ response }: RouteContext) {\n return response.json({ data: [] })\n }\n\n @get('/:id')\n async show({ response, params }: RouteContext) {\n return response.json({ data: { id: params.id } })\n }\n\n @post('/')\n async store({ request, response }: RouteContext) {\n const body = await request.body()\n return response.json({ data: body }, 201)\n }\n\n @put('/:id')\n async update({ request, response, params }: RouteContext) {\n const body = await request.body()\n return response.json({ data: { id: params.id, ...body } })\n }\n\n @del('/:id')\n async destroy({ response, params }: RouteContext) {\n return response.json({ message: \\`${className} deleted \\${params.id}\\` })\n }\n}\n\nexport const ${varName}Controller = ${className}\n`\n\n writeFileSync(fullPath, content, 'utf-8')\n console.log(\n `${colors.green('โ
')} Controller ${colors.bold(className)} dibuat di ${colors.cyan(fileName)}`,\n )\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nfunction toCamelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toLowerCase())\n}\n\nexport function makeMiddleware(name: string): void {\n const functionName = toCamelCase(name)\n const className = toPascalCase(name)\n const fileName = `${toKebabCase(name)}.middleware.ts`\n const targetDir = resolve(process.cwd(), 'src/server/middleware')\n const fullPath = resolve(targetDir, fileName)\n\n if (existsSync(fullPath)) {\n console.error(colors.red(`File ${fileName} sudah ada!`))\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n const content = `import type { RouteContext } from 'speexjs/server/router'\n\nexport function ${functionName}(options?: Record<string, unknown>) {\n return async (ctx: RouteContext, next: () => Promise<void>) => {\n const start = Date.now()\n\n await next()\n\n const duration = Date.now() - start\n console.log(\\`[${className}Middleware] \\${ctx.request.method} \\${ctx.request.url} \\${duration}ms\\`)\n }\n}\n`\n\n writeFileSync(fullPath, content, 'utf-8')\n console.log(\n `${colors.green('โ
')} Middleware ${colors.bold(functionName)} dibuat di ${colors.cyan(fileName)}`,\n )\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, c: string) => (c ?? '').toUpperCase())\n .replace(/^(.)/, (c: string) => c.toUpperCase())\n}\n\nfunction toKebabCase(str: string): string {\n return str\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase()\n}\n\nexport function makeSchema(name: string): void {\n const schemaName = `${toPascalCase(name)}Schema`\n const typeName = toPascalCase(name)\n const fileName = `${toKebabCase(name)}.schema.ts`\n const targetDir = resolve(process.cwd(), 'src/schemas')\n const fullPath = resolve(targetDir, fileName)\n\n if (existsSync(fullPath)) {\n console.error(colors.red(`File ${fileName} sudah ada!`))\n process.exit(1)\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n const content = `import { s, type Infer } from 'speexjs/schema'\n\nexport const ${schemaName} = s.object({\n id: s.string().uuid(),\n name: s.string().min(1).max(255),\n createdAt: s.string().datetime(),\n updatedAt: s.string().datetime().optional(),\n})\n\nexport type ${typeName} = Infer<typeof ${schemaName}>\n\nexport const create${typeName}Schema = s.object({\n name: s.string().min(1).max(255),\n})\n\nexport type Create${typeName} = Infer<typeof create${typeName}Schema>\n`\n\n writeFileSync(fullPath, content, 'utf-8')\n console.log(\n `${colors.green('โ
')} Schema ${colors.bold(schemaName)} dibuat di ${colors.cyan(fileName)}`,\n )\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\n\ninterface RouteInfo {\n method: string\n path: string\n}\n\nfunction extractDecorators(content: string): RouteInfo[] {\n const pattern = /@(get|post|put|patch|del|delete)\\s*\\(\\s*'([^']+)'\\s*\\)/g\n const results: RouteInfo[] = []\n\n let match: RegExpExecArray | null = pattern.exec(content)\n while (match !== null) {\n const method =\n match[1] === 'del' ? 'DELETE' : (match[1] as string).toUpperCase()\n const path = match[2] as string\n results.push({ method, path })\n match = pattern.exec(content)\n }\n\n return results\n}\n\nexport function listRoutes(): void {\n const routesDir = resolve(process.cwd(), 'src/server/controllers')\n\n if (!existsSync(routesDir)) {\n console.log(\n ` ${colors.yellow('!')} Tidak ada route terdaftar. Buat controller dulu:`,\n )\n console.log(` ${colors.cyan('speexjs make:controller <name>')}`)\n return\n }\n\n const files = readdirSync(routesDir).filter(f => f.endsWith('.ts'))\n\n if (files.length === 0) {\n console.log(\n ` ${colors.yellow('!')} Tidak ada route terdaftar. Buat controller dulu:`,\n )\n console.log(` ${colors.cyan('speexjs make:controller <name>')}`)\n return\n }\n\n let total = 0\n\n console.log()\n console.log(` ${colors.bold('๐ Daftar Route:')}`)\n console.log()\n\n for (const file of files) {\n const content = readFileSync(resolve(routesDir, file), 'utf-8')\n const routes = extractDecorators(content)\n\n if (routes.length > 0) {\n console.log(` ${colors.cyan('โโ')} ${colors.bold(file.replace('.controller.ts', ''))} ${colors.cyan('โโ')}`)\n\n for (const { method, path } of routes) {\n const coloredMethod = method === 'GET'\n ? colors.green(method.padEnd(8))\n : method === 'POST'\n ? colors.blue(method.padEnd(8))\n : method === 'PUT' || method === 'PATCH'\n ? colors.yellow(method.padEnd(8))\n : colors.red(method.padEnd(8))\n\n console.log(` ${coloredMethod} ${path}`)\n total++\n }\n\n console.log()\n }\n }\n\n console.log(` ${colors.dim(`${total} route${total !== 1 ? 's' : ''} ditemukan`)}`)\n console.log()\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { colors } from '../../native/colors.js'\nimport { logger } from '../../native/logger.js'\n\ninterface ServeOptions {\n port?: string | number\n host?: string\n dev?: string | boolean\n}\n\nexport async function serve(options: Record<string, any>): Promise<void> {\n const opts: ServeOptions = {\n port: options.port || options.p || 3000,\n host: options.host || options.H || 'localhost',\n dev: options.dev !== false,\n }\n\n const port = parseInt(String(opts.port), 10)\n const host = String(opts.host)\n\n const serverEntry = resolve(process.cwd(), 'src/app.ts')\n const serverEntryAlt = resolve(process.cwd(), 'src/server/index.ts')\n const serverEntryIndex = resolve(process.cwd(), 'src/index.ts')\n\n let entryPath: string | null = null\n if (existsSync(serverEntry)) entryPath = serverEntry\n else if (existsSync(serverEntryAlt)) entryPath = serverEntryAlt\n else if (existsSync(serverEntryIndex)) entryPath = serverEntryIndex\n\n if (!entryPath) {\n console.error(\n colors.red(\n 'Tidak ditemukan file entry point. Buat src/app.ts atau src/index.ts',\n ),\n )\n process.exit(1)\n }\n\n if (opts.dev) {\n logger.info(\n `Development server starting at ${colors.cyan(`http://${host}:${port}`)}`,\n )\n\n try {\n const { app } = await import(entryPath)\n\n if (!app || typeof app.listen !== 'function') {\n console.error(\n colors.red(\n 'Entry point harus export { app } dengan method .listen()',\n ),\n )\n process.exit(1)\n }\n\n app.listen(port, host, () => {\n console.log()\n console.log(` ${colors.bold('SpeexJS')} ${colors.green('running')}`)\n console.log(` ${colors.dim('โ')} ${colors.cyan(`http://${host}:${port}`)}`)\n console.log()\n })\n } catch (err: any) {\n console.error(colors.red(`Gagal menjalankan server: ${err.message}`))\n process.exit(1)\n }\n } else {\n try {\n const { app } = await import(entryPath)\n\n if (!app || typeof app.listen !== 'function') {\n console.error(\n colors.red(\n 'Entry point harus export { app } dengan method .listen()',\n ),\n )\n process.exit(1)\n }\n\n app.listen(port, host, () => {\n console.log()\n console.log(` ${colors.bold('SpeexJS')} ${colors.green('running')}`)\n console.log(` ${colors.dim('โ')} ${colors.cyan(`http://${host}:${port}`)}`)\n console.log()\n })\n } catch (err: any) {\n console.error(colors.red(`Gagal menjalankan server: ${err.message}`))\n process.exit(1)\n }\n }\n}\n","import { colors, isColorSupported } from './colors.js'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\nexport interface LoggerOptions {\n level?: LogLevel\n name?: string\n colors?: boolean\n timestamps?: boolean\n timezone?: 'WIB' | 'WITA' | 'WIT' | 'UTC'\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n}\n\nconst TIMEZONE_OFFSETS: Record<string, number> = {\n WIB: 7,\n WITA: 8,\n WIT: 9,\n UTC: 0,\n}\n\nfunction pad(n: number): string {\n return n.toString().padStart(2, '0')\n}\n\nexport function formatTimestamp(tz?: string): string {\n const offset = TIMEZONE_OFFSETS[tz ?? ''] ?? 7\n const now = new Date()\n const utc = now.getTime() + now.getTimezoneOffset() * 60000\n const local = new Date(utc + offset * 3600000)\n\n const y = local.getFullYear()\n const M = pad(local.getMonth() + 1)\n const d = pad(local.getDate())\n const h = pad(local.getHours())\n const m = pad(local.getMinutes())\n const s = pad(local.getSeconds())\n\n return `${y}-${M}-${d} ${h}:${m}:${s} ${tz ?? 'WIB'}`\n}\n\nconst LEVEL_PREFIX: Record<LogLevel, string> = {\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n}\n\nconst LEVEL_COLOR: Record<LogLevel, (s: string) => string> = {\n debug: colors.gray,\n info: colors.cyan,\n warn: colors.yellow,\n error: colors.red,\n}\n\nexport class Logger {\n private _level: LogLevel\n private _name: string\n private _useColors: boolean\n private _useTimestamps: boolean\n private _timezone: string\n\n constructor(options?: LoggerOptions) {\n this._level = options?.level ?? 'info'\n this._name = options?.name ?? ''\n this._useColors = options?.colors ?? isColorSupported()\n this._useTimestamps = options?.timestamps ?? true\n this._timezone = options?.timezone ?? 'WIB'\n }\n\n private _format(level: LogLevel, msg: string, meta?: Record<string, unknown>): string {\n const parts: string[] = []\n\n if (this._useTimestamps) {\n parts.push(formatTimestamp(this._timezone))\n }\n\n if (this._useColors) {\n parts.push(LEVEL_COLOR[level](LEVEL_PREFIX[level]))\n } else {\n parts.push(LEVEL_PREFIX[level])\n }\n\n if (this._name) {\n parts.push(this._useColors ? colors.dim(`[${this._name}]`) : `[${this._name}]`)\n }\n\n if (this._useColors) {\n parts.push(LEVEL_COLOR[level](msg))\n } else {\n parts.push(msg)\n }\n\n if (meta && Object.keys(meta).length > 0) {\n parts.push(JSON.stringify(meta))\n }\n\n return parts.join(' ')\n }\n\n debug(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.debug) return\n console.debug(this._format('debug', msg, meta))\n }\n\n info(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.info) return\n console.info(this._format('info', msg, meta))\n }\n\n warn(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.warn) return\n console.warn(this._format('warn', msg, meta))\n }\n\n error(msg: string, meta?: Record<string, unknown>): void {\n if (LOG_LEVELS[this._level] > LOG_LEVELS.error) return\n console.error(this._format('error', msg, meta))\n }\n\n child(name: string): Logger {\n const childName = this._name ? `${this._name}:${name}` : name\n return new Logger({\n level: this._level,\n name: childName,\n colors: this._useColors,\n timestamps: this._useTimestamps,\n timezone: this._timezone as LoggerOptions['timezone'],\n })\n }\n\n setLevel(level: LogLevel): void {\n this._level = level\n }\n}\n\nexport const logger = new Logger()\n","#!/usr/bin/env node\nimport { parseArgs } from '../native/args.js'\nimport { colors } from '../native/colors.js'\nimport { initProject } from './commands/init.js'\nimport { makeController } from './commands/make-controller.js'\nimport { makeMiddleware } from './commands/make-middleware.js'\nimport { makeSchema } from './commands/make-schema.js'\nimport { listRoutes } from './commands/list-routes.js'\nimport { serve } from './commands/serve.js'\n\nfunction showHelp(): void {\n console.log(`${colors.bold('SpeexJS')} ${colors.cyan('v0.2.0')}`)\n console.log('Fullstack JavaScript/TypeScript Framework')\n console.log()\n console.log(`${colors.bold('Usage:')}`)\n console.log(' SpeexJS init [name] [options] Buat project baru')\n console.log(' SpeexJS make:controller <name> Generate controller')\n console.log(' SpeexJS make:middleware <name> Generate middleware')\n console.log(' SpeexJS make:schema <name> Generate schema')\n console.log(' SpeexJS list-routes Lihat semua route')\n console.log(' SpeexJS serve [options] Jalankan server')\n console.log(' SpeexJS --help Bantuan ini')\n console.log()\n console.log(`${colors.bold('Aliases:')}`)\n console.log(' SpeexJS -v, --version Lihat versi')\n console.log()\n console.log(`${colors.bold('Options:')}`)\n console.log(' --template <type> blank, fullstack, api-only')\n console.log(' --frontend <fe> super, react, vue')\n console.log(' --port <number> Port server (default: 3000)')\n console.log(' --host <string> Host address (default: localhost)')\n}\n\nasync function main(): Promise<void> {\n const parsed = parseArgs(process.argv)\n const command = parsed.command\n\n switch (command) {\n case 'init': {\n await initProject(parsed.args[0] || 'my-app', parsed.options)\n break\n }\n case 'make:controller': {\n if (!parsed.args[0]) {\n console.error(colors.red('Nama controller diperlukan'))\n console.log(` ${colors.cyan('SpeexJS make:controller <name>')}`)\n process.exit(1)\n }\n await makeController(parsed.args[0])\n break\n }\n case 'make:middleware': {\n if (!parsed.args[0]) {\n console.error(colors.red('Nama middleware diperlukan'))\n console.log(` ${colors.cyan('SpeexJS make:middleware <name>')}`)\n process.exit(1)\n }\n await makeMiddleware(parsed.args[0])\n break\n }\n case 'make:schema': {\n if (!parsed.args[0]) {\n console.error(colors.red('Nama schema diperlukan'))\n console.log(` ${colors.cyan('SpeexJS make:schema <name>')}`)\n process.exit(1)\n }\n await makeSchema(parsed.args[0])\n break\n }\n case 'list-routes':\n case 'routes':\n case 'lr': {\n await listRoutes()\n break\n }\n case 'serve':\n case 'dev': {\n await serve(parsed.options)\n break\n }\n case 'help':\n case '--help':\n case '-h': {\n showHelp()\n break\n }\n case 'version':\n case '--version':\n case '-v': {\n console.log('SpeexJS v0.2.0')\n break\n }\n default: {\n if (command) {\n console.error(`${colors.red(`Command '${command}' tidak dikenal`)}`)\n console.log()\n }\n showHelp()\n if (command) process.exit(1)\n }\n }\n}\n\nmain().catch(err => {\n console.error(colors.red(`Error: ${err.message}`))\n process.exit(1)\n})\n"],"mappings":"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","names":["existsSync","mkdirSync","writeFileSync","resolve","toPascalCase","resolve","existsSync","mkdirSync","writeFileSync","existsSync","mkdirSync","writeFileSync","resolve","toPascalCase","toKebabCase","toCamelCase","resolve","existsSync","mkdirSync","writeFileSync","existsSync","mkdirSync","writeFileSync","resolve","toPascalCase","toKebabCase","resolve","existsSync","mkdirSync","writeFileSync","existsSync","resolve","resolve","existsSync","existsSync","resolve","resolve","existsSync"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "speexjs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Fullstack JavaScript/TypeScript framework รยขรขโยฌรขโฌย Server, Client, RPC, Schema, CLI, Database, Auth, Cache, Storage. Zero dependencies. รยฐร
ยธรขโฌยกรยฎรยฐร
ยธรขโฌยกรยฉ Indonesia First.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|