@nexa-stack/framework 1.0.0

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.
Files changed (81) hide show
  1. package/.env.example +46 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/bin/nexa.mjs +41 -0
  5. package/bin/nexa.ts +334 -0
  6. package/docs/AI.md +69 -0
  7. package/docs/ARCHITECTURE.md +74 -0
  8. package/docs/EXAMPLES.md +114 -0
  9. package/docs/FRAMEWORK.md +226 -0
  10. package/docs/LANGUAGE.md +39 -0
  11. package/docs/README.md +7 -0
  12. package/docs/READY.md +51 -0
  13. package/docs/REFERENCE.md +255 -0
  14. package/docs/START.md +98 -0
  15. package/docs/advanced.md +97 -0
  16. package/docs/authentication.md +54 -0
  17. package/docs/cli.md +15 -0
  18. package/docs/compare.md +51 -0
  19. package/docs/configuration.md +65 -0
  20. package/docs/database.md +396 -0
  21. package/docs/installation.md +57 -0
  22. package/docs/localization.md +47 -0
  23. package/docs/resources.md +75 -0
  24. package/docs/routing.md +59 -0
  25. package/docs/seeding.md +33 -0
  26. package/docs/services.md +146 -0
  27. package/package.json +77 -0
  28. package/packages/auth/src/auth.test.ts +23 -0
  29. package/packages/auth/src/auth.ts +287 -0
  30. package/packages/auth/src/index.ts +17 -0
  31. package/packages/cache/src/index.ts +203 -0
  32. package/packages/client/src/index.ts +49 -0
  33. package/packages/core/src/app.ts +97 -0
  34. package/packages/core/src/config.ts +55 -0
  35. package/packages/core/src/dev.ts +104 -0
  36. package/packages/core/src/fields.test.ts +81 -0
  37. package/packages/core/src/fields.ts +309 -0
  38. package/packages/core/src/index.ts +60 -0
  39. package/packages/core/src/lang.ts +79 -0
  40. package/packages/core/src/loader.ts +42 -0
  41. package/packages/core/src/migrate.ts +91 -0
  42. package/packages/core/src/policy.ts +36 -0
  43. package/packages/core/src/registry.ts +17 -0
  44. package/packages/core/src/reload.ts +92 -0
  45. package/packages/core/src/resource.test.ts +32 -0
  46. package/packages/core/src/resource.ts +87 -0
  47. package/packages/core/src/routes.ts +22 -0
  48. package/packages/core/src/runtime.ts +11 -0
  49. package/packages/database/src/builder.ts +266 -0
  50. package/packages/database/src/database.ts +252 -0
  51. package/packages/database/src/dialect.ts +186 -0
  52. package/packages/database/src/index.ts +6 -0
  53. package/packages/database/src/mysql.ts +114 -0
  54. package/packages/database/src/postgres.ts +117 -0
  55. package/packages/database/src/query.ts +115 -0
  56. package/packages/database/src/sqlite.ts +216 -0
  57. package/packages/database/src/types.ts +104 -0
  58. package/packages/events/src/index.ts +17 -0
  59. package/packages/export/src/index.ts +36 -0
  60. package/packages/log/src/index.ts +38 -0
  61. package/packages/mail/src/index.ts +130 -0
  62. package/packages/notifications/src/index.ts +84 -0
  63. package/packages/plugins/src/index.ts +39 -0
  64. package/packages/queue/src/index.ts +185 -0
  65. package/packages/queue/src/jobs.ts +9 -0
  66. package/packages/schedule/src/index.ts +64 -0
  67. package/packages/server/src/index.ts +1 -0
  68. package/packages/server/src/middleware.ts +143 -0
  69. package/packages/server/src/query.ts +40 -0
  70. package/packages/server/src/router.ts +813 -0
  71. package/packages/sms/src/index.ts +33 -0
  72. package/packages/storage/src/upload.ts +36 -0
  73. package/packages/testing/src/index.ts +67 -0
  74. package/packages/validation/src/index.ts +1 -0
  75. package/packages/validation/src/validate.test.ts +35 -0
  76. package/packages/validation/src/validate.ts +112 -0
  77. package/public/admin.html +369 -0
  78. package/public/compare.html +66 -0
  79. package/public/dev-bar.js +213 -0
  80. package/public/docs.html +315 -0
  81. package/public/index.html +66 -0
package/docs/START.md ADDED
@@ -0,0 +1,98 @@
1
+ # Nexa — Start here
2
+
3
+ Ship a full backend in hours: API, ORM, auth, queue, and admin.
4
+
5
+ **Runtime:** Node.js ≥ 20
6
+ **Default language:** English (`APP_LOCALE=en`)
7
+
8
+ ## Four words
9
+
10
+ | Word | Meaning |
11
+ |------|---------|
12
+ | `resource` | Table + API + CRUD |
13
+ | Fields (`string`…) | Column types |
14
+ | `.admin()` | Admin UI + auth + soft delete |
15
+ | `nexa serve` | Run |
16
+
17
+ ## Full app (one file)
18
+
19
+ ```ts
20
+ import { resource, string, text, boolean, select, money, belongsTo, belongsToMany } from "@nexa-stack/framework";
21
+
22
+ resource("clients", {
23
+ name: string().required().label("Name"),
24
+ phone: string().label("Phone"),
25
+ }, { label: "Clients" }).admin();
26
+
27
+ resource("orders", {
28
+ client: belongsTo("clients").required().label("Client"),
29
+ total: money().required().label("Total"),
30
+ status: select(["new", "paid", "cancelled"]).label("Status"),
31
+ note: text().label("Note"),
32
+ }, { label: "Orders" }).admin();
33
+ ```
34
+
35
+ ```bash
36
+ nexa serve
37
+ ```
38
+
39
+ → http://localhost:3333/admin
40
+ → `admin@nexa.dev` / `123456`
41
+
42
+ No controllers · no hand-written routes · missing columns are added automatically when you change a resource.
43
+
44
+ ## Commands
45
+
46
+ ```bash
47
+ nexa new my-app
48
+ nexa make:resource products # loads from resources/
49
+ nexa serve
50
+ nexa migrate:rollback # roll back last file migration
51
+ ```
52
+
53
+ ## Field types
54
+
55
+ `string` `text` `number` `boolean` `email` `money` `date` `datetime` `select([...])`
56
+ `belongsTo` `hasMany` `belongsToMany` `file` `image`
57
+
58
+ ## Extra power (optional)
59
+
60
+ ```ts
61
+ import { db } from "@nexa-stack/framework";
62
+
63
+ const rows = await db.from("orders")
64
+ .where("status", "paid")
65
+ .with("client")
66
+ .orderBy("id", "desc")
67
+ .get();
68
+
69
+ await db.transaction(async (tx) => {
70
+ await tx.from("orders").insert({ ... });
71
+ });
72
+ ```
73
+
74
+ Thin frontend bridge: `createClient({ baseUrl, token })`.
75
+
76
+ ## Scale (when you grow)
77
+
78
+ ```bash
79
+ nexa queue:work
80
+ # LIST_CACHE_TTL=15
81
+ # RATE_LIMIT_DRIVER=redis
82
+ ```
83
+
84
+ `/health` and `/ready` for load balancers.
85
+
86
+ ## Arabic UI (optional)
87
+
88
+ ```env
89
+ APP_LOCALE=en
90
+ ```
91
+
92
+ Keep `lang/ar.json` + `lang/en.json`. Admin can switch languages.
93
+
94
+ ## Security
95
+
96
+ `.admin()` requires admin auth. Soft delete is on by default.
97
+
98
+ **Full reference:** [REFERENCE.md](./REFERENCE.md)
@@ -0,0 +1,97 @@
1
+ # Advanced Features
2
+
3
+ ## Soft deletes
4
+
5
+ ```ts
6
+ resource("clients", {
7
+ name: string().required(),
8
+ }).softDeletes().admin();
9
+ ```
10
+
11
+ - `DELETE /api/clients/1` → soft (sets `deleted_at`)
12
+ - `DELETE /api/clients/1?force=1` → hard delete
13
+ - `POST /api/clients/1/restore` → restore
14
+ - `GET /api/clients?trashed=only` → trash only
15
+ - `GET /api/clients?trashed=with` → include deleted
16
+
17
+ ## Export
18
+
19
+ ```
20
+ GET /api/clients/export?format=csv
21
+ GET /api/clients/export?format=json
22
+ ```
23
+
24
+ ## SMS
25
+
26
+ ```ts
27
+ import { sms } from "./packages/core/src/index.js";
28
+ await sms("0501234567", "Verification code: 1234");
29
+ ```
30
+
31
+ ```env
32
+ SMS_DRIVER=log # default → storage/logs/sms.log
33
+ # SMS_DRIVER=webhook
34
+ # SMS_WEBHOOK=https://...
35
+ ```
36
+
37
+ ## Middleware
38
+
39
+ ```ts
40
+ import { use, rateLimit, cors } from "./packages/core/src/index.js";
41
+
42
+ use(cors());
43
+ use(rateLimit(100, 60_000)); // 100 req / minute
44
+
45
+ use(async (req, user, next) => {
46
+ console.log(req.method, req.url);
47
+ return next();
48
+ });
49
+ ```
50
+
51
+ Default on `start()`: CORS + rate limit (`RATE_LIMIT`, default 120/min).
52
+
53
+ ## Plugins
54
+
55
+ ```ts
56
+ import { plugin } from "./packages/core/src/index.js";
57
+
58
+ plugin({
59
+ name: "audit",
60
+ boot: () => console.log("audit ready"),
61
+ hooks: {
62
+ "resource.created": async ({ resource, data }) => {
63
+ console.log("created", resource, data);
64
+ },
65
+ },
66
+ });
67
+ ```
68
+
69
+ ## Testing helpers
70
+
71
+ ```ts
72
+ import { resource, string, createTestApp } from "./packages/core/src/index.js";
73
+
74
+ resource("items", { name: string().required() });
75
+ const app = await createTestApp();
76
+
77
+ const res = await app.request("POST", "/api/items", {
78
+ body: JSON.stringify({ name: "X" }),
79
+ });
80
+
81
+ const asAdmin = app.actingAs({ id: 1, email: "a@b.com", role: "admin" });
82
+ await asAdmin.request("GET", "/api/items");
83
+
84
+ app.close();
85
+ ```
86
+
87
+ ## vs Laravel
88
+
89
+ | Laravel | Nexa |
90
+ |---------|------|
91
+ | SoftDeletes trait | `.softDeletes()` |
92
+ | Excel/Export | `/export?format=csv` |
93
+ | Notification SMS | `sms()` |
94
+ | Middleware | `use()` |
95
+ | RateLimiter | `rateLimit()` |
96
+ | Service Provider / Package | `plugin()` |
97
+ | Feature tests | `createTestApp()` |
@@ -0,0 +1,54 @@
1
+ # Authentication
2
+
3
+ ## Login / Register
4
+
5
+ ```
6
+ POST /api/auth/register { email, password }
7
+ POST /api/auth/login { email, password } → { user, token }
8
+ ```
9
+
10
+ Use: `Authorization: Bearer {token}`
11
+
12
+ Protect resources: `.auth()` or `.policy({...})`
13
+
14
+ Default admin: `admin@nexa.dev` / `123456`
15
+
16
+ ## Password reset
17
+
18
+ ```
19
+ POST /api/auth/forgot-password { email }
20
+ POST /api/auth/reset-password { email, token, password }
21
+ ```
22
+
23
+ Token is emailed (`MAIL_DRIVER=log` → `storage/logs/mail.log` in dev).
24
+
25
+ ```ts
26
+ import { forgotPassword, resetPassword } from "@nexa-stack/framework";
27
+
28
+ await forgotPassword("ali@corp.com");
29
+ await resetPassword("ali@corp.com", token, "new-password");
30
+ ```
31
+
32
+ ## Email verification
33
+
34
+ On register, a verification email is sent.
35
+
36
+ ```
37
+ GET /api/auth/verify-email?email=...&token=...
38
+ POST /api/auth/verify-email { email, token }
39
+ POST /api/auth/resend-verification { email }
40
+ ```
41
+
42
+ ```ts
43
+ import { verifyEmail, resendVerification } from "@nexa-stack/framework";
44
+ ```
45
+
46
+ `users.email_verified_at` is set when verified.
47
+
48
+ ## .env
49
+
50
+ ```env
51
+ APP_URL=http://localhost:3333
52
+ APP_SECRET=change-me
53
+ MAIL_DRIVER=log
54
+ ```
package/docs/cli.md ADDED
@@ -0,0 +1,15 @@
1
+ # CLI
2
+
3
+ ```bash
4
+ npm run serve # or: npx nexa serve
5
+ npx nexa migrate # run migrations
6
+ npx nexa db:seed # seed database
7
+ npx nexa queue:work # process queued jobs
8
+ npx nexa schedule:work # run scheduled tasks
9
+ npx nexa make:resource clients
10
+ npm test # run tests
11
+ ```
12
+
13
+ ## make:resource
14
+
15
+ Creates `resources/clients.ts` — auto-loaded from `resources/` (no import needed).
@@ -0,0 +1,51 @@
1
+ # Nexa vs Laravel
2
+
3
+ Browser page: **[/compare](/compare)**
4
+
5
+ ## CLI
6
+
7
+ | Task | Laravel | Nexa |
8
+ |------|---------|------|
9
+ | Serve | `php artisan serve` | `nexa serve` |
10
+ | Migrate | `php artisan migrate` | `nexa migrate` |
11
+ | Seed | `php artisan db:seed` | `nexa db:seed` |
12
+ | Queue | `php artisan queue:work` | `nexa queue:work` |
13
+ | Schedule | `php artisan schedule:work` | `nexa schedule:work` |
14
+ | Make | `php artisan make:model X -mcr` | `nexa make:resource x` |
15
+ | Test | `php artisan test` | `nexa test` |
16
+
17
+ ## Defining a resource
18
+
19
+ **Laravel:** Migration + Model + Controller + Route
20
+ **Nexa:**
21
+
22
+ ```ts
23
+ resource("posts", {
24
+ title: string().required(),
25
+ body: text(),
26
+ }).admin().auth().softDeletes();
27
+ ```
28
+
29
+ ## Concepts
30
+
31
+ | Laravel | Nexa |
32
+ |---------|------|
33
+ | Eloquent Model | `resource()` |
34
+ | Migration files | auto from fields |
35
+ | Controller | auto CRUD |
36
+ | `Route::apiResource` | `/api/{name}` |
37
+ | FormRequest | field builders |
38
+ | SoftDeletes | `.softDeletes()` |
39
+ | Policy | `.policy()` |
40
+ | Filament/Nova | `.admin()` |
41
+
42
+ ## Services
43
+
44
+ | Laravel | Nexa |
45
+ |---------|------|
46
+ | `Mail::` | `mail()` |
47
+ | `Cache::` | `cache` |
48
+ | `Log::` | `log` |
49
+ | `dispatch()` | `dispatch()` |
50
+
51
+ Open [/compare](/compare) for side-by-side tables and code.
@@ -0,0 +1,65 @@
1
+ # Configuration
2
+
3
+ All config via `.env` (loaded automatically on start).
4
+
5
+ ## Core
6
+
7
+ | Key | Default | Description |
8
+ |-----|---------|-------------|
9
+ | `PORT` | `3333` | HTTP port |
10
+ | `APP_SECRET` | `change-me` | JWT signing secret |
11
+ | `APP_URL` | `http://localhost:3333` | Used in reset/verify email links |
12
+ | `APP_LOCALE` | `en` | Default UI language (`en` or `ar`) |
13
+
14
+ ## Database
15
+
16
+ | Key | Example | Description |
17
+ |-----|---------|-------------|
18
+ | `DB_PATH` | `./app.db` | SQLite file (default) |
19
+ | `DATABASE_URL` | `postgresql://user:pass@localhost:5432/nexa` | PostgreSQL |
20
+ | `DATABASE_URL` | `mysql://user:pass@localhost:3306/nexa` | MySQL / MariaDB |
21
+
22
+ If `DATABASE_URL` is set, it wins over `DB_PATH`.
23
+
24
+ ## Mail
25
+
26
+ | Key | Default | Description |
27
+ |-----|---------|-------------|
28
+ | `MAIL_DRIVER` | `log` | `log` or `smtp` |
29
+ | `MAIL_FROM` | `nexa@localhost` | From address |
30
+ | `MAIL_HOST` | | SMTP host |
31
+ | `MAIL_PORT` | `587` | SMTP port |
32
+ | `MAIL_USER` | | SMTP user |
33
+ | `MAIL_PASS` | | SMTP password |
34
+ | `MAIL_SECURE` | `false` | TLS |
35
+
36
+ `log` writes to `storage/logs/mail.log` (good for local/dev).
37
+
38
+ ## Cache / SMS / Limits
39
+
40
+ | Key | Default | Description |
41
+ |-----|---------|-------------|
42
+ | `CACHE_DRIVER` | `memory` | `memory` · `file` · `redis` |
43
+ | `REDIS_URL` | `redis://127.0.0.1:6379` | When cache is redis |
44
+ | `SMS_DRIVER` | `log` | `log` or `webhook` |
45
+ | `SMS_WEBHOOK` | | POST target for SMS |
46
+ | `RATE_LIMIT` | `120` | Requests per minute per IP (0 = off) |
47
+ | `LOG_LEVEL` | `debug` | `debug` · `info` · `warn` · `error` |
48
+
49
+ ## Example production `.env`
50
+
51
+ ```env
52
+ APP_SECRET=long-random-string
53
+ APP_URL=https://api.yourapp.com
54
+ DATABASE_URL=postgresql://nexa:secret@db:5432/nexa
55
+ MAIL_DRIVER=smtp
56
+ MAIL_HOST=smtp.mailgun.org
57
+ MAIL_PORT=587
58
+ MAIL_USER=...
59
+ MAIL_PASS=...
60
+ MAIL_FROM=noreply@yourapp.com
61
+ CACHE_DRIVER=redis
62
+ REDIS_URL=redis://redis:6379
63
+ RATE_LIMIT=120
64
+ LOG_LEVEL=info
65
+ ```