@driveflux/auth 4.0.88 → 4.0.90

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 (46) hide show
  1. package/dist/AuthProvider.d.ts.map +1 -1
  2. package/dist/AuthProvider.js +60 -79
  3. package/dist/authorization/define.js +28 -57
  4. package/dist/authorization/fields/index.js +7 -4
  5. package/dist/authorization/helpers.js +8 -10
  6. package/dist/authorization/index.js +6 -6
  7. package/dist/authorization/permissions-list.js +7 -5
  8. package/dist/authorization/quick.js +1 -1
  9. package/dist/authorization/roles/admin/business-development-executive.js +7 -20
  10. package/dist/authorization/roles/admin/ceo.js +2 -4
  11. package/dist/authorization/roles/admin/common.d.ts.map +1 -1
  12. package/dist/authorization/roles/admin/common.js +3 -5
  13. package/dist/authorization/roles/admin/concierge.js +10 -35
  14. package/dist/authorization/roles/admin/customer-success-executive.js +10 -40
  15. package/dist/authorization/roles/admin/data-analyst.js +4 -7
  16. package/dist/authorization/roles/admin/designer.js +4 -7
  17. package/dist/authorization/roles/admin/engineer.js +4 -7
  18. package/dist/authorization/roles/admin/finance-executive.js +4 -11
  19. package/dist/authorization/roles/admin/head-of-business-development.js +4 -14
  20. package/dist/authorization/roles/admin/head-of-data-analytics.js +4 -14
  21. package/dist/authorization/roles/admin/head-of-engineering.js +6 -17
  22. package/dist/authorization/roles/admin/head-of-finance.js +3 -8
  23. package/dist/authorization/roles/admin/head-of-human-resources.js +5 -13
  24. package/dist/authorization/roles/admin/head-of-marketing.js +5 -17
  25. package/dist/authorization/roles/admin/head-of-operations.js +3 -8
  26. package/dist/authorization/roles/admin/head-of-product.js +6 -17
  27. package/dist/authorization/roles/admin/head-of-sales.js +5 -17
  28. package/dist/authorization/roles/admin/human-resources-executive.js +5 -12
  29. package/dist/authorization/roles/admin/marketing-executive.js +4 -7
  30. package/dist/authorization/roles/admin/product-manager.js +4 -7
  31. package/dist/authorization/roles/admin/sales-executive.js +8 -24
  32. package/dist/authorization/roles/consumer/business-admin.js +6 -19
  33. package/dist/authorization/roles/consumer/business-user.js +6 -18
  34. package/dist/authorization/roles/consumer/member.js +6 -16
  35. package/dist/authorization/types.js +1 -1
  36. package/dist/authorization/update-user-permissions.js +15 -22
  37. package/dist/authorization/utils.js +11 -26
  38. package/dist/server/authenticate-user.js +7 -11
  39. package/dist/server/cors.js +12 -23
  40. package/dist/server/credentials-provider.js +2 -2
  41. package/dist/server/next-auth.d.ts +12 -1
  42. package/dist/server/next-auth.d.ts.map +1 -1
  43. package/dist/server/next-auth.js +109 -104
  44. package/dist/server/prisma-adapter.js +52 -88
  45. package/dist/server/verfiy-token.js +24 -39
  46. package/package.json +16 -16
@@ -8,7 +8,7 @@ import { nanoid } from 'nanoid';
8
8
  import CredentialsProvider from 'next-auth/providers/credentials';
9
9
  import FacebookProvider from 'next-auth/providers/facebook';
10
10
  import GoogleProvider from 'next-auth/providers/google';
11
- import { AUTH_COOKIE_CALLBACK_URL, AUTH_COOKIE_CSRF_TOKEN, AUTH_COOKIE_NONCE, AUTH_COOKIE_PKCE_CODE_VERIFIER, AUTH_COOKIE_SESSION_TOKEN, AUTH_COOKIE_STATE } from '../constants.js';
11
+ import { AUTH_COOKIE_CALLBACK_URL, AUTH_COOKIE_CSRF_TOKEN, AUTH_COOKIE_NONCE, AUTH_COOKIE_PKCE_CODE_VERIFIER, AUTH_COOKIE_SESSION_TOKEN, AUTH_COOKIE_STATE, } from '../constants.js';
12
12
  import { extractDefault } from '../default.js';
13
13
  import { translations } from '../translations.js';
14
14
  import { authenticateUser } from './authenticate-user.js';
@@ -21,79 +21,80 @@ const nextAuthUrl = process.env.NEXTAUTH_URL;
21
21
  if (!nextAuthUrl) {
22
22
  throw new Error('NEXTAUTH_URL is not set');
23
23
  }
24
- export const generateSessionToken = async (user)=>{
24
+ export const generateSessionToken = async (user) => {
25
25
  const secret = new TextEncoder().encode(config.auth.jwtSecret);
26
26
  const alg = 'HS256';
27
27
  const token = await new SignJWT({
28
- roles: user.groups
29
- }).setProtectedHeader({
30
- alg
31
- }).setIssuedAt().setSubject(user.id).setIssuer('flux.website').setAudience('flux.website').sign(secret);
28
+ roles: user.groups,
29
+ })
30
+ .setProtectedHeader({ alg })
31
+ .setIssuedAt()
32
+ .setSubject(user.id)
33
+ .setIssuer('flux.website')
34
+ .setAudience('flux.website')
35
+ .sign(secret);
32
36
  return token.toString();
33
37
  };
34
- export const getCredentialsOptions = ()=>{
38
+ export const getCredentialsOptions = () => {
35
39
  return {
36
40
  name: 'Credentials',
37
41
  credentials: {
38
- login: {
39
- label: translations.email,
40
- type: 'text'
41
- },
42
- password: {
43
- label: translations.password,
44
- type: 'password'
45
- }
42
+ login: { label: translations.email, type: 'text' },
43
+ password: { label: translations.password, type: 'password' },
46
44
  },
47
- async authorize (credentials) {
45
+ async authorize(credentials) {
48
46
  if (!credentials) {
49
47
  return null;
50
48
  }
51
49
  const authResult = await authenticateUser(credentials);
52
50
  return authResult.ok ? authResult.val : null;
53
- }
51
+ },
54
52
  };
55
53
  };
56
54
  export const authOptions = {
57
55
  adapter,
58
56
  providers: [
59
- ...config.auth.google ? [
60
- extractDefault(GoogleProvider)({
61
- ...config.auth.google,
62
- allowDangerousEmailAccountLinking: true
63
- })
64
- ] : [],
65
- ...config.auth.facebook ? [
66
- extractDefault(FacebookProvider)({
67
- ...config.auth.facebook,
68
- allowDangerousEmailAccountLinking: true
69
- })
70
- ] : [],
71
- extractDefault(CredentialsProvider)(getCredentialsOptions())
57
+ ...(config.auth.google
58
+ ? [
59
+ extractDefault(GoogleProvider)({
60
+ ...config.auth.google,
61
+ allowDangerousEmailAccountLinking: true,
62
+ }),
63
+ ]
64
+ : []),
65
+ ...(config.auth.facebook
66
+ ? [
67
+ extractDefault(FacebookProvider)({
68
+ ...config.auth.facebook,
69
+ allowDangerousEmailAccountLinking: true,
70
+ }),
71
+ ]
72
+ : []),
73
+ extractDefault(CredentialsProvider)(getCredentialsOptions()),
72
74
  ],
73
75
  callbacks: {
74
- async signIn ({ account, profile }) {
75
- const processName = (profile)=>{
76
+ async signIn({ account, profile }) {
77
+ const processName = (profile) => {
76
78
  if (profile?.given_name || profile?.family_name) {
77
79
  return {
78
80
  firstName: profile?.given_name || '',
79
- lastName: profile?.family_name || ''
81
+ lastName: profile?.family_name || '',
80
82
  };
81
83
  }
82
84
  if (!profile?.name) {
83
85
  return {
84
86
  firstName: '',
85
- lastName: ''
87
+ lastName: '',
86
88
  };
87
89
  }
88
- const r = (str)=>str.replace(/\s+/g, ' ').trim();
90
+ const r = (str) => str.replace(/\s+/g, ' ').trim();
89
91
  const names = profile?.name.trim();
90
92
  const nameSegments = names.split(' ');
91
- const firstName = r(nameSegments.filter((_s, i)=>i !== nameSegments?.length - 1).join(' '));
93
+ const firstName = r(nameSegments
94
+ .filter((_s, i) => i !== nameSegments?.length - 1)
95
+ .join(' '));
92
96
  const lastName = r(nameSegments?.[nameSegments?.length - 1]);
93
- return {
94
- firstName,
95
- lastName
96
- };
97
+ return { firstName, lastName };
97
98
  };
98
99
  if (account?.provider === 'google') {
99
100
  if (!profile?.email) {
@@ -104,7 +105,7 @@ export const authOptions = {
104
105
  // const password = await bcrypt.hash(nanoid(), nanoid())
105
106
  await prisma.user.upsert({
106
107
  where: {
107
- email: profile.email
108
+ email: profile.email,
108
109
  },
109
110
  create: {
110
111
  id: generateId('User'),
@@ -114,12 +115,13 @@ export const authOptions = {
114
115
  password,
115
116
  registrationComplete: false,
116
117
  metadata: {
117
- signupProvider: 'google'
118
- }
118
+ signupProvider: 'google',
119
+ },
119
120
  },
120
- update: {}
121
+ update: {},
121
122
  });
122
- } else if (account?.provider === 'facebook') {
123
+ }
124
+ else if (account?.provider === 'facebook') {
123
125
  if (!profile?.email) {
124
126
  throw new Error('Unauthenticated');
125
127
  }
@@ -127,7 +129,7 @@ export const authOptions = {
127
129
  const password = `${nanoid()}-${nanoid()}`;
128
130
  await prisma.user.upsert({
129
131
  where: {
130
- email: profile.email
132
+ email: profile.email,
131
133
  },
132
134
  create: {
133
135
  id: generateId('User'),
@@ -137,43 +139,46 @@ export const authOptions = {
137
139
  password,
138
140
  registrationComplete: false,
139
141
  metadata: {
140
- signupProvider: 'facebook'
141
- }
142
+ signupProvider: 'facebook',
143
+ },
142
144
  },
143
- update: {}
145
+ update: {},
144
146
  });
145
147
  }
146
148
  return true;
147
149
  },
148
- async session ({ session, user, trigger }) {
149
- const { password, permissions, stripeCustomerId, ...newUser } = {
150
- ...user
151
- };
150
+ async session({ session, user, trigger }) {
151
+ const { password, permissions, stripeCustomerId, ...newUser } = { ...user };
152
152
  const finalSession = {
153
153
  user: newUser,
154
154
  expires: new Date(session.expires).toISOString(),
155
155
  id: session.id,
156
- sessionToken: session.sessionToken
156
+ sessionToken: session.sessionToken,
157
157
  };
158
- const decodedToken = session.sessionToken ? decodeJwt(session.sessionToken) : null;
158
+ const decodedToken = session.sessionToken
159
+ ? decodeJwt(session.sessionToken)
160
+ : null;
159
161
  const tokenRoles = decodedToken?.roles;
160
162
  if (session.sessionToken) {
161
- if (trigger === 'update' || !tokenRoles || !areArraysSimilar(tokenRoles, user.groups)) {
163
+ if (trigger === 'update' ||
164
+ !tokenRoles ||
165
+ !areArraysSimilar(tokenRoles, user.groups)) {
162
166
  const newSessionToken = await generateSessionToken(user);
163
167
  // We can't call the update session from the patch because it searches by sessionToken and not by ID
164
168
  try {
165
169
  await prisma.session.update({
166
170
  where: {
167
- sessionToken: session.sessionToken
171
+ sessionToken: session.sessionToken,
168
172
  },
169
173
  data: {
170
- sessionToken: newSessionToken
171
- }
174
+ sessionToken: newSessionToken,
175
+ },
172
176
  });
173
- } catch (_e) {
174
- // Sometimes, concurrent requests can happen and one would update
175
- // before the other, so prisma won't find it based on sessionToken and throw
176
- // Nothing to do in this case
177
+ }
178
+ catch (_e) {
179
+ // Sometimes, concurrent requests can happen and one would update
180
+ // before the other, so prisma won't find it based on sessionToken and throw
181
+ // Nothing to do in this case
177
182
  }
178
183
  // @ts-expect-error dirty property to be removed in the patch
179
184
  finalSession.newSessionToken = newSessionToken;
@@ -188,26 +193,18 @@ export const authOptions = {
188
193
  await prisma.session.update({
189
194
  where: {
190
195
  id: session.id,
191
- OR: [
192
- {
193
- lastActiveAt: null
194
- },
195
- {
196
- lastActiveAt: {
197
- lt: threshold
198
- }
199
- }
200
- ]
196
+ OR: [{ lastActiveAt: null }, { lastActiveAt: { lt: threshold } }],
201
197
  },
202
198
  data: {
203
- lastActiveAt: new Date()
204
- }
199
+ lastActiveAt: new Date(),
200
+ },
205
201
  });
206
- } catch (_e) {
207
- // Silently fail
202
+ }
203
+ catch (_e) {
204
+ // Silently fail
208
205
  }
209
206
  return finalSession;
210
- }
207
+ },
211
208
  },
212
209
  cookies: {
213
210
  sessionToken: {
@@ -217,8 +214,12 @@ export const authOptions = {
217
214
  sameSite: 'lax',
218
215
  path: '/',
219
216
  secure: useSecureCookies,
220
- domain: process.env.NO_COOKIE_DOMAIN === 'true' ? undefined : nextAuthUrl === 'localhost' ? `.${nextAuthUrl}` : `.${new URL(nextAuthUrl).hostname}`
221
- }
217
+ domain: process.env.NO_COOKIE_DOMAIN === 'true'
218
+ ? undefined
219
+ : nextAuthUrl === 'localhost'
220
+ ? `.${nextAuthUrl}`
221
+ : `.${new URL(nextAuthUrl).hostname}`,
222
+ },
222
223
  },
223
224
  callbackUrl: {
224
225
  name: AUTH_COOKIE_CALLBACK_URL,
@@ -226,8 +227,8 @@ export const authOptions = {
226
227
  httpOnly: true,
227
228
  sameSite: 'lax',
228
229
  path: '/',
229
- secure: useSecureCookies
230
- }
230
+ secure: useSecureCookies,
231
+ },
231
232
  },
232
233
  csrfToken: {
233
234
  name: `${useSecureCookies ? '__Host-' : ''}${AUTH_COOKIE_CSRF_TOKEN}`,
@@ -235,8 +236,8 @@ export const authOptions = {
235
236
  httpOnly: true,
236
237
  sameSite: 'lax',
237
238
  path: '/',
238
- secure: useSecureCookies
239
- }
239
+ secure: useSecureCookies,
240
+ },
240
241
  },
241
242
  pkceCodeVerifier: {
242
243
  name: AUTH_COOKIE_PKCE_CODE_VERIFIER,
@@ -245,8 +246,8 @@ export const authOptions = {
245
246
  sameSite: 'lax',
246
247
  path: '/',
247
248
  secure: useSecureCookies,
248
- maxAge: 900
249
- }
249
+ maxAge: 900,
250
+ },
250
251
  },
251
252
  state: {
252
253
  name: AUTH_COOKIE_STATE,
@@ -255,8 +256,8 @@ export const authOptions = {
255
256
  sameSite: 'lax',
256
257
  path: '/',
257
258
  secure: useSecureCookies,
258
- maxAge: 900
259
- }
259
+ maxAge: 900,
260
+ },
260
261
  },
261
262
  nonce: {
262
263
  name: AUTH_COOKIE_NONCE,
@@ -264,13 +265,13 @@ export const authOptions = {
264
265
  httpOnly: true,
265
266
  sameSite: 'lax',
266
267
  path: '/',
267
- secure: useSecureCookies
268
- }
269
- }
268
+ secure: useSecureCookies,
269
+ },
270
+ },
270
271
  },
271
272
  useSecureCookies,
272
273
  jwt: {
273
- async encode (params) {
274
+ async encode(params) {
274
275
  const secret = new TextEncoder().encode(config.auth.jwtSecret);
275
276
  const alg = 'HS256';
276
277
  const tokenId = params.token?.sub;
@@ -279,36 +280,40 @@ export const authOptions = {
279
280
  }
280
281
  const user = await prisma.user.findUnique({
281
282
  where: {
282
- id: tokenId
283
- }
283
+ id: tokenId,
284
+ },
284
285
  });
285
286
  if (!user) {
286
287
  throw new Error('No user found');
287
288
  }
288
289
  const token = await new SignJWT({
289
290
  ...params.token,
290
- roles: user.groups
291
- }).setProtectedHeader({
292
- alg
293
- }).setIssuedAt().setSubject(user.id).setIssuer('flux.website').setAudience('flux.website').sign(secret);
291
+ roles: user.groups,
292
+ })
293
+ .setProtectedHeader({ alg })
294
+ .setIssuedAt()
295
+ .setSubject(user.id)
296
+ .setIssuer('flux.website')
297
+ .setAudience('flux.website')
298
+ .sign(secret);
294
299
  if (adapter.createSession) {
295
300
  await adapter.createSession({
296
301
  sessionToken: token,
297
302
  userId: user.id,
298
- expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000)
303
+ expires: new Date(Date.now() + (params.maxAge ?? MAX_AGE) * 1000),
299
304
  });
300
305
  }
301
306
  return token;
302
- }
307
+ },
303
308
  },
304
309
  session: {
305
310
  strategy: 'database',
306
311
  maxAge: MAX_AGE,
307
- generateSessionToken: async (user)=>{
312
+ generateSessionToken: async (user) => {
308
313
  return await generateSessionToken(user);
309
- }
314
+ },
310
315
  },
311
316
  pages: {
312
- signIn: '/signin'
313
- }
317
+ signIn: '/signin',
318
+ },
314
319
  };
@@ -4,172 +4,136 @@ export function PrismaAdapter() {
4
4
  return {
5
5
  // TODO
6
6
  // @ts-expect-error TypeScript is not working here
7
- createUser: async ({ id, groups, permissions, emailVerified, ...data })=>{
7
+ createUser: async ({ id, groups, permissions, emailVerified, ...data }) => {
8
8
  // @ts-expect-error
9
9
  const userData = {
10
10
  id: id || generateId('User'),
11
- groups: groups || [
12
- 'member'
13
- ],
11
+ groups: groups || ['member'],
14
12
  permissions: permissions || {},
15
13
  emailVerified: Boolean(emailVerified),
16
14
  email: data.email.toLowerCase().trim(),
17
- ...data
15
+ ...data,
18
16
  };
19
17
  const user = await prisma.user.create({
20
18
  data: {
21
- ...userData
22
- }
19
+ ...userData,
20
+ },
23
21
  });
24
22
  return user;
25
23
  },
26
24
  // TODO
27
25
  // @ts-expect-error
28
- getUser: (id)=>prisma.user.findUnique({
29
- where: {
30
- id
31
- }
32
- }),
26
+ getUser: (id) => prisma.user.findUnique({ where: { id } }),
33
27
  // TODO
34
28
  // @ts-expect-error
35
- getUserByEmail: (email)=>prisma.user.findUnique({
36
- where: {
37
- email: email.toLowerCase().trim()
38
- }
39
- }),
29
+ getUserByEmail: (email) => prisma.user.findUnique({ where: { email: email.toLowerCase().trim() } }),
40
30
  // TODO
41
31
  // @ts-expect-error
42
- async getUserByAccount (provider_providerAccountId) {
32
+ async getUserByAccount(provider_providerAccountId) {
43
33
  const account = await prisma.account.findUnique({
44
- where: {
45
- provider_providerAccountId
46
- },
47
- select: {
48
- user: true
49
- }
34
+ where: { provider_providerAccountId },
35
+ select: { user: true },
50
36
  });
51
37
  return account?.user ?? null;
52
38
  },
53
39
  // TODO
54
40
  // @ts-expect-error
55
- updateUser: ({ id, ...data })=>{
41
+ updateUser: ({ id, ...data }) => {
56
42
  // @ts-expect-error
57
43
  const userData = {
58
44
  email: data.email?.toLowerCase().trim(),
59
- ...data
45
+ ...data,
60
46
  };
61
- return prisma.user.update({
62
- where: {
63
- id
64
- },
65
- data: {
66
- ...userData
67
- }
68
- });
47
+ return prisma.user.update({ where: { id }, data: { ...userData } });
69
48
  },
70
49
  // TODO
71
50
  // @ts-expect-error
72
- deleteUser: (id)=>prisma.user.delete({
73
- where: {
74
- id
75
- }
76
- }),
51
+ deleteUser: (id) => prisma.user.delete({ where: { id } }),
77
52
  // @ts-expect-error
78
- linkAccount: ({ id, ...data })=>{
53
+ linkAccount: ({ id, ...data }) => {
79
54
  return prisma.account.create({
80
55
  // @ts-expect-error
81
56
  data: {
82
57
  id: id || generateId('Account'),
83
- ...data
84
- }
58
+ ...data,
59
+ },
85
60
  });
86
61
  },
87
62
  // @ts-expect-error
88
- unlinkAccount: (provider_providerAccountId)=>prisma.account.delete({
89
- where: {
90
- provider_providerAccountId
91
- }
92
- }),
63
+ unlinkAccount: (provider_providerAccountId) => prisma.account.delete({
64
+ where: { provider_providerAccountId },
65
+ }),
93
66
  // TODO
94
67
  // @ts-expect-error
95
- async getSessionAndUser (sessionToken) {
68
+ async getSessionAndUser(sessionToken) {
96
69
  const userAndSession = await prisma.session.findUnique({
97
- where: {
98
- sessionToken
99
- },
100
- include: {
101
- user: true
102
- }
70
+ where: { sessionToken },
71
+ include: { user: true },
103
72
  });
104
- if (!userAndSession) return null;
73
+ if (!userAndSession)
74
+ return null;
105
75
  const { user, ...session } = userAndSession;
106
- return {
107
- user,
108
- session
109
- };
76
+ return { user, session };
110
77
  },
111
78
  // TODO
112
79
  // @ts-expect-error
113
- async createSession ({ id, ...data }) {
80
+ async createSession({ id, ...data }) {
114
81
  const session = await prisma.session.create({
115
82
  data: {
116
83
  id: id || generateId('Session'),
117
- ...data
118
- }
84
+ ...data,
85
+ },
119
86
  });
120
87
  return session;
121
88
  },
122
- updateSession: (data)=>{
89
+ updateSession: (data) => {
123
90
  return prisma.session.update({
124
- where: {
125
- sessionToken: data.sessionToken
126
- },
127
- data
91
+ where: { sessionToken: data.sessionToken },
92
+ data,
128
93
  });
129
94
  },
130
- deleteSession: async (sessionToken)=>{
95
+ deleteSession: async (sessionToken) => {
131
96
  try {
132
- await prisma.session.delete({
133
- where: {
134
- sessionToken
135
- }
136
- });
137
- } catch (_e) {
138
- // TODO
139
- // DO nothing for now
97
+ await prisma.session.delete({ where: { sessionToken } });
98
+ }
99
+ catch (_e) {
100
+ // TODO
101
+ // DO nothing for now
140
102
  }
141
103
  },
142
104
  // TODO
143
105
  // @ts-expect-error
144
- async createVerificationToken ({ id, ...data }) {
106
+ async createVerificationToken({ id, ...data }) {
145
107
  const verificationToken = await prisma.verificationToken.create({
146
108
  data: {
147
109
  id: id || generateId('VerificationToken'),
148
- ...data
149
- }
110
+ ...data,
111
+ },
150
112
  });
151
113
  // TODO
152
114
  // @ts-expect-errors // MongoDB needs an ID, but we don't
153
- if (verificationToken.id) verificationToken.id = undefined;
115
+ if (verificationToken.id)
116
+ verificationToken.id = undefined;
154
117
  return verificationToken;
155
118
  },
156
- async useVerificationToken (identifier_token) {
119
+ async useVerificationToken(identifier_token) {
157
120
  try {
158
121
  const verificationToken = await prisma.verificationToken.delete({
159
- where: {
160
- identifier_token
161
- }
122
+ where: { identifier_token },
162
123
  });
163
124
  // TODO
164
125
  // @ts-expect-errors // MongoDB needs an ID, but we don't
165
- if (verificationToken.id) verificationToken.id = undefined;
126
+ if (verificationToken.id)
127
+ verificationToken.id = undefined;
166
128
  return verificationToken;
167
- } catch (error) {
129
+ }
130
+ catch (error) {
168
131
  // If token already used/deleted, just return null
169
132
  // https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
170
- if (error.code === 'P2025') return null;
133
+ if (error.code === 'P2025')
134
+ return null;
171
135
  throw error;
172
136
  }
173
- }
137
+ },
174
138
  };
175
139
  }