@darkstar-cli/cli 0.0.28 โ 0.0.30
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 +35 -338
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
> DarkStar is in **early alpha**. APIs will change without notice. The package is not stable โ use at your own risk.
|
|
4
4
|
|
|
5
5
|
> [!WARNING]
|
|
6
|
-
> ## ๐งช CUSTOM ORM โ
|
|
7
|
-
> DarkStar uses a **custom ORM** inspired by Eloquent, built from scratch for Node.js. It is **not Prisma, TypeORM or Sequelize**. Relationships (`hasOne`, `hasMany`, `belongsTo`)
|
|
6
|
+
> ## ๐งช CUSTOM ORM โ BUILT FROM SCRATCH
|
|
7
|
+
> DarkStar uses a **custom ORM** inspired by Eloquent, built from scratch for Node.js. It is **not Prisma, TypeORM or Sequelize**. Relationships (`hasOne`, `hasMany`, `belongsTo`, `belongsToMany`) and eager loading (`with()`) **are implemented**. Transactions are **not yet available**.
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
10
|
> ๐ฆ DarkStar is published on npm as **`@darkstar-cli/cli`**. Install with `npm install -g @darkstar-cli/cli`.
|
|
11
11
|
|
|
12
|
-
# ๐ช DarkStar โ
|
|
12
|
+
# ๐ช DarkStar โ CLI
|
|
13
13
|
|
|
14
14
|
> *"Forged in the void. Built to last."*
|
|
15
15
|
|
|
@@ -17,71 +17,23 @@
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## What is this package?
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
`@darkstar-cli/cli` is the **command-line tool** for the DarkStar framework. It:
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
- Creates projects (`darkstar new`)
|
|
25
|
+
- Generates code (`darkstar forge make:*`)
|
|
26
|
+
- Manages the database (`darkstar forge db:*`)
|
|
27
|
+
- Runs the dev server (`darkstar serve`)
|
|
25
28
|
|
|
26
|
-
**
|
|
29
|
+
The **ORM** and **core** are separate packages:
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
## Philosophy
|
|
31
|
-
|
|
32
|
-
- **Convention over configuration** โ ready-made structure, no unnecessary decisions
|
|
33
|
-
- **MVC as a first-class citizen** โ Controller โ Service โ Repository is the standard, not an opinion
|
|
34
|
-
- **CLI that does the heavy lifting** โ one command generates the entire layer
|
|
35
|
-
- **Centralized dependencies** โ you update DarkStar, not 40 separate packages
|
|
36
|
-
- **Expressive custom ORM** โ fluent Eloquent-style query builder, built from scratch for Node.js, no decorators
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Installation
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
npm install -g @darkstar-cli/cli
|
|
44
|
-
```
|
|
31
|
+
- `@darkstar-cli/orm` โ [documentation](https://github.com/SidneiAJr/Darkstar)
|
|
32
|
+
- `@darkstar-cli/core` โ Express-based HTTP layer
|
|
45
33
|
|
|
46
34
|
---
|
|
47
35
|
|
|
48
|
-
##
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
darkstar new my-project
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
The CLI will ask:
|
|
55
|
-
- Which database? (MySQL ยท PostgreSQL)
|
|
56
|
-
|
|
57
|
-
Generated structure:
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
my-project/
|
|
61
|
-
โโโ src/
|
|
62
|
-
โ โโโ controllers/
|
|
63
|
-
โ โโโ services/
|
|
64
|
-
โ โโโ repositories/
|
|
65
|
-
โ โโโ models/
|
|
66
|
-
โ โโโ routes/
|
|
67
|
-
โ โโโ schemas/
|
|
68
|
-
โ โโโ middlewares/
|
|
69
|
-
โ โโโ utils/
|
|
70
|
-
โ โโโ core/
|
|
71
|
-
โ โโโ app.ts
|
|
72
|
-
โโโ database/
|
|
73
|
-
โ โโโ migrations/
|
|
74
|
-
โ โโโ seeders/
|
|
75
|
-
โ โโโ Seeder.ts
|
|
76
|
-
โ โโโ DatabaseSeeder.ts
|
|
77
|
-
โโโ .env
|
|
78
|
-
โโโ darkstar.config.ts
|
|
79
|
-
โโโ package.json
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## CLI โ DarkStar Forge
|
|
36
|
+
## Commands
|
|
85
37
|
|
|
86
38
|
| Command | Description |
|
|
87
39
|
|---|---|
|
|
@@ -93,292 +45,37 @@ my-project/
|
|
|
93
45
|
| `darkstar forge make:repository <Name>` | Generates a Repository |
|
|
94
46
|
| `darkstar forge make:model <Name>` | Generates a Model |
|
|
95
47
|
| `darkstar forge make:migration <Name>` | Generates a Migration |
|
|
96
|
-
| `darkstar forge make:seeder <Name>` | Generates a Seeder (
|
|
48
|
+
| `darkstar forge make:seeder <Name>` | Generates a Seeder (reads fields from the migration) |
|
|
97
49
|
| `darkstar forge make:schema <Name>` | Generates a Schema |
|
|
98
50
|
| `darkstar forge make:middleware <Name>` | Generates a Middleware |
|
|
99
|
-
| `darkstar forge make:util <Name>` | Generates omitPassword and twoFactor utils |
|
|
100
|
-
| `darkstar forge make:security` | Generates RateLimitMiddleware with ready-made limiters |
|
|
51
|
+
| `darkstar forge make:util <Name>` | Generates `omitPassword` and `twoFactor` utils |
|
|
52
|
+
| `darkstar forge make:security` | Generates `RateLimitMiddleware` with 22 ready-made limiters |
|
|
53
|
+
| `darkstar forge make:deps [names...]` | Installs optional dependencies (bcrypt, jwt, zod, etc) |
|
|
101
54
|
| `darkstar forge db:create` | Creates the database |
|
|
102
55
|
| `darkstar forge db:migrate` | Runs pending migrations |
|
|
103
56
|
| `darkstar forge db:rollback` | Rolls back the last migration |
|
|
104
57
|
| `darkstar forge db:seed` | Seeds the database |
|
|
105
58
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
## Recommended workflow from scratch
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
# 1. Create the database
|
|
112
|
-
darkstar forge db:create
|
|
113
|
-
|
|
114
|
-
# 2. Generate the migration
|
|
115
|
-
darkstar forge make:migration CreateUsersTable
|
|
116
|
-
|
|
117
|
-
# 3. Edit the generated file in database/migrations/ with the desired fields
|
|
118
|
-
|
|
119
|
-
# 4. Run the migration
|
|
120
|
-
darkstar forge db:migrate
|
|
121
|
-
|
|
122
|
-
# 5. Generate the full API
|
|
123
|
-
darkstar forge make:api User
|
|
124
|
-
|
|
125
|
-
# 6. Generate the seeder (automatically reads fields from the migration)
|
|
126
|
-
darkstar forge make:seeder User
|
|
127
|
-
|
|
128
|
-
# 7. Seed the database
|
|
129
|
-
darkstar forge db:seed
|
|
130
|
-
|
|
131
|
-
# 8. Generate utils
|
|
132
|
-
darkstar forge make:util User
|
|
133
|
-
|
|
134
|
-
# 9. Generate security rate limiters
|
|
135
|
-
darkstar forge make:security
|
|
136
|
-
|
|
137
|
-
# 10. Start the server
|
|
138
|
-
darkstar serve
|
|
139
|
-
```
|
|
59
|
+
Full usage docs: see the [main repository](https://github.com/SidneiAJr/Darkstar).
|
|
140
60
|
|
|
141
61
|
---
|
|
142
62
|
|
|
143
|
-
##
|
|
144
|
-
|
|
145
|
-
A single `darkstar forge make:api User` command generates the entire MVC chain:
|
|
146
|
-
|
|
147
|
-
**`UserController.ts`**
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
import { DarkstarRequest, DarkstarResponse } from '@darkstar-cli/core'
|
|
151
|
-
import { UserService } from '../services/UserService'
|
|
152
|
-
|
|
153
|
-
export class UserController {
|
|
154
|
-
constructor(private userService: UserService) {}
|
|
155
|
-
|
|
156
|
-
async index(req: DarkstarRequest, res: DarkstarResponse) {
|
|
157
|
-
const data = await this.userService.findAll()
|
|
158
|
-
return res.ok(data)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async show(req: DarkstarRequest, res: DarkstarResponse) {
|
|
162
|
-
const data = await this.userService.findById(req.param('id')!)
|
|
163
|
-
if (!data) return res.notFound('User not found')
|
|
164
|
-
return res.ok(data)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async store(req: DarkstarRequest, res: DarkstarResponse) {
|
|
168
|
-
const data = await this.userService.create(req.all())
|
|
169
|
-
return res.created(data)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async update(req: DarkstarRequest, res: DarkstarResponse) {
|
|
173
|
-
const data = await this.userService.update(req.param('id')!, req.all())
|
|
174
|
-
return res.ok(data)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async destroy(req: DarkstarRequest, res: DarkstarResponse) {
|
|
178
|
-
await this.userService.delete(req.param('id')!)
|
|
179
|
-
return res.noContent()
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**`UserService.ts`**
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
import { UserRepository } from '../repositories/UserRepository'
|
|
188
|
-
|
|
189
|
-
export class UserService {
|
|
190
|
-
constructor(private userRepository: UserRepository) {}
|
|
191
|
-
|
|
192
|
-
findAll() { return this.userRepository.findAll() }
|
|
193
|
-
findById(id: string) { return this.userRepository.findById(id) }
|
|
194
|
-
create(data: Record<string, any>) { return this.userRepository.create(data) }
|
|
195
|
-
update(id: string, data: Record<string, any>) { return this.userRepository.update(id, data) }
|
|
196
|
-
delete(id: string) { return this.userRepository.delete(id) }
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
**`UserRepository.ts`**
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
import { User } from '../models/User'
|
|
204
|
-
|
|
205
|
-
export class UserRepository {
|
|
206
|
-
findAll() { return User.all() }
|
|
207
|
-
findById(id: string) { return User.find(id) }
|
|
208
|
-
create(data: Record<string, any>) { return User.create(data) }
|
|
209
|
-
update(id: string, data: Record<string, any>) { return User.where('id', id).update(data) }
|
|
210
|
-
delete(id: string) { return User.where('id', id).delete() }
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**`User.ts`**
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
import { Model } from '@darkstar-cli/orm'
|
|
218
|
-
|
|
219
|
-
export class User extends Model {
|
|
220
|
-
static table = 'users'
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**`UserSchema.ts`**
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
export const UserSchema = {}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
**`UserMiddleware.ts`**
|
|
231
|
-
|
|
232
|
-
```typescript
|
|
233
|
-
import { DarkstarRequest, DarkstarResponse, NextFunction } from '@darkstar-cli/core'
|
|
234
|
-
|
|
235
|
-
export class UserMiddleware {
|
|
236
|
-
handle(req: DarkstarRequest, res: DarkstarResponse, next: NextFunction) {
|
|
237
|
-
next()
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
---
|
|
243
|
-
|
|
244
|
-
## Utils โ `make:util`
|
|
245
|
-
|
|
246
|
-
The `darkstar forge make:util User` command generates ready-made utilities in `src/utils/user/`:
|
|
247
|
-
|
|
248
|
-
**`omitPassword.ts`**
|
|
249
|
-
|
|
250
|
-
Strips the `password` field from any object before returning it to the client โ useful in service and controller responses.
|
|
251
|
-
|
|
252
|
-
```typescript
|
|
253
|
-
export function omitUserPassword<T extends Record<string, any>>(obj: T): Omit<T, 'password'> {
|
|
254
|
-
const { password, ...rest } = obj
|
|
255
|
-
return rest
|
|
256
|
-
}
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
**`twoFactor.ts`**
|
|
260
|
-
|
|
261
|
-
Generates and validates a 6-digit numeric code. See Known Limitations for production caveats.
|
|
262
|
-
|
|
263
|
-
```typescript
|
|
264
|
-
import * as crypto from 'crypto'
|
|
265
|
-
|
|
266
|
-
export function generateUserTwoFactorCode(): string {
|
|
267
|
-
const code = crypto.randomInt(100000, 999999)
|
|
268
|
-
return code.toString()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export function validateUserTwoFactorCode(inputCode: string, expectedCode: string): boolean {
|
|
272
|
-
return inputCode.trim() === expectedCode.trim()
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
---
|
|
277
|
-
|
|
278
|
-
## Security โ `make:security`
|
|
279
|
-
|
|
280
|
-
The `darkstar forge make:security` command generates `src/middlewares/RateLimitMiddleware.ts` with 22 ready-made limiters covering:
|
|
281
|
-
|
|
282
|
-
- **Auth** โ login, register, forgot/reset password, refresh token, verify email, two-factor
|
|
283
|
-
- **CRUD** โ read, write, delete
|
|
284
|
-
- **Files** โ upload, download
|
|
285
|
-
- **Real-time** โ SSE, WebSocket
|
|
286
|
-
- **Communication** โ email, SMS, webhook
|
|
287
|
-
- **Search & reports** โ search, stats, report
|
|
288
|
-
- **Admin** โ general and destructive actions
|
|
289
|
-
- **Payments** โ checkout, refund
|
|
290
|
-
|
|
291
|
-
Usage in routes:
|
|
292
|
-
|
|
293
|
-
```typescript
|
|
294
|
-
import { loginLimiter, registerLimiter, globalLimiter } from '../middlewares/RateLimitMiddleware'
|
|
295
|
-
|
|
296
|
-
router.post('/auth/login', loginLimiter, ...)
|
|
297
|
-
router.post('/auth/register', registerLimiter, ...)
|
|
298
|
-
router.use('/api', globalLimiter)
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
## Routes
|
|
304
|
-
|
|
305
|
-
All routes are prefixed with `/api` by default. Example with `make:api User`:
|
|
306
|
-
|
|
307
|
-
```
|
|
308
|
-
GET /api/users
|
|
309
|
-
GET /api/users/:id
|
|
310
|
-
POST /api/users
|
|
311
|
-
PUT /api/users/:id
|
|
312
|
-
DELETE /api/users/:id
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
The prefix can be changed when booting the application:
|
|
316
|
-
|
|
317
|
-
```typescript
|
|
318
|
-
await app.boot('/') // no prefix
|
|
319
|
-
await app.boot('/v1') // versioned
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
324
|
-
## Custom ORM โ Eloquent-style Query Builder
|
|
325
|
-
|
|
326
|
-
> [!WARNING]
|
|
327
|
-
> DarkStar's ORM is an independent package (`@darkstar-cli/orm`), built from scratch. Do not confuse it with Prisma, TypeORM or Sequelize. Check the Known Limitations section before using in production.
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
// fetch all
|
|
331
|
-
const users = await User.all()
|
|
332
|
-
|
|
333
|
-
// fetch by id
|
|
334
|
-
const user = await User.find(1)
|
|
335
|
-
|
|
336
|
-
// chained filters
|
|
337
|
-
const admins = await User
|
|
338
|
-
.where('role', 'admin')
|
|
339
|
-
.where('active', true)
|
|
340
|
-
.orderBy('name')
|
|
341
|
-
.get()
|
|
342
|
-
|
|
343
|
-
// create
|
|
344
|
-
const user = await User.create({ name: 'Test', email: 'test@email.com' })
|
|
345
|
-
|
|
346
|
-
// update
|
|
347
|
-
await User.where('id', 1).update({ name: 'Test' })
|
|
348
|
-
|
|
349
|
-
// delete
|
|
350
|
-
await User.where('id', 1).delete()
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
---
|
|
354
|
-
|
|
355
|
-
## Known Limitations
|
|
63
|
+
## โ ๏ธ Known limitations
|
|
356
64
|
|
|
357
65
|
DarkStar is in **early alpha**. The limitations below are known and will be addressed in future releases.
|
|
358
66
|
|
|
359
|
-
###
|
|
67
|
+
### CLI
|
|
360
68
|
|
|
361
|
-
-
|
|
362
|
-
-
|
|
363
|
-
- **
|
|
364
|
-
- **`
|
|
365
|
-
- **No transaction API** โ there is no `DB.transaction(callback)` helper. Transactions must be managed manually through the raw driver.
|
|
366
|
-
- **SQLite has no advisory locks** โ `db:migrate` uses `GET_LOCK` (MySQL) and `pg_advisory_lock` (PostgreSQL) to prevent concurrent migrations. SQLite has no equivalent, so running migrations in parallel on SQLite is unsafe.
|
|
367
|
-
- **`hasTable()` uses `SHOW TABLES`, which is MySQL only** โ will fail on PostgreSQL and SQLite.
|
|
69
|
+
- **`darkstar new` uses `latest` for `@darkstar-cli/*`** โ the generated `package.json` references `@darkstar-cli/core` and `@darkstar-cli/orm` as `latest`. New projects always pull the newest version, which may include breaking changes while DarkStar is in alpha.
|
|
70
|
+
- **`darkstar serve` runs `npm run dev`** โ assumes the project has a `dev` script in `package.json`. If you rename it, `darkstar serve` will fail.
|
|
71
|
+
- **Automatic seeder registration depends on the comment `// registre seus seeders aqui`** โ if this comment is removed or modified in `DatabaseSeeder.ts`, `make:seeder` will not register the new seeder automatically.
|
|
72
|
+
- **`db:seed` runs `tsx` from the project's `node_modules/.bin/`** โ if `tsx` is not installed locally (via `npm install -D tsx`), the seeder will fail. `darkstar new` already installs it.
|
|
368
73
|
|
|
369
74
|
### IoC Container
|
|
370
75
|
|
|
371
76
|
- **Dependency resolution is based on constructor parameter names** โ the container parses the constructor source code as a string to infer dependencies. This breaks when code is minified, bundled or compiled in a way that renames parameters. Do not use with bundlers that mangle variable names (e.g. esbuild with `minifyIdentifiers: true`).
|
|
372
77
|
- **No circular dependency detection** โ circular dependencies will cause a stack overflow with no useful error message.
|
|
373
78
|
|
|
374
|
-
### CLI
|
|
375
|
-
|
|
376
|
-
- **`darkstar new` uses local `file:` paths** โ the generated `package.json` references `@darkstar-cli/core` and `@darkstar-cli/orm` as `file:` paths pointing to the monorepo. This will be updated to npm versions on release.
|
|
377
|
-
- **`make:model` generates a stub with `createModel` that does not exist in `@darkstar-cli/orm`** โ the standalone `make:model` command generates `import { createModel, Model }`, which is not exported by the ORM. Use `make:api` instead or copy the model stub from it.
|
|
378
|
-
- **`make:middleware` generates imports with `TanisRequest`/`TanisResponse`** โ the standalone `make:middleware` command still uses the old `Tanis*` aliases. They work at runtime but are inconsistent with the `Darkstar*` naming used everywhere else.
|
|
379
|
-
- **`darkstar serve` runs `npm run dev`** โ assumes the project has a `dev` script in `package.json`. If you rename it, `darkstar serve` will fail.
|
|
380
|
-
- **Automatic seeder registration depends on the comment `// register your seeders here`** โ if this comment is removed or modified in `DatabaseSeeder.ts`, `make:seeder` will not register the new seeder automatically.
|
|
381
|
-
|
|
382
79
|
### Validation
|
|
383
80
|
|
|
384
81
|
- **`UserSchema` is an empty object** โ schemas generated by `make:schema` and `make:api` are stubs with no validation logic. Integrate [Zod](https://zod.dev) or [Joi](https://joi.dev) manually for now.
|
|
@@ -389,16 +86,6 @@ DarkStar is in **early alpha**. The limitations below are known and will be addr
|
|
|
389
86
|
|
|
390
87
|
---
|
|
391
88
|
|
|
392
|
-
## Inspirations
|
|
393
|
-
|
|
394
|
-
- **Laravel** โ for the elegance and productivity
|
|
395
|
-
- **Pandorum** โ for the idea of forging something new in the void of space
|
|
396
|
-
- **Constellation CLI** โ same spirit of automating what is repetitive
|
|
397
|
-
|
|
398
|
-
---
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
89
|
## ๐ Security checklist
|
|
403
90
|
|
|
404
91
|
The stubs generated by `make:api` are **skeletons only**. Before going to production, you **must**:
|
|
@@ -419,11 +106,21 @@ DarkStar **does not do this automatically** because every project has different
|
|
|
419
106
|
|
|
420
107
|
The `make:api` command generates a working MVC skeleton, but it is **intentionally minimal**. Watch out for these common issues:
|
|
421
108
|
|
|
422
|
-
- **`password` is returned in API responses** โ the generated controller
|
|
109
|
+
- **`password` is returned in API responses** โ the generated controller strips it via `static hidden` (Laravel-style), but **related** models are not stripped automatically. Handle it in the controller for nested relations.
|
|
423
110
|
- **`POST` stores the password as plain text** โ the generated `store()` method does no hashing. Add `bcrypt.hash()` in the controller or service layer.
|
|
424
111
|
- **`update()` returns the number of affected rows, not the updated record** โ re-fetch the record if you need the new values.
|
|
425
112
|
- **`UserSchema` is an empty object** โ no validation is applied. Integrate Zod or Joi manually.
|
|
426
113
|
|
|
427
114
|
These are **not framework bugs** โ they are conscious design decisions. DarkStar ships with the structure, not the policy.
|
|
428
115
|
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Inspirations
|
|
119
|
+
|
|
120
|
+
- **Laravel** โ for the elegance and productivity
|
|
121
|
+
- **Pandorum** โ for the idea of forging something new in the void of space
|
|
122
|
+
- **Constellation CLI** โ same spirit of automating what is repetitive
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
429
126
|
> ๐ช DarkStar โ Open Source
|