From 2695d3f0877b16184c77bd31c8215986af1a5043 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 11:56:20 -0400 Subject: [PATCH 01/11] update gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ebd78b2861..748ad6c06b 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ packages/db/backup # internal temp scripts ___*.ts + +# 1password shell plugins +.op/ From ea7a0f63061a4c6ccc5a3ffc8eb70e9932a6e7ae Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:34:40 -0400 Subject: [PATCH 02/11] create util package & logger --- InReach.code-workspace | 35 ++++++++++++++++++---------------- apps/app/package.json | 1 + apps/app/tsconfig.json | 3 ++- packages/api/package.json | 2 ++ packages/api/tsconfig.json | 3 ++- packages/auth/package.json | 1 + packages/auth/tsconfig.json | 3 ++- packages/db/package.json | 1 + packages/db/tsconfig.json | 3 ++- packages/env/package.json | 1 + packages/env/tsconfig.json | 3 ++- packages/ui/package.json | 1 + packages/ui/tsconfig.json | 3 ++- packages/util/.eslintrc.js | 15 +++++++++++++++ packages/util/.lintstagedrc.js | 2 ++ packages/util/index.ts | 0 packages/util/logger/index.ts | 6 ++++++ packages/util/package.json | 22 +++++++++++++++++++++ packages/util/tsconfig.json | 18 +++++++++++++++++ packages/util/turbo.json | 5 +++++ pnpm-lock.yaml | 34 +++++++++++++++++++++++++++++++++ tsconfig.json | 3 ++- 22 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 packages/util/.eslintrc.js create mode 100644 packages/util/.lintstagedrc.js create mode 100644 packages/util/index.ts create mode 100644 packages/util/logger/index.ts create mode 100644 packages/util/package.json create mode 100644 packages/util/tsconfig.json create mode 100644 packages/util/turbo.json diff --git a/InReach.code-workspace b/InReach.code-workspace index 082e1b048b..dfc1c5ebed 100644 --- a/InReach.code-workspace +++ b/InReach.code-workspace @@ -37,37 +37,41 @@ "path": "./packages/api" }, { - "name": "📦 Authentication (@weareinreach/auth)", + "name": "🔐 Authentication (@weareinreach/auth)", "path": "./packages/auth" }, { - "name": "🚀 InReach main site (@weareinreach/web)", - "path": "./apps/web" - }, - { - "name": "📦 Shared configs (@weareinreach/config)", - "path": "./packages/config" + "name": "🛠️ Utilities (@weareinreach/util)", + "path": "./packages/util" }, { - "name": "📦 ESLint Config (@weareinreach/eslint-config)", - "path": "./packages/eslint-config" - }, - { - "name": "📦 AWS User Migration (@weareinreach/aws-user-migrate)", + "name": "🐑 AWS User Migration (@weareinreach/aws-user-migrate)", "path": "./packages/aws-user-migrate" }, { - "name": "📦 AWS Cognito Messaging (@weareinreach/aws-messaging)", + "name": "🐑 AWS Cognito Messaging (@weareinreach/aws-messaging)", "path": "./packages/aws-messaging" }, { - "name": "📦 AWS i18n Cache (@weareinreach/aws-i18n-cache)", + "name": "🐑 AWS i18n Cache (@weareinreach/aws-i18n-cache)", "path": "./packages/aws-cache" }, { - "name": "📦 Environment Variables (@weareinreach/env)", + "name": "⚙️ Environment Variables (@weareinreach/env)", "path": "./packages/env" }, + { + "name": "⚙️ Shared configs (@weareinreach/config)", + "path": "./packages/config" + }, + { + "name": "⚙️ ESLint Config (@weareinreach/eslint-config)", + "path": "./packages/eslint-config" + }, + { + "name": "🚀 InReach main site (@weareinreach/web)", + "path": "./apps/web" + }, { "name": "✨ InReach (root)", "path": "./" @@ -133,7 +137,6 @@ "eslint.options": { "cache": true }, - "eslint.packageManager": "pnpm", "eslint.rules.customizations": [ { "rule": "import/order", diff --git a/apps/app/package.json b/apps/app/package.json index 1f215385f3..7e1b5ac1a8 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -74,6 +74,7 @@ "@weareinreach/db": "workspace:*", "@weareinreach/env": "workspace:*", "@weareinreach/ui": "workspace:*", + "@weareinreach/util": "workspace:*", "axios": "1.4.0", "cookies-next": "2.1.2", "dayjs": "1.11.9", diff --git a/apps/app/tsconfig.json b/apps/app/tsconfig.json index b4b0dc5307..035c2caf7e 100644 --- a/apps/app/tsconfig.json +++ b/apps/app/tsconfig.json @@ -10,7 +10,8 @@ "~api/*": ["../../packages/api/*"], "~auth/*": ["../../packages/auth/*"], "~db/*": ["../../packages/db/*"], - "~ui/*": ["../../packages/ui/*"] + "~ui/*": ["../../packages/ui/*"], + "~util/*": ["../../packages/util/*"] } }, "include": [ diff --git a/packages/api/package.json b/packages/api/package.json index 669ae992d5..7f6e7fe707 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -19,6 +19,7 @@ "@crowdin/ota-client": "1.0.0", "@googlemaps/google-maps-services-js": "3.3.35", "@opentelemetry/api": "1.4.1", + "@sentry/node": "7.61.0", "@tanstack/react-query": "4.32.1", "@terraformer/wkt": "2.2.0", "@trpc/client": "10.36.0", @@ -30,6 +31,7 @@ "@weareinreach/auth": "workspace:*", "@weareinreach/db": "workspace:*", "@weareinreach/env": "workspace:*", + "@weareinreach/util": "workspace:*", "alex": "11.0.0", "geo-tz": "7.0.7", "geolib": "3.3.4", diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 2591a9dc96..d2c41d6f8a 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -9,7 +9,8 @@ "~auth/*": ["../../packages/auth/*"], "~db/*": ["../../packages/db/*"], "~ui/*": ["../../packages/ui/*"], - "~web/*": ["../../apps/web/src/*"] + "~web/*": ["../../apps/web/src/*"], + "~util/*": ["../../packages/util/*"] } }, "exclude": ["**/node_modules", "./**/.*/"], diff --git a/packages/auth/package.json b/packages/auth/package.json index eaa9572d1f..2dab371509 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -18,6 +18,7 @@ "@next-auth/prisma-adapter": "1.0.7", "@weareinreach/db": "workspace:*", "@weareinreach/env": "workspace:*", + "@weareinreach/util": "workspace:*", "aws-jwt-verify": "4.0.0", "tiny-invariant": "1.3.1", "tslog": "4.8.2", diff --git a/packages/auth/tsconfig.json b/packages/auth/tsconfig.json index daa14cbc09..2d0f635675 100644 --- a/packages/auth/tsconfig.json +++ b/packages/auth/tsconfig.json @@ -9,7 +9,8 @@ "~auth/*": ["./*"], "~db/*": ["../../packages/db/*"], "~ui/*": ["../../packages/ui/*"], - "~web/*": ["../../apps/web/src/*"] + "~web/*": ["../../apps/web/src/*"], + "~util/*": ["../../packages/util/*"] } }, "exclude": ["**/node_modules", "**/.*/"], diff --git a/packages/db/package.json b/packages/db/package.json index 2fbe6e31c0..6674fc5590 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -55,6 +55,7 @@ "@vercel/kv": "0.2.2", "@vercel/postgres-kysely": "0.4.1", "@weareinreach/env": "workspace:*", + "@weareinreach/util": "workspace:*", "json-difference": "1.9.1", "just-compare": "2.3.0", "just-deep-map-values": "1.2.0", diff --git a/packages/db/tsconfig.json b/packages/db/tsconfig.json index e35150d9ff..af2f0b2e52 100644 --- a/packages/db/tsconfig.json +++ b/packages/db/tsconfig.json @@ -11,7 +11,8 @@ "~auth/*": ["../../packages/auth/*"], "~db/*": ["./*"], "~ui/*": ["../../packages/ui/*"], - "~web/*": ["../../apps/web/src/*"] + "~web/*": ["../../apps/web/src/*"], + "~util/*": ["../../packages/util/*"] } }, "exclude": ["**/node_modules", "./**/.*/"], diff --git a/packages/env/package.json b/packages/env/package.json index 7abe0c2860..c87e794d96 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -10,6 +10,7 @@ "scripts": {}, "dependencies": { "@t3-oss/env-nextjs": "0.6.0", + "@weareinreach/util": "workspace:*", "chromatic": "6.20.0", "zod": "3.21.4" }, diff --git a/packages/env/tsconfig.json b/packages/env/tsconfig.json index bd7562a549..f792c55321 100644 --- a/packages/env/tsconfig.json +++ b/packages/env/tsconfig.json @@ -9,7 +9,8 @@ "~auth/*": ["../../packages/auth/*"], "~db/*": ["../../packages/db/*"], "~ui/*": ["../../packages/ui/*"], - "~web/*": ["../../apps/web/src/*"] + "~web/*": ["../../apps/web/src/*"], + "~util/*": ["../../packages/util/*"] } }, "exclude": ["node_modules"], diff --git a/packages/ui/package.json b/packages/ui/package.json index 6c1045ac9e..d38b282e2d 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -26,6 +26,7 @@ "@textea/json-viewer": "3.1.1", "@turf/helpers": "6.5.0", "@weareinreach/env": "workspace:*", + "@weareinreach/util": "workspace:*", "ajv": "8.12.0", "alex": "11.0.0", "cookies-next": "2.1.2", diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index c49aa575e5..c6e7368168 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -7,7 +7,8 @@ "~api/*": ["../../packages/api/*"], "~app/*": ["../../apps/app/src/*"], "~auth/*": ["../../packages/auth/*"], - "~db/*": ["../../packages/db/*"] + "~db/*": ["../../packages/db/*"], + "~util/*": ["../../packages/util/*"] }, "strict": true }, diff --git a/packages/util/.eslintrc.js b/packages/util/.eslintrc.js new file mode 100644 index 0000000000..554c184302 --- /dev/null +++ b/packages/util/.eslintrc.js @@ -0,0 +1,15 @@ +/* eslint-disable import/no-unused-modules */ +module.exports = { + extends: ['@weareinreach/eslint-config/next'], + overrides: [ + { + files: ['**/*.ts?(x)'], + + // parserOptions: { + // project: 'tsconfig.json', + // tsconfigRootDir: __dirname, + // }, + }, + ], + root: true, +} diff --git a/packages/util/.lintstagedrc.js b/packages/util/.lintstagedrc.js new file mode 100644 index 0000000000..990ab02126 --- /dev/null +++ b/packages/util/.lintstagedrc.js @@ -0,0 +1,2 @@ +/* eslint-disable import/no-unused-modules */ +module.exports = require('@weareinreach/config/lint-staged') diff --git a/packages/util/index.ts b/packages/util/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/util/logger/index.ts b/packages/util/logger/index.ts new file mode 100644 index 0000000000..246feb3744 --- /dev/null +++ b/packages/util/logger/index.ts @@ -0,0 +1,6 @@ +import { type ISettingsParam, Logger } from 'tslog' + +export const appLog = new Logger({ name: 'app', type: 'json', hideLogPositionForProduction: true }) + +export const createSubLog = (name: string, opts?: Omit, 'name'>) => + appLog.getSubLogger({ name, ...opts }) diff --git a/packages/util/package.json b/packages/util/package.json new file mode 100644 index 0000000000..bce8b96c5b --- /dev/null +++ b/packages/util/package.json @@ -0,0 +1,22 @@ +{ + "name": "@weareinreach/util", + "version": "0.100.0", + "private": true, + "main": "./index.ts", + "types": "./index.ts", + "scripts": { + "clean:node": "rm -rf ./node_modules/ || true", + "format": "prettier --write --cache --cache-strategy metadata .", + "lint": "eslint --cache .", + "lint:fix": "eslint --cache --fix .", + "type-check": "tsc --noEmit", + "with-env": "dotenv -e ../../.env --" + }, + "dependencies": { + "tslog": "4.8.2" + }, + "devDependencies": { + "@weareinreach/config": "workspace:*", + "@weareinreach/eslint-config": "0.100.0" + } +} diff --git a/packages/util/tsconfig.json b/packages/util/tsconfig.json new file mode 100644 index 0000000000..6550c9dda8 --- /dev/null +++ b/packages/util/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@weareinreach/config/tsconfig/base.json", + "compilerOptions": { + "baseUrl": "./", + "strict": true, + "paths": { + "~api/*": ["../../packages/api/*"], + "~app/*": ["../../apps/app/src/*"], + "~auth/*": ["../../packages/auth/*"], + "~db/*": ["../../packages/db/*"], + "~ui/*": ["../../packages/ui/*"], + "~util/*": ["./*"], + "~web/*": ["../../apps/web/src/*"] + } + }, + "exclude": ["**/node_modules/**"], + "include": ["./**/*.ts"] +} diff --git a/packages/util/turbo.json b/packages/util/turbo.json new file mode 100644 index 0000000000..fed7bb1a55 --- /dev/null +++ b/packages/util/turbo.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "pipeline": {} +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a22cc22d16..76c4ed2916 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -263,6 +263,9 @@ importers: '@weareinreach/ui': specifier: workspace:* version: link:../../packages/ui + '@weareinreach/util': + specifier: workspace:* + version: link:../../packages/util axios: specifier: 1.4.0 version: 1.4.0 @@ -577,6 +580,9 @@ importers: '@opentelemetry/api': specifier: 1.4.1 version: 1.4.1 + '@sentry/node': + specifier: 7.61.0 + version: 7.61.0 '@tanstack/react-query': specifier: 4.32.1 version: 4.32.1(react-dom@18.2.0)(react@18.2.0) @@ -610,6 +616,9 @@ importers: '@weareinreach/env': specifier: workspace:* version: link:../env + '@weareinreach/util': + specifier: workspace:* + version: link:../util alex: specifier: 11.0.0 version: 11.0.0 @@ -746,6 +755,9 @@ importers: '@weareinreach/env': specifier: workspace:* version: link:../env + '@weareinreach/util': + specifier: workspace:* + version: link:../util aws-jwt-verify: specifier: 4.0.0 version: 4.0.0 @@ -999,6 +1011,9 @@ importers: '@weareinreach/env': specifier: workspace:* version: link:../env + '@weareinreach/util': + specifier: workspace:* + version: link:../util json-difference: specifier: 1.9.1 version: 1.9.1 @@ -1261,6 +1276,9 @@ importers: '@t3-oss/env-nextjs': specifier: 0.6.0 version: 0.6.0(typescript@5.1.6)(zod@3.21.4) + '@weareinreach/util': + specifier: workspace:* + version: link:../util chromatic: specifier: 6.20.0 version: 6.20.0 @@ -1358,6 +1376,9 @@ importers: '@weareinreach/env': specifier: workspace:* version: link:../env + '@weareinreach/util': + specifier: workspace:* + version: link:../util ajv: specifier: 8.12.0 version: 8.12.0 @@ -1759,6 +1780,19 @@ importers: specifier: 3.21.4 version: 3.21.4 + packages/util: + dependencies: + tslog: + specifier: 4.8.2 + version: 4.8.2 + devDependencies: + '@weareinreach/config': + specifier: workspace:* + version: link:../config + '@weareinreach/eslint-config': + specifier: 0.100.0 + version: link:../eslint-config + packages: /@aashutoshrathi/word-wrap@1.2.6: diff --git a/tsconfig.json b/tsconfig.json index 9f1f69bf96..f783c8b166 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "~api/*": ["./packages/api/*"], "~auth/*": ["./packages/auth/*"], "~db/*": ["./packages/db/*"], - "~ui/*": ["./packages/ui/*"] + "~ui/*": ["./packages/ui/*"], + "~util/*": ["./packages/util/*"] }, "strict": true }, From 04f3e497c879371f4d8b98ef97c557d850eeda96 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:36:12 -0400 Subject: [PATCH 03/11] use shared logger --- apps/app/src/pages/api/i18n/load.ts | 4 ++-- apps/app/src/pages/api/trpc/[trpc].ts | 4 ++-- apps/app/src/utils/api.ts | 6 ++++++ apps/app/src/utils/vercel-kv.ts | 5 +++-- packages/api/cache/slugRedirect.ts | 5 +++-- packages/api/cache/slugToOrgId.ts | 5 +++-- packages/auth/lib/logger.ts | 4 ++-- packages/db/client/index.ts | 4 ++-- packages/db/lib/superjsonMiddleware.ts | 5 +++-- 9 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/app/src/pages/api/i18n/load.ts b/apps/app/src/pages/api/i18n/load.ts index 278bce0264..455362ee67 100644 --- a/apps/app/src/pages/api/i18n/load.ts +++ b/apps/app/src/pages/api/i18n/load.ts @@ -2,9 +2,9 @@ /* eslint-disable node/no-process-env */ import { context, trace } from '@opentelemetry/api' import { type NextApiRequest, type NextApiResponse } from 'next' -import { Logger } from 'tslog' import { z } from 'zod' +import { createSubLog } from '@weareinreach/util/logger' import { crowdinOpts } from '~app/data/crowdinOta' import { crowdinDistTimestamp, fetchCrowdinDbKey, fetchCrowdinFile } from '~app/utils/crowdin' import { redisReadCache, redisWriteCache } from '~app/utils/vercel-kv' @@ -14,7 +14,7 @@ const QuerySchema = z.object({ ns: z.string(), }) const tracer = trace.getTracer('inreach-app') -const log = new Logger({ name: 'i18n Loader' }) +const log = createSubLog('i18n Loader') export default async function handler(req: NextApiRequest, res: NextApiResponse) { const query = QuerySchema.parse(req.query) diff --git a/apps/app/src/pages/api/trpc/[trpc].ts b/apps/app/src/pages/api/trpc/[trpc].ts index 27711a6082..245adf0361 100644 --- a/apps/app/src/pages/api/trpc/[trpc].ts +++ b/apps/app/src/pages/api/trpc/[trpc].ts @@ -1,9 +1,9 @@ import { createNextApiHandler } from '@trpc/server/adapters/next' -import { Logger } from 'tslog' import { appRouter, createContext } from '@weareinreach/api' +import { createSubLog } from '@weareinreach/util/logger' -const log = new Logger({ name: 'tRPC', type: 'json', hideLogPositionForProduction: true }) +const log = createSubLog('tRPC') /* Creating a handler for the tRPC endpoint. */ export default createNextApiHandler({ diff --git a/apps/app/src/utils/api.ts b/apps/app/src/utils/api.ts index 28b2d285d8..33104af4ad 100644 --- a/apps/app/src/utils/api.ts +++ b/apps/app/src/utils/api.ts @@ -9,7 +9,9 @@ import { devtoolsLink } from 'trpc-client-devtools-link' import { type AppRouter } from '@weareinreach/api' import { transformer } from '@weareinreach/api/lib/transformer' import { getEnv } from '@weareinreach/env' +import { createSubLog } from '@weareinreach/util/logger' +const log = createSubLog('tRPC') const getBaseUrl = () => { if (typeof window !== 'undefined') return '' // browser should use relative url if (getEnv('VERCEL_URL')) return `https://${getEnv('VERCEL_URL')}` // SSR should use vercel url @@ -30,6 +32,10 @@ export const api = createTRPCNext({ // eslint-disable-next-line node/no-process-env (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') || (opts.direction === 'down' && opts.result instanceof Error), + console: { + log: log.info, + error: log.error, + }, }), httpBatchStreamLink({ diff --git a/apps/app/src/utils/vercel-kv.ts b/apps/app/src/utils/vercel-kv.ts index ae09ac71b8..2d11811aec 100644 --- a/apps/app/src/utils/vercel-kv.ts +++ b/apps/app/src/utils/vercel-kv.ts @@ -3,10 +3,11 @@ import { kv as redis } from '@vercel/kv' import { flatten, unflatten } from 'flat' import sizeof from 'object-sizeof' import formatBytes from 'pretty-bytes' -import { Logger } from 'tslog' + +import { createSubLog } from '@weareinreach/util/logger' const redisTTL = 86400 -const log = new Logger({ name: 'Vercel KV' }) +const log = createSubLog('Vercel KV') const tracer = trace.getTracer('inreach-app') export const redisReadCache = async (namespaces: string[], lang: string, otaManifestTimestamp: number) => { diff --git a/packages/api/cache/slugRedirect.ts b/packages/api/cache/slugRedirect.ts index 901ea23d33..9c9df41ed7 100644 --- a/packages/api/cache/slugRedirect.ts +++ b/packages/api/cache/slugRedirect.ts @@ -1,7 +1,8 @@ import { kv as redis } from '@vercel/kv' -import { Logger } from 'tslog' -const log = new Logger({ name: 'Cache - Slug redirect' }) +import { createSubLog } from '@weareinreach/util/logger' + +const log = createSubLog('Cache - Slug redirect') export const readSlugRedirectCache = async (slug: string) => { try { diff --git a/packages/api/cache/slugToOrgId.ts b/packages/api/cache/slugToOrgId.ts index 24e5882752..90df7f8a79 100644 --- a/packages/api/cache/slugToOrgId.ts +++ b/packages/api/cache/slugToOrgId.ts @@ -1,7 +1,8 @@ import { kv as redis } from '@vercel/kv' -import { Logger } from 'tslog' -const log = new Logger({ name: 'Cache - Slug to OrgId' }) +import { createSubLog } from '@weareinreach/util/logger' + +const log = createSubLog('Cache - Slug to OrgId') export const readSlugCache = async (slug: string) => { try { diff --git a/packages/auth/lib/logger.ts b/packages/auth/lib/logger.ts index ee4814c347..b4027b397e 100644 --- a/packages/auth/lib/logger.ts +++ b/packages/auth/lib/logger.ts @@ -1,3 +1,3 @@ -import { Logger } from 'tslog' +import { createSubLog } from '@weareinreach/util/logger' -export const logger = new Logger({ name: '@weareinreach/auth', hideLogPositionForProduction: true }) +export const logger = createSubLog('@weareinreach/auth') diff --git a/packages/db/client/index.ts b/packages/db/client/index.ts index 37e460d2da..d3816c0283 100644 --- a/packages/db/client/index.ts +++ b/packages/db/client/index.ts @@ -1,12 +1,12 @@ /* eslint-disable node/no-process-env */ import { type Prisma, PrismaClient } from '@prisma/client' import { createPrismaQueryEventHandler } from 'prisma-query-log' -import { Logger } from 'tslog' +import { createSubLog } from '@weareinreach/util/logger' import { idMiddleware } from '~db/lib/idMiddleware' import { superjsonMiddleware } from '~db/lib/superjsonMiddleware' -const log = new Logger({ name: 'prisma' }) +const log = createSubLog('prisma') const verboseLogging = Boolean( // eslint-disable-next-line turbo/no-undeclared-env-vars process.env.NODE_ENV === 'development' && (!!process.env.NEXT_VERBOSE || !!process.env.PRISMA_VERBOSE) diff --git a/packages/db/lib/superjsonMiddleware.ts b/packages/db/lib/superjsonMiddleware.ts index 6d1bf1f913..c82a4108c2 100644 --- a/packages/db/lib/superjsonMiddleware.ts +++ b/packages/db/lib/superjsonMiddleware.ts @@ -1,14 +1,15 @@ import { Prisma } from '@prisma/client' import superjson from 'superjson' import { type SuperJSONResult } from 'superjson/dist/types' -import { Logger } from 'tslog' import { z } from 'zod' +import { createSubLog } from '@weareinreach/util/logger' + import { NullableJsonValue } from './zod' const MODELS_TO_RUN: Prisma.ModelName[] = ['AttributeSupplement', 'Suggestion'] -const logger = new Logger({ name: 'SuperJSON middleware', minLevel: 3 }) +const logger = createSubLog('SuperJSON middleware', { minLevel: 3 }) const ResultSchema = z .object({ From 42a04d25a8b77b87c44197d627626f3952723481 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:37:51 -0400 Subject: [PATCH 04/11] trpc & prisma middleware --- apps/app/next.config.mjs | 2 +- apps/app/sentry.server.config.ts | 4 +++- packages/api/lib/middleware/index.ts | 1 + packages/api/lib/middleware/sentry.ts | 5 +++++ packages/api/lib/trpc.ts | 14 ++++++++------ 5 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 packages/api/lib/middleware/sentry.ts diff --git a/apps/app/next.config.mjs b/apps/app/next.config.mjs index caba15ff29..42ec175ff6 100644 --- a/apps/app/next.config.mjs +++ b/apps/app/next.config.mjs @@ -98,7 +98,7 @@ const defineSentryConfig = (nextConfig) => tunnelRoute: '/monitoring', // Hides source maps from generated client bundles - hideSourceMaps: true, + hideSourceMaps: false, // Automatically tree-shake Sentry logger statements to reduce bundle size disableLogger: true, diff --git a/apps/app/sentry.server.config.ts b/apps/app/sentry.server.config.ts index 39b2a992d3..c826751138 100644 --- a/apps/app/sentry.server.config.ts +++ b/apps/app/sentry.server.config.ts @@ -4,6 +4,8 @@ import * as Sentry from '@sentry/nextjs' +import { prisma } from '@weareinreach/db' + Sentry.init({ dsn: 'https://3398c2248c86498ab42fa8533e4f83f1@o1412293.ingest.sentry.io/6751163', @@ -11,5 +13,5 @@ Sentry.init({ tracesSampleRate: 1, // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, + integrations: [new Sentry.Integrations.Prisma({ client: prisma })], }) diff --git a/packages/api/lib/middleware/index.ts b/packages/api/lib/middleware/index.ts index a71d7a1aad..3401536bc3 100644 --- a/packages/api/lib/middleware/index.ts +++ b/packages/api/lib/middleware/index.ts @@ -1,4 +1,5 @@ // codegen:start {preset: barrel, include: ./*.ts} export * from './basicAuth' export * from './permissions' +export * from './sentry' // codegen:end diff --git a/packages/api/lib/middleware/sentry.ts b/packages/api/lib/middleware/sentry.ts new file mode 100644 index 0000000000..887ac751bd --- /dev/null +++ b/packages/api/lib/middleware/sentry.ts @@ -0,0 +1,5 @@ +import { Handlers } from '@sentry/node' + +import { t } from '../initTRPC' + +export const sentryMiddleware = t.middleware(Handlers.trpcMiddleware({ attachRpcInput: true })) diff --git a/packages/api/lib/trpc.ts b/packages/api/lib/trpc.ts index c79592a212..75dd8dbe29 100644 --- a/packages/api/lib/trpc.ts +++ b/packages/api/lib/trpc.ts @@ -1,22 +1,24 @@ import { t } from './initTRPC' -import { hasPermissions, isAdmin, isAuthed, isStaff } from './middleware' +import { hasPermissions, isAdmin, isAuthed, isStaff, sentryMiddleware } from './middleware' import { getPermissions, type PermissionedProcedure } from './permissions' export const defineRouter = t.router export const mergeRouters = t.mergeRouters +const baseProcedure = t.procedure.use(sentryMiddleware) + /** Unprotected procedure */ -export const publicProcedure = t.procedure +export const publicProcedure = baseProcedure /** Protected procedure */ -export const protectedProcedure = t.procedure.use(isAuthed) +export const protectedProcedure = baseProcedure.use(isAuthed) /** Admin procedure */ -export const adminProcedure = t.procedure.use(isAdmin) +export const adminProcedure = baseProcedure.use(isAdmin) /** Staff procedure */ -export const staffProcedure = t.procedure.use(isStaff) +export const staffProcedure = baseProcedure.use(isStaff) /** Permissioned router */ export const permissionedProcedure = (procedure: PermissionedProcedure) => - t.procedure.use(hasPermissions).meta(getPermissions(procedure)) + baseProcedure.use(hasPermissions).meta(getPermissions(procedure)) From 04bcddb1fce87f4b3a9837e252081f94f6abc7de Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:45:00 -0400 Subject: [PATCH 05/11] alter sentry load --- apps/app/next.config.mjs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/app/next.config.mjs b/apps/app/next.config.mjs index 42ec175ff6..9fa9207c30 100644 --- a/apps/app/next.config.mjs +++ b/apps/app/next.config.mjs @@ -15,7 +15,8 @@ const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const isVercelActiveDev = process.env.VERCEL_ENV === 'preview' && process.env.VERCEL_GIT_COMMIT_REF !== 'dev' -const isDev = process.env.NODE_ENV === 'development' +const isLocalDev = + process.env.NODE_ENV === 'development' && !['preview', 'production'].includes(process.env.VERCEL_ENV) const withBundleAnalyzer = bundleAnalyze({ enabled: process.env.ANALYZE === 'true' }) /** @type {import('next').NextConfig} */ @@ -49,8 +50,9 @@ const nextConfig = { if (isServer) { config.plugins = [...config.plugins, new PrismaPlugin()] } - config.plugins.push(new webpack.DefinePlugin({ __SENTRY_DEBUG__: false })) - + if (process.env.VERCEL_ENV === 'production') { + config.plugins.push(new webpack.DefinePlugin({ __SENTRY_DEBUG__: false })) + } return config }, } @@ -105,4 +107,4 @@ const defineSentryConfig = (nextConfig) => } ) -export default isDev ? defineNextConfig(nextConfig) : defineSentryConfig(defineNextConfig(nextConfig)) +export default isLocalDev ? defineNextConfig(nextConfig) : defineSentryConfig(defineNextConfig(nextConfig)) From 2cca596fbfdead4d5bbd5024eee03434b5c85cd9 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:19:23 -0400 Subject: [PATCH 06/11] sentry otel setup --- apps/app/instrumentation.node.ts | 32 +++++++++++--------------------- apps/app/next.config.mjs | 3 ++- apps/app/package.json | 1 + apps/app/sentry.server.config.ts | 5 ++--- pnpm-lock.yaml | 21 +++++++++++++++++++++ 5 files changed, 37 insertions(+), 25 deletions(-) diff --git a/apps/app/instrumentation.node.ts b/apps/app/instrumentation.node.ts index 2e94f09061..a10affbcdb 100644 --- a/apps/app/instrumentation.node.ts +++ b/apps/app/instrumentation.node.ts @@ -1,13 +1,11 @@ /* eslint-disable turbo/no-undeclared-env-vars */ /* eslint-disable node/no-process-env */ -// import { context, trace } from '@opentelemetry/api' import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' -// import { HttpInstrumentation } from '@opentelemetry/instrumentation-http' import { Resource } from '@opentelemetry/resources' import { NodeSDK } from '@opentelemetry/sdk-node' -import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node' import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' import { PrismaInstrumentation } from '@prisma/instrumentation' +import { SentryPropagator, SentrySpanProcessor } from '@sentry/opentelemetry-node' import { config } from 'dotenv' config({ path: '../../.env' }) @@ -18,27 +16,19 @@ if (!process.env.VERCEL) console.log('Initializing OpenTelemetry...') if (otelTraceOptions) { console.log(`Using custom server: ${otelTraceOptions.url}`) } + const sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'inreach-app', + [SemanticResourceAttributes.CLOUD_REGION]: process.env.VERCEL_REGION, + [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.VERCEL_ENV, + [SemanticResourceAttributes.HOST_ARCH]: process.arch, + [SemanticResourceAttributes.PROCESS_RUNTIME_VERSION]: process.version, + [SemanticResourceAttributes.OS_TYPE]: process.platform, }), - spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter(otelTraceOptions)), - instrumentations: [ - new PrismaInstrumentation({ middleware: true }), - // new HttpInstrumentation({ - // ignoreIncomingRequestHook: (req) => false, - // ignoreOutgoingRequestHook: (req) => { - // const ignored = [ - // // ip addresses - // /.*((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).*/, - // /.*localhost.*/, - // ] - // const { hostname } = req - // if (typeof hostname === 'string') return !ignored.some((rx) => rx.test(hostname)) - - // return false - // }, - // }), - ], + traceExporter: new OTLPTraceExporter(otelTraceOptions), + spanProcessor: new SentrySpanProcessor(), + textMapPropagator: new SentryPropagator(), + instrumentations: [new PrismaInstrumentation({ middleware: true })], }) sdk.start() diff --git a/apps/app/next.config.mjs b/apps/app/next.config.mjs index 9fa9207c30..12b1197c3b 100644 --- a/apps/app/next.config.mjs +++ b/apps/app/next.config.mjs @@ -107,4 +107,5 @@ const defineSentryConfig = (nextConfig) => } ) -export default isLocalDev ? defineNextConfig(nextConfig) : defineSentryConfig(defineNextConfig(nextConfig)) +// export default isLocalDev ? defineNextConfig(nextConfig) : defineSentryConfig(defineNextConfig(nextConfig)) +export default defineSentryConfig(defineNextConfig(nextConfig)) diff --git a/apps/app/package.json b/apps/app/package.json index 7e1b5ac1a8..37e7e811c8 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -57,6 +57,7 @@ "@opentelemetry/semantic-conventions": "1.15.1", "@prisma/instrumentation": "5.1.0", "@sentry/nextjs": "7.61.0", + "@sentry/opentelemetry-node": "7.61.0", "@tanstack/react-query": "4.32.1", "@tanstack/react-table": "8.9.3", "@tiptap/extension-link": "2.0.4", diff --git a/apps/app/sentry.server.config.ts b/apps/app/sentry.server.config.ts index c826751138..8ab470d526 100644 --- a/apps/app/sentry.server.config.ts +++ b/apps/app/sentry.server.config.ts @@ -4,8 +4,6 @@ import * as Sentry from '@sentry/nextjs' -import { prisma } from '@weareinreach/db' - Sentry.init({ dsn: 'https://3398c2248c86498ab42fa8533e4f83f1@o1412293.ingest.sentry.io/6751163', @@ -13,5 +11,6 @@ Sentry.init({ tracesSampleRate: 1, // Setting this option to true will print useful information to the console while you're setting up Sentry. - integrations: [new Sentry.Integrations.Prisma({ client: prisma })], + debug: false, + instrumenter: 'otel', }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 76c4ed2916..2d99bfa268 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -212,6 +212,9 @@ importers: '@sentry/nextjs': specifier: 7.61.0 version: 7.61.0(next@13.4.12)(react@18.2.0) + '@sentry/opentelemetry-node': + specifier: 7.61.0 + version: 7.61.0(@opentelemetry/api@1.4.1)(@opentelemetry/core@1.15.1)(@opentelemetry/sdk-trace-base@1.15.1)(@opentelemetry/semantic-conventions@1.15.1) '@tanstack/react-query': specifier: 4.32.1 version: 4.32.1(react-dom@18.2.0)(react@18.2.0) @@ -8441,6 +8444,24 @@ packages: - supports-color dev: false + /@sentry/opentelemetry-node@7.61.0(@opentelemetry/api@1.4.1)(@opentelemetry/core@1.15.1)(@opentelemetry/sdk-trace-base@1.15.1)(@opentelemetry/semantic-conventions@1.15.1): + resolution: {integrity: sha512-Q5o7pAu01Cleb6Q5eqh/h5bIV/upENtbuwhVPGCgRsrWSmnk4BwWEZU1CTkb/Y+z3BbmGQ+dliC6Jpr6rqCpVg==} + engines: {node: '>=8'} + peerDependencies: + '@opentelemetry/api': 1.x + '@opentelemetry/core': 1.x + '@opentelemetry/sdk-trace-base': 1.x + '@opentelemetry/semantic-conventions': 1.x + dependencies: + '@opentelemetry/api': 1.4.1 + '@opentelemetry/core': 1.15.1(@opentelemetry/api@1.4.1) + '@opentelemetry/sdk-trace-base': 1.15.1(@opentelemetry/api@1.4.1) + '@opentelemetry/semantic-conventions': 1.15.1 + '@sentry/core': 7.61.0 + '@sentry/types': 7.61.0 + '@sentry/utils': 7.61.0 + dev: false + /@sentry/react@7.61.0(react@18.2.0): resolution: {integrity: sha512-17ZPDdzx3hzJSHsVFAiw4hUT701LUVIcm568q38sPlSUmnOmNmPeHx/xcQkuxMoVsw/xgf/82B/BKKnIP5/diA==} engines: {node: '>=8'} From 1539b23b16c52ba4c5f601d42275681b5e941b4f Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:20:00 -0400 Subject: [PATCH 07/11] custom error pages --- apps/app/public/locales/en/common.json | 4 ++ apps/app/src/pages/404.tsx | 62 ++++++++++++++++++++++++ apps/app/src/pages/500.tsx | 66 ++++++++++++++++++++++++++ apps/app/src/pages/_error.tsx | 19 ++++++++ apps/app/src/types/nextjs-routes.d.ts | 2 + 5 files changed, 153 insertions(+) create mode 100644 apps/app/src/pages/404.tsx create mode 100644 apps/app/src/pages/500.tsx create mode 100644 apps/app/src/pages/_error.tsx diff --git a/apps/app/public/locales/en/common.json b/apps/app/public/locales/en/common.json index 480382151b..9918d3b1c9 100644 --- a/apps/app/public/locales/en/common.json +++ b/apps/app/public/locales/en/common.json @@ -84,6 +84,10 @@ "enter-password-placeholder": "Enter password...", "enter-review": "Enter your review...", "errors": { + "404-body": "We're sorry, the page you're looking for doesn't exist or has been moved. Start a search below to find safe, verified resources for the diverse LGBTQ+ community in your area.", + "404-title": "404: Page not found.", + "500-body": "We're sorry, something went wrong with our server. Please try again later, or start a search below to find safe, verified LGBTQ+ resources in your area.", + "500-title": "500: Something went wrong.", "oh-no": "Oh no!", "try-again-text": "Something went wrong! Please try again." }, diff --git a/apps/app/src/pages/404.tsx b/apps/app/src/pages/404.tsx new file mode 100644 index 0000000000..ff57cb8834 --- /dev/null +++ b/apps/app/src/pages/404.tsx @@ -0,0 +1,62 @@ +import { Center, Container, rem, Stack, Tabs, Text, Title } from '@mantine/core' +import { type GetStaticProps } from 'next' +import { useTranslation } from 'next-i18next' +import { useState } from 'react' + +import { SearchBox } from '@weareinreach/ui/components/core/SearchBox' +import { getServerSideTranslations } from '~app/utils/i18n' + +const NotFound = () => { + const [isLoading, setLoading] = useState(false) + const { t } = useTranslation('common') + + return ( + + + + {/* eslint-disable-next-line i18next/no-literal-string */} + 🏝️ + {t('errors.404-title')} + + {t('errors.404-body')} + + + {t('common:words.location')} + {t('common:words.organization')} + + +
+ +
+
+ + + +
+
+
+ ) +} + +export const getStaticProps: GetStaticProps = async ({ locale }) => { + return { + props: { + ...(await getServerSideTranslations(locale, ['common'])), + }, + revalidate: 60 * 60 * 24 * 7, + } +} + +export default NotFound diff --git a/apps/app/src/pages/500.tsx b/apps/app/src/pages/500.tsx new file mode 100644 index 0000000000..70857c6ab5 --- /dev/null +++ b/apps/app/src/pages/500.tsx @@ -0,0 +1,66 @@ +import { Center, Container, rem, Stack, Tabs, Text, Title } from '@mantine/core' +import * as Sentry from '@sentry/nextjs' +import { type GetStaticProps, type NextPage, type NextPageContext } from 'next' +import { useTranslation } from 'next-i18next' +import { useState } from 'react' + +import { SearchBox } from '@weareinreach/ui/components/core/SearchBox' +// import { getServerSideTranslations } from '~app/utils/i18n' + +const ServerError: NextPage = () => { + const [isLoading, setLoading] = useState(false) + const { t } = useTranslation('common') + + return ( + + + + {/* eslint-disable-next-line i18next/no-literal-string */} + 🔦 + {t('errors.500-title')} + + {t('errors.500-body')} + + + {t('common:words.location')} + {t('common:words.organization')} + + +
+ +
+
+ + + +
+
+
+ ) +} + +export const getStaticProps: GetStaticProps = async ({ locale }) => { + const getServerSideTranslations = await import('../utils/i18n').then((mod) => mod.getServerSideTranslations) + return { + props: { + ...(await getServerSideTranslations(locale, ['common'])), + }, + } +} +export const getInitialProps = async (ctx: NextPageContext) => { + await Sentry.captureUnderscoreErrorException(ctx) +} + +export default ServerError diff --git a/apps/app/src/pages/_error.tsx b/apps/app/src/pages/_error.tsx new file mode 100644 index 0000000000..4cc60d619b --- /dev/null +++ b/apps/app/src/pages/_error.tsx @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/nextjs' +import { type NextPageContext } from 'next' +import NextErrorComponent from 'next/error' +import { type ComponentProps } from 'react' + +const CustomErrorComponent = (props: ComponentProps) => ( + +) + +CustomErrorComponent.getInitialProps = async (contextData: NextPageContext) => { + // In case this is running in a serverless function, await this in order to give Sentry + // time to send the error before the lambda exits + await Sentry.captureUnderscoreErrorException(contextData) + + // This will contain the status code of the response + return NextErrorComponent.getInitialProps(contextData) +} + +export default CustomErrorComponent diff --git a/apps/app/src/types/nextjs-routes.d.ts b/apps/app/src/types/nextjs-routes.d.ts index b7fe1d71db..371fc7a4e9 100644 --- a/apps/app/src/types/nextjs-routes.d.ts +++ b/apps/app/src/types/nextjs-routes.d.ts @@ -11,6 +11,8 @@ declare module "nextjs-routes" { } from "next"; export type Route = + | StaticRoute<"/404"> + | StaticRoute<"/500"> | StaticRoute<"/account"> | StaticRoute<"/account/reviews"> | StaticRoute<"/account/saved"> From bf5f7e3b7d03e17a4feba3c452eb401ecba667c3 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:22:42 -0400 Subject: [PATCH 08/11] disable prebuild cache --- apps/app/turbo.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/app/turbo.json b/apps/app/turbo.json index 689ddab758..0d28210946 100644 --- a/apps/app/turbo.json +++ b/apps/app/turbo.json @@ -35,6 +35,9 @@ ], "outputs": [".next/**"] }, + "build:prebuild": { + "cache": false + }, "lint": { "outputs": [".next/cache/eslint/**"] }, From c79317fcd6d6d8ade5ecf6c9f6c45683e7a2c561 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 2 Aug 2023 19:06:04 -0400 Subject: [PATCH 09/11] sentry browser tracing --- apps/app/sentry.client.config.ts | 6 ++++++ apps/app/src/pages/_document.tsx | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/app/sentry.client.config.ts b/apps/app/sentry.client.config.ts index 0c6eddecfd..17ee0cb2d4 100644 --- a/apps/app/sentry.client.config.ts +++ b/apps/app/sentry.client.config.ts @@ -26,5 +26,11 @@ Sentry.init({ maskAllText: true, blockAllMedia: true, }), + new Sentry.BrowserTracing(), + ], + tracePropagationTargets: [ + 'https://app.inreach.org', + 'https://*-weareinreach.vercel.app', + 'http://localhost', ], }) diff --git a/apps/app/src/pages/_document.tsx b/apps/app/src/pages/_document.tsx index c05337a450..6b031b9324 100644 --- a/apps/app/src/pages/_document.tsx +++ b/apps/app/src/pages/_document.tsx @@ -24,7 +24,18 @@ export default class _Document extends Document { const currentLocale = this.props.__NEXT_DATA__.locale || i18nextConfig.i18n.defaultLocale return ( - + + { + // eslint-disable-next-line node/no-process-env + (process.env.NODE_ENV === 'development' || process.env.VERCEL_ENV === 'preview') && ( + // eslint-disable-next-line @next/next/no-sync-scripts +