diff --git a/packages/monitoring/README.md b/packages/monitoring/api/README.md similarity index 100% rename from packages/monitoring/README.md rename to packages/monitoring/api/README.md diff --git a/packages/monitoring/package.json b/packages/monitoring/api/package.json similarity index 90% rename from packages/monitoring/package.json rename to packages/monitoring/api/package.json index f2f3d1a5f..9bde3d2f9 100644 --- a/packages/monitoring/package.json +++ b/packages/monitoring/api/package.json @@ -4,9 +4,9 @@ "sideEffects": false, "version": "0.1.0", "scripts": { - "clean": "git clean -xdf .turbo node_modules", + "clean": "git clean -xdf ../.turbo node_modules", "format": "prettier --check \"**/*.{ts,tsx}\"", - "lint": "eslint .", + "lint": "eslint ..", "typecheck": "tsc --noEmit" }, "prettier": "@kit/prettier-config", @@ -17,6 +17,7 @@ "./components": "./src/components/index.ts" }, "devDependencies": { + "@kit/monitoring-core": "workspace:*", "@kit/baselime": "workspace:*", "@kit/eslint-config": "workspace:*", "@kit/prettier-config": "workspace:*", diff --git a/packages/monitoring/src/components/error-boundary.tsx b/packages/monitoring/api/src/components/error-boundary.tsx similarity index 100% rename from packages/monitoring/src/components/error-boundary.tsx rename to packages/monitoring/api/src/components/error-boundary.tsx diff --git a/packages/monitoring/src/components/index.ts b/packages/monitoring/api/src/components/index.ts similarity index 100% rename from packages/monitoring/src/components/index.ts rename to packages/monitoring/api/src/components/index.ts diff --git a/packages/monitoring/src/components/provider.tsx b/packages/monitoring/api/src/components/provider.tsx similarity index 81% rename from packages/monitoring/src/components/provider.tsx rename to packages/monitoring/api/src/components/provider.tsx index bc7fea910..1eb0135e2 100644 --- a/packages/monitoring/src/components/provider.tsx +++ b/packages/monitoring/api/src/components/provider.tsx @@ -13,6 +13,14 @@ const BaselimeProvider = lazy(async () => { }; }); +const SentryProvider = lazy(async () => { + const { SentryProvider } = await import('@kit/sentry/provider'); + + return { + default: SentryProvider, + }; +}); + type Config = { provider: InstrumentationProvider; providerToken: string; @@ -35,9 +43,8 @@ export function MonitoringProvider( ); - // sentry does not require a provider case InstrumentationProvider.Sentry: - return <>{props.children}; + return {props.children}; default: return <>{props.children}; diff --git a/packages/monitoring/src/get-monitoring-provider.ts b/packages/monitoring/api/src/get-monitoring-provider.ts similarity index 100% rename from packages/monitoring/src/get-monitoring-provider.ts rename to packages/monitoring/api/src/get-monitoring-provider.ts diff --git a/packages/monitoring/src/hooks/index.ts b/packages/monitoring/api/src/hooks/index.ts similarity index 100% rename from packages/monitoring/src/hooks/index.ts rename to packages/monitoring/api/src/hooks/index.ts diff --git a/packages/monitoring/src/hooks/use-capture-exception.ts b/packages/monitoring/api/src/hooks/use-capture-exception.ts similarity index 100% rename from packages/monitoring/src/hooks/use-capture-exception.ts rename to packages/monitoring/api/src/hooks/use-capture-exception.ts diff --git a/packages/monitoring/api/src/hooks/use-monitoring.ts b/packages/monitoring/api/src/hooks/use-monitoring.ts new file mode 100644 index 000000000..aaeea4ea3 --- /dev/null +++ b/packages/monitoring/api/src/hooks/use-monitoring.ts @@ -0,0 +1,12 @@ +import { useContext } from 'react'; + +import { MonitoringContext } from '@kit/monitoring-core'; + +/** + * @name useMonitoring + * @description Asynchronously load the monitoring service based on the MONITORING_PROVIDER environment variable. + * Use Suspense to suspend while loading the service. + */ +export function useMonitoring() { + return useContext(MonitoringContext); +} diff --git a/packages/monitoring/src/instrumentation.ts b/packages/monitoring/api/src/instrumentation.ts similarity index 100% rename from packages/monitoring/src/instrumentation.ts rename to packages/monitoring/api/src/instrumentation.ts diff --git a/packages/monitoring/src/monitoring-providers.enum.ts b/packages/monitoring/api/src/monitoring-providers.enum.ts similarity index 100% rename from packages/monitoring/src/monitoring-providers.enum.ts rename to packages/monitoring/api/src/monitoring-providers.enum.ts diff --git a/packages/monitoring/src/server.ts b/packages/monitoring/api/src/server.ts similarity index 100% rename from packages/monitoring/src/server.ts rename to packages/monitoring/api/src/server.ts diff --git a/packages/monitoring/src/services/get-server-monitoring-service.ts b/packages/monitoring/api/src/services/get-server-monitoring-service.ts similarity index 94% rename from packages/monitoring/src/services/get-server-monitoring-service.ts rename to packages/monitoring/api/src/services/get-server-monitoring-service.ts index 3a00ae359..bfc67ae4d 100644 --- a/packages/monitoring/src/services/get-server-monitoring-service.ts +++ b/packages/monitoring/api/src/services/get-server-monitoring-service.ts @@ -1,6 +1,7 @@ +import { ConsoleMonitoringService } from '@kit/monitoring-core'; + import { getMonitoringProvider } from '../get-monitoring-provider'; import { InstrumentationProvider } from '../monitoring-providers.enum'; -import { ConsoleMonitoringService } from './console-monitoring.service'; const MONITORING_PROVIDER = getMonitoringProvider(); diff --git a/packages/monitoring/tsconfig.json b/packages/monitoring/api/tsconfig.json similarity index 100% rename from packages/monitoring/tsconfig.json rename to packages/monitoring/api/tsconfig.json diff --git a/packages/monitoring/baselime/package.json b/packages/monitoring/baselime/package.json index 81d4df9e5..80279117a 100644 --- a/packages/monitoring/baselime/package.json +++ b/packages/monitoring/baselime/package.json @@ -18,16 +18,22 @@ "dependencies": { "@baselime/node-opentelemetry": "^0.5.8", "@baselime/react-rum": "^0.2.9", + "@kit/monitoring-core": "workspace:*", "@tanstack/react-table": "^8.16.0", "next": "14.3.0-canary.7", "tailwind-merge": "^2.3.0", "zod": "^3.23.0" }, "devDependencies": { + "@types/react": "^18.2.79", "@kit/eslint-config": "workspace:*", "@kit/prettier-config": "workspace:*", "@kit/tailwind-config": "workspace:*", - "@kit/tsconfig": "workspace:*" + "@kit/tsconfig": "workspace:*", + "react": "18.2.0" + }, + "peerDependencies": { + "react": "18.2.0" }, "eslintConfig": { "root": true, diff --git a/packages/monitoring/baselime/src/components/provider.tsx b/packages/monitoring/baselime/src/components/provider.tsx index e35d14fd7..15ee4e3d2 100644 --- a/packages/monitoring/baselime/src/components/provider.tsx +++ b/packages/monitoring/baselime/src/components/provider.tsx @@ -1,5 +1,11 @@ +import { useRef } from 'react'; + import { BaselimeRum } from '@baselime/react-rum'; +import { MonitoringContext } from '@kit/monitoring-core'; + +import { useBaselime } from '../hooks/use-baselime'; + export function BaselimeProvider({ children, apiKey, @@ -16,7 +22,18 @@ export function BaselimeProvider({ enableWebVitals={enableWebVitals} fallback={ErrorPage ?? null} > - {children} + {children} ); } + +function MonitoringProvider(props: React.PropsWithChildren) { + const service = useBaselime(); + const provider = useRef(service); + + return ( + + {props.children} + + ); +} diff --git a/packages/monitoring/baselime/src/hooks/use-baselime.ts b/packages/monitoring/baselime/src/hooks/use-baselime.ts index d582f33f5..80e2c7480 100644 --- a/packages/monitoring/baselime/src/hooks/use-baselime.ts +++ b/packages/monitoring/baselime/src/hooks/use-baselime.ts @@ -1,6 +1,8 @@ +import { useMemo } from 'react'; + import { useBaselimeRum } from '@baselime/react-rum'; -import { MonitoringService } from '../../../src/services/monitoring.service'; +import { MonitoringService } from '@kit/monitoring-core'; /** * @name useBaselime @@ -9,12 +11,14 @@ import { MonitoringService } from '../../../src/services/monitoring.service'; export function useBaselime(): MonitoringService { const { captureException, setUser } = useBaselimeRum(); - return { - captureException(error: Error, extra?: React.ErrorInfo | undefined) { - void captureException(error, extra); - }, - identifyUser(params) { - setUser(params.id); - }, - } satisfies MonitoringService; + return useMemo(() => { + return { + captureException(error: Error, extra?: React.ErrorInfo | undefined) { + void captureException(error, extra); + }, + identifyUser(params) { + setUser(params.id); + }, + } satisfies MonitoringService; + }, [captureException, setUser]); } diff --git a/packages/monitoring/baselime/src/services/baselime-server-monitoring.service.ts b/packages/monitoring/baselime/src/services/baselime-server-monitoring.service.ts index 313b4d338..bdb776120 100644 --- a/packages/monitoring/baselime/src/services/baselime-server-monitoring.service.ts +++ b/packages/monitoring/baselime/src/services/baselime-server-monitoring.service.ts @@ -1,11 +1,11 @@ import process from 'node:process'; import { z } from 'zod'; -import { MonitoringService } from '../../../src/services/monitoring.service'; +import { MonitoringService } from '@kit/monitoring-core'; const apiKey = z .string({ - required_error: 'API_KEY is required', + required_error: 'BASELIME_API_KEY is required', }) .parse(process.env.BASELIME_API_KEY); diff --git a/packages/monitoring/core/package.json b/packages/monitoring/core/package.json new file mode 100644 index 000000000..5e5f8c0aa --- /dev/null +++ b/packages/monitoring/core/package.json @@ -0,0 +1,41 @@ +{ + "name": "@kit/monitoring-core", + "private": true, + "sideEffects": false, + "version": "0.1.0", + "scripts": { + "clean": "git clean -xdf .turbo node_modules", + "format": "prettier --check \"**/*.{ts,tsx}\"", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "prettier": "@kit/prettier-config", + "exports": { + ".": "./src/index.ts" + }, + "devDependencies": { + "@kit/eslint-config": "workspace:*", + "@kit/prettier-config": "workspace:*", + "@kit/tailwind-config": "workspace:*", + "@kit/tsconfig": "workspace:*", + "@types/react": "^18.2.79", + "react": "18.2.0" + }, + "peerDependencies": { + "react": "^18.2.0" + }, + "eslintConfig": { + "root": true, + "extends": [ + "@kit/eslint-config/base", + "@kit/eslint-config/react" + ] + }, + "typesVersions": { + "*": { + "*": [ + "src/*" + ] + } + } +} diff --git a/packages/monitoring/src/services/console-monitoring.service.ts b/packages/monitoring/core/src/console-monitoring.service.ts similarity index 80% rename from packages/monitoring/src/services/console-monitoring.service.ts rename to packages/monitoring/core/src/console-monitoring.service.ts index 1b77c2026..6afddb45d 100644 --- a/packages/monitoring/src/services/console-monitoring.service.ts +++ b/packages/monitoring/core/src/console-monitoring.service.ts @@ -1,4 +1,4 @@ -import { MonitoringService } from './monitoring.service'; +import { MonitoringService } from '@kit/monitoring-core'; export class ConsoleMonitoringService implements MonitoringService { identifyUser() { diff --git a/packages/monitoring/core/src/index.ts b/packages/monitoring/core/src/index.ts new file mode 100644 index 000000000..b47a370e6 --- /dev/null +++ b/packages/monitoring/core/src/index.ts @@ -0,0 +1,3 @@ +export * from './monitoring.service'; +export * from './monitoring.context'; +export * from './console-monitoring.service'; diff --git a/packages/monitoring/core/src/monitoring.context.ts b/packages/monitoring/core/src/monitoring.context.ts new file mode 100644 index 000000000..ed2a40d94 --- /dev/null +++ b/packages/monitoring/core/src/monitoring.context.ts @@ -0,0 +1,8 @@ +import { createContext } from 'react'; + +import { ConsoleMonitoringService } from './console-monitoring.service'; +import { MonitoringService } from './monitoring.service'; + +export const MonitoringContext = createContext( + new ConsoleMonitoringService(), +); diff --git a/packages/monitoring/src/services/monitoring.service.ts b/packages/monitoring/core/src/monitoring.service.ts similarity index 100% rename from packages/monitoring/src/services/monitoring.service.ts rename to packages/monitoring/core/src/monitoring.service.ts diff --git a/packages/monitoring/core/tsconfig.json b/packages/monitoring/core/tsconfig.json new file mode 100644 index 000000000..c4697e934 --- /dev/null +++ b/packages/monitoring/core/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@kit/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["*.ts", "src"], + "exclude": ["node_modules"] +} diff --git a/packages/monitoring/sentry/package.json b/packages/monitoring/sentry/package.json index 3e43fb710..249201b80 100644 --- a/packages/monitoring/sentry/package.json +++ b/packages/monitoring/sentry/package.json @@ -12,13 +12,14 @@ "exports": { ".": "./src/index.ts", "./server": "./src/server.ts", - "./client": "./src/client.ts", + "./provider": "./src/components/provider.tsx", "./instrumentation": "./src/instrumentation.ts", "./config/client": "./src/config/sentry.client.config.ts", "./config/server": "./src/config/sentry.server.config.ts", "./config/edge": "./src/config/sentry.server.edge.ts" }, "dependencies": { + "@kit/monitoring-core": "workspace:*", "@opentelemetry/resources": "1.23.0", "@opentelemetry/sdk-node": "0.50.0", "@opentelemetry/semantic-conventions": "^1.23.0", @@ -30,10 +31,15 @@ "zod": "^3.23.0" }, "devDependencies": { + "@types/react": "^18.2.79", "@kit/eslint-config": "workspace:*", "@kit/prettier-config": "workspace:*", "@kit/tailwind-config": "workspace:*", - "@kit/tsconfig": "workspace:*" + "@kit/tsconfig": "workspace:*", + "react": "18.2.0" + }, + "peerDependencies": { + "react": "18.2.0" }, "eslintConfig": { "root": true, diff --git a/packages/monitoring/sentry/src/client.ts b/packages/monitoring/sentry/src/client.ts deleted file mode 100644 index 72a7600c0..000000000 --- a/packages/monitoring/sentry/src/client.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './hooks/use-sentry'; diff --git a/packages/monitoring/sentry/src/components/provider.tsx b/packages/monitoring/sentry/src/components/provider.tsx new file mode 100644 index 000000000..1a71e3765 --- /dev/null +++ b/packages/monitoring/sentry/src/components/provider.tsx @@ -0,0 +1,19 @@ +import { useRef } from 'react'; + +import { MonitoringContext } from '@kit/monitoring-core'; + +import { SentryServerMonitoringService } from '../services/sentry-server-monitoring.service'; + +export function SentryProvider({ children }: React.PropsWithChildren) { + return {children}; +} + +function MonitoringProvider(props: React.PropsWithChildren) { + const service = useRef(new SentryServerMonitoringService()); + + return ( + + {props.children} + + ); +} diff --git a/packages/monitoring/sentry/src/hooks/use-sentry.ts b/packages/monitoring/sentry/src/hooks/use-sentry.ts deleted file mode 100644 index 3fa2bb502..000000000 --- a/packages/monitoring/sentry/src/hooks/use-sentry.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { useMemo } from 'react'; - -import { SentryServerMonitoringService } from '../services/sentry-server-monitoring.service'; - -/** - * @name useSentry - * @description Get the Sentry monitoring service. Sentry can be used in the browser and server - so we don't need to differentiate between the two. - * @returns {SentryServerMonitoringService} - */ -export function useSentry(): SentryServerMonitoringService { - return useMemo(() => new SentryServerMonitoringService(), []); -} diff --git a/packages/monitoring/sentry/src/services/sentry-server-monitoring.service.ts b/packages/monitoring/sentry/src/services/sentry-server-monitoring.service.ts index a0704e055..57c9817ce 100644 --- a/packages/monitoring/sentry/src/services/sentry-server-monitoring.service.ts +++ b/packages/monitoring/sentry/src/services/sentry-server-monitoring.service.ts @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/nextjs'; -import { MonitoringService } from '../../../src/services/monitoring.service'; +import { MonitoringService } from '@kit/monitoring-core'; /** * @class diff --git a/packages/monitoring/src/hooks/use-monitoring.ts b/packages/monitoring/src/hooks/use-monitoring.ts deleted file mode 100644 index 411d36be0..000000000 --- a/packages/monitoring/src/hooks/use-monitoring.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { getMonitoringProvider } from '../get-monitoring-provider'; -import { InstrumentationProvider } from '../monitoring-providers.enum'; -import { ConsoleMonitoringService } from '../services/console-monitoring.service'; -import { MonitoringService } from '../services/monitoring.service'; - -const MONITORING = getMonitoringProvider(); - -let serviceFactory: () => MonitoringService; - -/** - * @name useMonitoring - * @description Asynchronously load the monitoring service based on the MONITORING_PROVIDER environment variable. - * Use Suspense to suspend while loading the service. - */ -export function useMonitoring() { - if (!serviceFactory) { - throw withMonitoringService(); - } - - return serviceFactory(); -} - -async function withMonitoringService() { - serviceFactory = await loadMonitoringService(); -} - -async function loadMonitoringService(): Promise<() => MonitoringService> { - if (!MONITORING) { - return Promise.resolve(() => new ConsoleMonitoringService()); - } - - switch (MONITORING) { - case InstrumentationProvider.Baselime: { - const { useBaselime } = await import('@kit/baselime/client'); - - return useBaselime; - } - - case InstrumentationProvider.Sentry: { - const { useSentry } = await import('@kit/sentry/client'); - - return useSentry; - } - - default: { - throw new Error( - `Unknown instrumentation provider: ${MONITORING as string}`, - ); - } - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 48133437f..313e1df18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,7 +103,7 @@ importers: version: link:../../packages/mailers '@kit/monitoring': specifier: workspace:^ - version: link:../../packages/monitoring + version: link:../../packages/monitoring/api '@kit/next': specifier: workspace:^ version: link:../../packages/next @@ -672,7 +672,7 @@ importers: version: link:../../mailers '@kit/monitoring': specifier: workspace:^ - version: link:../../monitoring + version: link:../../monitoring/api '@kit/prettier-config': specifier: workspace:* version: link:../../../tooling/prettier @@ -791,6 +791,9 @@ importers: react: specifier: 18.2.0 version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) react-hook-form: specifier: ^7.51.3 version: 7.51.3(react@18.2.0) @@ -894,7 +897,7 @@ importers: version: link:../../mailers '@kit/monitoring': specifier: workspace:* - version: link:../../monitoring + version: link:../../monitoring/api '@kit/prettier-config': specifier: workspace:* version: link:../../../tooling/prettier @@ -1042,7 +1045,7 @@ importers: specifier: ^3.23.0 version: 3.23.0 - packages/monitoring: + packages/monitoring/api: dependencies: '@tanstack/react-table': specifier: ^8.16.0 @@ -1059,22 +1062,25 @@ importers: devDependencies: '@kit/baselime': specifier: workspace:* - version: link:baselime + version: link:../baselime '@kit/eslint-config': specifier: workspace:* - version: link:../../tooling/eslint + version: link:../../../tooling/eslint + '@kit/monitoring-core': + specifier: workspace:* + version: link:../core '@kit/prettier-config': specifier: workspace:* - version: link:../../tooling/prettier + version: link:../../../tooling/prettier '@kit/sentry': specifier: workspace:* - version: link:sentry + version: link:../sentry '@kit/tailwind-config': specifier: workspace:* - version: link:../../tooling/tailwind + version: link:../../../tooling/tailwind '@kit/tsconfig': specifier: workspace:* - version: link:../../tooling/typescript + version: link:../../../tooling/typescript '@types/react': specifier: ^18.2.79 version: 18.2.79 @@ -1090,6 +1096,9 @@ importers: '@baselime/react-rum': specifier: ^0.2.9 version: 0.2.9(react@18.2.0) + '@kit/monitoring-core': + specifier: workspace:* + version: link:../core '@tanstack/react-table': specifier: ^8.16.0 version: 8.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -1115,9 +1124,39 @@ importers: '@kit/tsconfig': specifier: workspace:* version: link:../../../tooling/typescript + '@types/react': + specifier: ^18.2.79 + version: 18.2.79 + react: + specifier: 18.2.0 + version: 18.2.0 + + packages/monitoring/core: + devDependencies: + '@kit/eslint-config': + specifier: workspace:* + version: link:../../../tooling/eslint + '@kit/prettier-config': + specifier: workspace:* + version: link:../../../tooling/prettier + '@kit/tailwind-config': + specifier: workspace:* + version: link:../../../tooling/tailwind + '@kit/tsconfig': + specifier: workspace:* + version: link:../../../tooling/typescript + '@types/react': + specifier: ^18.2.79 + version: 18.2.79 + react: + specifier: 18.2.0 + version: 18.2.0 packages/monitoring/sentry: dependencies: + '@kit/monitoring-core': + specifier: workspace:* + version: link:../core '@opentelemetry/resources': specifier: 1.23.0 version: 1.23.0(@opentelemetry/api@1.8.0) @@ -1158,6 +1197,12 @@ importers: '@kit/tsconfig': specifier: workspace:* version: link:../../../tooling/typescript + '@types/react': + specifier: ^18.2.79 + version: 18.2.79 + react: + specifier: 18.2.0 + version: 18.2.0 packages/next: dependencies: