@flowerforce/flowerbase 1.2.1-beta.9 → 1.3.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 (82) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +9 -3
  3. package/dist/auth/controller.d.ts.map +1 -1
  4. package/dist/auth/controller.js +2 -2
  5. package/dist/auth/plugins/jwt.js +3 -3
  6. package/dist/auth/providers/anon-user/controller.d.ts +8 -0
  7. package/dist/auth/providers/anon-user/controller.d.ts.map +1 -0
  8. package/dist/auth/providers/anon-user/controller.js +90 -0
  9. package/dist/auth/providers/anon-user/dtos.d.ts +10 -0
  10. package/dist/auth/providers/anon-user/dtos.d.ts.map +1 -0
  11. package/dist/auth/providers/anon-user/dtos.js +2 -0
  12. package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
  13. package/dist/auth/providers/custom-function/controller.js +32 -35
  14. package/dist/auth/providers/custom-function/dtos.d.ts +4 -1
  15. package/dist/auth/providers/custom-function/dtos.d.ts.map +1 -1
  16. package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
  17. package/dist/auth/providers/local-userpass/controller.js +41 -33
  18. package/dist/auth/providers/local-userpass/dtos.d.ts +6 -0
  19. package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -1
  20. package/dist/auth/utils.d.ts +24 -1
  21. package/dist/auth/utils.d.ts.map +1 -1
  22. package/dist/auth/utils.js +13 -1
  23. package/dist/constants.d.ts +4 -0
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/constants.js +7 -3
  26. package/dist/features/functions/controller.d.ts.map +1 -1
  27. package/dist/features/functions/controller.js +27 -11
  28. package/dist/features/functions/utils.d.ts +1 -1
  29. package/dist/features/triggers/index.d.ts.map +1 -1
  30. package/dist/features/triggers/index.js +49 -7
  31. package/dist/features/triggers/interface.d.ts +1 -0
  32. package/dist/features/triggers/interface.d.ts.map +1 -1
  33. package/dist/features/triggers/utils.d.ts.map +1 -1
  34. package/dist/features/triggers/utils.js +67 -26
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +18 -12
  37. package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
  38. package/dist/services/mongodb-atlas/index.js +2 -2
  39. package/dist/services/mongodb-atlas/model.d.ts +2 -2
  40. package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
  41. package/dist/services/mongodb-atlas/utils.d.ts.map +1 -1
  42. package/dist/services/mongodb-atlas/utils.js +3 -1
  43. package/dist/shared/handleUserRegistration.d.ts.map +1 -1
  44. package/dist/shared/handleUserRegistration.js +66 -1
  45. package/dist/shared/models/handleUserRegistration.model.d.ts +2 -1
  46. package/dist/shared/models/handleUserRegistration.model.d.ts.map +1 -1
  47. package/dist/shared/models/handleUserRegistration.model.js +1 -0
  48. package/dist/utils/context/helpers.d.ts +5 -5
  49. package/dist/utils/context/helpers.d.ts.map +1 -1
  50. package/dist/utils/context/index.d.ts.map +1 -1
  51. package/dist/utils/context/index.js +12 -14
  52. package/dist/utils/initializer/exposeRoutes.js +1 -1
  53. package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
  54. package/dist/utils/initializer/registerPlugins.js +12 -4
  55. package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
  56. package/dist/utils/rules-matcher/utils.js +3 -0
  57. package/package.json +1 -1
  58. package/src/auth/controller.ts +5 -2
  59. package/src/auth/plugins/jwt.ts +5 -5
  60. package/src/auth/providers/anon-user/controller.ts +91 -0
  61. package/src/auth/providers/anon-user/dtos.ts +10 -0
  62. package/src/auth/providers/custom-function/controller.ts +34 -39
  63. package/src/auth/providers/custom-function/dtos.ts +5 -1
  64. package/src/auth/providers/local-userpass/controller.ts +56 -43
  65. package/src/auth/providers/local-userpass/dtos.ts +7 -0
  66. package/src/auth/utils.ts +22 -1
  67. package/src/constants.ts +5 -1
  68. package/src/features/functions/controller.ts +27 -11
  69. package/src/features/triggers/index.ts +44 -1
  70. package/src/features/triggers/interface.ts +1 -0
  71. package/src/features/triggers/utils.ts +89 -37
  72. package/src/index.ts +18 -12
  73. package/src/services/mongodb-atlas/index.ts +654 -654
  74. package/src/services/mongodb-atlas/model.ts +2 -2
  75. package/src/services/mongodb-atlas/utils.ts +3 -0
  76. package/src/shared/handleUserRegistration.ts +83 -2
  77. package/src/shared/models/handleUserRegistration.model.ts +2 -1
  78. package/src/utils/__tests__/registerPlugins.test.ts +5 -1
  79. package/src/utils/context/index.ts +32 -36
  80. package/src/utils/initializer/exposeRoutes.ts +1 -1
  81. package/src/utils/initializer/registerPlugins.ts +8 -0
  82. package/src/utils/rules-matcher/utils.ts +3 -0
@@ -2,9 +2,9 @@ import { FastifyInstance } from 'fastify'
2
2
  import {
3
3
  Collection,
4
4
  Document,
5
- Filter as MongoFilter,
6
5
  FindCursor,
7
6
  FindOneAndUpdateOptions,
7
+ Filter as MongoFilter,
8
8
  UpdateFilter,
9
9
  WithId
10
10
  } from 'mongodb'
@@ -67,7 +67,7 @@ export type GetOperatorsFunction = (
67
67
  watch: (...params: Parameters<Method<'watch'>>) => ReturnType<Method<'watch'>>
68
68
  aggregate: (
69
69
  ...params: [...Parameters<Method<'aggregate'>>, isClient: boolean]
70
- ) => Promise<ReturnType<Method<'aggregate'>>>
70
+ ) => ReturnType<Method<'aggregate'>>
71
71
  insertMany: (
72
72
  ...params: Parameters<Method<'insertMany'>>
73
73
  ) => ReturnType<Method<'insertMany'>>
@@ -23,12 +23,14 @@ export const getValidRule = <T extends Role | Filter>({
23
23
  record = null
24
24
  }: GetValidRuleParams<T>) => {
25
25
  if (!filters.length) return []
26
+ const rootRecord = record ?? null
26
27
 
27
28
  return filters.filter((f) => {
28
29
  if (Object.keys(f.apply_when).length === 0) return true
29
30
 
30
31
  // expandQuery traduce i placeholder (%%user, %%true)
31
32
  const conditions = expandQuery(f.apply_when, {
33
+ '%%root': rootRecord,
32
34
  '%%user': user,
33
35
  '%%true': true
34
36
  /** values */
@@ -40,6 +42,7 @@ export const getValidRule = <T extends Role | Filter>({
40
42
  conditions as Parameters<typeof rulesMatcherUtils.checkRule>[0],
41
43
  {
42
44
  ...(record ?? {}),
45
+ '%%root': rootRecord,
43
46
  '%%user': user,
44
47
  '%%true': true
45
48
  },
@@ -1,5 +1,7 @@
1
1
  import { AUTH_CONFIG, DB_NAME } from "../constants"
2
- import { hashPassword } from "../utils/crypto"
2
+ import { StateManager } from "../state"
3
+ import { GenerateContext } from "../utils/context"
4
+ import { generateToken, hashPassword } from "../utils/crypto"
3
5
  import { HandleUserRegistration } from "./models/handleUserRegistration.model"
4
6
 
5
7
  /**
@@ -17,6 +19,10 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
17
19
  }
18
20
 
19
21
  const { authCollection } = AUTH_CONFIG
22
+ const localUserpassConfig = AUTH_CONFIG.localUserpassConfig
23
+ const autoConfirm = localUserpassConfig?.autoConfirm === true
24
+ const runConfirmationFunction = localUserpassConfig?.runConfirmationFunction === true
25
+ const confirmationFunctionName = localUserpassConfig?.confirmationFunctionName
20
26
  const mongo = app?.mongo
21
27
  const db = mongo.client.db(DB_NAME)
22
28
  const hashedPassword = await hashPassword(password)
@@ -29,7 +35,7 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
29
35
  const result = await db?.collection(authCollection!).insertOne({
30
36
  email,
31
37
  password: hashedPassword,
32
- status: skipUserCheck ? 'confirmed' : 'pending',
38
+ status: skipUserCheck || autoConfirm ? 'confirmed' : 'pending',
33
39
  createdAt: new Date(),
34
40
  custom_data: {
35
41
  // TODO: aggiungere dati personalizzati alla registrazione
@@ -58,6 +64,81 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
58
64
  }
59
65
  )
60
66
 
67
+ if (!result?.insertedId || skipUserCheck || autoConfirm) {
68
+ return result
69
+ }
70
+
71
+ if (!runConfirmationFunction) {
72
+ throw new Error('Missing confirmation function')
73
+ }
74
+
75
+ if (!confirmationFunctionName) {
76
+ throw new Error('Missing confirmation function name')
77
+ }
78
+
79
+ const functionsList = StateManager.select('functions')
80
+ const services = StateManager.select('services')
81
+ const confirmationFunction = functionsList[confirmationFunctionName]
82
+ if (!confirmationFunction) {
83
+ throw new Error(`Confirmation function not found: ${confirmationFunctionName}`)
84
+ }
85
+
86
+ const token = generateToken()
87
+ const tokenId = generateToken()
88
+ await db?.collection(authCollection!).updateOne(
89
+ { _id: result.insertedId },
90
+ {
91
+ $set: {
92
+ confirmationToken: token,
93
+ confirmationTokenId: tokenId
94
+ }
95
+ }
96
+ )
97
+
98
+ type ConfirmationResult = { status?: 'success' | 'pending' | 'fail' }
99
+ let confirmationStatus: ConfirmationResult['status'] = 'fail'
100
+ try {
101
+ const response = await GenerateContext({
102
+ args: [{
103
+ token,
104
+ tokenId,
105
+ username: email
106
+ }],
107
+ app,
108
+ rules: {},
109
+ user: {},
110
+ currentFunction: confirmationFunction,
111
+ functionsList,
112
+ services,
113
+ runAsSystem: true
114
+ }) as ConfirmationResult
115
+ confirmationStatus = response?.status ?? 'fail'
116
+ } catch {
117
+ confirmationStatus = 'fail'
118
+ }
119
+
120
+ if (confirmationStatus === 'success') {
121
+ await db?.collection(authCollection!).updateOne(
122
+ { _id: result.insertedId },
123
+ {
124
+ $set: { status: 'confirmed' },
125
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
126
+ }
127
+ )
128
+ return result
129
+ }
130
+
131
+ if (confirmationStatus === 'pending') {
132
+ return result
133
+ }
134
+
135
+ await db?.collection(authCollection!).updateOne(
136
+ { _id: result.insertedId },
137
+ {
138
+ $set: { status: 'failed' },
139
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
140
+ }
141
+ )
61
142
  return result
62
143
 
63
144
  }
@@ -28,5 +28,6 @@ export type HandleUserRegistration = (
28
28
 
29
29
  export enum PROVIDER {
30
30
  LOCAL_USERPASS = "local-userpass",
31
- CUSTOM_FUNCTION = "custom-function"
31
+ CUSTOM_FUNCTION = "custom-function",
32
+ ANON_USER = "anon-user"
32
33
  }
@@ -3,6 +3,7 @@ import fastifyMongodb from '@fastify/mongodb'
3
3
  import { authController } from '../../auth/controller'
4
4
  import jwtAuthPlugin from '../../auth/plugins/jwt'
5
5
  import fastifyRawBody from 'fastify-raw-body'
6
+ import { anonUserController } from '../../auth/providers/anon-user/controller'
6
7
  import { customFunctionController } from '../../auth/providers/custom-function/controller'
7
8
  import { localUserPassController } from '../../auth/providers/local-userpass/controller'
8
9
  import { Functions } from '../../features/functions/interface'
@@ -36,7 +37,7 @@ describe('registerPlugins', () => {
36
37
  })
37
38
 
38
39
  // Check Plugins Registration
39
- expect(registerMock).toHaveBeenCalledTimes(7)
40
+ expect(registerMock).toHaveBeenCalledTimes(8)
40
41
  expect(registerMock).toHaveBeenCalledWith(cors, {
41
42
  origin: '*',
42
43
  methods: ['POST', 'GET']
@@ -63,6 +64,9 @@ describe('registerPlugins', () => {
63
64
  expect(registerMock).toHaveBeenCalledWith(customFunctionController, {
64
65
  prefix: `${MOCKED_API_VERSION}/app/:appId/auth/providers/custom-function`
65
66
  })
67
+ expect(registerMock).toHaveBeenCalledWith(anonUserController, {
68
+ prefix: `${MOCKED_API_VERSION}/app/:appId/auth/providers/anon-user`
69
+ })
66
70
  })
67
71
 
68
72
  it('should handle errors in the catch block', async () => {
@@ -214,11 +214,11 @@ export async function GenerateContext({
214
214
  const moduleCache = new Map<string, vm.Module>()
215
215
 
216
216
  const loadModule = async (specifier: string): Promise<vm.Module> => {
217
- const importTarget = resolveImportTarget(specifier, customRequire)
218
- const cached = moduleCache.get(importTarget)
219
- if (cached) return cached
217
+ const importTarget = resolveImportTarget(specifier, customRequire)
218
+ const cached = moduleCache.get(importTarget)
219
+ if (cached) return cached
220
220
 
221
- const namespace = await dynamicImport(importTarget)
221
+ const namespace = await dynamicImport(importTarget)
222
222
  const exportNames = Object.keys(namespace)
223
223
  if ('default' in namespace && !exportNames.includes('default')) {
224
224
  exportNames.push('default')
@@ -234,34 +234,25 @@ export async function GenerateContext({
234
234
  { context: vmContext, identifier: importTarget }
235
235
  )
236
236
 
237
- moduleCache.set(importTarget, syntheticModule)
238
- return syntheticModule
239
- }
240
-
241
- const importModuleDynamically = (async (
242
- specifier: string
243
- ): Promise<vm.Module> => {
244
- const module = await loadModule(specifier)
245
- if (module.status === 'unlinked') {
246
- await module.link(loadModule)
247
- }
248
- if (module.status === 'linked') {
249
- await module.evaluate()
237
+ moduleCache.set(importTarget, syntheticModule)
238
+ return syntheticModule
250
239
  }
251
- return module
252
- }) as unknown as vm.ScriptOptions['importModuleDynamically']
253
-
254
- const sourceModule = new vmModules.SourceTextModule(
255
- wrapEsmModule(functionToRun.code),
256
- {
257
- context: vmContext,
258
- identifier: entryFile,
259
- initializeImportMeta: (meta) => {
260
- meta.url = pathToFileURL(entryFile).href
261
- },
262
- importModuleDynamically
263
- }
264
- )
240
+
241
+ const importModuleDynamically =
242
+ ((specifier: string) => loadModule(specifier) as unknown as vm.Module) as unknown as
243
+ vm.SourceTextModuleOptions['importModuleDynamically']
244
+
245
+ const sourceModule = new vmModules.SourceTextModule(
246
+ wrapEsmModule(functionToRun.code),
247
+ {
248
+ context: vmContext,
249
+ identifier: entryFile,
250
+ initializeImportMeta: (meta) => {
251
+ meta.url = pathToFileURL(entryFile).href
252
+ },
253
+ importModuleDynamically
254
+ }
255
+ )
265
256
 
266
257
  await sourceModule.link(loadModule)
267
258
  await sourceModule.evaluate()
@@ -281,9 +272,9 @@ export async function GenerateContext({
281
272
  }
282
273
 
283
274
  sandboxModule.exports = resolveExport(vmContext) ?? sandboxModule.exports
284
- }
285
- catch (e) {
286
- console.log(e)
275
+ } catch (error) {
276
+ console.error(error)
277
+ throw error
287
278
  }
288
279
 
289
280
  if (deserializeArgs) {
@@ -294,6 +285,11 @@ export async function GenerateContext({
294
285
 
295
286
  return await (sandboxModule.exports as ExportedFunction)(...args)
296
287
  }
297
- const res = await functionsQueue.add(run, enqueue)
298
- return res
288
+ try {
289
+ const res = await functionsQueue.add(run, enqueue)
290
+ return res
291
+ } catch (error) {
292
+ console.error(error)
293
+ throw error
294
+ }
299
295
  }
@@ -18,7 +18,7 @@ export const exposeRoutes = async (fastify: FastifyInstance) => {
18
18
  const headerHost = req.headers.host ?? 'localhost:3000'
19
19
  const hostname = headerHost.split(':')[0]
20
20
  const port = DEFAULT_CONFIG?.PORT ?? 3000
21
- const host = `${hostname}:${port}`
21
+ const host = port === 8080 ? hostname : `${hostname}:${port}`
22
22
  const wsSchema = 'wss'
23
23
 
24
24
  return {
@@ -5,6 +5,7 @@ import fastifyRawBody from 'fastify-raw-body'
5
5
  import { CorsConfig } from '../../'
6
6
  import { authController } from '../../auth/controller'
7
7
  import jwtAuthPlugin from '../../auth/plugins/jwt'
8
+ import { anonUserController } from '../../auth/providers/anon-user/controller'
8
9
  import { customFunctionController } from '../../auth/providers/custom-function/controller'
9
10
  import { localUserPassController } from '../../auth/providers/local-userpass/controller'
10
11
  import { API_VERSION } from '../../constants'
@@ -133,6 +134,13 @@ const getRegisterConfig = async ({
133
134
  options: {
134
135
  prefix: `${API_VERSION}/app/:appId/auth/providers/custom-function`
135
136
  }
137
+ },
138
+ {
139
+ pluginName: 'anonUserController',
140
+ plugin: anonUserController,
141
+ options: {
142
+ prefix: `${API_VERSION}/app/:appId/auth/providers/anon-user`
143
+ }
136
144
  }
137
145
  ] as RegisterConfig[]
138
146
  }
@@ -154,6 +154,9 @@ const rulesMatcherUtils: RulesMatcherUtils = {
154
154
  },
155
155
  forceArray: (a) => (Array.isArray(a) ? a : [a]),
156
156
  getPath: (path, prefix) => {
157
+ if (typeof path !== 'string' || path.length === 0) {
158
+ return ''
159
+ }
157
160
  if (path.indexOf('^') === 0) {
158
161
  return _trimStart(path, '^')
159
162
  }