From 30529e6eb5567103374bb60b5e25426a6bf14636 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Sun, 25 Aug 2024 02:43:47 +0100 Subject: [PATCH 1/5] ar(fix) [DPTM-8] Dockerize and GCP: skip accelerate --- next.config.mjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/next.config.mjs b/next.config.mjs index dcb829d..dfeb203 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -19,7 +19,10 @@ const nextConfig = { return config; }, - output: process.env.NEXUS_STANDALONE === 'true' ? 'standalone' : undefined, + output: + process.env.NEXUS_STANDALONE === 'true' && process.env.NEXUS_STANDALONE_PRISMA_ONLY !== 'true' + ? 'standalone' + : undefined, basePath: process.env.NEXUS_BASE_PATH, transpilePackages: ['next-auth'], images: { From ceecca648dd7c423b2d62430aa9f0e84e2349f07 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Sun, 25 Aug 2024 03:07:08 +0100 Subject: [PATCH 2/5] ar(fix) [DPTM-8] Dockerize and GCP: skip accelerate --- lib/model/prisma-private-connector.ts | 6 +++++- lib/model/prisma-public-connector.ts | 7 +++++-- package.json | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/model/prisma-private-connector.ts b/lib/model/prisma-private-connector.ts index 6bfbe89..5c40a15 100644 --- a/lib/model/prisma-private-connector.ts +++ b/lib/model/prisma-private-connector.ts @@ -4,7 +4,11 @@ import { PrismaClient as PrivatePrismaStandalone } from '@dreampipcom/db-private import { withAccelerate } from '@prisma/extension-accelerate'; const prismaClientSingleton = () => { - return new PrivatePrisma().$extends(withAccelerate()); + if (process.env.NEXUS_STANDALONE_PRISMA_ONLY === 'true') { + return new PrivatePrisma(); + } else { + return new PrivatePrisma().$extends(withAccelerate()); + } }; const prismaClientSingletonStandalone = () => { diff --git a/lib/model/prisma-public-connector.ts b/lib/model/prisma-public-connector.ts index ae2b4b5..0e3e31c 100644 --- a/lib/model/prisma-public-connector.ts +++ b/lib/model/prisma-public-connector.ts @@ -4,9 +4,12 @@ import { PrismaClient as PublicPrismaStandalone } from '@dreampipcom/db-public/p import { withAccelerate } from '@prisma/extension-accelerate'; const prismaClientSingleton = () => { - return new PublicPrisma().$extends(withAccelerate()); + if (process.env.NEXUS_STANDALONE_PRISMA_ONLY === 'true') { + return new PublicPrisma(); + } else { + return new PublicPrisma().$extends(withAccelerate()); + } }; - const prismaClientSingletonStandalone = () => { return new PublicPrismaStandalone(); }; diff --git a/package.json b/package.json index 5df9de6..0d5b139 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "seed": "node --loader ts-node/esm prisma/seed.mts" }, "dependencies": { - "@sentry/nextjs": "^8.20.0", + "@sentry/nextjs": "8.20.0", "next": "14.2.4" }, "devDependencies": { @@ -66,7 +66,7 @@ "@vercel/functions": "1.4.0", "@vercel/kv": "2.0.0", "bson": "6.8.0", - "dotenv": "^16.4.5", + "dotenv": "16.4.5", "eslint": "8", "eslint-config-alloy": "5.1.2", "eslint-config-next": "14.0.4", @@ -76,7 +76,7 @@ "next-auth": "5.0.0-beta.20", "nodemailer": "6.9.14", "patch-package": "8.0.0", - "pm2": "^5.4.2", + "pm2": "5.4.2", "prettier": "3.2.4", "prisma": "5.18.0", "server-only": "0.0.1", From 87a9784c815c37d80fad44250c76feb3344a116f Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:35:07 +0100 Subject: [PATCH 3/5] ar(feat) [DPCP-40]: Parse Services. (#31) * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. * ar(feat) [DPCP-40]: Parse Services. --- .env.local.public | 1 + lib/auth/constants.ts | 15 +- lib/model/interfaces/get-private-abilities.ts | 31 +- .../get-private-common-abilities.ts | 17 +- .../interfaces/get-private-common-services.ts | 17 +- lib/model/interfaces/get-private-services.ts | 40 +- .../interfaces/get-public-listings-iface.ts | 17 +- .../interfaces/middleware/authorization.ts | 7 +- .../update-private-user-abilities.ts | 4 +- .../update-private-user-favorite-listings.ts | 12 +- .../update-private-user-services.ts | 4 +- lib/model/prisma-private-connector.ts | 8 +- lib/model/prisma-public-connector.ts | 8 +- package.json | 10 +- prisma/mock/abilities.mts | 23 +- prisma/mock/communities.mts | 30 +- prisma/mock/listings.mts | 17 +- prisma/mock/public.mts | 83 ++- prisma/mock/services.mts | 7 +- prisma/mock/user.mts | 35 +- prisma/schema-private.prisma | 29 + prisma/schema-public.prisma | 17 + prisma/seed.mts | 675 ++++++++++++++++-- src/app/api/v1/public/route.ts | 7 - .../v1/services/dpcp-vibemodulator/route.ts | 60 ++ src/app/api/v1/services/rickmorty/route.ts | 53 ++ src/app/api/v1/user/route.ts | 47 +- 27 files changed, 1093 insertions(+), 181 deletions(-) create mode 100644 src/app/api/v1/services/dpcp-vibemodulator/route.ts create mode 100644 src/app/api/v1/services/rickmorty/route.ts diff --git a/.env.local.public b/.env.local.public index 207055d..ef950f4 100644 --- a/.env.local.public +++ b/.env.local.public @@ -34,6 +34,7 @@ NEXUS_BASE_PATH= # for docker images only NEXUS_STANDALONE= +NEXUS_STANDALONE_PRISMA_ONLY= # keep alive secret for private endpoints healthcheck NEXUS_KEEPALIVE= diff --git a/lib/auth/constants.ts b/lib/auth/constants.ts index 4bef719..4d7fe1c 100644 --- a/lib/auth/constants.ts +++ b/lib/auth/constants.ts @@ -15,6 +15,7 @@ import { GetPrivateCommonServices, UpdatePrivateUserAbilities, GetPrivateCommonAbilities, + GetPrivateAbilities, } from '@controller'; import { PrivatePrisma } from '@model'; @@ -35,6 +36,8 @@ export const GetSession = async ({ cookies = '' }) => { } }; +// to-do: admin sanitizer + // schema sanitizer const allUsersSideEffects = async ({ user }: any) => { const services = await GetPrivateCommonServices({}); @@ -42,8 +45,14 @@ const allUsersSideEffects = async ({ user }: any) => { const commonServices = services.map((service: any) => service?.id).map((el: any) => el); const commonAbilities = abilities.map((ability: any) => ability?.id).map((el: any) => el); + const [dpcpAbility] = await GetPrivateAbilities({ type: 'R', target: 'dpcp-vibemodulator', action: 'view-listings' }); + await UpdatePrivateUserServices({ user, services: [...commonServices, ...user.servicesIds], upsert: false }); - await UpdatePrivateUserAbilities({ user, abilities: [...commonAbilities, ...user.abilitiesIds], upsert: false }); + await UpdatePrivateUserAbilities({ + user, + abilities: [...commonAbilities, ...user.abilitiesIds, dpcpAbility.id], + upsert: false, + }); }; export const providers: any[] = [ @@ -126,7 +135,7 @@ export const authConfig = { return true; }, async redirect() { - return `${process.env.MAIN_URL}/dash`; + return `${process.env.MAIN_URL}/dash/signin`; }, // async jwt({ user, token }) { // if (user) { @@ -191,7 +200,7 @@ export const authConfig = { trustHost: true, pages: { signIn: '/dash/signin', - signOut: '/', + signOut: '/dash/signin', error: '/dash/error', // Error code passed in query string as ?error= verifyRequest: '/dash/verify', // (used for check email message) // newUser: '/' // New users will be directed here on first sign in (leave the property out if not of interest) diff --git a/lib/model/interfaces/get-private-abilities.ts b/lib/model/interfaces/get-private-abilities.ts index 8a2e9e2..130e5a8 100644 --- a/lib/model/interfaces/get-private-abilities.ts +++ b/lib/model/interfaces/get-private-abilities.ts @@ -1,3 +1,4 @@ +/* eslint @typescript-eslint/no-unused-vars:0 */ // @controller/get-private-services.ts import { whoAmI } from '@controller'; import { PrivatePrisma } from '@model'; @@ -7,8 +8,11 @@ const PAGE_SIZE = 100; const getPrivateAbilities = async ({ id, name, - locale = 'es', + locale = 'en', user, + type, + target, + action, page = 0, offset = 0, limit = PAGE_SIZE, @@ -18,8 +22,16 @@ const getPrivateAbilities = async ({ const adaptQuery: any = { where: { - id, - name: { [locale]: name }, + OR: [ + { + id, + }, + { + type, + target, + action, + }, + ], }, skip: page * (limit + offset), take: limit, @@ -31,7 +43,7 @@ const getPrivateAbilities = async ({ const supportedQueries: Record = { user: { query: { - OR: [{ id: { in: loggedUser?.servicesIds }, name: { [locale]: name } }, { userOwner: loggedUser?.id }], + OR: [{ id: { in: loggedUser?.abilities } }, { userOwnerId: loggedUser.id }], }, }, // group: { @@ -49,15 +61,16 @@ const getPrivateAbilities = async ({ return acc; }, {}); - adaptQuery.where = { - ...adaptQuery.where, - ...query, - }; + adaptQuery.where.OR = query?.OR; } catch (e) { - throw new Error('Code 001: Wrong filter'); + throw new Error('Code 000/2: Wrong filter'); } } + if (!(adaptQuery?.where?.OR?.length > 0)) { + throw new Error('Code 000/1: Malformed request'); + } + const response = await PrivatePrisma.abilities.findMany(adaptQuery); return response; diff --git a/lib/model/interfaces/get-private-common-abilities.ts b/lib/model/interfaces/get-private-common-abilities.ts index 3c4b47e..931051c 100644 --- a/lib/model/interfaces/get-private-common-abilities.ts +++ b/lib/model/interfaces/get-private-common-abilities.ts @@ -7,7 +7,11 @@ const getPrivateCommonAbilities = async ({ page = 0, offset = 0, limit = PAGE_SI // to-do: move, this will be a middleware const adaptQuery: any = { where: { - nature: 'COMMON', + OR: [ + { + nature: 'COMMON', + }, + ], }, skip: page * (limit + offset), take: limit, @@ -37,15 +41,16 @@ const getPrivateCommonAbilities = async ({ page = 0, offset = 0, limit = PAGE_SI return acc; }, {}); - adaptQuery.where = { - ...adaptQuery.where, - ...query, - }; + adaptQuery.where.OR = query?.OR; } catch (e) { - throw new Error('Code 001: Wrong filter'); + throw new Error('Code 000/2: Wrong filter'); } } + if (!(adaptQuery?.where?.OR?.length > 0)) { + throw new Error('Code 000/1: Malformed request'); + } + const response = await PrivatePrisma.abilities.findMany(adaptQuery); return response; diff --git a/lib/model/interfaces/get-private-common-services.ts b/lib/model/interfaces/get-private-common-services.ts index bc60d1b..8177a7a 100644 --- a/lib/model/interfaces/get-private-common-services.ts +++ b/lib/model/interfaces/get-private-common-services.ts @@ -7,7 +7,11 @@ const getPrivateCommonServices = async ({ page = 0, offset = 0, limit = PAGE_SIZ // to-do: move, this will be a middleware const adaptQuery: any = { where: { - nature: 'COMMON', + OR: [ + { + nature: 'COMMON', + }, + ], }, skip: page * (limit + offset), take: limit, @@ -37,15 +41,16 @@ const getPrivateCommonServices = async ({ page = 0, offset = 0, limit = PAGE_SIZ return acc; }, {}); - adaptQuery.where = { - ...adaptQuery.where, - ...query, - }; + adaptQuery.where.OR = query?.OR; } catch (e) { - throw new Error('Code 001: Wrong filter'); + throw new Error('Code 000/2: Wrong filter'); } } + if (!(adaptQuery?.where?.OR?.length > 0)) { + throw new Error('Code 000/1: Malformed request'); + } + const response = await PrivatePrisma.services.findMany(adaptQuery); return response; diff --git a/lib/model/interfaces/get-private-services.ts b/lib/model/interfaces/get-private-services.ts index 08f065f..a00c3cb 100644 --- a/lib/model/interfaces/get-private-services.ts +++ b/lib/model/interfaces/get-private-services.ts @@ -1,14 +1,15 @@ +/* eslint @typescript-eslint/no-unused-vars:0 */ // @controller/get-private-services.ts import { PrivatePrisma } from '@model'; -import { whoAmI } from '@controller'; +import { whoAmI, canI } from '@controller'; const PAGE_SIZE = 100; const getPrivateServices = async ({ id, - name, - locale = 'es', user, + locale = 'en', + target, page = 0, offset = 0, limit = PAGE_SIZE, @@ -18,8 +19,14 @@ const getPrivateServices = async ({ const adaptQuery: any = { where: { - id, - name: { [locale]: name }, + OR: [ + { + id, + }, + { + slug: target, + }, + ], }, skip: page * (limit + offset), take: limit, @@ -31,7 +38,7 @@ const getPrivateServices = async ({ const supportedQueries: Record = { user: { query: { - OR: [{ id: { in: loggedUser?.servicesIds }, name: { [locale]: name } }, { userOwner: loggedUser?.id }], + OR: [{ id: { in: loggedUser?.services } }, { userOwnerId: loggedUser.id }], }, }, // group: { @@ -49,18 +56,25 @@ const getPrivateServices = async ({ return acc; }, {}); - adaptQuery.where = { - ...adaptQuery.where, - ...query, - }; + adaptQuery.where.OR = query?.OR; + + const response = await PrivatePrisma.services.findMany(adaptQuery); + return response; } catch (e) { - throw new Error('Code 001: Wrong filter'); + throw new Error(`Code 000/2: Wrong filter: ${e}`); } } - const response = await PrivatePrisma.services.findMany(adaptQuery); + if (!(adaptQuery?.where?.OR?.length > 0)) { + throw new Error('Code 000/1: Malformed request'); + } - return response; + if (await canI({ type: 'R', action: 'view-listings', target, user: loggedUser })) { + const response = await PrivatePrisma.services.findMany(adaptQuery); + return response; + } else { + throw new Error(`Code 001/0: Not authorized.`); + } }; export default getPrivateServices; diff --git a/lib/model/interfaces/get-public-listings-iface.ts b/lib/model/interfaces/get-public-listings-iface.ts index c5fed8a..054e2b4 100644 --- a/lib/model/interfaces/get-public-listings-iface.ts +++ b/lib/model/interfaces/get-public-listings-iface.ts @@ -5,6 +5,13 @@ const PAGE_SIZE = 100; const getPublicListings = async ({ page = 0, offset = 0, limit = PAGE_SIZE, filters = [] }: any) => { const adaptQuery: any = { + where: { + OR: [ + { + status: 'ACTIVE', + }, + ], + }, skip: page * (limit + offset), take: limit, cacheStrategy: process.env.NEXUS_STANDALONE !== 'true' ? { ttl: 90, swr: 60 * 60 * 24 * 7 } : undefined, @@ -45,14 +52,16 @@ const getPublicListings = async ({ page = 0, offset = 0, limit = PAGE_SIZE, filt return acc; }, {}); - adaptQuery.where = { - ...query, - }; + adaptQuery.where.OR = query?.OR; } catch (e) { - throw new Error('Code 001: Wrong filter'); + throw new Error('Code 000/2: Wrong filter'); } } + if (!(adaptQuery?.where?.OR?.length > 0)) { + throw new Error('Code 000/1: Malformed request'); + } + const response = await PublicPrisma.publicListings.findMany(adaptQuery); return response; diff --git a/lib/model/interfaces/middleware/authorization.ts b/lib/model/interfaces/middleware/authorization.ts index 658c415..6fe9083 100644 --- a/lib/model/interfaces/middleware/authorization.ts +++ b/lib/model/interfaces/middleware/authorization.ts @@ -2,11 +2,11 @@ import { getSession, GetSession } from '@auth'; import { GetPrivateAbilities } from '@controller'; import { cookies as nextCookies } from 'next/headers'; -export const canI = async ({ name, user }: any) => { +export const canI = async ({ type, target, action, user }: any) => { try { - const ability = await GetPrivateAbilities({ name }); + const abilities = await GetPrivateAbilities({ type, target, action }); // to-do add authorization/validation checks - const yes = user?.abilities?.includes(ability[0]?.id); + const yes = abilities?.some((ability) => user?.abilities.includes(ability.id)); // return the capacity return yes; } catch (e) { @@ -18,7 +18,6 @@ export const whoAmI = async ({ cookies }: any) => { const cookieString = nextCookies().getAll().toString(); const session = (await getSession()) || (await GetSession({ cookies: cookieString || cookies })); // to-do add authorization/validation checks - console.log({ cookieString, session }); return session?.user; } catch (e) { throw new Error(`Code 007: Can't identify user ${e}`); diff --git a/lib/model/interfaces/update-private-user-abilities.ts b/lib/model/interfaces/update-private-user-abilities.ts index ef1f72e..1778a71 100644 --- a/lib/model/interfaces/update-private-user-abilities.ts +++ b/lib/model/interfaces/update-private-user-abilities.ts @@ -6,7 +6,7 @@ import { PrivatePrisma } from '@model'; const updatePrivateUserAbilities = async ({ upsert = false, user, abilities }: any) => { try { // to-do: move this will be a middleware - if (abilities?.length === 0) return new Error('Code 002: Missing data (abilities)'); + if (abilities?.length === 0) return new Error('Code 002/1: Missing data (abilities)'); const loggedUser = user || (await whoAmI({})); @@ -29,7 +29,7 @@ const updatePrivateUserAbilities = async ({ upsert = false, user, abilities }: a return response; } catch (e) { - throw new Error(`Code 003: Missing results: ${e}`); + throw new Error(`Code 002/0: Missing results: ${e}`); } }; diff --git a/lib/model/interfaces/update-private-user-favorite-listings.ts b/lib/model/interfaces/update-private-user-favorite-listings.ts index 640481c..4ab59e9 100644 --- a/lib/model/interfaces/update-private-user-favorite-listings.ts +++ b/lib/model/interfaces/update-private-user-favorite-listings.ts @@ -3,17 +3,15 @@ import { whoAmI, canI } from '@controller'; import { PrivatePrisma } from '@model'; -const updatePrivateUserFavoriteListings = async ({ upsert = true, user, listings = [], type = 'id' }: any) => { +const updatePrivateUserFavoriteListings = async ({ upsert = true, user, target, listings = [], type = 'id' }: any) => { try { if (listings?.length === 0) return new Error('Code 002: Missing data (listings)'); const loggedUser = user || (await whoAmI({})); - console.log({ user, loggedUser }); - const delta = upsert ? listings.filter((listing: any) => !loggedUser?.favorites?.includes(listing)) : []; - if ((await canI({ name: 'Ability 1', user: loggedUser })) && type === 'id') { + if ((await canI({ type: 'U', action: 'favorite', target, user: loggedUser })) && type === 'id') { const swapUserData = loggedUser.favorites.filter((listing: string) => !listings.includes(listing)); const payload = upsert ? { @@ -31,7 +29,7 @@ const updatePrivateUserFavoriteListings = async ({ upsert = true, user, listings const response = await PrivatePrisma.user.update(adaptQuery); return response; - } else if ((await canI({ name: 'Ability 1', user: loggedUser })) && type === 'string') { + } else if ((await canI({ type: 'U', action: 'favorite', target, user: loggedUser })) && type === 'string') { const userData = loggedUser?.favoritesStrings; const swapData = userData.filter((listing: string) => listings.includes(listing)); const transaction = userData @@ -54,10 +52,10 @@ const updatePrivateUserFavoriteListings = async ({ upsert = true, user, listings const response = await PrivatePrisma.user.update(adaptQuery); return response; } else { - throw new Error(`403: Not authorized.`); + throw new Error(`Code 001/0: Not authorized.`); } } catch (e) { - throw new Error(`Code 003: Missing results: ${e}`); + throw new Error(`Code 002/0: Missing results: ${e}`); } }; diff --git a/lib/model/interfaces/update-private-user-services.ts b/lib/model/interfaces/update-private-user-services.ts index 094ff9a..d8a6d7e 100644 --- a/lib/model/interfaces/update-private-user-services.ts +++ b/lib/model/interfaces/update-private-user-services.ts @@ -6,7 +6,7 @@ import { PrivatePrisma } from '@model'; const updatePrivateUserServices = async ({ upsert = false, user, services }: any) => { try { // to-do: move this will be a middleware - if (services?.length === 0) return new Error('Code 002: Missing data (services)'); + if (services?.length === 0) return new Error('Code 002/0: Missing data (services)'); const loggedUser = user || (await whoAmI({})); @@ -29,7 +29,7 @@ const updatePrivateUserServices = async ({ upsert = false, user, services }: any return response; } catch (e) { - throw new Error(`Code 003: Missing results: ${e}`); + throw new Error(`Code 002/0: Missing results: ${e}`); } }; diff --git a/lib/model/prisma-private-connector.ts b/lib/model/prisma-private-connector.ts index 5c40a15..3bef84e 100644 --- a/lib/model/prisma-private-connector.ts +++ b/lib/model/prisma-private-connector.ts @@ -5,14 +5,20 @@ import { withAccelerate } from '@prisma/extension-accelerate'; const prismaClientSingleton = () => { if (process.env.NEXUS_STANDALONE_PRISMA_ONLY === 'true') { + console.log('--- USING EDGE, BUT NOT USING PRISMA ACCELERATE'); return new PrivatePrisma(); } else { + console.log('--- USING EDGE AND USING PRISMA ACCELERATE'); return new PrivatePrisma().$extends(withAccelerate()); } }; const prismaClientSingletonStandalone = () => { - return new PrivatePrismaStandalone(); + if (process.env.NEXUS_STANDALONE === 'true') { + console.log('--- NOT USING EDGE AND NOT USING PRISMA ACCELERATE'); + return new PrivatePrismaStandalone(); + } + return; }; declare const globalThis: { diff --git a/lib/model/prisma-public-connector.ts b/lib/model/prisma-public-connector.ts index 0e3e31c..f4c6f5b 100644 --- a/lib/model/prisma-public-connector.ts +++ b/lib/model/prisma-public-connector.ts @@ -5,13 +5,19 @@ import { withAccelerate } from '@prisma/extension-accelerate'; const prismaClientSingleton = () => { if (process.env.NEXUS_STANDALONE_PRISMA_ONLY === 'true') { + console.log('--- USING EDGE, BUT NOT USING PRISMA ACCELERATE'); return new PublicPrisma(); } else { + console.log('--- USING EDGE AND USING PRISMA ACCELERATE'); return new PublicPrisma().$extends(withAccelerate()); } }; const prismaClientSingletonStandalone = () => { - return new PublicPrismaStandalone(); + if (process.env.NEXUS_STANDALONE === 'true') { + console.log('--- NOT USING EDGE AND NOT USING PRISMA ACCELERATE'); + return new PublicPrismaStandalone(); + } + return; }; declare const globalThis: { diff --git a/package.json b/package.json index 0d5b139..dce6405 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,11 @@ "schema:pull:public": "npx prisma db pull --schema prisma/schema-public.prisma", "schema:push:all": "npm run schema:push:private && npm run schema:push:public", "schema:pull:all": "npm run schema:pull:private && npm run schema:pull:public", - "schema:seed:private": "npm run schema:generate:private && prisma db seed --schema=./prisma/schema-private.prisma -- private", - "schema:seed:getseeds": "npm run schema:generate:private && node --loader ts-node/esm prisma/getSeeds.mts --schema=./prisma/schema-private.prisma -- private", - "schema:seed:public": "npm run schema:generate:public && prisma db seed --schema=./prisma/schema-public.prisma -- public", - "schema:seed:all": "npm run schema:seed:private && npm run schema:seed:public", + "schema:seed:private": "NEXUS_STANDALONE=true npm run schema:generate:private:standalone && prisma db seed --schema=./prisma/schema-private.prisma -- private", + "schema:seed:getseeds": "NEXUS_STANDALONE=true npm run schema:generate:private:standalone && node --loader ts-node/esm prisma/getSeeds.mts --schema=./prisma/schema-private.prisma -- private", + "schema:seed:public": "NEXUS_STANDALONE=true npm run schema:generate:private:standalone && npm run schema:generate:public:standalone && prisma db seed --schema=./prisma/schema-public.prisma -- public", + "schema:seed:mock": "NEXUS_STANDALONE=true npm run schema:generate:private:standalone && npm run schema:generate:public:standalone && prisma db seed --schema=./prisma/schema-public.prisma -- mock", + "schema:seed:all": "NEXUS_STANDALONE=true npm run schema:seed:private && npm run schema:seed:public", "schema:generate:private": "npx prisma generate --no-engine --schema=./prisma/schema-private.prisma", "schema:generate:public": "npx prisma generate --no-engine --schema=./prisma/schema-public.prisma", "schema:generate:all": "npm run schema:generate:private && npm run schema:generate:public", @@ -27,6 +28,7 @@ "schema:generate:public:standalone": "npx prisma generate --schema=./prisma/schema-public.prisma", "schema:generate:all:standalone": "npm run schema:generate:private:standalone && npm run schema:generate:public:standalone", "dev": "npm run schema:generate:all && next dev -p 3001", + "dev:vm": "npm run schema:generate:all:standalone && next dev -p 3001", "build": "npm run schema:generate:all && next build", "build:vm": "npm run schema:generate:all:standalone && next build", "start": "next start", diff --git a/prisma/mock/abilities.mts b/prisma/mock/abilities.mts index 00c7c6b..bbe62ba 100644 --- a/prisma/mock/abilities.mts +++ b/prisma/mock/abilities.mts @@ -10,14 +10,25 @@ import { mockTerm, mockTerm2 } from './taxonomies.mts'; import { HOMock } from './helpers.mts'; -export const createMockAbility = ({ community, user, roles, refUsers, refCommunities }: any): any => { +export const createMockAbility = ({ + name, + action, + type, + nature, + target, + community, + user, + roles, + refUsers, + refCommunities, +}: any): any => { const data = { - name: { - es: 'Ability 1', - }, + name, + target, + action, status: 'ACTIVE', - type: 'R', - nature: 'COMMON', + type, + nature, roles: { connect: roles, }, diff --git a/prisma/mock/communities.mts b/prisma/mock/communities.mts index 94b302a..555e287 100644 --- a/prisma/mock/communities.mts +++ b/prisma/mock/communities.mts @@ -5,18 +5,20 @@ import { createMockListing } from './listings.mts'; import { createMockMessage } from './messages.mts'; import { createMockTerm } from './taxonomies.mts'; import { createMockRole } from './roles.mts'; +import { HOMock } from './helpers.mts'; -export const createMockCommunity = (): any => { +export const createMockCommunity = ({ name, description, urls, image, user, refUsers }): any => { const id = faker.database.mongodbObjectId(); - return { + const data = { id, - name: 'My Community 1', - description: 'My community 1 description', - urls: ['https://mycommunity.com'], - image: faker.image.avatar(), + name: name || 'My Community 1', + description: description || 'My community 1 description', + urls: urls || ['https://mycommunity.com'], + image: image || faker.image.avatar(), users: { - create: [createMockUser(), createMockUser()], + create: !refUsers ? [createMockUser({}), createMockUser({})] : undefined, + connect: refUsers ? refUsers : undefined, }, status: 'ACTIVE', favorites: { @@ -52,15 +54,11 @@ export const createMockCommunity = (): any => { messagesReceived: { create: [], }, - userOwner: { - create: createMockUser(), - }, - userCreator: { - create: createMockUser(), - }, }; + + return HOMock(data, { user }); }; -export const mockCommunity = createMockCommunity(); -export const mockCommunity2 = createMockCommunity(); -export const mockCommunity3 = createMockCommunity(); +export const mockCommunity = createMockCommunity({}); +export const mockCommunity2 = createMockCommunity({}); +export const mockCommunity3 = createMockCommunity({}); diff --git a/prisma/mock/listings.mts b/prisma/mock/listings.mts index 35dee53..df2f523 100644 --- a/prisma/mock/listings.mts +++ b/prisma/mock/listings.mts @@ -8,11 +8,11 @@ import { createMockTerm, mockTerm } from './taxonomies.mts'; import { HOMock } from './helpers.mts'; -const mockLocation = { - name: 'Home', +const mockLocation = () => ({ + name: faker.company.name(), geo: { - lat: 0.75, - lng: 1.02, + lat: faker.location.latitude(), + lng: faker.location.longitude(), radius: 0.98, }, address: { @@ -25,18 +25,23 @@ const mockLocation = { zipCode: '000000', phone: '01010101010', }, -}; +}); export const createMockListing = ({ community, user, communityFavorited, favorited, audiences, model }: any) => { const data = { title: { es: 'INTERNAL aud', }, + images: [ + faker.image.urlLoremFlickr({ category: 'crypto' }), + faker.image.urlLoremFlickr({ category: 'crypto' }), + faker.image.urlLoremFlickr({ category: 'crypto' }), + ], description: { es: 'Lorem ipsum dolor sit amet consectetur', }, status: 'ACTIVE', - location: mockLocation, + location: mockLocation(), favorited: { connect: favorited, }, diff --git a/prisma/mock/public.mts b/prisma/mock/public.mts index f235f49..bfe567d 100644 --- a/prisma/mock/public.mts +++ b/prisma/mock/public.mts @@ -4,11 +4,11 @@ import { faker } from '@faker-js/faker'; import { HOMock } from './helpers.mts'; -const mockLocation = { - name: 'Home', +const mockLocation = () => ({ + name: faker.company.name(), geo: { - lat: 0.75, - lng: 1.02, + lat: faker.location.latitude(), + lng: faker.location.longitude(), radius: 0.98, }, address: { @@ -17,7 +17,7 @@ const mockLocation = { country: 'Sit', zipCode: '000000', }, -}; +}); export const createMockPubListing = ({ user, @@ -35,14 +35,81 @@ export const createMockPubListing = ({ userCreator: user, communityCreator: community, communityOwner: community, + images: [ + faker.image.urlLoremFlickr({ category: 'crypto' }), + faker.image.urlLoremFlickr({ category: 'crypto' }), + faker.image.urlLoremFlickr({ category: 'crypto' }), + ], title: { - es: 'Lorem ipsum title', + en: faker.airline.airplane().name, + it: faker.airline.airplane().name, + pt: faker.airline.airplane().name, + es: faker.airline.airplane().name, + de: faker.airline.airplane().name, + fr: faker.airline.airplane().name, + ro: faker.airline.airplane().name, + cz: faker.airline.airplane().name, + pl: faker.airline.airplane().name, + et: faker.airline.airplane().name, + sv: faker.airline.airplane().name, + ja: faker.airline.airplane().name, + ru: faker.airline.airplane().name, + ar: faker.airline.airplane().name, + he: faker.airline.airplane().name, + zh: faker.airline.airplane().name, + nl: faker.airline.airplane().name, + da: faker.airline.airplane().name, + hu: faker.airline.airplane().name, + ca: faker.airline.airplane().name, + eu: faker.airline.airplane().name, + gl: faker.airline.airplane().name, + sw: faker.airline.airplane().name, + hi: faker.airline.airplane().name, + ms: faker.airline.airplane().name, + bn: faker.airline.airplane().name, + pa: faker.airline.airplane().name, + tr: faker.airline.airplane().name, + fi: faker.airline.airplane().name, + el: faker.airline.airplane().name, + uk: faker.airline.airplane().name, }, description: { - es: 'Lorem ipsum description', + en: faker.finance.transactionDescription(), + it: faker.finance.transactionDescription(), + pt: faker.finance.transactionDescription(), + es: faker.finance.transactionDescription(), + de: faker.finance.transactionDescription(), + fr: faker.finance.transactionDescription(), + ro: faker.finance.transactionDescription(), + cz: faker.finance.transactionDescription(), + pl: faker.finance.transactionDescription(), + et: faker.finance.transactionDescription(), + sv: faker.finance.transactionDescription(), + ja: faker.finance.transactionDescription(), + ru: faker.finance.transactionDescription(), + ar: faker.finance.transactionDescription(), + he: faker.finance.transactionDescription(), + zh: faker.finance.transactionDescription(), + nl: faker.finance.transactionDescription(), + da: faker.finance.transactionDescription(), + hu: faker.finance.transactionDescription(), + ca: faker.finance.transactionDescription(), + eu: faker.finance.transactionDescription(), + gl: faker.finance.transactionDescription(), + sw: faker.finance.transactionDescription(), + hi: faker.finance.transactionDescription(), + ms: faker.finance.transactionDescription(), + bn: faker.finance.transactionDescription(), + pa: faker.finance.transactionDescription(), + tr: faker.finance.transactionDescription(), + fi: faker.finance.transactionDescription(), + el: faker.finance.transactionDescription(), + uk: faker.finance.transactionDescription(), }, + scheduledFor: faker.date.future(), + value: faker.number.float(3500), status: 'ACTIVE', - location: mockLocation, + location: mockLocation(), taxonomies, }; diff --git a/prisma/mock/services.mts b/prisma/mock/services.mts index af3098a..afae92a 100644 --- a/prisma/mock/services.mts +++ b/prisma/mock/services.mts @@ -10,11 +10,10 @@ import { mockTerm, mockTerm2 } from './taxonomies.mts'; import { HOMock } from './helpers.mts'; -export const createMockService = ({ community, user, features, refUsers, refCommunities }: any): any => { +export const createMockService = ({ name, slug, community, user, features, refUsers, refCommunities }: any): any => { const data = { - name: { - es: 'Service 1', - }, + name, + slug, status: 'ACTIVE', type: 'CONSUMER', nature: 'COMMON', diff --git a/prisma/mock/user.mts b/prisma/mock/user.mts index 1f80fed..ded2522 100644 --- a/prisma/mock/user.mts +++ b/prisma/mock/user.mts @@ -1,5 +1,6 @@ // user.ts import { faker } from '@faker-js/faker'; +import { HOMock } from './helpers.mts'; interface UserModel { id: string; @@ -19,19 +20,23 @@ export const _mockUser = { userId: '66315b93521b49388fe71aa8', }; -export const createMockUser = () => ({ - id: faker.database.mongodbObjectId(), - name: faker.person.fullName(), - email: faker.internet.email(), - image: faker.image.avatar(), - firstName: 'Vars', - lastName: 'Nothing', - birthday: new Date(), - location: { - name: 'Nowhere', - }, -}); +export const createMockUser = ({ name, firstName, lastName, location, email, avatar }: any) => { + const data = { + id: faker.database.mongodbObjectId(), + name: name || faker.person.fullName(), + email: email || faker.internet.email(), + image: avatar || faker.image.avatar(), + firstName: firstName || 'DreamPip', + lastName: lastName || 'Superuser', + birthday: new Date(), + location: location || { + name: 'Nowhere', + }, + }; + + return data; +}; -export const mockUser = createMockUser(); -export const mockUser2 = createMockUser(); -export const mockUser3 = createMockUser(); +export const mockUser = createMockUser({}); +export const mockUser2 = createMockUser({}); +export const mockUser3 = createMockUser({}); diff --git a/prisma/schema-private.prisma b/prisma/schema-private.prisma index 3717f7f..2f57c95 100644 --- a/prisma/schema-private.prisma +++ b/prisma/schema-private.prisma @@ -239,6 +239,9 @@ model Listings { description ILocaleString //model description status EListingStatus location ILocation + scheduledFor DateTime? @db.Date + value Float? + images String[] taxonomies Taxonomies[] @relation("listingTaxonomies", fields: [taxonomiesIds], references: [id]) taxonomiesIds String[] @db.ObjectId @@ -352,6 +355,7 @@ model Messages { model Roles { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String? status ERoleStatus type ERoleType nature ERoleNature @@ -370,6 +374,7 @@ model Roles { model Services { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String? status EServiceStatus type EServiceType nature EServiceNature @@ -400,6 +405,7 @@ model Services { model Features { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String? status EFeatureStatus type EFeatureType nature EFeatureNature @@ -428,9 +434,12 @@ model Features { model Abilities { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String? status EAbilityStatus type EAbilityType nature EAbilityNature + target String? + action String? features Features[] @relation("featureAbilities", fields: [featuresIds], references: [id]) featuresIds String[] @db.ObjectId @@ -461,6 +470,7 @@ model Abilities { model Moods { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String description ILocaleString title ILocaleString @@ -488,6 +498,7 @@ model Moods { model Actions { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String description ILocaleString title ILocaleString @@ -515,6 +526,7 @@ model Actions { model Thoughts { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String description ILocaleString title ILocaleString @@ -542,6 +554,7 @@ model Thoughts { model Projects { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String description ILocaleString title ILocaleString @@ -574,6 +587,7 @@ model Projects { model Investments { id String @id @default(auto()) @map("_id") @db.ObjectId name ILocaleString + slug String description ILocaleString title ILocaleString @@ -639,6 +653,20 @@ type ILocaleString { bg String? bs String? sq String? + ja String? + ru String? + ar String? + he String? + zh String? + gl String? + sw String? + hi String? + ms String? + bn String? + pa String? + tr String? + fi String? + uk String? } @@ -878,6 +906,7 @@ enum EAbilityStatus { enum EAbilityNature { ROLE_BASED + BILLING_BASED PRIVILEGE COMMON TEMPORARY diff --git a/prisma/schema-public.prisma b/prisma/schema-public.prisma index 64c2522..bb49ead 100644 --- a/prisma/schema-public.prisma +++ b/prisma/schema-public.prisma @@ -19,6 +19,9 @@ model PublicListings { description ILocaleString status EListingStatus location ILocation + scheduledFor DateTime? @db.Date + value Float? + images String[] taxonomies ITaxonomiesFacade[] reviews IReviewFacade[] @@ -86,6 +89,20 @@ type ILocaleString { bg String? bs String? sq String? + ja String? + ru String? + ar String? + he String? + zh String? + gl String? + sw String? + hi String? + ms String? + bn String? + pa String? + tr String? + fi String? + uk String? } enum ECurrency { diff --git a/prisma/seed.mts b/prisma/seed.mts index 958c1b1..9e1931b 100644 --- a/prisma/seed.mts +++ b/prisma/seed.mts @@ -6,8 +6,8 @@ import { faker } from '@faker-js/faker'; import { PrismaClient as PrivatePrisma } from '@dreampipcom/db-private/prisma-client'; import { PrismaClient as PublicPrisma } from '@dreampipcom/db-public/prisma-client'; -import { mockUser, mockUser2, mockUser3 } from './mock/user.mts'; -import { mockCommunity, mockCommunity2, mockCommunity3 } from './mock/communities.mts'; +import { createMockUser, mockUser, mockUser2, mockUser3 } from './mock/user.mts'; +import { createMockCommunity, mockCommunity, mockCommunity2, mockCommunity3 } from './mock/communities.mts'; import { createMockListing } from './mock/listings.mts'; import { createMockAudience } from './mock/audiences.mts'; import { createMockTerm } from './mock/taxonomies.mts'; @@ -17,6 +17,7 @@ import { createMockPubListing } from './mock/public.mts'; import { createMockAbility } from './mock/abilities.mts'; import { createMockFeature } from './mock/features.mts'; import { createMockService } from './mock/services.mts'; +import _ from 'lodash'; export const cleanupDatabase = () => { const propertyNames = Object.getOwnPropertyNames(pvtPrisma); @@ -38,24 +39,512 @@ if (seedType === 'private') { const main = async () => { try { - // await pvtPrisma.products.deleteMany(); + // user0 + const user0 = await pvtPrisma.user.create({ + data: createMockUser({ + name: 'DreamPip', + firstName: 'DreamPip', + lastName: 'Superuser', + email: process.env.NEXUS_EMAIL, + }), + }); - // // cleanup the existing database - const allProperties = Reflect.ownKeys(Object.getPrototypeOf(pvtPrisma)); - const modelNames = allProperties.filter( - (x) => x != 'constructor' && x != 'on' && x != 'connect' && x != 'runDisconnect' && x != 'disconnect', - ); + // community0 + const community0 = await pvtPrisma.communities.create({ + data: createMockCommunity({ + name: 'DreamPip', + description: 'Fintech for compassion.', + urls: ['https://www.dreampip.com'], + user: user0.id, + refUsers: [{ id: user0.id }], + }), + }); - // if (modelNames.length > 0) { - // console.log("WARNING! ERASING DB.") - // cleanupDatabase() - // console.log("~ ERASED ~") - // } + // roles + const role1name = { + en: 'Superuser', + it: 'Superutente', + pt: 'Superusuário', + es: 'Superusuario', + de: 'Superbenutzer', + fr: 'Superutilisateur', + ro: 'Superutilizator', + cz: 'Superuživatel', + pl: 'Superużytkownik', + et: 'Superkasutaja', + sv: 'Superanvändare', + ja: 'スーパーユーザー', + ru: 'Суперпользователь', + ar: 'المستخدم الخارق', + he: 'משתמש מרשים', + zh: '超级用户', + nl: 'Supergebruiker', + da: 'Superbruger', + hu: 'Szuperfelhasználó', + ca: 'Superusuari', + eu: 'Supererabiltzaile', + gl: 'Superusuario', + sw: 'Mtumiaji Mkuu', + hi: 'सुपरउपयोगकर्ता', + ms: 'Superpengguna', + bn: 'সুপার ব্যবহারকারী', + pa: 'ਸੁਪਰਯੂਜ਼ਰ', + tr: 'Süper Kullanıcı', + fi: 'Superkäyttäjä', + el: 'Σούπερχρήστης', + uk: 'Суперкористувач', + }; - /* - ~~~~ PRIVATE ~~~~ - */ + const role2name = { + en: 'Admin', + it: 'Amministratore', + pt: 'Admin', + es: 'Administrador', + de: 'Administrator', + fr: 'Administrateur', + ro: 'Administrator', + cz: 'Správce', + pl: 'Administrator', + et: 'Administraator', + sv: 'Administratör', + ja: '管理者', + ru: 'Администратор', + ar: 'مدير', + he: 'מנהל', + zh: '管理员', + nl: 'Beheerder', + da: 'Administrator', + hu: 'Adminisztrátor', + ca: 'Administrador', + eu: 'Administratzaile', + gl: 'Administrador', + sw: 'Msimamizi', + hi: 'प्रशासक', + ms: 'Pentadbir', + bn: 'প্রশাসক', + pa: 'ਐਡਮਿਨ', + tr: 'Yönetici', + fi: 'Ylläpitäjä', + el: 'Διαχειριστής', + uk: 'Адміністратор', + }; + const role3name = { + en: 'Manager', + it: 'Manager', + pt: 'Gerente', + es: 'Gerente', + de: 'Manager', + fr: 'Manager', + ro: 'Manager', + cz: 'Manažer', + pl: 'Menedżer', + et: 'Juht', + sv: 'Chef', + ja: 'マネージャー', + ru: 'Менеджер', + ar: 'مدير', + he: 'מנהל', + zh: '经理', + nl: 'Manager', + da: 'Manager', + hu: 'Menedzser', + ca: 'Gerent', + eu: 'Kudeatzaile', + gl: 'Xestor', + sw: 'Meneja', + hi: 'प्रबंधक', + ms: 'Pengurus', + bn: 'ম্যানেজার', + pa: 'ਮੈਨੇਜਰ', + tr: 'Yönetici', + fi: 'Johtaja', + el: 'Διευθυντής', + uk: 'Менеджер', + }; + + const role4name = { + en: 'User', + it: 'Utente', + pt: 'Usuário', + es: 'Usuario', + de: 'Benutzer', + fr: 'Utilisateur', + ro: 'Utilizator', + cz: 'Uživatel', + pl: 'Użytkownik', + et: 'Kasutaja', + sv: 'Användare', + ja: 'ユーザー', + ru: 'Пользователь', + ar: 'مستخدم', + he: 'משתמש', + zh: '用户', + nl: 'Gebruiker', + da: 'Bruger', + hu: 'Felhasználó', + ca: 'Usuari', + eu: 'Erabiltzaile', + gl: 'Usuario', + sw: 'Mtumiaji', + hi: 'उपयोगकर्ता', + ms: 'Pengguna', + bn: 'ব্যবহারকারী', + pa: 'ਵਰਤੋਂਕਾਰ', + tr: 'Kullanıcı', + fi: 'Käyttäjä', + el: 'Χρήστης', + uk: 'Користувач', + }; + + const role1 = await pvtPrisma.roles.create({ + data: createMockRole({ + name: role1name, + slug: 'role-su', + user: user0.id, + community: community0.id, + refUsers: [{ id: user0.id }], + refCommunities: [], + }), + }); + + const role2 = await pvtPrisma.roles.create({ + data: createMockRole({ + name: role2name, + slug: 'role-admin', + user: user0.id, + community: community0.id, + refUsers: [], + refCommunities: [], + }), + }); + + const role3 = await pvtPrisma.roles.create({ + data: createMockRole({ + name: role3name, + slug: 'role-manager', + user: user0.id, + community: community0.id, + refUsers: [], + refCommunities: [], + }), + }); + + const role4 = await pvtPrisma.roles.create({ + data: createMockRole({ + name: role4name, + slug: 'role-user', + user: user0.id, + community: community0.id, + refUsers: [], + refCommunities: [], + }), + }); + + // abilities + const ability1name = { + en: 'Favorite Listings', + it: 'Aggiungi ai Preferiti', + pt: 'Favoritar Listagens', + es: 'Marcar como Favorito', + de: 'Anzeigen favorisieren', + fr: 'Mettre en Favori', + ro: 'Favoritează liste', + cz: 'Oblíbené inzeráty', + pl: 'Dodaj do Ulubionych', + et: 'Lisa lemmikutesse', + sv: 'Gör till Favoriter', + ja: 'お気に入りにする', + ru: 'Добавить в Избранное', + ar: 'القوائم المفضلة', + he: 'הוסף למועדפים', + zh: '收藏清单', + nl: 'Favoriete vermeldingen', + da: 'Favoritlister', + hu: 'Kedvenc hirdetések', + ca: 'Afegir a Preferits', + eu: 'Gehitu Gogokoenetara', + gl: 'Engadir a Favoritos', + sw: 'Orodhesha Pendwa', + hi: 'पसंदीदा सूची', + ms: 'Senarai Kegemaran', + bn: 'পছন্দের তালিকা', + pa: 'ਪਸੰਦੀਦਾ ਸੂਚੀਆਂ', + tr: 'Favori İlanlar', + fi: 'Suosikkiluettelot', + el: 'Αγαπημένες καταχωρήσεις', + uk: 'Обрані оголошення', + }; + + const ability2name = { + en: 'View Listings', + it: 'Visualizza inserzioni', + pt: 'Ver listagens', + es: 'Ver listados', + de: 'Anzeigen anzeigen', + fr: 'Voir les annonces', + ro: 'Vizualizare liste', + cz: 'Zobrazit inzeráty', + pl: 'Wyświetl oferty', + et: 'Vaata kuulutusi', + sv: 'Visa listor', + ja: 'リストを表示する', + ru: 'Просмотр объявлений', + ar: 'عرض القوائم', + he: 'הצג רשימות', + zh: '查看列表', + nl: 'Bekijk aanbiedingen', + da: 'Se lister', + hu: 'Listázások megtekintése', + ca: 'Veure llistats', + eu: 'Eman ikuspegiak', + gl: 'Ver listados', + sw: 'Tazama Orodha', + hi: 'लिस्टिंग देखें', + ms: 'Lihat Senarai', + bn: 'লিস্টিং দেখুন', + pa: 'ਲਿਸਟਿੰਗ ਵੇਖੋ', + tr: 'İlanları Görüntüle', + fi: 'Näytä ilmoitukset', + el: 'Προβολή καταχωρήσεων', + uk: 'Переглянути оголошення', + }; + + const ability1 = await pvtPrisma.abilities.create({ + data: createMockAbility({ + name: ability2name, + user: user0.id, + slug: 'abil-view-rm', + community: community0.id, + type: 'R', + action: 'view-listings', + nature: 'COMMON', + target: 'rickmorty', + roles: [{ id: role1.id }, { id: role2.id }], + refUsers: [{ id: user0.id }], + refCommunities: [{ id: community0.id }], + }), + }); + + const ability2 = await pvtPrisma.abilities.create({ + data: createMockAbility({ + name: ability2name, + user: user0.id, + slug: 'abil-view-vm', + type: 'R', + action: 'view-listings', + nature: 'PRIVILEGE', + target: 'dpcp-vibemodulator', + community: community0.id, + roles: [{ id: role1.id }], + refUsers: [{ id: user0.id }], + refCommunities: [{ id: community0.id }], + }), + }); + + const ability3 = await pvtPrisma.abilities.create({ + data: createMockAbility({ + name: ability1name, + user: user0.id, + slug: 'abil-favorite-rm', + type: 'U', + action: 'favorite', + nature: 'COMMON', + target: 'rickmorty', + community: community0.id, + roles: [{ id: role1.id }], + refUsers: [{ id: user0.id }], + refCommunities: [{ id: community0.id }], + }), + }); + + // // features + const feature1name = { + en: 'Favoriting of entries', + it: 'Aggiunta ai preferiti delle voci', + pt: 'Favoritar entradas', + es: 'Marcar entradas como favoritas', + de: 'Einträge favorisieren', + fr: 'Mise en favori des entrées', + ro: 'Adăugarea la favorite a intrărilor', + cz: 'Přidání záznamů do oblíbených', + pl: 'Dodawanie wpisów do ulubionych', + et: 'Kirjete lemmikuks märkimine', + sv: 'Favoritmarkera poster', + ja: 'エントリーのお気に入り登録', + ru: 'Добавление в избранное записей', + ar: 'تحديد الإدخالات كمفضلة', + he: 'הוספת כתבות למועדפים', + zh: '添加收藏条目', + nl: 'Toevoegen van items aan favorieten', + da: 'Tilføjelse af emner til favoritter', + hu: 'Bejegyzések kedvencekké nyilvánítása', + ca: 'Afavorir entrades', + eu: 'Sarrera gehitzea gogokoak direla', + gl: 'Engadido de entradas a favoritos', + sw: 'Kupendezesha vya kuingia', + hi: 'प्रविष्टियों को पसंदीदा बनाना', + ms: 'Menanda buku entri', + bn: 'এন্ট্রিগুলিকে পছন্দমূলক করা', + pa: 'ਇੰਟਰੀਆਂ ਨੂੰ ਪਸੰਦੀਦਾ ਬਣਾਉਣਾ', + tr: 'Girişleri favorilere ekleme', + fi: 'Merkintöjen suosiminen', + el: 'Προτίμηση καταχωρήσεων', + uk: 'Додавання записів до обраного', + }; + + const feature1 = await pvtPrisma.features.create({ + data: createMockFeature({ + name: feature1name, + slug: 'feat-favorite-entries', + user: user0.id, + community: community0.id, + abilities: [{ id: ability1.id }], + refUsers: [{ id: user0.id }], + refCommunities: [{ id: community0.id }], + }), + }); + + // // services + const service1name = { + en: 'The Rick Morty Experience', + it: "L'esperienza di Rick Morty", + pt: 'A Experiência Rick Morty', + es: 'La Experiencia Rick Morty', + de: 'Das Rick Morty Erlebnis', + fr: "L'expérience Rick Morty", + ro: 'Experiența Rick Morty', + cz: 'Rick Morty Zážitek', + pl: 'Doświadczenie Rick Morty', + et: 'Rick Morty Kogemus', + sv: 'Rick Morty-upplevelsen', + ja: 'リック・モーティ体験', + ru: 'Опыт Рика и Морти', + ar: 'تجربة ريك مورتي', + he: 'חוויית ריק מורטי', + zh: '瑞克莫蒂体验', + nl: 'De Rick Morty-ervaring', + da: 'Rick Morty Oplevelsen', + hu: 'A Rick és Morty Élménye', + ca: "L'experiència Rick Morty", + eu: 'The Rick Morty Esperientzia', + gl: 'A Experiencia Rick Morty', + sw: 'Uzoefu wa Rick Morty', + hi: 'रिक मोर्टी अनुभव', + ms: 'Pengalaman Rick Morty', + bn: 'রিক এবং মর্টি অভিজ্ঞতা', + pa: 'ਰਿਕ ਮੋਰਟੀ ਦਾ ਅਨੁਭਵ', + tr: 'Rick Morty Deneyimi', + fi: 'Rick Morty Kokemus', + el: 'Η Εμπειρία Rick Morty', + uk: 'Досвід Ріка і Морті', + }; + + const service2name = { + en: 'The Vibe Modulator', + it: 'Il Modulatore di Vibrazioni', + pt: 'O Modulador de Vibração', + es: 'El Modulador de Vibra', + de: 'Der Vibe-Modulator', + fr: 'Le Modulateur de Vibration', + ro: 'Modulatorul de Vibrații', + cz: 'Vibrační Modulátor', + pl: 'Modulator Nastroju', + et: 'Vibe Modulaator', + sv: 'Vibe-modulatorn', + ja: 'バイブモジュレーター', + ru: 'Вибромодулятор', + ar: 'معدل الجو', + he: 'מייסד הוייב', + zh: '振动调制器', + nl: 'De Vibe Modulator', + da: 'Vibe-modulatoren', + hu: 'Vibe modulátor', + ca: 'El Modulador de Vibra', + eu: 'The Vibe Modulator', + gl: 'O Modulador de Vibration', + sw: 'Mbadala wa Vibe', + hi: 'द वाइब मॉड्यूलेटर', + ms: 'Modulator Getaran', + bn: 'দ্য ভাইব মড্যুলেটর', + pa: 'ਵਾਇਬ ਮੋਡੂਲੇਟਰ', + tr: 'Vibe Modülatör', + fi: 'Vibe-modulaattori', + el: 'Ο Μετατροπέας Δόνησης', + uk: 'Вібромодулятор', + }; + + const service1 = await pvtPrisma.services.create({ + data: createMockService({ + name: service1name, + slug: 'rickmorty', + user: user0.id, + community: community0.id, + features: [{ id: feature1.id }], + refUsers: [{ id: user0.id }], + refCommunities: [{ id: community0.id }], + }), + }); + + const service2 = await pvtPrisma.services.create({ + data: createMockService({ + name: service2name, + slug: 'dpcp-vibemodulator', + user: user0.id, + community: community0.id, + refUsers: [{ id: user0.id }], + refCommunities: [{ id: community0.id }], + }), + }); + + console.log(`Private Database has been seeded. 🌱`); + } catch (error) { + throw error; + } + }; + func = main; +} else if (seedType === 'public') { + console.log('~ SEEDING PUBLIC DB ~'); + + const pvtPrisma = new PrivatePrisma({ + datasourceUrl: process.env.PRISMA_PRIVATE_URI, + }); + + const pubPrisma = new PublicPrisma({ + datasourceUrl: process.env.PRISMA_PUBLIC_URI, + }); + + const main = async () => { + try { + const facadeEntry = (fields: string[], facades: Record) => (entry: any) => { + const facader = fields.reduce((fac, field, index) => { + let content = entry[field]; + if (facades && facades[field]) { + content = facades[field](content); + } + fac[field] = content; + return fac; + }, {}); + + return facader; + }; + + console.log(`Public Database has been seeded. 🌱`); + } catch (error) { + throw error; + } + }; + func = main; +} else if (seedType === 'mock') { + console.log('~ SEEDIND DBS WITH MOCK DATA ~'); + console.log('~ SEEDING PRIVATE DB WITH MOCK DATA ~'); + + const pvtPrisma = new PrivatePrisma({ + datasourceUrl: process.env.PRISMA_PRIVATE_URI, + }); + + const main = async () => { + try { const user1 = await pvtPrisma.user.create({ data: mockUser }); const user2 = await pvtPrisma.user.create({ data: mockUser2 }); const user3 = await pvtPrisma.user.create({ data: mockUser3 }); @@ -84,18 +573,77 @@ if (seedType === 'private') { }); // // abilities + + const ability1name = { + en: 'Favorite Listings (mock)', + it: 'Aggiungi ai Preferiti (mock)', + pt: 'Favoritar Listagens (mock)', + es: 'Marcar como Favorito (mock)', + de: 'Anzeigen favorisieren (mock)', + fr: 'Mettre en Favori (mock)', + ro: 'Favoritează liste (mock)', + cz: 'Oblíbené inzeráty (mock)', + pl: 'Dodaj do Ulubionych (mock)', + et: 'Lisa lemmikutesse (mock)', + sv: 'Gör till Favoriter (mock)', + ja: 'お気に入りにする (mock)', + ru: 'Добавить в Избранное (mock)', + }; + + const ability2name = { + en: 'View Listings (mock)', + it: 'Visualizza inserzioni (mock)', + pt: 'Ver listagens (mock)', + es: 'Ver listados (mock)', + de: 'Anzeigen anzeigen (mock)', + fr: 'Voir les annonces (mock)', + ro: 'Vizualizare liste (mock)', + cz: 'Zobrazit inzeráty (mock)', + pl: 'Wyświetl oferty (mock)', + et: 'Vaata kuulutusi (mock)', + sv: 'Visa listor (mock)', + ja: 'リストを表示する (mock)', + ru: 'Просмотр объявлений (mock)', + }; + const ability1 = await pvtPrisma.abilities.create({ data: createMockAbility({ + name: ability2name, user: user1.id, community: community1.id, + type: 'R', + action: 'view-listings-mock', + nature: 'COMMON', + target: 'rickmorty', roles: [{ id: role1.id }, { id: role2.id }], refUsers: [{ id: user1.id }], refCommunities: [{ id: community1.id }], }), }); + const ability2 = await pvtPrisma.abilities.create({ data: createMockAbility({ + name: ability2name, user: user1.id, + type: 'R', + action: 'view-listings-mock', + nature: 'PRIVILEGE', + target: 'dpcp-vibemodulator', + community: community1.id, + roles: [{ id: role1.id }, { id: role2.id }], + refUsers: [{ id: user1.id }, { id: user2.id }, { id: user3.id }], + refCommunities: [{ id: community2.id }, { id: community3.id }], + }), + }); + + const ability3 = await pvtPrisma.abilities.create({ + data: createMockAbility({ + name: ability1name, + user: user1.id, + type: 'U', + action: 'favorite-mock', + nature: 'COMMON', + target: 'rickmorty', community: community1.id, roles: [{ id: role1.id }, { id: role2.id }], refUsers: [{ id: user1.id }, { id: user2.id }, { id: user3.id }], @@ -124,8 +672,42 @@ if (seedType === 'private') { }); // // services + const service1name = { + en: 'The Rick Morty Experience (mock)', + it: "L'esperienza di Rick Morty", + pt: 'A Experiência Rick Morty (mock)', + es: 'La Experiencia Rick Morty (mock)', + de: 'Das Rick Morty Erlebnis (mock)', + fr: "L'expérience Rick Morty", + ro: 'Experiența Rick Morty (mock)', + cz: 'Rick Morty Zážitek (mock)', + pl: 'Doświadczenie Rick Morty (mock)', + et: 'Rick Morty Kogemus (mock)', + sv: 'Rick Morty-upplevelsen (mock)', + ja: 'リック・モーティ体験 (mock)', + ru: 'Опыт Рика и Морти (mock)', + }; + + const service2name = { + en: 'The Vibe Modulator (mock)', + it: 'Il Modulatore di Vibrazioni (mock)', + pt: 'O Modulador de Vibração (mock)', + es: 'El Modulador de Vibra (mock)', + de: 'Der Vibe-Modulator (mock)', + fr: 'Le Modulateur de Vibration (mock)', + ro: 'Modulatorul de Vibrații (mock)', + cz: 'Vibrační Modulátor (mock)', + pl: 'Modulator Nastroju (mock)', + et: 'Vibe Modulaator (mock)', + sv: 'Vibe-modulatorn (mock)', + ja: 'バイブモジュレーター (mock)', + ru: 'Вибромодулятор (mock)', + }; + const service1 = await pvtPrisma.services.create({ data: createMockService({ + name: service1name, + slug: 'rickmorty-mock', user: user1.id, community: community1.id, features: [{ id: feature1.id }, { id: feature2.id }], @@ -133,8 +715,11 @@ if (seedType === 'private') { refCommunities: [{ id: community1.id }], }), }); + const service2 = await pvtPrisma.services.create({ data: createMockService({ + name: service2name, + slug: 'dpcp-vibemodulator-mock', user: user1.id, community: community1.id, refUsers: [{ id: user2.id }, { id: user3.id }], @@ -151,6 +736,7 @@ if (seedType === 'private') { communityFavorited: [{ id: community2.id }, { id: community3.id }], }), }); + const listing2 = await pvtPrisma.listings.create({ data: createMockListing({ favorited: [{ id: user2.id }, { id: user3.id }], @@ -170,6 +756,7 @@ if (seedType === 'private') { targetUser: [{ id: user2.id }], }), }); + const term2 = await pvtPrisma.taxonomies.create({ data: createMockTerm({ community: community3.id, @@ -191,6 +778,7 @@ if (seedType === 'private') { toListings: [], }), }); + const message2 = await pvtPrisma.messages.create({ data: createMockMessage({ community: community3.id, @@ -201,6 +789,7 @@ if (seedType === 'private') { toListings: [{ id: listing1.id }, { id: listing2.id }], }), }); + const message3 = await pvtPrisma.messages.create({ data: createMockMessage({ community: community3.id, @@ -212,42 +801,16 @@ if (seedType === 'private') { }), }); - console.log(`Private Database has been seeded. 🌱`); + console.log(`Private Database has been seeded with mock data. 🌱`); } catch (error) { throw error; } - }; - func = main; -} else { - console.log('~ SEEDING PUBLIC DB ~'); - - const pvtPrisma = new PrivatePrisma({ - datasourceUrl: process.env.PRISMA_PRIVATE_URI, - }); - - const pubPrisma = new PublicPrisma({ - datasourceUrl: process.env.PRISMA_PUBLIC_URI, - }); - - const main = async () => { try { - // await pvtPrisma.products.deleteMany(); - - // // cleanup the existing database - const allProperties = Reflect.ownKeys(Object.getPrototypeOf(pubPrisma)); - const modelNames = allProperties.filter( - (x) => x != 'constructor' && x != 'on' && x != 'connect' && x != 'runDisconnect' && x != 'disconnect', - ); + console.log('~ SEEDING PUBLIC DB WITH MOCK DATA ~'); - // if (modelNames.length > 0) { - // console.log("WARNING! ERASING DB.") - // cleanupDatabase() - // console.log("~ ERASED ~") - // } - - /* - ~~~~ PUBLIC ~~~~ - */ + const pubPrisma = new PublicPrisma({ + datasourceUrl: process.env.PRISMA_PUBLIC_URI, + }); const facadeEntry = (fields: string[], facades: Record) => (entry: any) => { const facader = fields.reduce((fac, field, index) => { @@ -264,11 +827,6 @@ if (seedType === 'private') { const facadeTaxonomy = facadeEntry(['id', 'name', 'description', 'status', 'type', 'nature', 'audiencesIds']); - // const decorateAd = facadeEntry([ - // 'userFits', - // 'communityFits', - // ]); - const facadeMessage = facadeEntry([ 'id', 'name', @@ -329,11 +887,22 @@ if (seedType === 'private') { }), }); - console.log(`Public Database has been seeded. 🌱`); + _.times(100, async () => { + await pubPrisma.publicListings.create({ + data: createMockPubListing({ + community: facadeCommunity(community), + user: facadeUser(user), + taxonomies: [facadeTaxonomy(term)], + }), + }); + }); + + console.log(`Public Database has been seeded with mock data. 🌱`); } catch (error) { throw error; } }; + func = main; } diff --git a/src/app/api/v1/public/route.ts b/src/app/api/v1/public/route.ts index 6254110..6db80f5 100644 --- a/src/app/api/v1/public/route.ts +++ b/src/app/api/v1/public/route.ts @@ -15,11 +15,6 @@ const generateErrorResponse = (e: any, status: number) => { // export const dynamic = 'force-static'; export async function GET(request: CombineRequest) { - console.log({ - request: request.cookies, - requestOrigin: request.headers.get('x-forwarded-host'), - cache: request.headers.get('cache-control'), - }); try { const url = new URL(request.url); const query = url.searchParams; @@ -42,8 +37,6 @@ export async function GET(request: CombineRequest) { filters: filterArray, }); - console.log({ headers: request.headers }); - const headers = { 'content-type': 'application/json', 'Cache-Control': 'maxage=0, s-maxage=60, stale-while-revalidate=86400', diff --git a/src/app/api/v1/services/dpcp-vibemodulator/route.ts b/src/app/api/v1/services/dpcp-vibemodulator/route.ts new file mode 100644 index 0000000..008b791 --- /dev/null +++ b/src/app/api/v1/services/dpcp-vibemodulator/route.ts @@ -0,0 +1,60 @@ +// @api/v1/services/dpcp-vibemodulator/index.ts +import type { NextApiRequest } from 'next'; +import type { NextRequest } from 'next/server'; +import { NextResponse } from 'next/server'; +import { GetPrivateServices } from '@controller'; +import { GetSession } from '@auth'; +type CombineRequest = NextRequest & NextApiRequest; + +const generateErrorResponse = (e: any, status: number) => { + return { + ok: false, + status, + message: e.message, + }; +}; + +// export const dynamic = 'force-static'; +export async function GET(request: CombineRequest) { + try { + const cookies = request?.cookies?.toString() || request?.headers?.get('cookies'); + const session = await GetSession({ cookies: cookies || '' }); + const user = session?.user; + + const url = new URL(request.url); + const query = url.searchParams; + + const page = query.get('page'); + const limit = query.get('limit'); + const offset = query.get('offset'); + const filters = query.get('filters'); + + const filterArray = filters ? (Array.isArray(filters) ? filters : [filters]) : []; + + const coercedPage = Number(page ? (Array.isArray(page) ? page[0] : page) : 0); + const coercedLimit = Number(limit ? (Array.isArray(limit) ? limit[0] : limit) : 100); + const coercedOffset = Number(offset ? (Array.isArray(offset) ? offset[0] : offset) : 0); + + const data = await GetPrivateServices({ + user, + target: 'dpcp-vibemodulator', + page: coercedPage, + limit: coercedLimit, + offset: coercedOffset, + filters: filterArray, + }); + + return NextResponse.json( + { + ok: true, + status: 200, + data, + }, + { + status: 200, + }, + ); + } catch (e) { + return NextResponse.json(generateErrorResponse(e, 403), { status: 403 }); + } +} diff --git a/src/app/api/v1/services/rickmorty/route.ts b/src/app/api/v1/services/rickmorty/route.ts new file mode 100644 index 0000000..30bccad --- /dev/null +++ b/src/app/api/v1/services/rickmorty/route.ts @@ -0,0 +1,53 @@ +// @api/v1/services/rickmorty/index.ts +import type { NextApiRequest } from 'next'; +import type { NextRequest } from 'next/server'; +import { NextResponse } from 'next/server'; +import { GetPublicListings } from '@controller'; +type CombineRequest = NextRequest & NextApiRequest; + +const generateErrorResponse = (e: any, status: number) => { + return { + ok: false, + status, + message: e.message, + }; +}; + +// export const dynamic = 'force-static'; +export async function GET(request: CombineRequest) { + try { + const url = new URL(request.url); + const query = url.searchParams; + + const page = query.get('page'); + const limit = query.get('limit'); + const offset = query.get('offset'); + const filters = query.get('filters'); + + const filterArray = filters ? (Array.isArray(filters) ? filters : [filters]) : []; + + const coercedPage = Number(page ? (Array.isArray(page) ? page[0] : page) : 0); + const coercedLimit = Number(limit ? (Array.isArray(limit) ? limit[0] : limit) : 100); + const coercedOffset = Number(offset ? (Array.isArray(offset) ? offset[0] : offset) : 0); + + const data = await GetPublicListings({ + page: coercedPage, + limit: coercedLimit, + offset: coercedOffset, + filters: filterArray, + }); + + return NextResponse.json( + { + ok: true, + status: 200, + data, + }, + { + status: 200, + }, + ); + } catch (e) { + return NextResponse.json(generateErrorResponse(e, 403), { status: 403 }); + } +} diff --git a/src/app/api/v1/user/route.ts b/src/app/api/v1/user/route.ts index 54a3e28..74c9e87 100644 --- a/src/app/api/v1/user/route.ts +++ b/src/app/api/v1/user/route.ts @@ -3,7 +3,12 @@ import type { NextApiRequest } from 'next'; import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; import { GetSession } from '@auth'; -import { UpdatePrivateUserFavoriteListings, GetPrivateCommonAbilities } from '@controller'; +import { + GetPrivateAbilities, + GetPrivateServices, + UpdatePrivateUserFavoriteListings, + GetPrivateCommonAbilities, +} from '@controller'; type CombineRequest = NextRequest & NextApiRequest; const generateErrorResponse = (e: any, status: number) => { @@ -35,12 +40,46 @@ export async function POST(request: CombineRequest) { } } - return NextResponse.json(generateErrorResponse('Not authorized', 403), { status: 403 }); + const cookies = request?.cookies?.toString() || request?.headers?.get('cookies'); + const session = await GetSession({ cookies: cookies || '' }); + const user = session?.user; + + const body = await request?.json(); + const action = body?.action; + // const listings = body?.action; + + if (!!user && !!action) { + const payload = { data: {} }; + try { + if (action === 'get-own-abilities') { + payload.data = await GetPrivateAbilities({ filters: ['user'], user }); + } else if (action === 'get-own-services') { + payload.data = await GetPrivateServices({ filters: ['user'], user }); + } else { + throw new Error('Code 000/1: No specified action'); + } + } catch (e) { + return NextResponse.json(generateErrorResponse(e, 400), { status: 400 }); + } + + return NextResponse.json( + { + ok: true, + status: 200, + data: payload.data, + }, + { + status: 200, + }, + ); + } + + return NextResponse.json(generateErrorResponse('Code 000: Malformed request', 400), { status: 400 }); } export async function PATCH(request: CombineRequest) { try { - const cookies = request?.headers.get('cookies'); + const cookies = request?.cookies?.toString() || request?.headers?.get('cookies'); const session = await GetSession({ cookies: cookies || '' }); const url = new URL(request.url); const query = url.searchParams; @@ -58,7 +97,7 @@ export async function PATCH(request: CombineRequest) { // [DPCP-116]: https://www.notion.so/angeloreale/Hypnos-Add-transactional-websockets-de3667b32a4c4cd4ade76080203e68fd?pvs=4 // might have idempotency issues. - // need ui to signal request was received, + // need optimistic ui to signal request was sent + received, // but subsequent webhook to confirm it was processed correctly // const headers = { // 'content-type': 'application/json', From 3bad2cdac5d8ac5937ea1fb217a8c44197dadcf2 Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Mon, 26 Aug 2024 03:33:02 +0100 Subject: [PATCH 4/5] [Snyk] Upgrade @sentry/nextjs from 8.20.0 to 8.22.0 (#32) * fix: upgrade @sentry/nextjs from 8.20.0 to 8.22.0 Snyk has created this PR to upgrade @sentry/nextjs from 8.20.0 to 8.22.0. See this package in npm: @sentry/nextjs See this project in Snyk: https://app.snyk.io/org/angeloreale/project/0ce13fdb-820a-4a03-9e39-a46edd73375a?utm_source=github&utm_medium=referral&page=upgrade-pr * ar(config) sentry --------- Co-authored-by: snyk-bot --- .gitignore | 4 +- next.config.mjs | 68 ++++++------ package-lock.json | 218 +++++++++++++++++++++++---------------- package.json | 2 +- sentry.client.config.ts | 29 ++++++ sentry.edge.config.ts | 16 +++ sentry.server.config.ts | 18 ++++ src/app/global-error.tsx | 23 +++++ src/instrumentation.ts | 9 ++ 9 files changed, 257 insertions(+), 130 deletions(-) create mode 100644 sentry.client.config.ts create mode 100644 sentry.edge.config.ts create mode 100644 sentry.server.config.ts create mode 100644 src/app/global-error.tsx create mode 100644 src/instrumentation.ts diff --git a/.gitignore b/.gitignore index b2b9c57..14bf5bf 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,6 @@ next-env.d.ts # private *.private -stub.json \ No newline at end of file +stub.json +# Sentry Config File +.env.sentry-build-plugin diff --git a/next.config.mjs b/next.config.mjs index dfeb203..efba8b6 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,3 +1,4 @@ +import { withSentryConfig } from '@sentry/nextjs'; import { PrismaPlugin } from '@prisma/nextjs-monorepo-workaround-plugin'; // const headers = [ @@ -65,49 +66,42 @@ const nextConfig = { }, }; -export default nextConfig; +export default withSentryConfig(nextConfig, { + // For all available options, see: + // https://github.com/getsentry/sentry-webpack-plugin#options -// Injected content via Sentry wizard below + org: 'dreampip', + project: 'hypnos', -// const { withSentryConfig } = require('@sentry/nextjs'); + // Only print logs for uploading source maps in CI + silent: !process.env.CI, -// module.exports = withSentryConfig( -// module.exports, -// { -// // For all available options, see: -// // https://github.com/getsentry/sentry-webpack-plugin#options + // For all available options, see: + // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ -// // Suppresses source map uploading logs during build -// silent: true, -// org: 'dreampip', -// project: 'hypnos', -// }, -// { -// // For all available options, see: -// // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ + // Upload a larger set of source maps for prettier stack traces (increases build time) + widenClientFileUpload: true, -// // Upload a larger set of source maps for prettier stack traces (increases build time) -// widenClientFileUpload: true, - -// // Transpiles SDK to be compatible with IE11 (increases bundle size) -// transpileClientSDK: true, + // Automatically annotate React components to show their full name in breadcrumbs and session replay + reactComponentAnnotation: { + enabled: true, + }, -// // Uncomment to route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. -// // This can increase your server load as well as your hosting bill. -// // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client- -// // side errors will fail. -// // tunnelRoute: "/monitoring", + // Uncomment to route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. + // This can increase your server load as well as your hosting bill. + // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client- + // side errors will fail. + // tunnelRoute: "/monitoring", -// // Hides source maps from generated client bundles -// hideSourceMaps: true, + // Hides source maps from generated client bundles + hideSourceMaps: true, -// // Automatically tree-shake Sentry logger statements to reduce bundle size -// disableLogger: true, + // Automatically tree-shake Sentry logger statements to reduce bundle size + disableLogger: true, -// // Enables automatic instrumentation of Vercel Cron Monitors. -// // See the following for more information: -// // https://docs.sentry.io/product/crons/ -// // https://vercel.com/docs/cron-jobs -// automaticVercelMonitors: true, -// }, -// ); + // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) + // See the following for more information: + // https://docs.sentry.io/product/crons/ + // https://vercel.com/docs/cron-jobs + automaticVercelMonitors: true, +}); diff --git a/package-lock.json b/package-lock.json index 56c4958..a031ff0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "HPL3-ECO-AND-ANC", "dependencies": { - "@sentry/nextjs": "^8.20.0", + "@sentry/nextjs": "^8.22.0", "next": "14.2.4" }, "devDependencies": { @@ -963,6 +963,15 @@ "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@opentelemetry/instrumentation": { "version": "0.52.1", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.52.1.tgz", @@ -1002,9 +1011,9 @@ } }, "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.41.0.tgz", - "integrity": "sha512-/B7fbMdaf3SYe5f1P973tkqd6s7XZirjpfkoJ63E7nltU30qmlgm9tY5XwZOzAFI0rHS9tbrFI2HFPAvQUFe/A==", + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.41.1.tgz", + "integrity": "sha512-uRx0V3LPGzjn2bxAnV8eUsDT82vT7NTwI0ezEuPMBOTOsnPpGhWdhcdNdhH80sM4TrWrOfXm9HGEdfWE3TRIww==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "^1.8.0", @@ -1085,6 +1094,15 @@ "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@opentelemetry/instrumentation-http/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -1288,6 +1306,15 @@ "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@opentelemetry/sdk-metrics": { "version": "1.25.1", "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz", @@ -1322,7 +1349,7 @@ "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/semantic-conventions": { + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { "version": "1.25.1", "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", @@ -1331,6 +1358,15 @@ "node": ">=14" } }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.26.0.tgz", + "integrity": "sha512-U9PJlOswJPSgQVPI+XEuNLElyFWkb0hAiMg+DExD9V0St03X2lPHGMdxMY/LrVmoukuIpXJ12oyrOtEZ4uXFkw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@opentelemetry/sql-common": { "version": "0.40.1", "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", @@ -1807,58 +1843,58 @@ "license": "MIT" }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.20.0.tgz", - "integrity": "sha512-GGYNiELnT4ByidHyS4/M8UF8Oxagm5R13QyTncQGq8nZcQhcFZ9mdxLnf1/R4+j44Fph2Cgzafe8jGP/AMA9zw==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.22.0.tgz", + "integrity": "sha512-R0u8KPaSivueIwUOhmYxcisKaJq3gx+I0xOcWoluDB3OI1Ds/QOSP/vmTsMg/mjwG/nUJ8RRM8pj0s8vlqCrjg==", "license": "MIT", "dependencies": { - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.20.0.tgz", - "integrity": "sha512-mFvAoVpVShkDB2AgEr/dE96NSTPKI/lGMBznZMg7ZEcwZhLfH7HvLYCadIskRfzqFTLOUpbm9ciIO4SyR/4bDA==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.22.0.tgz", + "integrity": "sha512-Sy2+v0xBmVnZ5LQ48603CvLy5vVQvAZ+hc9xQSAHexts07NkvApMU1qv26YNwxlAWfDha1wXiW6ryd4YDzaoVA==", "license": "MIT", "dependencies": { - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.20.0.tgz", - "integrity": "sha512-sCiI7SOAHq5XsxkixtoMofeSyKd/hVgDV+4145f6nN9m7nLzig4PBQwh2SgK2piJ2mfaXfqcdzA1pShPYldaJA==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.22.0.tgz", + "integrity": "sha512-sF8RyMPJP1fSIyyBDAbtybvKCu0dy8ZAfMwLP7ZqEnWrhZqktVuqM7/++EAFMlD5YaWJXm1IDuOXjgSQjUtSIQ==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.20.0", - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry-internal/browser-utils": "8.22.0", + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.20.0.tgz", - "integrity": "sha512-LXV/pMH9KMw6CtImenMsiBkYIFIc97pDJ/rC7mVImKIROQ45fxGp/JBXM4Id0GENyA2+SySMWVQCAAapSfHZTw==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.22.0.tgz", + "integrity": "sha512-/gV8qN3JqWw0LXTMuCGB8RDI8Bx1VESNRBdh/7Cmc5+hxYBfcketuix3S8mHWcE/JO+Ed9g1Abzys6GphTB9LA==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "8.20.0", - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry-internal/replay": "8.22.0", + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" @@ -1873,18 +1909,18 @@ } }, "node_modules/@sentry/browser": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.20.0.tgz", - "integrity": "sha512-JDZbCreY44/fHYN28QzsAwEHXa2rc1hzM6GE4RSlXCdAhNfrjVxyYDxhw/50pVEHZg1WXxf7ZmERjocV5VJHsw==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.22.0.tgz", + "integrity": "sha512-t3b+/9WWcP9SQTWwrHrB57B33ENgmUjyFlW2+JSlCXkSJBSmAoquPZ/GPjOuPaSr3HIA0mu9uEr4A41d5diASQ==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.20.0", - "@sentry-internal/feedback": "8.20.0", - "@sentry-internal/replay": "8.20.0", - "@sentry-internal/replay-canvas": "8.20.0", - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry-internal/browser-utils": "8.22.0", + "@sentry-internal/feedback": "8.22.0", + "@sentry-internal/replay": "8.22.0", + "@sentry-internal/replay-canvas": "8.22.0", + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" @@ -2095,34 +2131,34 @@ } }, "node_modules/@sentry/core": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.20.0.tgz", - "integrity": "sha512-R81snuw+67VT4aCxr6ShST/s0Y6FlwN2YczhDwaGyzumn5rlvA6A4JtQDeExduNoDDyv4T3LrmW8wlYZn3CJJw==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.22.0.tgz", + "integrity": "sha512-fYPnxp7UkY2tckaOtivIySxnJvlbekuxs+Qi6rkUv9JpF+TYKpt7OPNUAbgVIhS0xazAEN6iKTfmnmpUbFRLmQ==", "license": "MIT", "dependencies": { - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/nextjs": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-8.20.0.tgz", - "integrity": "sha512-ZMi50qeklxibnNehlghNvlmzz1NIvYUGglDMy/m/N67SfXiq5PXyVziJAoCKQXR7nrvoQx0Mx17Z9ZFIwgjSJQ==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-8.22.0.tgz", + "integrity": "sha512-XYb/3ocQLhZmdqqTgI7xce7AiRpHn3L6Sj3RVTBwNb4nb+XOfQ8o0LKF7v7yo6LGoQin+IWpWPACnNc8zH7fBA==", "license": "MIT", "dependencies": { "@opentelemetry/instrumentation-http": "0.52.1", "@opentelemetry/semantic-conventions": "^1.25.1", "@rollup/plugin-commonjs": "26.0.1", - "@sentry/core": "8.20.0", - "@sentry/node": "8.20.0", - "@sentry/opentelemetry": "8.20.0", - "@sentry/react": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0", - "@sentry/vercel-edge": "8.20.0", + "@sentry/core": "8.22.0", + "@sentry/node": "8.22.0", + "@sentry/opentelemetry": "8.22.0", + "@sentry/react": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0", + "@sentry/vercel-edge": "8.22.0", "@sentry/webpack-plugin": "2.20.1", "chalk": "3.0.0", "resolve": "1.22.8", @@ -2198,9 +2234,9 @@ } }, "node_modules/@sentry/node": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-8.20.0.tgz", - "integrity": "sha512-i4ywT2m0Gw65U3uwI4NwiNcyqp9YF6/RsusfH1pg4YkiL/RYp7FS0MPVgMggfvoue9S3KjCgRVlzTLwFATyPXQ==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-8.22.0.tgz", + "integrity": "sha512-xDLB4TJXT8iFKwoFneOIJtlfpsUB6L0m32Do97TrQ1dY2WilspksznrU2Ac+XfshdNxa8Sqr4tSj07Yzn0VNiQ==", "license": "MIT", "dependencies": { "@opentelemetry/api": "^1.9.0", @@ -2208,7 +2244,7 @@ "@opentelemetry/core": "^1.25.1", "@opentelemetry/instrumentation": "^0.52.1", "@opentelemetry/instrumentation-connect": "0.38.0", - "@opentelemetry/instrumentation-express": "0.41.0", + "@opentelemetry/instrumentation-express": "0.41.1", "@opentelemetry/instrumentation-fastify": "0.38.0", "@opentelemetry/instrumentation-graphql": "0.42.0", "@opentelemetry/instrumentation-hapi": "0.40.0", @@ -2226,11 +2262,11 @@ "@opentelemetry/sdk-trace-base": "^1.25.1", "@opentelemetry/semantic-conventions": "^1.25.1", "@prisma/instrumentation": "5.17.0", - "@sentry/core": "8.20.0", - "@sentry/opentelemetry": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0", - "import-in-the-middle": "^1.10.0" + "@sentry/core": "8.22.0", + "@sentry/opentelemetry": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0", + "import-in-the-middle": "^1.11.0" }, "engines": { "node": ">=14.18" @@ -2240,14 +2276,14 @@ } }, "node_modules/@sentry/opentelemetry": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-8.20.0.tgz", - "integrity": "sha512-NFcLK6+t9wUc4HlGKeuDn6W4KjZxZfZmWlrK2/tgC5KzG1cnVeOnWUrJzGHTa+YDDdIijpjiFUcpXGPkX3rmIg==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-8.22.0.tgz", + "integrity": "sha512-JqNsoyPdZ88Me2SdxAqq/5agcMzUzZ5xIjrM4ETC1aaeD+cPij/xL4U31b8S7aFJy3miaaZqFzpBy9A/YtFxLw==", "license": "MIT", "dependencies": { - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" @@ -2261,15 +2297,15 @@ } }, "node_modules/@sentry/react": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.20.0.tgz", - "integrity": "sha512-vqA0o9ysdfA24/ADhsJwsmCNdUWRu2ycmVN1Sr76v+ZggyOCFzE7XD13kbqk1G3jPb8nptNu/6Zwpcy5pP4mtw==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.22.0.tgz", + "integrity": "sha512-LcO8SPfjYsx3Zvg1mQwjreVvtriVxde+6njIJyXU9TArB0e8bFexvd4MGXdBExgW9aY449hNaStgKRWMNHeVHQ==", "license": "MIT", "dependencies": { - "@sentry/browser": "8.20.0", - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0", + "@sentry/browser": "8.22.0", + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0", "hoist-non-react-statics": "^3.3.2" }, "engines": { @@ -2280,35 +2316,35 @@ } }, "node_modules/@sentry/types": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.20.0.tgz", - "integrity": "sha512-6IP278KojOpiAA7vrd1hjhUyn26cl0n0nGsShzic5ztCVs92sTeVRnh7MTB9irDVtAbOEyt/YH6go3h+Jia1pA==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.22.0.tgz", + "integrity": "sha512-1MLK3xO+uF2oJaa+M98aLIrQsEHzV7xnVWPfE3MhejYLNQebj4rQnQKTut/xZNIF9W0Q+bRcakLarC3ce2a74g==", "license": "MIT", "engines": { "node": ">=14.18" } }, "node_modules/@sentry/utils": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.20.0.tgz", - "integrity": "sha512-+1I5H8dojURiEUGPliDwheQk8dhjp8uV1sMccR/W/zjFrt4wZyPs+Ttp/V7gzm9LDJoNek9tmELert/jQqWTgg==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.22.0.tgz", + "integrity": "sha512-0ITG2+3EtyMtyc/nQG8aB9z9eIQ4L43nM/KuNgYSnM1vPl/zegbaLT0Ek/xkQB1OLIOLkEPQ6x9GWe+248/n3g==", "license": "MIT", "dependencies": { - "@sentry/types": "8.20.0" + "@sentry/types": "8.22.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/vercel-edge": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-8.20.0.tgz", - "integrity": "sha512-4UiK72M9mf3++YapeIdwUcF0d1uzWfgYm8fx3YgEz6bQUdrts3Jg4e+dbvpv57uUAiTnNN3JKZmkT1ep9ZonKw==", + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-8.22.0.tgz", + "integrity": "sha512-2kkyJ+mvAOEIcM+YY21kMCjx2OI1r+4qYaKPwXWagns41+BcqAl1I8/lU6ZjbNP2wm9iy4kmYcZwx8P5VLtWAw==", "license": "MIT", "dependencies": { - "@sentry/core": "8.20.0", - "@sentry/types": "8.20.0", - "@sentry/utils": "8.20.0" + "@sentry/core": "8.22.0", + "@sentry/types": "8.22.0", + "@sentry/utils": "8.22.0" }, "engines": { "node": ">=14.18" diff --git a/package.json b/package.json index dce6405..dfbaa6b 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "seed": "node --loader ts-node/esm prisma/seed.mts" }, "dependencies": { - "@sentry/nextjs": "8.20.0", + "@sentry/nextjs": "8.22.0", "next": "14.2.4" }, "devDependencies": { diff --git a/sentry.client.config.ts b/sentry.client.config.ts new file mode 100644 index 0000000..17b0793 --- /dev/null +++ b/sentry.client.config.ts @@ -0,0 +1,29 @@ +// This file configures the initialization of Sentry on the client. +// The config you add here will be used whenever a users loads a page in their browser. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: 'https://1ffe607dfb2fb221b8239d51270bae61@o4507585573814272.ingest.us.sentry.io/4507841280606208', + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: false, + replaysOnErrorSampleRate: 1.0, + + // This sets the sample rate to be 10%. You may want this to be 100% while + // in development and sample at a lower rate in production + replaysSessionSampleRate: 0.1, + + // You can remove this option if you're not planning to use the Sentry Session Replay feature: + integrations: [ + Sentry.replayIntegration({ + // Additional Replay configuration goes in here, for example: + maskAllText: true, + blockAllMedia: true, + }), + ], +}); diff --git a/sentry.edge.config.ts b/sentry.edge.config.ts new file mode 100644 index 0000000..ea76e8b --- /dev/null +++ b/sentry.edge.config.ts @@ -0,0 +1,16 @@ +// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on). +// The config you add here will be used whenever one of the edge features is loaded. +// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: 'https://1ffe607dfb2fb221b8239d51270bae61@o4507585573814272.ingest.us.sentry.io/4507841280606208', + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: false, +}); diff --git a/sentry.server.config.ts b/sentry.server.config.ts new file mode 100644 index 0000000..f11c236 --- /dev/null +++ b/sentry.server.config.ts @@ -0,0 +1,18 @@ +// This file configures the initialization of Sentry on the server. +// The config you add here will be used whenever the server handles a request. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: 'https://1ffe607dfb2fb221b8239d51270bae61@o4507585573814272.ingest.us.sentry.io/4507841280606208', + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: false, + + // Uncomment the line below to enable Spotlight (https://spotlightjs.com) + // spotlight: process.env.NODE_ENV === 'development', +}); diff --git a/src/app/global-error.tsx b/src/app/global-error.tsx new file mode 100644 index 0000000..20c1750 --- /dev/null +++ b/src/app/global-error.tsx @@ -0,0 +1,23 @@ +'use client'; + +import * as Sentry from '@sentry/nextjs'; +import NextError from 'next/error'; +import { useEffect } from 'react'; + +export default function GlobalError({ error }: { error: Error & { digest?: string } }) { + useEffect(() => { + Sentry.captureException(error); + }, [error]); + + return ( + + + {/* `NextError` is the default Next.js error page component. Its type + definition requires a `statusCode` prop. However, since the App Router + does not expose status codes for errors, we simply pass 0 to render a + generic error message. */} + + + + ); +} diff --git a/src/instrumentation.ts b/src/instrumentation.ts new file mode 100644 index 0000000..6a02852 --- /dev/null +++ b/src/instrumentation.ts @@ -0,0 +1,9 @@ +export async function register() { + if (process.env.NEXT_RUNTIME === 'nodejs') { + await import('../sentry.server.config'); + } + + if (process.env.NEXT_RUNTIME === 'edge') { + await import('../sentry.edge.config'); + } +} From 1b944a06f5be98037b499392af769eb10f28f85a Mon Sep 17 00:00:00 2001 From: Angelo Reale <12191809+angeloreale@users.noreply.github.com> Date: Mon, 26 Aug 2024 03:38:20 +0100 Subject: [PATCH 5/5] fix: upgrade next from 14.2.4 to 14.2.5 (#15) Snyk has created this PR to upgrade next from 14.2.4 to 14.2.5. See this package in npm: next See this project in Snyk: https://app.snyk.io/org/angeloreale/project/0ce13fdb-820a-4a03-9e39-a46edd73375a?utm_source=github&utm_medium=referral&page=upgrade-pr Co-authored-by: snyk-bot --- package-lock.json | 88 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index a031ff0..f4c0763 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "HPL3-ECO-AND-ANC", "dependencies": { "@sentry/nextjs": "^8.22.0", - "next": "14.2.4" + "next": "14.2.5" }, "devDependencies": { "@auth/prisma-adapter": "2.4.2", @@ -680,9 +680,9 @@ } }, "node_modules/@next/env": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz", - "integrity": "sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", + "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -733,9 +733,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz", - "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", + "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", "cpu": [ "arm64" ], @@ -749,9 +749,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz", - "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", + "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", "cpu": [ "x64" ], @@ -765,9 +765,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz", - "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", + "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", "cpu": [ "arm64" ], @@ -781,9 +781,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz", - "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", + "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", "cpu": [ "arm64" ], @@ -797,9 +797,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz", - "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", + "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", "cpu": [ "x64" ], @@ -813,9 +813,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz", - "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", + "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", "cpu": [ "x64" ], @@ -829,9 +829,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz", - "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", + "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", "cpu": [ "arm64" ], @@ -845,9 +845,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz", - "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", + "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", "cpu": [ "ia32" ], @@ -861,9 +861,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz", - "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", + "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", "cpu": [ "x64" ], @@ -7045,12 +7045,12 @@ } }, "node_modules/next": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", - "integrity": "sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==", + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", + "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", "license": "MIT", "dependencies": { - "@next/env": "14.2.4", + "@next/env": "14.2.5", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -7065,15 +7065,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.4", - "@next/swc-darwin-x64": "14.2.4", - "@next/swc-linux-arm64-gnu": "14.2.4", - "@next/swc-linux-arm64-musl": "14.2.4", - "@next/swc-linux-x64-gnu": "14.2.4", - "@next/swc-linux-x64-musl": "14.2.4", - "@next/swc-win32-arm64-msvc": "14.2.4", - "@next/swc-win32-ia32-msvc": "14.2.4", - "@next/swc-win32-x64-msvc": "14.2.4" + "@next/swc-darwin-arm64": "14.2.5", + "@next/swc-darwin-x64": "14.2.5", + "@next/swc-linux-arm64-gnu": "14.2.5", + "@next/swc-linux-arm64-musl": "14.2.5", + "@next/swc-linux-x64-gnu": "14.2.5", + "@next/swc-linux-x64-musl": "14.2.5", + "@next/swc-win32-arm64-msvc": "14.2.5", + "@next/swc-win32-ia32-msvc": "14.2.5", + "@next/swc-win32-x64-msvc": "14.2.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", diff --git a/package.json b/package.json index dfbaa6b..23783ea 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ }, "dependencies": { "@sentry/nextjs": "8.22.0", - "next": "14.2.4" + "next": "14.2.5" }, "devDependencies": { "@auth/prisma-adapter": "2.4.2",