zyket 1.2.21 → 1.2.22

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
@@ -291,7 +291,29 @@ 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 --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/`.
294
+ Requirements: `DATABASE_DIALECT` must be `sqlite` or `postgresql`.
295
+
296
+ ### Creating / updating the auth tables
297
+
298
+ `AuthService.migrate()` runs whatever better-auth migrations are still pending — creating missing tables and adding missing columns — using the **installed** better-auth, so it always matches the schema your app expects:
299
+
300
+ ```js
301
+ kernel.boot().then(async () => {
302
+ const { pending, tablesCreated, fieldsAdded } = await kernel.container.get('auth').migrate();
303
+ // { pending: 5, tablesCreated: ['user','account','organization',…], fieldsAdded: [] }
304
+ });
305
+ ```
306
+
307
+ | Call | Effect |
308
+ |------|--------|
309
+ | `await auth.migrate()` | applies pending migrations; returns `{ pending, tablesCreated, fieldsAdded }` |
310
+ | `await auth.migrate({ dryRun: true })` | applies nothing; adds `sql` (the compiled statements) to the return value |
311
+
312
+ Run it after adding a plugin, an `additionalFields` entry, or on a fresh database. It is idempotent — `pending: 0` when there is nothing to do — but it is **not** automatic: nothing migrates on boot unless you call it. `sqlite`/`postgresql` only (it throws otherwise).
313
+
314
+ The external CLI still works — `npx @better-auth/cli migrate --config src/services/auth/auth.js` — and `--config` is required, because the CLI only auto-discovers `auth.js` under `src/{auth,lib,server,utils}/`, never under `src/services/`. Prefer `migrate()`: the CLI bundles its own better-auth copy, so it can disagree with your installed version about the schema (it currently creates a `verification` table that better-auth 1.6 no longer uses).
315
+
316
+ **No `session` / `verification` tables?** That's expected. The `auth` service always wires better-auth's `secondaryStorage` to the `cache` service, and better-auth then keeps sessions and verification tokens there instead of in SQL. With the default in-memory cache that means **sessions do not survive a restart and are not shared between instances** — set `CACHE_URL=redis://…` for durable, shared sessions, or opt back into SQL with `session: { storeSessionInDatabase: true }` / `verification: { storeInDatabase: true }` in a subclass.
295
317
 
296
318
  ### Protecting routes & sockets
297
319
 
package/bin/cli.js CHANGED
@@ -285,7 +285,10 @@ 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 --config src/services/auth/auth.js # create the auth tables');
288
+ if (usesAuth) {
289
+ console.log(' npx @better-auth/cli migrate --config src/services/auth/auth.js # create the auth tables');
290
+ console.log(" # or, from inside the app: await container.get('auth').migrate()");
291
+ }
289
292
  console.log(' node index.js\n');
290
293
  if (fs.existsSync(path.join(process.cwd(), 'README.md'))) {
291
294
  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.21",
3
+ "version": "1.2.22",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -35,7 +35,11 @@ Use this skill to take a user from zero to a running Zyket application, or to ex
35
35
  ```
36
36
  This copies the template, merges its `.env.example` onto sensible defaults, writes `package.json` with the right dependencies, and installs them.
37
37
 
38
- 3. **If the template uses auth** (`src/services/auth` exists), create the tables once:
38
+ 3. **If the template uses auth** (`src/services/auth` exists), create the tables. From inside the app (preferred — uses the installed better-auth):
39
+ ```js
40
+ kernel.boot().then(() => kernel.container.get('auth').migrate());
41
+ ```
42
+ Or with the CLI, which needs `--config` because it never scans `src/services/`:
39
43
  ```bash
40
44
  npx @better-auth/cli migrate --config src/services/auth/auth.js
41
45
  ```
@@ -61,7 +65,7 @@ Flip the env flag, then add the component. Confirm details in `AGENTS.md §3–4
61
65
 
62
66
  1. Register the auth service in `index.js`: `["auth", require("./src/services/auth"), ["@service_container"]]`.
63
67
  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 --config src/services/auth/auth.js`.
68
+ 3. Require `DATABASE_DIALECT` = `sqlite` or `postgresql`; create/update the tables with `await container.get('auth').migrate()` (see `AGENTS.md §6`) or the CLI with `--config src/services/auth/auth.js`. Re-run it after adding a plugin or an additional field.
65
69
  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
70
 
67
71
  ### D. Building a feature (recipe)
@@ -80,7 +84,8 @@ Delegate individual component scaffolding to the **`generate`** skill (e.g. `/zy
80
84
  - **Connection guards don't block** — do connect-time auth inside `connection.js` (throw to disconnect).
81
85
  - **`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
86
  - **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`.
87
+ - **`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`, or call `container.get('auth').migrate()` instead.
88
+ - **No `session`/`verification` table after migrating** — expected: `secondaryStorage` is wired to the `cache`, so better-auth keeps them there. With the default in-memory cache, sessions die on restart; set `CACHE_URL=redis://…` in production.
84
89
  - **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.
85
90
  - **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.
86
91
 
@@ -8,6 +8,7 @@ const crypto = require("crypto");
8
8
 
9
9
  module.exports = class AuthService extends Service {
10
10
  #container;
11
+ #authOptions;
11
12
  client;
12
13
 
13
14
  constructor(container) {
@@ -131,7 +132,77 @@ module.exports = class AuthService extends Service {
131
132
  throw new Error("allowUserToCreateOrganization method not implemented");
132
133
  }
133
134
 
135
+ // Run the better-auth migrations that are still pending: create missing
136
+ // tables and add missing columns. Same work as
137
+ // `npx @better-auth/cli migrate --config src/services/auth/auth.js`, but from
138
+ // inside the app — so adding a plugin (two-factor, jwt, …) or a new
139
+ // additional field only needs `await container.get('auth').migrate()`.
140
+ //
141
+ // Pass `{ dryRun: true }` to get the SQL back without touching the database.
142
+ // Returns { pending, tablesCreated, fieldsAdded, sql } so callers can log,
143
+ // assert, or refuse to boot on a dirty schema.
144
+ async migrate({ dryRun = false } = {}) {
145
+ if (!['postgresql', 'sqlite'].includes(process.env.DATABASE_DIALECT)) {
146
+ throw new Error('AuthService.migrate() only supports PostgreSQL and SQLite as database dialects');
147
+ }
148
+
149
+ const logger = this.#logger();
150
+ // ESM-only subpath; import() keeps this working regardless of Node's
151
+ // require(esm) support.
152
+ const { getMigrations } = await import('better-auth/db/migration');
153
+ const { toBeCreated, toBeAdded, runMigrations, compileMigrations } = await getMigrations(this.authOptions);
154
+
155
+ const tablesCreated = toBeCreated.map((table) => table.table);
156
+ const fieldsAdded = toBeAdded.flatMap(
157
+ (table) => Object.keys(table.fields).map((field) => `${table.table}.${field}`)
158
+ );
159
+ const pending = tablesCreated.length + fieldsAdded.length;
160
+
161
+ if (pending === 0) {
162
+ logger.info('Auth schema is up to date, nothing to migrate');
163
+ return { pending: 0, tablesCreated: [], fieldsAdded: [], sql: dryRun ? '' : undefined };
164
+ }
165
+
166
+ const summary = [
167
+ tablesCreated.length ? `tables: ${tablesCreated.join(', ')}` : null,
168
+ fieldsAdded.length ? `fields: ${fieldsAdded.join(', ')}` : null,
169
+ ].filter(Boolean).join(' | ');
170
+
171
+ if (dryRun) {
172
+ const sql = await compileMigrations();
173
+ logger.info(`Auth migrations pending (dry run, nothing applied) — ${summary}`);
174
+ return { pending, tablesCreated, fieldsAdded, sql };
175
+ }
176
+
177
+ await runMigrations();
178
+ logger.info(`Auth migrations applied — ${summary}`);
179
+ return { pending, tablesCreated, fieldsAdded };
180
+ }
181
+
182
+ // The logger is unavailable when the service is built outside a booted
183
+ // kernel (e.g. the better-auth CLI loading src/services/auth/auth.js), and
184
+ // the DI container throws on unknown services rather than returning null.
185
+ #logger() {
186
+ try {
187
+ return this.#container?.get('logger') || console;
188
+ } catch {
189
+ return console;
190
+ }
191
+ }
192
+
193
+ // Built once and reused: every access to `auth` would otherwise open another
194
+ // SQLite handle / pg Pool. `migrate()` needs the very same options object,
195
+ // since that is what defines the expected schema.
196
+ get authOptions() {
197
+ if (!this.#authOptions) this.#authOptions = this.#buildAuthOptions();
198
+ return this.#authOptions;
199
+ }
200
+
134
201
  get auth() {
202
+ return betterAuth(this.authOptions);
203
+ }
204
+
205
+ #buildAuthOptions() {
135
206
  const cache = this.#container.get('cache');
136
207
 
137
208
  // Environment-aware cookie security:
@@ -144,7 +215,7 @@ module.exports = class AuthService extends Service {
144
215
  const cookieSameSite = crossDomain ? 'none' : 'lax';
145
216
  const cookieSecure = crossDomain || isProduction;
146
217
 
147
- return betterAuth({
218
+ return {
148
219
  hooks: this.hooks,
149
220
  plugins: [
150
221
  admin(),
@@ -215,10 +286,6 @@ module.exports = class AuthService extends Service {
215
286
  baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3000',
216
287
  secret: this.#requireAuthSecret(),
217
288
  trustedOrigins: process.env.TRUSTED_ORIGINS?.split(',') || ['http://localhost:5173', 'http://localhost:6632']
218
- })
219
- }
220
-
221
- get client() {
222
- return this.client;
289
+ };
223
290
  }
224
291
  }
@@ -23,12 +23,25 @@ Auth endpoints are mounted by better-auth under `/api/auth/*`.
23
23
  ## Setup
24
24
  ```bash
25
25
  npm install
26
- # 1) Create the better-auth tables (uses src/services/auth/auth.js)
26
+ # 1) Create the better-auth tables
27
27
  npx @better-auth/cli migrate --config src/services/auth/auth.js
28
28
  # 2) Run
29
29
  node index.js
30
30
  ```
31
31
 
32
+ Instead of the CLI you can migrate from inside the app — it uses the
33
+ better-auth version this project actually installs:
34
+
35
+ ```js
36
+ kernel.boot().then(() => kernel.container.get('auth').migrate());
37
+ ```
38
+
39
+ Re-run it after adding a better-auth plugin or an `additionalFields` entry.
40
+ There is no `session`/`verification` table: `secondaryStorage` is wired to the
41
+ cache service, so better-auth keeps those there (set `CACHE_URL=redis://…` if
42
+ sessions must survive a restart).
43
+
44
+
32
45
  The `Task` table is created automatically via `sequelize.sync()` on boot.
33
46
 
34
47
  ## Auth quick test
@@ -9,8 +9,8 @@ const kernel = new Kernel({
9
9
  });
10
10
 
11
11
  kernel.boot().then(async () => {
12
- // Create the example tables (Task). better-auth tables are created via the
13
- // better-auth CLI migrate step (see README).
12
+ // Create the example tables (Task). The better-auth tables come from
13
+ // `container.get('auth').migrate()` or the better-auth CLI (see README).
14
14
  await kernel.container.get('database').sync();
15
15
  kernel.container.get('logger').info('api-rest template ready — try GET /tasks');
16
16
  }).catch((error) => {
@@ -17,6 +17,19 @@ npm install
17
17
  npx @better-auth/cli migrate --config src/services/auth/auth.js
18
18
  node index.js
19
19
  ```
20
+
21
+ Instead of the CLI you can migrate from inside the app — it uses the
22
+ better-auth version this project actually installs:
23
+
24
+ ```js
25
+ kernel.boot().then(() => kernel.container.get('auth').migrate());
26
+ ```
27
+
28
+ Re-run it after adding a better-auth plugin or an `additionalFields` entry.
29
+ There is no `session`/`verification` table: `secondaryStorage` is wired to the
30
+ cache service, so better-auth keeps those there (set `CACHE_URL=redis://…` if
31
+ sessions must survive a restart).
32
+
20
33
  This starts the API + websocket server on `:3000` and the Vite frontend on `:5173`.
21
34
  Open http://localhost:5173, register a user, and start chatting (open two
22
35
  browsers/users to see real-time delivery).
@@ -26,9 +26,22 @@ 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 --config src/services/auth/auth.js # creates user/session/organization/member tables
29
+ npx @better-auth/cli migrate --config src/services/auth/auth.js # creates the user/account/organization/member tables
30
30
  node index.js
31
31
  ```
32
+
33
+ Instead of the CLI you can migrate from inside the app — it uses the
34
+ better-auth version this project actually installs:
35
+
36
+ ```js
37
+ kernel.boot().then(() => kernel.container.get('auth').migrate());
38
+ ```
39
+
40
+ Re-run it after adding a better-auth plugin or an `additionalFields` entry.
41
+ There is no `session`/`verification` table: `secondaryStorage` is wired to the
42
+ cache service, so better-auth keeps those there (set `CACHE_URL=redis://…` if
43
+ sessions must survive a restart).
44
+
32
45
  This starts the API on `:3000` and the Vite dashboard on `:5173`. Open
33
46
  http://localhost:5173, sign up, create an organization, set it active, and add
34
47
  projects (scoped to that organization).