@flowerforce/flowerbase 1.2.1-beta.2 → 1.2.1-beta.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.
Files changed (103) hide show
  1. package/README.md +37 -6
  2. package/dist/auth/controller.d.ts.map +1 -1
  3. package/dist/auth/controller.js +55 -4
  4. package/dist/auth/plugins/jwt.d.ts.map +1 -1
  5. package/dist/auth/plugins/jwt.js +52 -6
  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 +35 -25
  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 +159 -73
  18. package/dist/auth/providers/local-userpass/dtos.d.ts +17 -2
  19. package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -1
  20. package/dist/auth/utils.d.ts +76 -14
  21. package/dist/auth/utils.d.ts.map +1 -1
  22. package/dist/auth/utils.js +55 -61
  23. package/dist/constants.d.ts +12 -0
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/constants.js +16 -4
  26. package/dist/features/functions/controller.d.ts.map +1 -1
  27. package/dist/features/functions/controller.js +31 -12
  28. package/dist/features/functions/dtos.d.ts +3 -0
  29. package/dist/features/functions/dtos.d.ts.map +1 -1
  30. package/dist/features/functions/interface.d.ts +3 -0
  31. package/dist/features/functions/interface.d.ts.map +1 -1
  32. package/dist/features/functions/utils.d.ts +3 -2
  33. package/dist/features/functions/utils.d.ts.map +1 -1
  34. package/dist/features/functions/utils.js +19 -7
  35. package/dist/features/triggers/index.d.ts.map +1 -1
  36. package/dist/features/triggers/index.js +49 -7
  37. package/dist/features/triggers/interface.d.ts +1 -0
  38. package/dist/features/triggers/interface.d.ts.map +1 -1
  39. package/dist/features/triggers/utils.d.ts.map +1 -1
  40. package/dist/features/triggers/utils.js +67 -26
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +48 -13
  43. package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
  44. package/dist/services/mongodb-atlas/index.js +72 -2
  45. package/dist/services/mongodb-atlas/model.d.ts +3 -2
  46. package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
  47. package/dist/services/mongodb-atlas/utils.d.ts.map +1 -1
  48. package/dist/services/mongodb-atlas/utils.js +3 -1
  49. package/dist/shared/handleUserRegistration.d.ts.map +1 -1
  50. package/dist/shared/handleUserRegistration.js +66 -1
  51. package/dist/shared/models/handleUserRegistration.model.d.ts +2 -1
  52. package/dist/shared/models/handleUserRegistration.model.d.ts.map +1 -1
  53. package/dist/shared/models/handleUserRegistration.model.js +1 -0
  54. package/dist/utils/context/helpers.d.ts +6 -6
  55. package/dist/utils/context/helpers.d.ts.map +1 -1
  56. package/dist/utils/context/index.d.ts +1 -1
  57. package/dist/utils/context/index.d.ts.map +1 -1
  58. package/dist/utils/context/index.js +176 -9
  59. package/dist/utils/context/interface.d.ts +1 -1
  60. package/dist/utils/context/interface.d.ts.map +1 -1
  61. package/dist/utils/crypto/index.d.ts +1 -0
  62. package/dist/utils/crypto/index.d.ts.map +1 -1
  63. package/dist/utils/crypto/index.js +6 -2
  64. package/dist/utils/initializer/exposeRoutes.js +1 -1
  65. package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
  66. package/dist/utils/initializer/registerPlugins.js +12 -4
  67. package/dist/utils/roles/helpers.js +2 -1
  68. package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
  69. package/dist/utils/rules-matcher/utils.js +3 -0
  70. package/package.json +1 -2
  71. package/src/auth/controller.ts +71 -5
  72. package/src/auth/plugins/jwt.test.ts +93 -0
  73. package/src/auth/plugins/jwt.ts +67 -8
  74. package/src/auth/providers/anon-user/controller.ts +91 -0
  75. package/src/auth/providers/anon-user/dtos.ts +10 -0
  76. package/src/auth/providers/custom-function/controller.ts +40 -31
  77. package/src/auth/providers/custom-function/dtos.ts +5 -1
  78. package/src/auth/providers/local-userpass/controller.ts +211 -101
  79. package/src/auth/providers/local-userpass/dtos.ts +20 -2
  80. package/src/auth/utils.ts +66 -83
  81. package/src/constants.ts +14 -2
  82. package/src/features/functions/controller.ts +42 -12
  83. package/src/features/functions/dtos.ts +3 -0
  84. package/src/features/functions/interface.ts +3 -0
  85. package/src/features/functions/utils.ts +29 -8
  86. package/src/features/triggers/index.ts +44 -1
  87. package/src/features/triggers/interface.ts +1 -0
  88. package/src/features/triggers/utils.ts +89 -37
  89. package/src/index.ts +49 -13
  90. package/src/services/mongodb-atlas/__tests__/findOneAndUpdate.test.ts +95 -0
  91. package/src/services/mongodb-atlas/index.ts +665 -567
  92. package/src/services/mongodb-atlas/model.ts +16 -3
  93. package/src/services/mongodb-atlas/utils.ts +3 -0
  94. package/src/shared/handleUserRegistration.ts +83 -2
  95. package/src/shared/models/handleUserRegistration.model.ts +2 -1
  96. package/src/utils/__tests__/registerPlugins.test.ts +5 -1
  97. package/src/utils/context/index.ts +238 -18
  98. package/src/utils/context/interface.ts +1 -1
  99. package/src/utils/crypto/index.ts +5 -1
  100. package/src/utils/initializer/exposeRoutes.ts +1 -1
  101. package/src/utils/initializer/registerPlugins.ts +8 -0
  102. package/src/utils/roles/helpers.ts +3 -2
  103. package/src/utils/rules-matcher/utils.ts +3 -0
@@ -1,5 +1,13 @@
1
1
  import { FastifyInstance } from 'fastify'
2
- import { Collection, Document, FindCursor, WithId } from 'mongodb'
2
+ import {
3
+ Collection,
4
+ Document,
5
+ FindCursor,
6
+ FindOneAndUpdateOptions,
7
+ Filter as MongoFilter,
8
+ UpdateFilter,
9
+ WithId
10
+ } from 'mongodb'
3
11
  import { User } from '../../auth/dtos'
4
12
  import { Filter, Rules } from '../../features/rules/interface'
5
13
  import { Role } from '../../utils/roles/interface'
@@ -50,11 +58,16 @@ export type GetOperatorsFunction = (
50
58
  updateOne: (
51
59
  ...params: Parameters<Method<'updateOne'>>
52
60
  ) => ReturnType<Method<'updateOne'>>
61
+ findOneAndUpdate: (
62
+ filter: MongoFilter<Document>,
63
+ update: UpdateFilter<Document> | Document[],
64
+ options?: FindOneAndUpdateOptions
65
+ ) => Promise<Document | null>
53
66
  find: (...params: Parameters<Method<'find'>>) => FindCursor
54
67
  watch: (...params: Parameters<Method<'watch'>>) => ReturnType<Method<'watch'>>
55
68
  aggregate: (
56
69
  ...params: [...Parameters<Method<'aggregate'>>, isClient: boolean]
57
- ) => Promise<ReturnType<Method<'aggregate'>>>
70
+ ) => ReturnType<Method<'aggregate'>>
58
71
  insertMany: (
59
72
  ...params: Parameters<Method<'insertMany'>>
60
73
  ) => ReturnType<Method<'insertMany'>>
@@ -73,4 +86,4 @@ export enum CRUD_OPERATIONS {
73
86
  UPDATE = "UPDATE",
74
87
  DELETE = "DELETE"
75
88
 
76
- }
89
+ }
@@ -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 () => {
@@ -1,10 +1,116 @@
1
1
  import { createRequire } from 'node:module'
2
+ import path from 'node:path'
3
+ import { pathToFileURL } from 'node:url'
2
4
  import vm from 'vm'
3
5
  import { EJSON } from 'bson'
4
6
  import { StateManager } from '../../state'
5
7
  import { generateContextData } from './helpers'
6
8
  import { GenerateContextParams } from './interface'
7
9
 
10
+ const dynamicImport = new Function('specifier', 'return import(specifier)') as (
11
+ specifier: string
12
+ ) => Promise<Record<string, unknown>>
13
+
14
+ const transformImportsToRequire = (code: string): string => {
15
+ let importIndex = 0
16
+ const lines = code.split(/\r?\n/)
17
+
18
+ return lines
19
+ .map((line) => {
20
+ const trimmed = line.trim()
21
+
22
+ if (/^import\s+type\s+/.test(trimmed)) {
23
+ return ''
24
+ }
25
+
26
+ const sideEffectMatch = trimmed.match(/^import\s+['"]([^'"]+)['"]\s*;?$/)
27
+ if (sideEffectMatch) {
28
+ return `require('${sideEffectMatch[1]}')`
29
+ }
30
+
31
+ const match = trimmed.match(/^import\s+(.+?)\s+from\s+['"]([^'"]+)['"]\s*;?$/)
32
+ if (!match) return line
33
+
34
+ const [, importClause, source] = match
35
+ const clause = importClause.trim()
36
+
37
+ if (clause.startsWith('{') && clause.endsWith('}')) {
38
+ const named = clause.slice(1, -1).trim()
39
+ return `const { ${named} } = require('${source}')`
40
+ }
41
+
42
+ const namespaceMatch = clause.match(/^\*\s+as\s+(\w+)$/)
43
+ if (namespaceMatch) {
44
+ return `const ${namespaceMatch[1]} = require('${source}')`
45
+ }
46
+
47
+ if (clause.includes(',')) {
48
+ const [defaultPart, restRaw] = clause.split(',', 2)
49
+ const defaultName = defaultPart.trim()
50
+ const rest = restRaw.trim()
51
+ const tmpName = `__fb_import_${importIndex++}`
52
+ const linesOut = [`const ${tmpName} = require('${source}')`]
53
+
54
+ if (defaultName) {
55
+ linesOut.push(`const ${defaultName} = ${tmpName}`)
56
+ }
57
+
58
+ if (rest.startsWith('{') && rest.endsWith('}')) {
59
+ const named = rest.slice(1, -1).trim()
60
+ linesOut.push(`const { ${named} } = ${tmpName}`)
61
+ } else {
62
+ const nsMatch = rest.match(/^\*\s+as\s+(\w+)$/)
63
+ if (nsMatch) {
64
+ linesOut.push(`const ${nsMatch[1]} = ${tmpName}`)
65
+ }
66
+ }
67
+
68
+ return linesOut.join('\n')
69
+ }
70
+
71
+ return `const ${clause} = require('${source}')`
72
+ })
73
+ .join('\n')
74
+ }
75
+
76
+ const wrapEsmModule = (code: string): string => {
77
+ const prelude = [
78
+ 'const __fb_module = { exports: {} };',
79
+ 'let exports = __fb_module.exports;',
80
+ 'let module = __fb_module;',
81
+ 'const __fb_require = globalThis.__fb_require;',
82
+ 'const require = __fb_require;',
83
+ 'const __filename = globalThis.__fb_filename;',
84
+ 'const __dirname = globalThis.__fb_dirname;'
85
+ ].join('\n')
86
+
87
+ const trailer = [
88
+ 'globalThis.__fb_module = __fb_module;',
89
+ 'globalThis.__fb_exports = exports;'
90
+ ].join('\n')
91
+
92
+ return `${prelude}\n${code}\n${trailer}`
93
+ }
94
+
95
+ const resolveImportTarget = (specifier: string, customRequire: NodeRequire): string => {
96
+ try {
97
+ const resolved = customRequire.resolve(specifier)
98
+ if (resolved.startsWith('node:')) return resolved
99
+ if (path.isAbsolute(resolved)) {
100
+ return pathToFileURL(resolved).href
101
+ }
102
+ return resolved
103
+ } catch {
104
+ return specifier
105
+ }
106
+ }
107
+
108
+ const shouldFallbackFromVmModules = (error: unknown): boolean => {
109
+ if (!error || typeof error !== 'object') return false
110
+ const code = (error as { code?: string }).code
111
+ return code === 'ERR_VM_MODULES_DISABLED' || code === 'ERR_VM_MODULES_NOT_SUPPORTED'
112
+ }
113
+
8
114
  /**
9
115
  * > Used to generate the current context
10
116
  * @testable
@@ -28,7 +134,7 @@ export async function GenerateContext({
28
134
  deserializeArgs = true,
29
135
  enqueue,
30
136
  request
31
- }: GenerateContextParams) {
137
+ }: GenerateContextParams): Promise<unknown> {
32
138
  if (!currentFunction) return
33
139
 
34
140
  const functionsQueue = StateManager.select("functionsQueue")
@@ -48,28 +154,142 @@ export async function GenerateContext({
48
154
  request
49
155
  })
50
156
 
51
- try {
52
- const entryFile = require.main?.filename ?? process.cwd();
53
- const customRequire = createRequire(entryFile);
54
-
55
- vm.runInContext(functionToRun.code, vm.createContext({
56
- ...contextData, require: customRequire,
57
- exports,
58
- module,
59
- __filename: __filename,
60
- __dirname: __dirname
61
- }));
157
+ type ExportedFunction = (...args: unknown[]) => unknown
158
+ type SandboxModule = { exports: unknown }
159
+ type SandboxContext = vm.Context & {
160
+ exports?: unknown
161
+ module?: SandboxModule
162
+ __fb_module?: SandboxModule
163
+ __fb_exports?: unknown
164
+ __fb_require?: NodeRequire
165
+ __fb_filename?: string
166
+ __fb_dirname?: string
167
+ }
168
+
169
+ const isExportedFunction = (value: unknown): value is ExportedFunction =>
170
+ typeof value === 'function'
171
+
172
+ const getDefaultExport = (value: unknown): ExportedFunction | undefined => {
173
+ if (!value || typeof value !== 'object') return undefined
174
+ if (!('default' in value)) return undefined
175
+ const maybeDefault = (value as { default?: unknown }).default
176
+ return isExportedFunction(maybeDefault) ? maybeDefault : undefined
62
177
  }
63
- catch (e) {
64
- console.log(e)
178
+
179
+ const resolveExport = (ctx: SandboxContext): ExportedFunction | undefined => {
180
+ const moduleExports = ctx.module?.exports ?? ctx.__fb_module?.exports
181
+ if (isExportedFunction(moduleExports)) return moduleExports
182
+ const contextExports = ctx.exports ?? ctx.__fb_exports
183
+ if (isExportedFunction(contextExports)) return contextExports
184
+ return getDefaultExport(moduleExports) ?? getDefaultExport(contextExports)
185
+ }
186
+
187
+ const sandboxModule: SandboxModule = { exports: {} }
188
+
189
+ try {
190
+ const entryFile = require.main?.filename ?? process.cwd()
191
+ const customRequire = createRequire(entryFile)
192
+
193
+ const vmContext: SandboxContext = vm.createContext({
194
+ ...contextData,
195
+ require: customRequire,
196
+ exports: sandboxModule.exports,
197
+ module: sandboxModule,
198
+ __filename,
199
+ __dirname,
200
+ __fb_require: customRequire,
201
+ __fb_filename: __filename,
202
+ __fb_dirname: __dirname
203
+ }) as SandboxContext
204
+
205
+ const vmModules = vm as typeof vm & {
206
+ SourceTextModule?: typeof vm.SourceTextModule
207
+ SyntheticModule?: typeof vm.SyntheticModule
208
+ }
209
+ const hasStaticImport = /\bimport\s+/.test(functionToRun.code)
210
+ let usedVmModules = false
211
+
212
+ if (hasStaticImport && vmModules.SourceTextModule && vmModules.SyntheticModule) {
213
+ try {
214
+ const moduleCache = new Map<string, vm.Module>()
215
+
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
220
+
221
+ const namespace = await dynamicImport(importTarget)
222
+ const exportNames = Object.keys(namespace)
223
+ if ('default' in namespace && !exportNames.includes('default')) {
224
+ exportNames.push('default')
225
+ }
226
+
227
+ const syntheticModule = new vmModules.SyntheticModule(
228
+ exportNames,
229
+ function () {
230
+ for (const name of exportNames) {
231
+ this.setExport(name, namespace[name])
232
+ }
233
+ },
234
+ { context: vmContext, identifier: importTarget }
235
+ )
236
+
237
+ moduleCache.set(importTarget, syntheticModule)
238
+ return syntheticModule
239
+ }
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
+ )
256
+
257
+ await sourceModule.link(loadModule)
258
+ await sourceModule.evaluate()
259
+ usedVmModules = true
260
+ } catch (error) {
261
+ if (!shouldFallbackFromVmModules(error)) {
262
+ throw error
263
+ }
264
+ }
265
+ }
266
+
267
+ if (!usedVmModules) {
268
+ const codeToRun = functionToRun.code.includes('import ')
269
+ ? transformImportsToRequire(functionToRun.code)
270
+ : functionToRun.code
271
+ vm.runInContext(codeToRun, vmContext)
272
+ }
273
+
274
+ sandboxModule.exports = resolveExport(vmContext) ?? sandboxModule.exports
275
+ } catch (error) {
276
+ console.error(error)
277
+ throw error
65
278
  }
66
279
 
67
280
  if (deserializeArgs) {
68
- return await module.exports(...EJSON.deserialize(args))
281
+ return await (sandboxModule.exports as ExportedFunction)(
282
+ ...EJSON.deserialize(args)
283
+ )
69
284
  }
70
285
 
71
- return await module.exports(...args)
286
+ return await (sandboxModule.exports as ExportedFunction)(...args)
287
+ }
288
+ try {
289
+ const res = await functionsQueue.add(run, enqueue)
290
+ return res
291
+ } catch (error) {
292
+ console.error(error)
293
+ throw error
72
294
  }
73
- const res = await functionsQueue.add(run, enqueue)
74
- return res
75
295
  }
@@ -20,5 +20,5 @@ export interface GenerateContextParams {
20
20
 
21
21
  type ContextRequest = Pick<FastifyRequest, "ips" | "host" | "hostname" | "url" | "method" | "ip" | "id">
22
22
  export interface GenerateContextDataParams extends Omit<GenerateContextParams, 'args'> {
23
- GenerateContext: (params: GenerateContextParams) => Promise<void>
23
+ GenerateContext: (params: GenerateContextParams) => Promise<unknown>
24
24
  }
@@ -36,6 +36,10 @@ export const comparePassword = async (plaintext: string, storedPassword: string)
36
36
  * > Generate a random token
37
37
  * @param length -> the token length
38
38
  */
39
- export const generateToken = (length = 32) => {
39
+ export const generateToken = (length = 64) => {
40
40
  return crypto.randomBytes(length).toString('hex')
41
41
  }
42
+
43
+ export const hashToken = (token: string) => {
44
+ return crypto.createHash('sha256').update(token).digest('hex')
45
+ }
@@ -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
  }
@@ -34,7 +34,7 @@ const evaluateComplexExpression = async (
34
34
  condition: [string, Record<string, any>],
35
35
  params: MachineContext['params'],
36
36
  user: MachineContext['user']
37
- ) => {
37
+ ): Promise<boolean> => {
38
38
  const [key, config] = condition
39
39
 
40
40
  const functionConfig = config['%function']
@@ -67,5 +67,6 @@ const evaluateComplexExpression = async (
67
67
  functionsList,
68
68
  services
69
69
  })
70
- return key === '%%true' ? response : !response
70
+ const isTruthy = Boolean(response)
71
+ return key === '%%true' ? isTruthy : !isTruthy
71
72
  }
@@ -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
  }