zyket 1.2.20 → 1.2.21

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/AGENTS.md CHANGED
@@ -20,7 +20,7 @@ npx zyket init api-rest # default | api-rest | saas-multitenant | realtim
20
20
  `init` scaffolds the chosen template's files, generates a `.env` (defaults merged with the template's `.env.example`), writes a `package.json` with the right dependencies, and runs `npm install`. Templates that ship auth need their tables created once:
21
21
 
22
22
  ```bash
23
- npx @better-auth/cli migrate
23
+ npx @better-auth/cli migrate --config src/services/auth/auth.js
24
24
  node index.js
25
25
  ```
26
26
 
@@ -49,10 +49,10 @@ kernel.boot(clearConsole = true, secretsPath = "<cwd>/.env")
49
49
  ```
50
50
 
51
51
  Boot order:
52
- 1. Load `.env` (creates one with defaults if missing).
53
- 2. Start the HTTP server on `PORT` (default 3000).
52
+ 1. Load `.env` (creates one with defaults if missing, including a random `AUTH_SECRET`).
53
+ 2. Start the HTTP server on `PORT` (default 3000). Until the Express service attaches, requests are answered `503 {"success":false,"message":"Server is starting"}` with `Retry-After: 1` — so a health check during boot gets an answer instead of hanging. With `DISABLE_EXPRESS=true` every HTTP request keeps getting that 503.
54
54
  3. Register **core services** (auto-selected from env, see §4) then your `services`.
55
- 4. Call `boot({ httpServer })` on every service in order.
55
+ 4. Call `boot({ httpServer })` on every service in order. `express` boots before `socketio` on purpose: engine.io wraps the existing request listener, so reversing them breaks the socket.io polling transport.
56
56
  5. Load each `extensions` instance via `extension.load(container)` (after services).
57
57
 
58
58
  `kernel.container` exposes the DI container (`container.get('name')`, `container.has('name')`).
@@ -291,7 +291,7 @@ module.exports = class CustomAuthService extends AuthService {
291
291
  };
292
292
  ```
293
293
 
294
- Requirements: `DATABASE_DIALECT` must be `sqlite` or `postgresql`. Run `npx @better-auth/cli migrate` to create auth tables (it reads `src/services/auth/auth.js`).
294
+ Requirements: `DATABASE_DIALECT` must be `sqlite` or `postgresql`. Run `npx @better-auth/cli migrate --config src/services/auth/auth.js` to create the auth tables. The `--config` flag is required: the CLI only auto-discovers `auth.js` under `src/{auth,lib,server,utils}/`, never under `src/services/`.
295
295
 
296
296
  ### Protecting routes & sockets
297
297
 
@@ -402,6 +402,6 @@ See `SECURITY.md` for the full audit. Essentials before production:
402
402
  3. **Access data** — `const { Thing } = container.get('database').models;`.
403
403
  4. **Realtime (optional)** — `src/handlers/<event>.js` with `guards = ["auth"]`; broadcast with `io`.
404
404
  5. **Background (optional)** — add the queue to `QUEUES`, `DISABLE_BULLMQ=false`, add `src/workers/<name>.js`, enqueue with `container.get('bullmq').addJob(...)`.
405
- 6. **Run** — `npx @better-auth/cli migrate` (first time) then `node index.js`.
405
+ 6. **Run** — `npx @better-auth/cli migrate --config src/services/auth/auth.js` (first time) then `node index.js`.
406
406
 
407
407
  To scaffold any component quickly, use the `generate` skill (`/zyket:generate route things/[id]`).
package/README.md CHANGED
@@ -19,7 +19,7 @@ npx zyket init api-rest # default | api-rest | saas-multitenant | realtime-
19
19
  `init` scaffolds the template, generates a `.env`, writes `package.json` with the right dependencies, and installs them. Templates that ship authentication need their tables created once:
20
20
 
21
21
  ```bash
22
- npx @better-auth/cli migrate
22
+ npx @better-auth/cli migrate --config src/services/auth/auth.js
23
23
  node index.js
24
24
  ```
25
25
 
package/bin/cli.js CHANGED
@@ -285,7 +285,7 @@ function npmInstall() {
285
285
  // Templates that ship auth need their tables created first.
286
286
  const usesAuth = fs.existsSync(path.join(process.cwd(), 'src', 'services', 'auth'));
287
287
  console.log('\nNext steps:');
288
- if (usesAuth) console.log(' npx @better-auth/cli migrate # create the auth tables');
288
+ if (usesAuth) console.log(' npx @better-auth/cli migrate --config src/services/auth/auth.js # create the auth tables');
289
289
  console.log(' node index.js\n');
290
290
  if (fs.existsSync(path.join(process.cwd(), 'README.md'))) {
291
291
  console.log('See README.md for template-specific details.\n');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zyket",
3
- "version": "1.2.20",
3
+ "version": "1.2.21",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -13,45 +13,45 @@
13
13
  "license": "ISC",
14
14
  "description": "",
15
15
  "dependencies": {
16
- "@bull-board/express": "^6.20.6",
17
- "@tailwindcss/vite": "^4.2.2",
18
- "@vitejs/plugin-react": "^6.0.1",
19
- "better-auth": "^1.5.6",
16
+ "@bull-board/express": "^8.3.0",
17
+ "@tailwindcss/vite": "^4.3.3",
18
+ "@vitejs/plugin-react": "^6.0.4",
19
+ "better-auth": "^1.6.25",
20
20
  "better-sqlite3": "^12.8.0",
21
- "bullmq": "^5.71.0",
21
+ "bullmq": "^5.81.2",
22
22
  "colors": "^1.4.0",
23
23
  "cors": "^2.8.6",
24
- "dotenv": "^17.3.1",
24
+ "dotenv": "^17.4.2",
25
25
  "express": "^5.2.1",
26
26
  "express-basic-auth": "^1.2.1",
27
27
  "fast-glob": "^3.3.3",
28
- "mariadb": "^3.5.2",
28
+ "mariadb": "^3.5.3",
29
29
  "minio": "^8.0.7",
30
- "multer": "^2.1.1",
31
- "node-cron": "^4.2.1",
32
- "node-dependency-injection": "^3.2.6",
33
- "pg": "^8.20.0",
30
+ "multer": "^2.2.0",
31
+ "node-cron": "^4.6.0",
32
+ "node-dependency-injection": "^4.2.2",
33
+ "pg": "^8.22.0",
34
34
  "prompts": "^2.4.2",
35
35
  "prop-types": "^15.8.1",
36
- "react": "^19.2.4",
37
- "react-dom": "^19.2.4",
38
- "react-router-dom": "^7.14.0",
39
- "redis": "^5.11.0",
36
+ "react": "^19.2.8",
37
+ "react-dom": "^19.2.8",
38
+ "react-router-dom": "^7.18.1",
39
+ "redis": "^6.1.0",
40
40
  "sequelize": "^6.37.8",
41
41
  "socket.io": "^4.8.3",
42
42
  "socket.io-client": "^4.8.3",
43
43
  "sqlite3": "^6.0.1",
44
- "swagger-jsdoc": "^6.2.8",
44
+ "swagger-jsdoc": "^6.3.0",
45
45
  "swagger-ui-express": "^5.0.1",
46
- "tailwindcss": "^4.2.2",
46
+ "tailwindcss": "^4.3.3",
47
47
  "typescript": "^5.9.3",
48
- "umzug": "^3.8.2",
49
- "vite": "^8.0.2",
50
- "zustand": "^5.0.12"
48
+ "umzug": "^3.8.3",
49
+ "vite": "^8.1.5",
50
+ "zustand": "^5.0.14"
51
51
  },
52
52
  "optionalDependencies": {
53
53
  "@socket.io/redis-adapter": "^8.3.0",
54
- "ioredis": "^5.6.1"
54
+ "ioredis": "^5.11.1"
55
55
  },
56
56
  "overrides": {
57
57
  "ajv": "^8.17.1",
@@ -37,7 +37,7 @@ Use this skill to take a user from zero to a running Zyket application, or to ex
37
37
 
38
38
  3. **If the template uses auth** (`src/services/auth` exists), create the tables once:
39
39
  ```bash
40
- npx @better-auth/cli migrate
40
+ npx @better-auth/cli migrate --config src/services/auth/auth.js
41
41
  ```
42
42
 
43
43
  4. **Run:** `node index.js`. The API is on `PORT` (3000); a frontend, if any, on `VITE_PORT` (5173).
@@ -61,7 +61,7 @@ Flip the env flag, then add the component. Confirm details in `AGENTS.md §3–4
61
61
 
62
62
  1. Register the auth service in `index.js`: `["auth", require("./src/services/auth"), ["@service_container"]]`.
63
63
  2. Subclass `AuthService` (see `AGENTS.md §6`) to set `organizationEnabled`, `requireEmailVerification`, email senders, etc.
64
- 3. Require `DATABASE_DIALECT` = `sqlite` or `postgresql`; run `npx @better-auth/cli migrate`.
64
+ 3. Require `DATABASE_DIALECT` = `sqlite` or `postgresql`; run `npx @better-auth/cli migrate --config src/services/auth/auth.js`.
65
65
  4. Protect routes with `new RequireAuthMiddleware()` (or `['admin']` / `RequireAdminMiddleware`) and sockets with the `AuthGuard` (`module.exports = require('zyket').AuthGuard` in `src/guards/auth.js`; enforce connect-time auth inside `src/handlers/connection.js` via `container.get('auth').getSession(socket.handshake.headers)`).
66
66
 
67
67
  ### D. Building a feature (recipe)
@@ -79,7 +79,8 @@ Delegate individual component scaffolding to the **`generate`** skill (e.g. `/zy
79
79
  - **PATCH routes don't dispatch** — only `get/post/put/delete` methods are wired.
80
80
  - **Connection guards don't block** — do connect-time auth inside `connection.js` (throw to disconnect).
81
81
  - **`bullmq`/`scheduler`/`events` default ON when the `DISABLE_*` var is absent**, but the generated `.env` ships them as `true`. Set them to `false` explicitly to enable.
82
- - **Auth fails to boot** if `AUTH_SECRET` is missing or a known placeholder — let the framework generate it.
82
+ - **Auth fails to boot** if `AUTH_SECRET` is missing or a known placeholder — let the framework generate it (it lands in `.env` when the file is created).
83
+ - **`better-auth migrate` says "No configuration file found"** — the CLI only auto-discovers `auth.js` under `src/{auth,lib,server,utils}/`, never under `src/services/`. Always pass `--config src/services/auth/auth.js`.
83
84
  - **Frontend can't resolve `vite`/`react`/`better-auth`** — the project (not just zyket) must declare those deps; `npx zyket init` does this automatically for templates with a frontend.
84
85
  - **Boot crashes with `Cannot read properties of undefined (reading 'BarBarToken')`** — a TypeScript 7 got hoisted into the tree, which `node-dependency-injection`'s bundled `typescript-estree@5` can't read. Zyket pins `typescript` to `^5` and `npx zyket init` writes a matching `overrides` block; on a project predating that, add `"overrides": { "typescript": "^5.9.3" }` to `package.json` and reinstall.
85
86
 
@@ -19,6 +19,18 @@ module.exports = class HTTPServer {
19
19
  }
20
20
  console.log(`HTTP Server listening on port ${this.#port}`)
21
21
 
22
+ // The socket accepts connections from this point on, but Express only
23
+ // attaches its request listener once its service boots. Without a
24
+ // placeholder, anything arriving in between (health checks, an eager
25
+ // client) would be accepted and then never answered — the request hangs
26
+ // forever and the socket leaks. Answer 503 until Express takes over; it
27
+ // replaces this listener when it boots. With DISABLE_EXPRESS=true the
28
+ // placeholder stays, which is also the honest answer.
29
+ this.#server.on('request', (request, response) => {
30
+ response.writeHead(503, { 'Content-Type': 'application/json', 'Retry-After': '1' })
31
+ response.end(JSON.stringify({ success: false, message: 'Server is starting' }))
32
+ })
33
+
22
34
  this.#server.listen(this.#port, () => {})
23
35
  }
24
36
 
@@ -111,7 +111,9 @@ module.exports = class Express extends Service {
111
111
  }
112
112
  });
113
113
 
114
- // Attach Express to HTTP server - this allows dynamic route registration
114
+ // Attach Express to the HTTP server, replacing the kernel's "still
115
+ // booting" placeholder. This happens exactly once: the Express router is
116
+ // mutable, so routes registered later need no re-attachment.
115
117
  this.#httpServer.removeAllListeners("request");
116
118
  this.#httpServer.on("request", this.#app);
117
119
 
@@ -166,16 +168,13 @@ module.exports = class Express extends Service {
166
168
  });
167
169
  }
168
170
  }
169
-
170
- this.#httpServer.removeAllListeners("request");
171
- this.#httpServer.on("request", this.#app);
171
+ // No re-attachment: the app is already the server's request listener and
172
+ // its router picks up these routes immediately. Re-attaching would wipe
173
+ // engine.io's wrapper and kill the socket.io polling transport.
172
174
  }
173
175
 
174
176
  async regiterRawAllRoutes(path, handler) {
175
177
  this.#app.all(path, handler);
176
-
177
- this.#httpServer.removeAllListeners("request");
178
- this.#httpServer.on("request", this.#app);
179
178
  }
180
179
 
181
180
  async #loadCorsOrCreateDefault() {
@@ -25,7 +25,12 @@ module.exports = [
25
25
  s3Activated ? ["s3", S3, ["@service_container", process.env.S3_ENDPOINT, process.env.S3_PORT, process.env.S3_USE_SSL === "true", process.env.S3_ACCESS_KEY, process.env.S3_SECRET_KEY, process.env.S3_PUBLIC_BUCKETS, process.env.S3_PRIVATE_BUCKETS]] : null,
26
26
  schedulerActivated ? ["scheduler", Scheduler, ["@service_container"]] : null,
27
27
  bullmqActivated ? ["bullmq", require("./bullmq"), ["@service_container"]] : null,
28
+ // Express must boot BEFORE socketio: engine.io's attach() wraps whatever
29
+ // "request" listener is already on the HTTP server and delegates non-socket
30
+ // requests to it. Booting it the other way round means Express replaces
31
+ // engine.io's listener and the polling transport (the default first hop for
32
+ // every socket.io client) breaks with "xhr poll error".
33
+ expressActivated ? ["express", Express, ["@service_container"]] : null,
28
34
  socketActivated ? ["socketio", SocketIO, ["@service_container"]] : null,
29
35
  viteActivated ? ["vite", require("./vite"), ["@service_container", process.env.VITE_ROOT, Number(process.env.VITE_PORT) || 5173]] : null,
30
- expressActivated ? ["express", Express, ["@service_container"]] : null,
31
36
  ].filter(Boolean);
@@ -24,7 +24,7 @@ Auth endpoints are mounted by better-auth under `/api/auth/*`.
24
24
  ```bash
25
25
  npm install
26
26
  # 1) Create the better-auth tables (uses src/services/auth/auth.js)
27
- npx @better-auth/cli migrate
27
+ npx @better-auth/cli migrate --config src/services/auth/auth.js
28
28
  # 2) Run
29
29
  node index.js
30
30
  ```
@@ -1,5 +1,6 @@
1
- // Used by the better-auth CLI (`npx @better-auth/cli generate|migrate`) to
2
- // discover your auth configuration.
1
+ // Your auth configuration for the better-auth CLI. The CLI does not scan
2
+ // src/services/, so point it here explicitly:
3
+ // npx @better-auth/cli generate|migrate --config src/services/auth/auth.js
3
4
  const AuthService = require('./index.js');
4
5
 
5
6
  const auth = new AuthService({
@@ -14,7 +14,7 @@ connect or send messages.
14
14
  ## Setup
15
15
  ```bash
16
16
  npm install
17
- npx @better-auth/cli migrate
17
+ npx @better-auth/cli migrate --config src/services/auth/auth.js
18
18
  node index.js
19
19
  ```
20
20
  This starts the API + websocket server on `:3000` and the Vite frontend on `:5173`.
@@ -1,4 +1,6 @@
1
- // Used by the better-auth CLI (`npx @better-auth/cli generate|migrate`).
1
+ // Your auth configuration for the better-auth CLI. The CLI does not scan
2
+ // src/services/, so point it here explicitly:
3
+ // npx @better-auth/cli generate|migrate --config src/services/auth/auth.js
2
4
  const AuthService = require('./index.js');
3
5
 
4
6
  const auth = new AuthService({
@@ -26,7 +26,7 @@ routes, not on re-implementing what better-auth already exposes.
26
26
  ## Setup
27
27
  ```bash
28
28
  npm install
29
- npx @better-auth/cli migrate # creates user/session/organization/member tables
29
+ npx @better-auth/cli migrate --config src/services/auth/auth.js # creates user/session/organization/member tables
30
30
  node index.js
31
31
  ```
32
32
  This starts the API on `:3000` and the Vite dashboard on `:5173`. Open
@@ -1,4 +1,6 @@
1
- // Used by the better-auth CLI (`npx @better-auth/cli generate|migrate`).
1
+ // Your auth configuration for the better-auth CLI. The CLI does not scan
2
+ // src/services/, so point it here explicitly:
3
+ // npx @better-auth/cli generate|migrate --config src/services/auth/auth.js
2
4
  const AuthService = require('./index.js');
3
5
 
4
6
  const auth = new AuthService({
@@ -1,4 +1,5 @@
1
1
  const fs = require('fs');
2
+ const crypto = require('crypto');
2
3
 
3
4
  module.exports = class EnvManager {
4
5
  static load(secretsPath) {
@@ -43,6 +44,10 @@ module.exports = class EnvManager {
43
44
  VITE_ROOT: './frontend',
44
45
  VITE_PORT: 5173,
45
46
  DISABLE_VITE: true,
47
+ // Generated here, not on first boot: the better-auth CLI reads .env when
48
+ // it loads your auth config, so `migrate` has to work before the app has
49
+ // ever run. A per-project random value, never a shared placeholder.
50
+ AUTH_SECRET: crypto.randomBytes(32).toString('hex'),
46
51
  }
47
52
 
48
53
  return header + Object.entries(envsToCreate).reduce((acc, [key, value]) => {