miolo 3.0.0-beta.154 → 3.0.0-beta.155

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 (31) hide show
  1. package/bin/create/index.mjs +1 -1
  2. package/bin/create/validation.mjs +1 -1
  3. package/package.json +4 -3
  4. package/src/config/.env +19 -8
  5. package/src/config/defaults.mjs +28 -21
  6. package/src/config/index.mjs +10 -17
  7. package/src/engines/cron/syscheck.mjs +2 -2
  8. package/src/middleware/auth/basic.mjs +6 -4
  9. package/src/middleware/auth/guest.mjs +1 -0
  10. package/src/middleware/auth/passport/index.mjs +299 -0
  11. package/src/middleware/ssr/ssr_render.mjs +4 -2
  12. package/src/server.mjs +5 -10
  13. package/template/.agent/skills/miolo-auth/SKILL.md +273 -118
  14. package/template/.agent/skills/miolo-session-context/SKILL.md +4 -3
  15. package/template/.env +9 -2
  16. package/template/db/sql/01_users.sql +3 -0
  17. package/template/package.json +7 -7
  18. package/template/src/cli/pages/offline/Login.jsx +0 -3
  19. package/template/src/cli/pages/offline/LoginForm.jsx +89 -79
  20. package/template/src/cli/pages/todos/context/TodosProvider.jsx +2 -2
  21. package/template/src/server/db/io/users/auth.mjs +36 -4
  22. package/template/src/server/db/triggers/user.mjs +5 -4
  23. package/template/src/server/miolo/auth/passport.mjs +93 -0
  24. package/template/src/server/miolo/db.mjs +4 -15
  25. package/template/src/server/miolo/index.mjs +4 -2
  26. package/src/middleware/auth/credentials/index.mjs +0 -183
  27. package/template/.env.production +0 -111
  28. package/template/src/server/miolo/auth/credentials.mjs +0 -47
  29. /package/src/middleware/auth/{credentials → passport}/session/index.mjs +0 -0
  30. /package/src/middleware/auth/{credentials → passport}/session/store.mjs +0 -0
  31. /package/src/middleware/auth/{credentials → passport}/session/store_koa_redis.mjs +0 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: miolo-auth
3
- description: Authentication configuration and strategies for miolo applications. Use when implementing, modifying, or troubleshooting authentication, configuring auth strategies (credentials, basic, guest), or setting up user sessions.
3
+ description: Authentication configuration and strategies for miolo applications. Use when implementing, modifying, or troubleshooting authentication, configuring auth strategies (passport, basic, guest), or setting up user sessions.
4
4
  ---
5
5
 
6
6
  # Miolo Authentication
@@ -9,14 +9,13 @@ Authentication configuration and strategies for miolo applications.
9
9
 
10
10
  ## Authentication Strategies
11
11
 
12
- Miolo supports multiple built-in authentication strategies in `src/server/miolo/auth/`:
12
+ Miolo supports multiple built-in authentication strategies:
13
13
 
14
14
  ```
15
15
  src/server/miolo/auth/
16
- ├── credentials.mjs # Username/password authentication
16
+ ├── passport.mjs # Passport-based auth (local + OAuth2)
17
17
  ├── basic.mjs # HTTP Basic authentication
18
- ├── guest.mjs # Guest/anonymous access
19
- └── custom.mjs # Custom authentication logic
18
+ └── guest.mjs # Guest/anonymous access
20
19
  ```
21
20
 
22
21
  ## Configuring Authentication
@@ -24,56 +23,189 @@ src/server/miolo/auth/
24
23
  Authentication is configured in `src/server/miolo/index.mjs`:
25
24
 
26
25
  ```javascript
27
- import auth from './auth/credentials.mjs'
26
+ import passport from './auth/passport.mjs'
28
27
  // or: import auth from './auth/basic.mjs'
29
28
  // or: import auth from './auth/guest.mjs'
30
29
 
31
30
  export default {
32
- auth,
31
+ auth: {
32
+ passport // Enables Passport.js with local + Google OAuth2
33
+ },
33
34
  // ... other config
34
35
  }
35
36
  ```
36
37
 
37
- ## Credentials Strategy (Default)
38
+ ## Passport Strategy (Recommended)
38
39
 
39
- Username/password authentication with database-backed users.
40
+ Unified authentication using Passport.js supporting both **local (username/password)** and **Google OAuth2**.
40
41
 
41
- **File:** `src/server/miolo/auth/credentials.mjs`
42
+ **File:** `src/server/miolo/auth/passport.mjs`
42
43
 
43
44
  ```javascript
44
- import { db_user_auth } from '#server/db/io/users/auth.mjs'
45
+ import { db_find_user_by_id, db_auth_user,
46
+ db_user_find_or_create_from_google } from '#server/db/io/users/auth.mjs'
47
+
48
+ const get_user_id = (user, done, ctx) => {
49
+ const uid = user?.id
50
+ if (uid != undefined) {
51
+ return done(null, uid)
52
+ } else {
53
+ const err = new Error('User id is undefined')
54
+ return done(err, null)
55
+ }
56
+ }
45
57
 
46
- export default {
47
- urls: {
48
- login: '/page/login',
49
- logout: '/page/logout',
50
- home: '/'
51
- },
58
+ const find_user_by_id = (id, done, ctx) => {
59
+ ctx.miolo.logger.debug(`[auth] find_user_by_id() - Searching user id ${id}`)
60
+ db_find_user_by_id(ctx.miolo, id).then(user => {
61
+ if (user == undefined) {
62
+ const err = new Error('User not found')
63
+ return done(err, null)
64
+ } else {
65
+ return done(null, user)
66
+ }
67
+ })
68
+ }
52
69
 
53
- async login(ctx, credentials) {
54
- const { username, password } = credentials
55
-
56
- const user = await db_user_auth(ctx, { username, password })
57
-
58
- if (!user) {
59
- return { ok: false, error: 'Invalid credentials' }
70
+ const local_auth_user = (username, password, done, ctx) => {
71
+ ctx.miolo.logger.debug(`[auth][local] Checking credentials for ${username}`)
72
+
73
+ db_auth_user(ctx.miolo, username, password).then(([user, msg]) => {
74
+ if (user == undefined) {
75
+ const err = new Error(msg)
76
+ return done(err, null)
77
+ } else {
78
+ return done(null, user)
60
79
  }
61
-
62
- return { ok: true, user }
63
- },
80
+ })
81
+ }
64
82
 
65
- async logout(ctx) {
66
- // Cleanup if needed
67
- return { ok: true }
83
+ const google_auth_user = async (accessToken, refreshToken, profile, done, ctx) => {
84
+ try {
85
+ const google_id = profile.id
86
+ const email = profile.emails?.[0]?.value
87
+ const name = profile.displayName
88
+ const google_picture = profile.photos?.[0]?.value
89
+
90
+ ctx.miolo.logger.info(`[auth][google] Authenticated user: ${email}`)
91
+
92
+ return db_user_find_or_create_from_google(
93
+ ctx.miolo, email, name, google_id, google_picture
94
+ ).then(([user, msg]) => {
95
+ if (user == undefined) {
96
+ const err = new Error(msg)
97
+ return done(err, null)
98
+ } else {
99
+ return done(null, user)
100
+ }
101
+ })
102
+ } catch (error) {
103
+ ctx.miolo.logger.error(`[auth][google] Error: ${error}`)
104
+ return done(error, null)
68
105
  }
69
106
  }
107
+
108
+ export default {
109
+ get_user_id,
110
+ find_user_by_id,
111
+ local_auth_user,
112
+ local_url_login: '/login',
113
+ local_url_logout: '/logout',
114
+ local_url_login_redirect: undefined,
115
+ local_url_logout_redirect: '/',
116
+ google_auth_user,
117
+ google_client_id: process.env.MIOLO_AUTH_GOOGLE_CLIENT_ID,
118
+ google_client_secret: process.env.MIOLO_AUTH_GOOGLE_CLIENT_SECRET,
119
+ google_url_login: '/auth/google',
120
+ google_url_callback: process.env.MIOLO_AUTH_GOOGLE_CALLBACK_URL || '/auth/google/callback',
121
+ google_url_logout: '/logout',
122
+ google_url_logout_redirect: '/'
123
+ }
70
124
  ```
71
125
 
72
- **Key elements:**
73
- - `urls` - Define login, logout, home page paths
74
- - `login(ctx, credentials)` - Validates credentials, returns user or error
75
- - `logout(ctx)` - Optional cleanup on logout
76
- - Uses database function from `db/io/users/auth.mjs`
126
+ ### Passport Configuration Elements
127
+
128
+ #### Common Functions
129
+ - `get_user_id(user, done, ctx)` - Extracts user ID for session storage
130
+ - `find_user_by_id(id, done, ctx)` - Retrieves user by ID (session deserialization)
131
+
132
+ #### Local Authentication (Username/Password)
133
+ - `local_auth_user(username, password, done, ctx)` - Validates credentials
134
+ - `local_url_login` - Login endpoint (default: `/login`)
135
+ - `local_url_logout` - Logout endpoint (default: `/logout`)
136
+ - `local_url_login_redirect` - Redirect after login (optional)
137
+ - `local_url_logout_redirect` - Redirect after logout (default: `/`)
138
+
139
+ #### Google OAuth2 Authentication
140
+ - `google_auth_user(accessToken, refreshToken, profile, done, ctx)` - Handles Google profile
141
+ - `google_client_id` - Google OAuth2 client ID (from env)
142
+ - `google_client_secret` - Google OAuth2 client secret (from env)
143
+ - `google_url_login` - OAuth initiation endpoint (default: `/auth/google`)
144
+ - `google_url_callback` - OAuth callback endpoint (from env or `/auth/google/callback`)
145
+ - `google_url_logout` - Logout endpoint (default: `/logout`)
146
+ - `google_url_logout_redirect` - Redirect after logout (default: `/`)
147
+
148
+ ### Environment Variables
149
+
150
+ **Required for Google OAuth2 (.env):**
151
+ ```
152
+ MIOLO_AUTH_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
153
+ MIOLO_AUTH_GOOGLE_CLIENT_SECRET=your-client-secret
154
+ MIOLO_AUTH_GOOGLE_CALLBACK_URL=http://localhost:8001/auth/google/callback
155
+ ```
156
+
157
+ **Session configuration:**
158
+ ```
159
+ MIOLO_SESSION_SALT=your-random-salt-here
160
+ MIOLO_SESSION_SECRET=your-session-secret
161
+ MIOLO_SESSION_SAME_SITE=lax # Required for Google OAuth2
162
+ ```
163
+
164
+ ### Google Cloud Console Setup
165
+
166
+ 1. Go to [Google Cloud Console](https://console.cloud.google.com/)
167
+ 2. Create a project or select existing one
168
+ 3. Enable Google+ API
169
+ 4. Create OAuth 2.0 credentials:
170
+ - Application type: Web application
171
+ - Authorized JavaScript origins: `http://localhost:8001`
172
+ - Authorized redirect URIs: `http://localhost:8001/auth/google/callback`
173
+ 5. Copy Client ID and Client Secret to your `.env`
174
+
175
+ ### OAuth2 Flow
176
+
177
+ 1. User clicks "Login with Google" → `window.location.href = '/auth/google'`
178
+ 2. Server redirects to Google authentication page
179
+ 3. User authenticates with Google
180
+ 4. Google redirects back to `/auth/google/callback`
181
+ 5. `google_auth_user` processes Google profile
182
+ 6. User found/created in database
183
+ 7. User logged in and redirected to home
184
+
185
+ ### Frontend Login Button
186
+
187
+ ```jsx
188
+ // For local login (POST form)
189
+ <form onSubmit={handleLocalLogin}>
190
+ <input name="username" />
191
+ <input name="password" type="password" />
192
+ <button type="submit">Login</button>
193
+ </form>
194
+
195
+ // For Google OAuth2 (Navigate to endpoint)
196
+ <button onClick={() => window.location.href = '/auth/google'}>
197
+ Login with Google
198
+ </button>
199
+ ```
200
+
201
+ **IMPORTANT:** Google OAuth2 requires **navigation**, not fetch/AJAX:
202
+ ```javascript
203
+ // ✅ CORRECT
204
+ window.location.href = '/auth/google'
205
+
206
+ // ❌ WRONG - Causes CORS errors
207
+ fetch('/auth/google')
208
+ ```
77
209
 
78
210
  ## Basic Authentication
79
211
 
@@ -86,7 +218,6 @@ export default {
86
218
  async login(ctx, credentials) {
87
219
  const { username, password } = credentials
88
220
 
89
- // Validate against environment or database
90
221
  if (username === process.env.API_USER &&
91
222
  password === process.env.API_PASSWORD) {
92
223
  return {
@@ -100,19 +231,16 @@ export default {
100
231
  }
101
232
  ```
102
233
 
103
- ## Guest/Anonymous Access
234
+ ## Guest Authentication
104
235
 
105
- Allow unauthenticated access (useful for read-only apps).
236
+ Anonymous access without credentials.
106
237
 
107
238
  **File:** `src/server/miolo/auth/guest.mjs`
108
239
 
109
240
  ```javascript
110
241
  export default {
111
- async login(ctx) {
112
- return {
113
- ok: true,
114
- user: { id: 0, username: 'guest', role: 'guest' }
115
- }
242
+ make_guest_token: (session) => {
243
+ return `guest-${Date.now()}-${Math.random()}`
116
244
  }
117
245
  }
118
246
  ```
@@ -124,12 +252,15 @@ After successful login, user is available in routes:
124
252
  ```javascript
125
253
  export async function r_protected_route(ctx, params) {
126
254
  const user = ctx.state.user
255
+ const isAuthenticated = ctx.session.authenticated
127
256
 
128
257
  // User object contains:
129
258
  // - id
130
- // - username
259
+ // - username (for local auth)
131
260
  // - email
132
- // - any other fields returned from login
261
+ // - name
262
+ // - google_id (for Google auth)
263
+ // - google_picture (for Google auth)
133
264
 
134
265
  ctx.miolo.logger.info(`User ${user.id} accessing route`)
135
266
 
@@ -160,36 +291,91 @@ export default [{
160
291
  }]
161
292
  ```
162
293
 
163
- ## Database User Authentication
294
+ ## Database Functions
164
295
 
165
- User authentication typically queries the database:
296
+ ### User Authentication (Local)
166
297
 
167
298
  **File:** `src/server/db/io/users/auth.mjs`
168
299
 
169
300
  ```javascript
170
301
  import { sha512 } from '#server/utils/crypt.mjs'
171
302
 
172
- export async function db_user_auth(ctx, params) {
173
- const { username, password } = params
303
+ export async function db_auth_user(miolo, username, password) {
304
+ const conn = miolo.db
305
+ const options = { transaction: undefined }
174
306
 
175
307
  const salt = process.env.MIOLO_SESSION_SALT
176
308
  const hashedPassword = sha512(password, salt)
177
309
 
178
- const user = await ctx.miolo.db.query(`
179
- SELECT id, username, email, name
310
+ const query = `
311
+ SELECT id, username, name, email, active, admin
312
+ FROM u_user
313
+ WHERE username = $1 AND password = $2 AND active = 1`
314
+
315
+ const ruser = await conn.selectOne(query, [username, hashedPassword], options)
316
+
317
+ if (ruser?.id == undefined) {
318
+ return [undefined, 'Invalid credentials']
319
+ } else {
320
+ return [ruser, undefined]
321
+ }
322
+ }
323
+ ```
324
+
325
+ ### User by ID
326
+
327
+ ```javascript
328
+ export async function db_find_user_by_id(miolo, id) {
329
+ const conn = miolo.db
330
+ const options = { transaction: undefined }
331
+
332
+ const query = `
333
+ SELECT id, username, name, email, active, admin,
334
+ google_id, google_picture
180
335
  FROM u_user
181
- WHERE username = $1 AND password = $2
182
- `, [username, hashedPassword])
336
+ WHERE id = $1`
183
337
 
184
- return user.rows[0] || null
338
+ const ruser = await conn.selectOne(query, [id], options)
339
+ return ruser
185
340
  }
186
341
  ```
187
342
 
188
- **Key elements:**
189
- - Hash password with session salt
190
- - Query user by username and hashed password
191
- - Return user object or null
192
- - Don't return password in user object
343
+ ### Google OAuth2 User
344
+
345
+ ```javascript
346
+ export async function db_user_find_or_create_from_google(
347
+ miolo, email, name, google_id, google_picture
348
+ ) {
349
+ const conn = miolo.db
350
+ const options = { transaction: undefined }
351
+
352
+ // Try to find existing user by google_id
353
+ const query = `
354
+ SELECT id, username, name, email, active, admin,
355
+ google_id, google_picture
356
+ FROM u_user
357
+ WHERE google_id = $1`
358
+
359
+ const ruser = await conn.selectOne(query, [google_id], options)
360
+
361
+ if (ruser?.id == undefined) {
362
+ // Create new user
363
+ const UUser = await conn.get_model('u_user')
364
+ const data = {
365
+ name,
366
+ email,
367
+ google_id,
368
+ google_picture,
369
+ active: 1
370
+ }
371
+ const uid = await UUser.insert(data, options)
372
+ data.id = uid
373
+ return [data, undefined]
374
+ } else {
375
+ return [ruser, undefined]
376
+ }
377
+ }
378
+ ```
193
379
 
194
380
  ## Password Hashing
195
381
 
@@ -207,71 +393,38 @@ const hashedPassword = sha512(plainPassword, salt)
207
393
  MIOLO_SESSION_SALT=your-random-salt-here
208
394
  ```
209
395
 
210
- ## Changing Password
396
+ ## Database Trigger for Password Hashing
211
397
 
212
- Pattern for password change:
213
-
214
- **File:** `src/server/db/io/users/pwd.mjs`
398
+ **File:** `src/server/db/triggers/user.mjs`
215
399
 
216
400
  ```javascript
217
401
  import { sha512 } from '#server/utils/crypt.mjs'
218
402
 
219
- export async function db_user_change_password(ctx, params) {
220
- const { user_id, old_password, new_password } = params
221
-
222
- const salt = process.env.MIOLO_SESSION_SALT
223
-
224
- // Verify old password
225
- const user = await ctx.miolo.db.query(`
226
- SELECT id FROM u_user
227
- WHERE id = $1 AND password = $2
228
- `, [user_id, sha512(old_password, salt)])
229
-
230
- if (user.rows.length === 0) {
231
- throw new Error('Invalid current password')
403
+ async function beforeInsertUser(conn, params, options) {
404
+ const raw_pwd = params?.password
405
+ if (raw_pwd) {
406
+ const cry_pwd = sha512(raw_pwd, process.env.MIOLO_SESSION_SALT)
407
+ params.password = cry_pwd
232
408
  }
233
-
234
- // Update to new password
235
- const newHash = sha512(new_password, salt)
236
- await ctx.miolo.db.query(`
237
- UPDATE u_user
238
- SET password = $1
239
- WHERE id = $2
240
- `, [newHash, user_id])
241
-
242
- return { changed: true }
409
+ return [params, options, true]
243
410
  }
244
- ```
245
411
 
246
- ## Custom Authentication
412
+ export default {
413
+ before_insert: beforeInsertUser
414
+ }
415
+ ```
247
416
 
248
- For complex scenarios, implement custom logic:
417
+ ## Session Configuration
249
418
 
250
- **File:** `src/server/miolo/auth/custom.mjs`
419
+ **Important for OAuth2:** The session must use `sameSite: 'lax'` to work with Google redirects.
251
420
 
421
+ **In** `packages/miolo/src/config/defaults.mjs`:
252
422
  ```javascript
253
- export default {
254
- urls: {
255
- login: '/auth/custom',
256
- logout: '/auth/logout',
257
- home: '/'
258
- },
259
-
260
- async login(ctx, credentials) {
261
- // Custom logic: OAuth, LDAP, etc.
262
- const user = await yourCustomAuthLogic(credentials)
263
-
264
- if (!user) {
265
- return { ok: false, error: 'Authentication failed' }
266
- }
267
-
268
- return { ok: true, user }
269
- },
270
-
271
- async logout(ctx) {
272
- // Custom cleanup
273
- await yourCustomLogoutLogic(ctx)
274
- return { ok: true }
423
+ session: {
424
+ options: {
425
+ sameSite: 'lax', // Required for OAuth2
426
+ secure: false, // Set true in production with HTTPS
427
+ maxAge: 86400000, // 24 hours
275
428
  }
276
429
  }
277
430
  ```
@@ -280,16 +433,18 @@ export default {
280
433
 
281
434
  1. **Never store plain passwords** - Always hash with salt
282
435
  2. **Use strong session salt** - Set `MIOLO_SESSION_SALT` in `.env`
283
- 3. **Don't return passwords** - User object should never include password
436
+ 3. **Don't return passwords** - User object should never include password field
284
437
  4. **Validate on server** - Never trust client-side authentication
285
438
  5. **Use HTTPS in production** - Protect credentials in transit
286
- 6. **Rate limit login attempts** - Prevent brute force attacks
287
- 7. **Log authentication events** - Track successful and failed logins
439
+ 6. **Set secure cookies in production** - `MIOLO_SESSION_SECURE=true`
440
+ 7. **Use sameSite=lax for OAuth2** - Required for external OAuth redirects
441
+ 8. **Rate limit login attempts** - Prevent brute force attacks
442
+ 9. **Log authentication events** - Track successful and failed logins
288
443
 
289
444
  ## Examples from miolo-sample
290
445
 
291
446
  See actual implementations:
292
- - `src/server/miolo/auth/credentials.mjs` - Default auth strategy
293
- - `src/server/db/io/users/auth.mjs` - User authentication query
294
- - `src/server/db/io/users/pwd.mjs` - Password change logic
447
+ - `src/server/miolo/auth/passport.mjs` - Passport authentication config
448
+ - `src/server/db/io/users/auth.mjs` - User authentication queries
449
+ - `src/server/db/triggers/user.mjs` - Password hashing trigger
295
450
  - `src/server/utils/crypt.mjs` - Hashing utilities
@@ -59,11 +59,12 @@ export async function r_get_profile(ctx, params) {
59
59
  **Available properties:**
60
60
  - `ctx.session.user` - User object (or `null`)
61
61
  - `ctx.session.authenticated` - Boolean authentication status
62
+ - `ctx.session.auth_method` - Authentication method (local, google, etc.)
62
63
  - `ctx.session.token` - Auth token (guest auth only)
63
64
 
64
65
  ### Credentials Auth Methods
65
66
 
66
- When using credentials authentication strategy, additional methods are available:
67
+ When using local authentication strategy, additional methods are available:
67
68
 
68
69
  ```javascript
69
70
  export async function r_user_login(ctx, params) {
@@ -99,14 +100,14 @@ export async function r_protected_route(ctx, params) {
99
100
  }
100
101
  ```
101
102
 
102
- **Available methods (credentials auth):**
103
+ **Available methods (local auth):**
103
104
  - `ctx.isAuthenticated()` - Returns `true` if user is authenticated
104
105
  - `ctx.isUnauthenticated()` - Returns `true` if user is NOT authenticated
105
106
  - `await ctx.login(username, password)` - Attempt to authenticate user
106
107
  - `ctx.logout()` - End user session
107
108
 
108
109
  **User access:**
109
- - `ctx.state.user` - Authenticated user object (credentials auth)
110
+ - `ctx.state.user` - Authenticated user object (local auth)
110
111
  - `ctx.session.user` - User object (all auth methods)
111
112
 
112
113
  ### Backend Usage Example
package/template/.env CHANGED
@@ -21,6 +21,13 @@ MIOLO_REQUEST_SLOW=4 # seconds to consider slow a request
21
21
  MIOLO_GEOIP_ENABLED=true
22
22
  MIOLO_GEOIP_LOCAL_IPS=127.0.0.1,172.22.0.1,172.19.0.1
23
23
 
24
+ #
25
+ # If google auth
26
+ #
27
+ MIOLO_AUTH_GOOGLE_CLIENT_ID=123456
28
+ MIOLO_AUTH_GOOGLE_CLIENT_SECRET=123456
29
+ MIOLO_AUTH_GOOGLE_CALLBACK_URL=/auth/google/callback
30
+
24
31
  #
25
32
  # Session
26
33
  #
@@ -30,7 +37,7 @@ MIOLO_SESSION_SECRET=00000000-0000-0000-0000-000000000000
30
37
  MIOLO_SESSION_MAX_AGE=864000000
31
38
  MIOLO_SESSION_SECURE=false
32
39
  MIOLO_SESSION_RENEW=true
33
- MIOLO_SESSION_SAME_SITE=strict # lax | strict
40
+ MIOLO_SESSION_SAME_SITE=lax # lax | strict
34
41
 
35
42
  #
36
43
  # Database
@@ -51,7 +58,7 @@ MIOLO_DB_POOL_IDLE_TIMEOUT_MS=10000
51
58
  # Logging
52
59
  #
53
60
 
54
- MIOLO_LOG_LEVEL=info
61
+ MIOLO_LOG_LEVEL=debug
55
62
  MIOLO_LOG_CONSOLE_ENABLED=true
56
63
  MIOLO_LOG_FILE_ENABLED=false
57
64
  MIOLO_LOG_MAIL_ENABLED=false
@@ -10,6 +10,9 @@ CREATE TABLE u_user (
10
10
 
11
11
  admin boolean,
12
12
 
13
+ google_id text,
14
+ google_picture text,
15
+
13
16
  last_login_date integer,
14
17
  last_login_ip text,
15
18
  login_count integer DEFAULT 0,
@@ -36,17 +36,17 @@
36
36
  "@radix-ui/react-separator": "^1.1.8",
37
37
  "@radix-ui/react-slot": "^1.2.4",
38
38
  "@radix-ui/react-tooltip": "^1.2.8",
39
- "@stepperize/react": "^6.0.0",
40
- "@tailwindcss/postcss": "^4.1.18",
39
+ "@stepperize/react": "^6.0.1",
40
+ "@tailwindcss/postcss": "^4.2.0",
41
41
  "@tanstack/react-table": "^8.21.3",
42
42
  "class-variance-authority": "^0.7.1",
43
43
  "clsx": "^2.1.1",
44
44
  "farrapa": "^3.0.0-beta.3",
45
45
  "intre": "^3.0.0-beta.3",
46
46
  "joi": "^18.0.2",
47
- "lucide-react": "^0.563.0",
48
- "miolo-cli": "^3.0.0-beta.154",
49
- "miolo-react": "^3.0.0-beta.154",
47
+ "lucide-react": "^0.574.0",
48
+ "miolo-cli": "^3.0.0-beta.155",
49
+ "miolo-react": "^3.0.0-beta.155",
50
50
  "next-themes": "^0.4.6",
51
51
  "radix-ui": "^1.4.3",
52
52
  "react": "^19.2.4",
@@ -55,12 +55,12 @@
55
55
  "recharts": "^3.7.0",
56
56
  "sonner": "^2.0.7",
57
57
  "tailwind": "^4.0.0",
58
- "tailwind-merge": "^3.4.0",
58
+ "tailwind-merge": "^3.4.1",
59
59
  "tinguir": "^0.0.7",
60
60
  "tw-animate-css": "^1.4.0"
61
61
  },
62
62
  "devDependencies": {
63
- "miolo": "^3.0.0-beta.154",
63
+ "miolo": "^3.0.0-beta.155",
64
64
  "sass-embedded": "^1.97.3",
65
65
  "xeira": "^2.0.0-beta.10"
66
66
  },
@@ -1,10 +1,8 @@
1
1
  import React from 'react'
2
2
 
3
- import useSessionContext from '#cli/context/session/useSessionContext.mjs'
4
3
  import { LoginForm } from "./LoginForm.jsx"
5
4
 
6
5
  const Login = () => {
7
- const {login} = useSessionContext()
8
6
 
9
7
  return (
10
8
  <div className="grid min-h-svh lg:grid-cols-2">
@@ -29,7 +27,6 @@ const Login = () => {
29
27
  <div className="flex flex-1 items-center justify-center">
30
28
  <div className="w-full max-w-xs">
31
29
  <LoginForm
32
- onLogin = {login}
33
30
  /* TODO orgotLink*/
34
31
  />
35
32
  </div>