@flowerforce/flowerbase 1.7.5 → 1.7.6-beta.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 (62) hide show
  1. package/dist/auth/controller.d.ts.map +1 -1
  2. package/dist/auth/controller.js +11 -10
  3. package/dist/auth/plugins/jwt.js +1 -1
  4. package/dist/auth/providers/anon-user/controller.js +1 -1
  5. package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
  6. package/dist/auth/providers/custom-function/controller.js +36 -10
  7. package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
  8. package/dist/auth/providers/local-userpass/controller.js +15 -14
  9. package/dist/auth/utils.d.ts +1 -0
  10. package/dist/auth/utils.d.ts.map +1 -1
  11. package/dist/constants.d.ts +1 -0
  12. package/dist/constants.d.ts.map +1 -1
  13. package/dist/constants.js +4 -3
  14. package/dist/features/triggers/index.js +1 -1
  15. package/dist/features/triggers/utils.d.ts.map +1 -1
  16. package/dist/features/triggers/utils.js +38 -30
  17. package/dist/monitoring/routes/users.d.ts.map +1 -1
  18. package/dist/monitoring/routes/users.js +7 -6
  19. package/dist/monitoring/utils.d.ts.map +1 -1
  20. package/dist/monitoring/utils.js +5 -4
  21. package/dist/services/api/index.d.ts +4 -0
  22. package/dist/services/api/index.d.ts.map +1 -1
  23. package/dist/services/api/utils.d.ts +1 -0
  24. package/dist/services/api/utils.d.ts.map +1 -1
  25. package/dist/services/index.d.ts +4 -0
  26. package/dist/services/index.d.ts.map +1 -1
  27. package/dist/shared/handleUserDeletion.js +1 -1
  28. package/dist/shared/handleUserRegistration.js +2 -2
  29. package/dist/utils/context/helpers.d.ts +12 -0
  30. package/dist/utils/context/helpers.d.ts.map +1 -1
  31. package/dist/utils/initializer/exposeRoutes.js +1 -1
  32. package/dist/utils/rules-matcher/interface.d.ts +5 -1
  33. package/dist/utils/rules-matcher/interface.d.ts.map +1 -1
  34. package/dist/utils/rules-matcher/interface.js +2 -0
  35. package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
  36. package/dist/utils/rules-matcher/utils.js +51 -16
  37. package/package.json +1 -1
  38. package/src/auth/__tests__/controller.test.ts +1 -0
  39. package/src/auth/controller.ts +12 -11
  40. package/src/auth/plugins/jwt.ts +2 -2
  41. package/src/auth/providers/anon-user/__tests__/controller.test.ts +1 -0
  42. package/src/auth/providers/anon-user/controller.ts +2 -2
  43. package/src/auth/providers/custom-function/controller.ts +39 -12
  44. package/src/auth/providers/local-userpass/controller.ts +16 -15
  45. package/src/auth/utils.ts +1 -0
  46. package/src/constants.ts +3 -2
  47. package/src/features/triggers/__tests__/index.test.ts +1 -0
  48. package/src/features/triggers/index.ts +2 -2
  49. package/src/features/triggers/utils.ts +42 -31
  50. package/src/monitoring/routes/users.ts +8 -7
  51. package/src/monitoring/ui.css +5 -1
  52. package/src/monitoring/ui.events.js +2 -2
  53. package/src/monitoring/ui.shared.js +2 -1
  54. package/src/monitoring/utils.ts +6 -5
  55. package/src/shared/handleUserDeletion.ts +2 -2
  56. package/src/shared/handleUserRegistration.ts +3 -3
  57. package/src/utils/__tests__/operators.test.ts +24 -0
  58. package/src/utils/__tests__/rule.test.ts +39 -0
  59. package/src/utils/__tests__/rulesMatcherInterfaces.test.ts +2 -0
  60. package/src/utils/initializer/exposeRoutes.ts +2 -2
  61. package/src/utils/rules-matcher/interface.ts +5 -1
  62. package/src/utils/rules-matcher/utils.ts +78 -32
@@ -1,5 +1,6 @@
1
1
  import { FastifyInstance } from 'fastify'
2
- import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
2
+ import { ObjectId } from 'mongodb'
3
+ import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
3
4
  import { StateManager } from '../../../state'
4
5
  import { GenerateContext } from '../../../utils/context'
5
6
  import { hashToken } from '../../../utils/crypto'
@@ -16,7 +17,8 @@ export async function customFunctionController(app: FastifyInstance) {
16
17
 
17
18
  const functionsList = StateManager.select('functions')
18
19
  const services = StateManager.select('services')
19
- const db = app.mongo.client.db(DB_NAME)
20
+ const authDb = app.mongo.client.db(AUTH_DB_NAME)
21
+ const customUserDb = app.mongo.client.db(DB_NAME)
20
22
  const { authCollection, refreshTokensCollection, userCollection, user_id_field } = AUTH_CONFIG
21
23
  const refreshTokenTtlMs = DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000
22
24
 
@@ -30,7 +32,10 @@ export async function customFunctionController(app: FastifyInstance) {
30
32
  app.post<LoginDto>(
31
33
  AUTH_ENDPOINTS.LOGIN,
32
34
  {
33
- schema: LOGIN_SCHEMA
35
+ schema: LOGIN_SCHEMA,
36
+ errorHandler: (_error, _request, reply) => {
37
+ reply.code(500).send({ message: 'Internal Server Error' })
38
+ }
34
39
  },
35
40
  async function (req, reply) {
36
41
  const customFunctionProvider = AUTH_CONFIG.authProviders?.['custom-function']
@@ -54,7 +59,7 @@ export async function customFunctionController(app: FastifyInstance) {
54
59
  id
55
60
  } = req
56
61
 
57
- type CustomFunctionAuthResult = { id?: string }
62
+ type CustomFunctionAuthResult = { id?: string; email?: string }
58
63
  const authResult = await GenerateContext({
59
64
  args: [
60
65
  req.body
@@ -77,21 +82,39 @@ export async function customFunctionController(app: FastifyInstance) {
77
82
  }
78
83
  }) as CustomFunctionAuthResult
79
84
 
80
-
81
85
  if (!authResult.id) {
82
86
  reply.code(401).send({ message: 'Unauthorized' })
83
87
  return
84
88
  }
85
89
 
86
- const authUser = await db.collection(authCollection!).findOne({ email: authResult.id })
90
+ const email = authResult.email ?? authResult.id
91
+ let authUser = await authDb.collection(authCollection!).findOne({ email })
87
92
  if (!authUser) {
88
- reply.code(401).send({ message: 'Unauthorized' })
89
- return
93
+ const authUserId = new ObjectId()
94
+ await authDb.collection(authCollection!).insertOne({
95
+ _id: authUserId,
96
+ email,
97
+ status: 'confirmed',
98
+ createdAt: new Date(),
99
+ custom_data: {},
100
+ identities: [
101
+ {
102
+ id: authResult.id.toString(),
103
+ provider_id: authResult.id.toString(),
104
+ provider_type: 'custom-function',
105
+ provider_data: { email }
106
+ }
107
+ ]
108
+ })
109
+ authUser = {
110
+ _id: authUserId,
111
+ email
112
+ }
90
113
  }
91
114
 
92
115
  const user =
93
116
  user_id_field && userCollection
94
- ? await db
117
+ ? await customUserDb
95
118
  .collection(userCollection)
96
119
  .findOne({ [user_id_field]: authUser._id.toString() })
97
120
  : {}
@@ -107,21 +130,25 @@ export async function customFunctionController(app: FastifyInstance) {
107
130
  ...(user || {})
108
131
  }
109
132
  }
133
+
110
134
  const refreshToken = this.createRefreshToken(currentUserData)
111
135
  const refreshTokenHash = hashToken(refreshToken)
112
- await db.collection(refreshTokensCollection).insertOne({
136
+ await authDb.collection(refreshTokensCollection).insertOne({
113
137
  userId: authUser._id,
114
138
  tokenHash: refreshTokenHash,
115
139
  createdAt: new Date(),
116
140
  expiresAt: new Date(Date.now() + refreshTokenTtlMs),
117
141
  revokedAt: null
118
142
  })
119
- return {
120
- access_token: this.createAccessToken(currentUserData),
143
+ const accessToken = this.createAccessToken(currentUserData)
144
+
145
+ const responsePayload = {
146
+ access_token: accessToken,
121
147
  refresh_token: refreshToken,
122
148
  device_id: '',
123
149
  user_id: authUser._id.toString()
124
150
  }
151
+ reply.code(200).send(responsePayload)
125
152
  }
126
153
  )
127
154
 
@@ -1,6 +1,6 @@
1
1
  import { FastifyInstance } from 'fastify'
2
2
  import { ObjectId } from 'mongodb'
3
- import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
3
+ import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
4
4
  import handleUserRegistration from '../../../shared/handleUserRegistration'
5
5
  import { PROVIDER } from '../../../shared/models/handleUserRegistration.model'
6
6
  import { StateManager } from '../../../state'
@@ -44,7 +44,8 @@ export async function localUserPassController(app: FastifyInstance) {
44
44
  const { authCollection, userCollection, user_id_field } = AUTH_CONFIG
45
45
  const { resetPasswordCollection } = AUTH_CONFIG
46
46
  const { refreshTokensCollection } = AUTH_CONFIG
47
- const db = app.mongo.client.db(DB_NAME)
47
+ const authDb = app.mongo.client.db(AUTH_DB_NAME)
48
+ const customUserDb = app.mongo.client.db(DB_NAME)
48
49
  const resetPasswordTtlSeconds = DEFAULT_CONFIG.RESET_PASSWORD_TTL_SECONDS
49
50
  const rateLimitWindowMs = DEFAULT_CONFIG.AUTH_RATE_LIMIT_WINDOW_MS
50
51
  const loginMaxAttempts = DEFAULT_CONFIG.AUTH_LOGIN_MAX_ATTEMPTS
@@ -54,7 +55,7 @@ export async function localUserPassController(app: FastifyInstance) {
54
55
  const resolveLocalUserpassProvider = () => AUTH_CONFIG.authProviders?.['local-userpass']
55
56
 
56
57
  try {
57
- await db.collection(resetPasswordCollection).createIndex(
58
+ await authDb.collection(resetPasswordCollection).createIndex(
58
59
  { createdAt: 1 },
59
60
  { expireAfterSeconds: resetPasswordTtlSeconds }
60
61
  )
@@ -63,7 +64,7 @@ export async function localUserPassController(app: FastifyInstance) {
63
64
  }
64
65
 
65
66
  try {
66
- await db.collection(refreshTokensCollection).createIndex(
67
+ await authDb.collection(refreshTokensCollection).createIndex(
67
68
  { expiresAt: 1 },
68
69
  { expireAfterSeconds: 0 }
69
70
  )
@@ -76,7 +77,7 @@ export async function localUserPassController(app: FastifyInstance) {
76
77
  extraArguments?: unknown[]
77
78
  ) => {
78
79
  const { resetPasswordConfig } = AUTH_CONFIG
79
- const authUser = await db.collection(authCollection!).findOne({
80
+ const authUser = await authDb.collection(authCollection!).findOne({
80
81
  email
81
82
  })
82
83
 
@@ -87,7 +88,7 @@ export async function localUserPassController(app: FastifyInstance) {
87
88
  const token = generateToken()
88
89
  const tokenId = generateToken()
89
90
 
90
- await db
91
+ await authDb
91
92
  ?.collection(resetPasswordCollection)
92
93
  .updateOne(
93
94
  { email },
@@ -194,7 +195,7 @@ export async function localUserPassController(app: FastifyInstance) {
194
195
  return
195
196
  }
196
197
 
197
- const existing = await db.collection(authCollection!).findOne({
198
+ const existing = await authDb.collection(authCollection!).findOne({
198
199
  confirmationToken: req.body.token,
199
200
  confirmationTokenId: req.body.tokenId
200
201
  }) as { _id: ObjectId; status?: string } | null
@@ -205,7 +206,7 @@ export async function localUserPassController(app: FastifyInstance) {
205
206
  }
206
207
 
207
208
  if (existing.status !== 'confirmed') {
208
- await db.collection(authCollection!).updateOne(
209
+ await authDb.collection(authCollection!).updateOne(
209
210
  { _id: existing._id },
210
211
  {
211
212
  $set: { status: 'confirmed' },
@@ -241,7 +242,7 @@ export async function localUserPassController(app: FastifyInstance) {
241
242
  res.status(429).send({ message: 'Too many requests' })
242
243
  return
243
244
  }
244
- const authUser = await db.collection(authCollection!).findOne({
245
+ const authUser = await authDb.collection(authCollection!).findOne({
245
246
  email: req.body.username
246
247
  })
247
248
 
@@ -260,7 +261,7 @@ export async function localUserPassController(app: FastifyInstance) {
260
261
 
261
262
  const user =
262
263
  user_id_field && userCollection
263
- ? await db!
264
+ ? await customUserDb
264
265
  .collection(userCollection)
265
266
  .findOne({ [user_id_field]: authUser._id.toString() })
266
267
  : {}
@@ -284,7 +285,7 @@ export async function localUserPassController(app: FastifyInstance) {
284
285
 
285
286
  const refreshToken = this.createRefreshToken(userWithCustomData)
286
287
  const refreshTokenHash = hashToken(refreshToken)
287
- await db.collection(refreshTokensCollection).insertOne({
288
+ await authDb.collection(refreshTokensCollection).insertOne({
288
289
  userId: authUser._id,
289
290
  tokenHash: refreshTokenHash,
290
291
  createdAt: new Date(),
@@ -382,7 +383,7 @@ export async function localUserPassController(app: FastifyInstance) {
382
383
  }
383
384
  const { token, tokenId, password } = req.body
384
385
 
385
- const resetRequest = await db
386
+ const resetRequest = await authDb
386
387
  ?.collection(resetPasswordCollection)
387
388
  .findOne({ token, tokenId })
388
389
 
@@ -396,11 +397,11 @@ export async function localUserPassController(app: FastifyInstance) {
396
397
  Date.now() - createdAt.getTime() > resetPasswordTtlSeconds * 1000
397
398
 
398
399
  if (isExpired) {
399
- await db?.collection(resetPasswordCollection).deleteOne({ _id: resetRequest._id })
400
+ await authDb?.collection(resetPasswordCollection).deleteOne({ _id: resetRequest._id })
400
401
  throw new Error(AUTH_ERRORS.INVALID_RESET_PARAMS)
401
402
  }
402
403
  const hashedPassword = await hashPassword(password)
403
- await db.collection(authCollection!).updateOne(
404
+ await authDb.collection(authCollection!).updateOne(
404
405
  { email: resetRequest.email },
405
406
  {
406
407
  $set: {
@@ -409,7 +410,7 @@ export async function localUserPassController(app: FastifyInstance) {
409
410
  }
410
411
  )
411
412
 
412
- await db?.collection(resetPasswordCollection).deleteOne({ _id: resetRequest._id })
413
+ await authDb?.collection(resetPasswordCollection).deleteOne({ _id: resetRequest._id })
413
414
  }
414
415
  )
415
416
  }
package/src/auth/utils.ts CHANGED
@@ -122,6 +122,7 @@ export enum AUTH_ERRORS {
122
122
 
123
123
  export interface AuthConfig {
124
124
  auth_collection?: string
125
+ auth_database?: string
125
126
  'api-key': ApiKey
126
127
  'local-userpass': LocalUserpass
127
128
  'custom-function': CustomFunction
package/src/constants.ts CHANGED
@@ -14,12 +14,12 @@ const monitEnabled = typeof monitEnabledEnv === 'string'
14
14
  : false
15
15
 
16
16
  const {
17
- database_name,
17
+ database_name = 'main',
18
18
  collection_name = 'users',
19
19
  user_id_field = 'id',
20
20
  on_user_creation_function_name
21
21
  } = loadCustomUserData()
22
- const { auth_collection = 'auth_users', ...configuration } = loadAuthConfig()
22
+ const { auth_collection = 'auth_users', auth_database, ...configuration } = loadAuthConfig()
23
23
 
24
24
  export const DEFAULT_CONFIG = {
25
25
  PORT: Number(process.env.PORT) || 3000,
@@ -62,6 +62,7 @@ export const DEFAULT_CONFIG = {
62
62
  export const API_VERSION = `/api/client/${DEFAULT_CONFIG.API_VERSION}`
63
63
  export const HTTPS_SCHEMA = DEFAULT_CONFIG.HTTPS_SCHEMA
64
64
  export const DB_NAME = database_name
65
+ export const AUTH_DB_NAME = auth_database ?? database_name
65
66
 
66
67
  type AuthProviders = Record<string, { disabled?: boolean; config?: unknown }>
67
68
  // TODO spostare nell'oggetto providers anche le altre configurazioni
@@ -3,6 +3,7 @@ import { TRIGGER_HANDLERS } from '../utils'
3
3
 
4
4
  jest.mock('../../../constants', () => ({
5
5
  AUTH_CONFIG: {},
6
+ AUTH_DB_NAME: 'test-auth-db',
6
7
  DB_NAME: 'test-db'
7
8
  }))
8
9
 
@@ -1,4 +1,4 @@
1
- import { AUTH_CONFIG, DB_NAME } from '../../constants'
1
+ import { AUTH_CONFIG, AUTH_DB_NAME } from '../../constants'
2
2
  import { services } from '../../services'
3
3
  import { Function, Functions } from '../functions/interface'
4
4
  import { ActivateTriggersParams } from './dtos'
@@ -36,7 +36,7 @@ export const activateTriggers = async ({
36
36
  config: {
37
37
  isAutoTrigger: true,
38
38
  collection: AUTH_CONFIG.authCollection ?? 'auth_users',
39
- database: DB_NAME,
39
+ database: AUTH_DB_NAME,
40
40
  full_document: true,
41
41
  full_document_before_change: false,
42
42
  match: {},
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs'
2
2
  import path from 'node:path'
3
3
  import cron from 'node-cron'
4
- import { AUTH_CONFIG, DB_NAME } from '../../constants'
4
+ import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME } from '../../constants'
5
5
  import { createEventId, sanitize } from '../../monitoring/utils'
6
6
  import { StateManager } from '../../state'
7
7
  import { readJsonContent } from '../../utils'
@@ -246,11 +246,11 @@ const handleAuthenticationTrigger = async ({
246
246
  const { database, isAutoTrigger, operation_types = [], operation_type } = config
247
247
  const providerFilter = normalizeProviders(config.providers ?? [])
248
248
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
249
- const collection = app.mongo.client.db(database || DB_NAME).collection(authCollection)
249
+ const collection = app.mongo.client.db(database || AUTH_DB_NAME).collection(authCollection)
250
250
  const operationCandidates = operation_type ? mapOpInverse[operation_type] : operation_types
251
251
  const normalizedOps = normalizeOperationTypes(operationCandidates)
252
252
  const baseMeta = {
253
- database: database || DB_NAME,
253
+ database: database || AUTH_DB_NAME,
254
254
  collection: authCollection,
255
255
  operationTypes: normalizedOps,
256
256
  providers: providerFilter,
@@ -277,6 +277,17 @@ const handleAuthenticationTrigger = async ({
277
277
  changeStream.on('error', (error) => {
278
278
  if (shouldIgnoreStreamError(error)) return
279
279
  console.error('Authentication trigger change stream error', error)
280
+ emitTriggerEvent({
281
+ status: 'error',
282
+ triggerName,
283
+ triggerType,
284
+ functionName,
285
+ meta: {
286
+ ...baseMeta,
287
+ event: 'CHANGE_STREAM'
288
+ },
289
+ error
290
+ })
280
291
  })
281
292
  changeStream.on('change', async function (change) {
282
293
  const operationType = change['operationType' as keyof typeof change] as
@@ -365,13 +376,6 @@ const handleAuthenticationTrigger = async ({
365
376
  updateDescription
366
377
  }
367
378
  try {
368
- emitTriggerEvent({
369
- status: 'fired',
370
- triggerName,
371
- triggerType,
372
- functionName,
373
- meta: { ...baseMeta, event: 'LOGOUT' }
374
- })
375
379
  await GenerateContext({
376
380
  args: [{ user: userData, ...op }],
377
381
  app,
@@ -383,6 +387,13 @@ const handleAuthenticationTrigger = async ({
383
387
  services,
384
388
  runAsSystem: true
385
389
  })
390
+ emitTriggerEvent({
391
+ status: 'fired',
392
+ triggerName,
393
+ triggerType,
394
+ functionName,
395
+ meta: { ...baseMeta, event: 'LOGOUT' }
396
+ })
386
397
  } catch (error) {
387
398
  emitTriggerEvent({
388
399
  status: 'error',
@@ -417,13 +428,6 @@ const handleAuthenticationTrigger = async ({
417
428
  updateDescription
418
429
  }
419
430
  try {
420
- emitTriggerEvent({
421
- status: 'fired',
422
- triggerName,
423
- triggerType,
424
- functionName,
425
- meta: { ...baseMeta, event: 'DELETE' }
426
- })
427
431
  await GenerateContext({
428
432
  args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
429
433
  app,
@@ -435,6 +439,13 @@ const handleAuthenticationTrigger = async ({
435
439
  services,
436
440
  runAsSystem: true
437
441
  })
442
+ emitTriggerEvent({
443
+ status: 'fired',
444
+ triggerName,
445
+ triggerType,
446
+ functionName,
447
+ meta: { ...baseMeta, event: 'DELETE' }
448
+ })
438
449
  } catch (error) {
439
450
  emitTriggerEvent({
440
451
  status: 'error',
@@ -471,13 +482,6 @@ const handleAuthenticationTrigger = async ({
471
482
  updateDescription
472
483
  }
473
484
  try {
474
- emitTriggerEvent({
475
- status: 'fired',
476
- triggerName,
477
- triggerType,
478
- functionName,
479
- meta: { ...baseMeta, event: 'UPDATE' }
480
- })
481
485
  await GenerateContext({
482
486
  args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
483
487
  app,
@@ -489,6 +493,13 @@ const handleAuthenticationTrigger = async ({
489
493
  services,
490
494
  runAsSystem: true
491
495
  })
496
+ emitTriggerEvent({
497
+ status: 'fired',
498
+ triggerName,
499
+ triggerType,
500
+ functionName,
501
+ meta: { ...baseMeta, event: 'UPDATE' }
502
+ })
492
503
  } catch (error) {
493
504
  emitTriggerEvent({
494
505
  status: 'error',
@@ -575,13 +586,6 @@ const handleAuthenticationTrigger = async ({
575
586
  }
576
587
 
577
588
  try {
578
- emitTriggerEvent({
579
- status: 'fired',
580
- triggerName,
581
- triggerType,
582
- functionName,
583
- meta: { ...baseMeta, event: 'CREATE' }
584
- })
585
589
  await GenerateContext({
586
590
  args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
587
591
  app,
@@ -593,6 +597,13 @@ const handleAuthenticationTrigger = async ({
593
597
  services,
594
598
  runAsSystem: true
595
599
  })
600
+ emitTriggerEvent({
601
+ status: 'fired',
602
+ triggerName,
603
+ triggerType,
604
+ functionName,
605
+ meta: { ...baseMeta, event: 'CREATE' }
606
+ })
596
607
  } catch (error) {
597
608
  emitTriggerEvent({
598
609
  status: 'error',
@@ -1,7 +1,7 @@
1
1
  import type { FastifyInstance } from 'fastify'
2
2
  import { ObjectId } from 'mongodb'
3
3
  import { loadAuthConfig, loadCustomUserData, PASSWORD_RULES } from '../../auth/utils'
4
- import { AUTH_CONFIG, DB_NAME } from '../../constants'
4
+ import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME } from '../../constants'
5
5
  import handleUserRegistration from '../../shared/handleUserRegistration'
6
6
  import { PROVIDER } from '../../shared/models/handleUserRegistration.model'
7
7
  import { hashPassword } from '../../utils/crypto'
@@ -47,7 +47,8 @@ export const registerUserRoutes = (app: FastifyInstance, deps: UserRoutesDeps) =
47
47
  const resolvedAuthLimit = Math.min(Number.isFinite(parsedAuthLimit) && parsedAuthLimit > 0 ? parsedAuthLimit : 100, 500)
48
48
  const resolvedCustomLimit = Math.min(Number.isFinite(parsedCustomLimit) && parsedCustomLimit > 0 ? parsedCustomLimit : 25, 500)
49
49
  const resolvedCustomPage = Math.max(Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1, 1)
50
- const db = app.mongo.client.db(DB_NAME)
50
+ const authDb = app.mongo.client.db(AUTH_DB_NAME)
51
+ const customDb = app.mongo.client.db(DB_NAME)
51
52
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
52
53
  const userCollection = AUTH_CONFIG.userCollection
53
54
 
@@ -69,7 +70,7 @@ export const registerUserRoutes = (app: FastifyInstance, deps: UserRoutesDeps) =
69
70
  ]
70
71
  }
71
72
  : {}
72
- const authItems = await db
73
+ const authItems = await authDb
73
74
  .collection(authCollection)
74
75
  .find(authFilter)
75
76
  .sort({ createdAt: -1, _id: -1 })
@@ -94,11 +95,11 @@ export const registerUserRoutes = (app: FastifyInstance, deps: UserRoutesDeps) =
94
95
  ]
95
96
  }
96
97
  : {}
97
- const total = await db.collection(userCollection).countDocuments(customFilter)
98
+ const total = await customDb.collection(userCollection).countDocuments(customFilter)
98
99
  const totalPages = Math.max(1, Math.ceil(total / Math.max(resolvedCustomLimit, 1)))
99
100
  const page = Math.min(resolvedCustomPage, totalPages)
100
101
  const skip = Math.max(0, (page - 1) * resolvedCustomLimit)
101
- const customItems = await db
102
+ const customItems = await customDb
102
103
  .collection(userCollection)
103
104
  .find(customFilter)
104
105
  .sort({ createdAt: -1, _id: -1 })
@@ -193,7 +194,7 @@ export const registerUserRoutes = (app: FastifyInstance, deps: UserRoutesDeps) =
193
194
  return { error: passwordError }
194
195
  }
195
196
 
196
- const db = app.mongo.client.db(DB_NAME)
197
+ const db = app.mongo.client.db(AUTH_DB_NAME)
197
198
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
198
199
  const selector: Record<string, unknown> = {}
199
200
 
@@ -231,7 +232,7 @@ export const registerUserRoutes = (app: FastifyInstance, deps: UserRoutesDeps) =
231
232
  app.patch(`${prefix}/api/users/:id/status`, async (req, reply) => {
232
233
  const params = req.params as { id: string }
233
234
  const body = req.body as { disabled?: boolean; status?: string; email?: string }
234
- const db = app.mongo.client.db(DB_NAME)
235
+ const db = app.mongo.client.db(AUTH_DB_NAME)
235
236
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
236
237
  const selector: Record<string, unknown> = {}
237
238
 
@@ -365,13 +365,17 @@ button.danger {
365
365
 
366
366
  .event-row {
367
367
  display: grid;
368
- grid-template-columns: 86px 90px 70px 160px 160px 1fr;
368
+ grid-template-columns: 170px 90px 70px 160px 160px 1fr;
369
369
  gap: 8px;
370
370
  padding: 4px 6px;
371
371
  border-bottom: 1px dashed rgba(26, 47, 34, 0.6);
372
372
  cursor: pointer;
373
373
  }
374
374
 
375
+ .event-row > div:first-child {
376
+ white-space: nowrap;
377
+ }
378
+
375
379
  .event-row.event-header {
376
380
  position: sticky;
377
381
  top: 0;
@@ -26,7 +26,7 @@
26
26
  wsStatus,
27
27
  clearEvents
28
28
  } = dom;
29
- const { formatTime, highlightJson } = utils;
29
+ const { formatDateTime, highlightJson } = utils;
30
30
  const { setActiveTab } = helpers;
31
31
 
32
32
  const isOptionsEvent = (event) => {
@@ -141,7 +141,7 @@
141
141
  row.className = 'event-row';
142
142
  row.dataset.id = event.id;
143
143
  const typeClass = event.type === 'error' ? 'error' : (event.type === 'warn' ? 'warn' : '');
144
- row.innerHTML = '<div>' + formatTime(event.ts) + '</div>' +
144
+ row.innerHTML = '<div>' + formatDateTime(event.ts) + '</div>' +
145
145
  '<div class="event-type ' + typeClass + '">' + (event.type || '-') + '</div>' +
146
146
  '<div class="event-run" title="' + (runMode || '-') + '">' + (runMode || '-') + '</div>' +
147
147
  '<div class="event-invoked" title="' + (invokedFrom || '-') + '">' + (invokedFrom || '-') + '</div>' +
@@ -52,7 +52,8 @@
52
52
  month: '2-digit',
53
53
  day: '2-digit',
54
54
  hour: '2-digit',
55
- minute: '2-digit'
55
+ minute: '2-digit',
56
+ second: '2-digit'
56
57
  });
57
58
  };
58
59
 
@@ -2,7 +2,7 @@ import fs from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import type { FastifyInstance, FastifyRequest } from 'fastify'
4
4
  import { ObjectId } from 'mongodb'
5
- import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../constants'
5
+ import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME, DEFAULT_CONFIG } from '../constants'
6
6
  import type { Rules } from '../features/rules/interface'
7
7
  import { getValidRule } from '../services/mongodb-atlas/utils'
8
8
  import { checkApplyWhen } from '../utils/roles/machines/utils'
@@ -380,7 +380,8 @@ export const resolveUserContext = async (
380
380
  if (!userId) return undefined
381
381
  const normalizedUserId = userId.trim()
382
382
 
383
- const db = app.mongo.client.db(DB_NAME)
383
+ const authDb = app.mongo.client.db(AUTH_DB_NAME)
384
+ const customDb = app.mongo.client.db(DB_NAME)
384
385
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
385
386
  const userCollection = AUTH_CONFIG.userCollection
386
387
  const userIdField = AUTH_CONFIG.user_id_field ?? 'id'
@@ -388,14 +389,14 @@ export const resolveUserContext = async (
388
389
  const authSelector = isObjectId
389
390
  ? { _id: new ObjectId(normalizedUserId) }
390
391
  : { id: normalizedUserId }
391
- const authUser = await db.collection(authCollection).findOne(authSelector)
392
+ const authUser = await authDb.collection(authCollection).findOne(authSelector)
392
393
 
393
394
  let customUser: Record<string, unknown> | null = null
394
395
  if (userCollection) {
395
396
  const customSelector = { [userIdField]: normalizedUserId }
396
- customUser = await db.collection(userCollection).findOne(customSelector)
397
+ customUser = await customDb.collection(userCollection).findOne(customSelector)
397
398
  if (!customUser && isObjectId) {
398
- customUser = await db.collection(userCollection).findOne({ _id: new ObjectId(normalizedUserId) })
399
+ customUser = await customDb.collection(userCollection).findOne({ _id: new ObjectId(normalizedUserId) })
399
400
  }
400
401
  }
401
402
 
@@ -1,5 +1,5 @@
1
1
  import { ObjectId } from "bson"
2
- import { AUTH_CONFIG, DB_NAME } from "../constants"
2
+ import { AUTH_CONFIG, AUTH_DB_NAME } from "../constants"
3
3
  import { emitServiceEvent } from "../services/monitoring"
4
4
  import { HandleUserDeletion } from "./models/handleUserDeletion.model"
5
5
 
@@ -33,7 +33,7 @@ const handleUserDeletion: HandleUserDeletion = (app, opt) => async ({ id, email
33
33
 
34
34
  const { authCollection } = AUTH_CONFIG
35
35
  const mongo = app?.mongo
36
- const db = mongo.client.db(DB_NAME)
36
+ const db = mongo.client.db(AUTH_DB_NAME)
37
37
  const collection = db.collection<Record<string, unknown>>(authCollection!)
38
38
  let query: Record<string, unknown>
39
39
 
@@ -1,8 +1,8 @@
1
- import { AUTH_CONFIG, DB_NAME } from "../constants"
1
+ import { AUTH_CONFIG, AUTH_DB_NAME } from "../constants"
2
+ import { emitServiceEvent } from "../services/monitoring"
2
3
  import { StateManager } from "../state"
3
4
  import { GenerateContext } from "../utils/context"
4
5
  import { generateToken, hashPassword } from "../utils/crypto"
5
- import { emitServiceEvent } from "../services/monitoring"
6
6
  import { HandleUserRegistration } from "./models/handleUserRegistration.model"
7
7
 
8
8
  /**
@@ -35,7 +35,7 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
35
35
  const runConfirmationFunction = localUserpassConfig?.runConfirmationFunction === true
36
36
  const confirmationFunctionName = localUserpassConfig?.confirmationFunctionName
37
37
  const mongo = app?.mongo
38
- const db = mongo.client.db(DB_NAME)
38
+ const db = mongo.client.db(AUTH_DB_NAME)
39
39
  const hashedPassword = await hashPassword(password)
40
40
 
41
41
  const existingUser = await db?.collection(authCollection!).findOne({ email })