Merged in feat/sentry (pull request #1089)
This commit is contained in:
committed by
Joakim Jäderberg
parent
e0c5b59860
commit
3982b1ba56
@@ -52,3 +52,6 @@ ENABLE_BOOKING_FLOW="false"
|
|||||||
ENABLE_BOOKING_WIDGET="false"
|
ENABLE_BOOKING_WIDGET="false"
|
||||||
ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH="false"
|
ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH="false"
|
||||||
SHOW_SITE_WIDE_ALERT="false"
|
SHOW_SITE_WIDE_ALERT="false"
|
||||||
|
|
||||||
|
NEXT_PUBLIC_SENTRY_ENVIRONMENT="test"
|
||||||
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE="0"
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -47,3 +47,5 @@ certificates
|
|||||||
|
|
||||||
# localfile with all the CSS variables exported from design system
|
# localfile with all the CSS variables exported from design system
|
||||||
variables.css
|
variables.css
|
||||||
|
# Sentry Config File
|
||||||
|
.env.sentry-build-plugin
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
|
|
||||||
export default function Error({
|
export default function Error({
|
||||||
@@ -8,7 +8,10 @@ export default function Error({
|
|||||||
error: Error & { digest?: string }
|
error: Error & { digest?: string }
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!error) return
|
||||||
|
|
||||||
console.error({ breadcrumbsError: error })
|
console.error({ breadcrumbsError: error })
|
||||||
|
Sentry.captureException(error)
|
||||||
}, [error])
|
}, [error])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
|
|
||||||
export default function Error({
|
export default function Error({
|
||||||
@@ -8,7 +9,10 @@ export default function Error({
|
|||||||
error: Error & { digest?: string }
|
error: Error & { digest?: string }
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.error({ breadcrumbsError: error })
|
if (!error) return
|
||||||
|
|
||||||
|
console.error(error)
|
||||||
|
Sentry.captureException(error)
|
||||||
}, [error])
|
}, [error])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
|
||||||
import type { ErrorPage } from "@/types/next/error"
|
import type { ErrorPage } from "@/types/next/error"
|
||||||
|
|
||||||
export default function ProfileError({ error }: ErrorPage) {
|
export default function ProfileError({ error }: ErrorPage) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!error) return
|
||||||
|
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
Sentry.captureException(error)
|
||||||
|
}, [error])
|
||||||
|
|
||||||
return <h1>Error happened, Profile</h1>
|
return <h1>Error happened, Profile</h1>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use client" // Error components must be Client Components
|
"use client" // Error components must be Client Components
|
||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
import {
|
import {
|
||||||
useParams,
|
useParams,
|
||||||
usePathname,
|
usePathname,
|
||||||
@@ -33,13 +33,17 @@ export default function Error({
|
|||||||
const isFirstLoadRef = useRef<boolean>(true)
|
const isFirstLoadRef = useRef<boolean>(true)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Log the error to an error reporting service
|
if (!error) return
|
||||||
|
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
||||||
if (error.message === SESSION_EXPIRED) {
|
if (error.message === SESSION_EXPIRED) {
|
||||||
const loginUrl = login[params.lang]
|
const loginUrl = login[params.lang]
|
||||||
window.location.assign(loginUrl)
|
window.location.assign(loginUrl)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sentry.captureException(error)
|
||||||
}, [error, params.lang])
|
}, [error, params.lang])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
export default function Error() {
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
|
||||||
|
export default function Error({
|
||||||
|
error,
|
||||||
|
}: {
|
||||||
|
error: Error & { digest?: string }
|
||||||
|
}) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!error) return
|
||||||
|
|
||||||
|
console.error(error)
|
||||||
|
Sentry.captureException(error)
|
||||||
|
}, [error])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
|
||||||
import styles from "./global-error.module.css"
|
import styles from "./global-error.module.css"
|
||||||
|
|
||||||
export default function GlobalError({
|
export default function GlobalError({
|
||||||
@@ -8,6 +11,11 @@ export default function GlobalError({
|
|||||||
error: Error & { digest?: string }
|
error: Error & { digest?: string }
|
||||||
}) {
|
}) {
|
||||||
console.log({ global_error: error })
|
console.log({ global_error: error })
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Sentry.captureException(error)
|
||||||
|
}, [error])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LangRoute } from "@/types/routes"
|
import type { LangRoute } from "@/types/routes"
|
||||||
|
|
||||||
export const signup: LangRoute = {
|
export const signup: LangRoute = {
|
||||||
en: "/en/scandic-friends/join",
|
en: "/en/scandic-friends/join",
|
||||||
|
|||||||
5
env/client.ts
vendored
5
env/client.ts
vendored
@@ -5,6 +5,8 @@ export const env = createEnv({
|
|||||||
client: {
|
client: {
|
||||||
NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]),
|
NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]),
|
||||||
NEXT_PUBLIC_PORT: z.string().default("3000"),
|
NEXT_PUBLIC_PORT: z.string().default("3000"),
|
||||||
|
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
|
||||||
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.01),
|
||||||
NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE: z
|
NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE: z
|
||||||
.string()
|
.string()
|
||||||
// only allow "true" or "false"
|
// only allow "true" or "false"
|
||||||
@@ -16,6 +18,9 @@ export const env = createEnv({
|
|||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV,
|
NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV,
|
||||||
NEXT_PUBLIC_PORT: process.env.NEXT_PUBLIC_PORT,
|
NEXT_PUBLIC_PORT: process.env.NEXT_PUBLIC_PORT,
|
||||||
|
NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
||||||
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
|
||||||
|
process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
|
||||||
NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE:
|
NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE:
|
||||||
process.env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE,
|
process.env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE,
|
||||||
},
|
},
|
||||||
|
|||||||
4
env/server.ts
vendored
4
env/server.ts
vendored
@@ -129,6 +129,8 @@ export const env = createEnv({
|
|||||||
// transform to boolean
|
// transform to boolean
|
||||||
.transform((s) => s === "true")
|
.transform((s) => s === "true")
|
||||||
.default("false"),
|
.default("false"),
|
||||||
|
SENTRY_ENVIRONMENT: z.string().default("development"),
|
||||||
|
SENTRY_SERVER_SAMPLERATE: z.coerce.number().default(0.01),
|
||||||
},
|
},
|
||||||
emptyStringAsUndefined: true,
|
emptyStringAsUndefined: true,
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
@@ -193,5 +195,7 @@ export const env = createEnv({
|
|||||||
ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH:
|
ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH:
|
||||||
process.env.ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH,
|
process.env.ENABLE_BOOKING_WIDGET_HOTELRESERVATION_PATH,
|
||||||
SHOW_SITE_WIDE_ALERT: process.env.SHOW_SITE_WIDE_ALERT,
|
SHOW_SITE_WIDE_ALERT: process.env.SHOW_SITE_WIDE_ALERT,
|
||||||
|
SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
||||||
|
SENTRY_SERVER_SAMPLERATE: process.env.SENTRY_SERVER_SAMPLERATE,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
|
||||||
import { env } from "./env/server"
|
import { env } from "./env/server"
|
||||||
|
|
||||||
export async function register() {
|
export async function register() {
|
||||||
|
await configureSentry()
|
||||||
|
await configureApplicationInsights()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const onRequestError = Sentry.captureRequestError
|
||||||
|
|
||||||
|
async function configureApplicationInsights() {
|
||||||
if (
|
if (
|
||||||
process.env.NEXT_RUNTIME === "nodejs" &&
|
process.env.NEXT_RUNTIME === "nodejs" &&
|
||||||
env.APPLICATION_INSIGHTS_CONNECTION_STRING
|
env.APPLICATION_INSIGHTS_CONNECTION_STRING
|
||||||
@@ -11,11 +20,8 @@ export async function register() {
|
|||||||
const { PeriodicExportingMetricReader } = await import(
|
const { PeriodicExportingMetricReader } = await import(
|
||||||
"@opentelemetry/sdk-metrics"
|
"@opentelemetry/sdk-metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
const connectionString: string = env.APPLICATION_INSIGHTS_CONNECTION_STRING
|
const connectionString: string = env.APPLICATION_INSIGHTS_CONNECTION_STRING
|
||||||
|
|
||||||
const traceExporter = new AzureMonitorTraceExporter({ connectionString })
|
const traceExporter = new AzureMonitorTraceExporter({ connectionString })
|
||||||
|
|
||||||
const azureMetricExporter = new AzureMonitorMetricExporter({
|
const azureMetricExporter = new AzureMonitorMetricExporter({
|
||||||
connectionString,
|
connectionString,
|
||||||
})
|
})
|
||||||
@@ -23,7 +29,6 @@ export async function register() {
|
|||||||
exporter: azureMetricExporter,
|
exporter: azureMetricExporter,
|
||||||
exportIntervalMillis: 10000,
|
exportIntervalMillis: 10000,
|
||||||
})
|
})
|
||||||
|
|
||||||
registerOTel({
|
registerOTel({
|
||||||
serviceName: "scandic-web",
|
serviceName: "scandic-web",
|
||||||
traceExporter,
|
traceExporter,
|
||||||
@@ -31,3 +36,14 @@ export async function register() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function configureSentry() {
|
||||||
|
switch (process.env.NEXT_RUNTIME) {
|
||||||
|
case "edge": {
|
||||||
|
await import("./sentry.edge.config")
|
||||||
|
}
|
||||||
|
case "nodejs": {
|
||||||
|
await import("./sentry.server.config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { NextMiddleware, NextResponse } from "next/server"
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
import { type NextMiddleware, NextResponse } from "next/server"
|
||||||
|
|
||||||
import { Lang } from "@/constants/languages"
|
import { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
@@ -63,20 +64,22 @@ export const middleware: NextMiddleware = async (request, event) => {
|
|||||||
|
|
||||||
if (middleware.matcher(request)) {
|
if (middleware.matcher(request)) {
|
||||||
const result = await middleware.middleware(request, event)
|
const result = await middleware.middleware(request, event)
|
||||||
|
|
||||||
const _continue = result?.headers.get("x-continue")
|
const _continue = result?.headers.get("x-continue")
|
||||||
if (_continue) {
|
if (_continue) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Clean up internal headers
|
// Clean up internal headers
|
||||||
result?.headers.delete("x-sh-origin")
|
result?.headers.delete("x-sh-origin")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof NextResponse && e.status) {
|
if (e instanceof NextResponse && e.status) {
|
||||||
const cause = await e.json()
|
const cause = await e.json()
|
||||||
console.error(`NextResponse Error in middleware`)
|
console.error(`NextResponse Error in middleware`, cause)
|
||||||
console.error(cause)
|
Sentry.captureException(cause)
|
||||||
|
|
||||||
return NextResponse.rewrite(
|
return NextResponse.rewrite(
|
||||||
new URL(`/${lang}/middleware-error/${e.status}`, request.nextUrl),
|
new URL(`/${lang}/middleware-error/${e.status}`, request.nextUrl),
|
||||||
@@ -90,8 +93,9 @@ export const middleware: NextMiddleware = async (request, event) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(`Error in middleware`)
|
console.error(`Error in middleware`, e)
|
||||||
console.error(e)
|
Sentry.captureException(e)
|
||||||
|
|
||||||
return NextResponse.rewrite(
|
return NextResponse.rewrite(
|
||||||
new URL(`/${lang}/middleware-error/500`, request.nextUrl),
|
new URL(`/${lang}/middleware-error/500`, request.nextUrl),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { NextResponse } from "next/server"
|
import { type NextMiddleware, NextResponse } from "next/server"
|
||||||
|
|
||||||
import { notFound } from "@/server/errors/next"
|
import { notFound } from "@/server/errors/next"
|
||||||
|
|
||||||
@@ -7,9 +7,7 @@ import { removeTrailingSlash } from "@/utils/url"
|
|||||||
|
|
||||||
import { fetchAndCacheEntry, getDefaultRequestHeaders } from "./utils"
|
import { fetchAndCacheEntry, getDefaultRequestHeaders } from "./utils"
|
||||||
|
|
||||||
import type { NextMiddleware } from "next/server"
|
import type { MiddlewareMatcher } from "@/types/middleware"
|
||||||
|
|
||||||
import { MiddlewareMatcher } from "@/types/middleware"
|
|
||||||
|
|
||||||
export const middleware: NextMiddleware = async (request) => {
|
export const middleware: NextMiddleware = async (request) => {
|
||||||
const { nextUrl } = request
|
const { nextUrl } = request
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { NextMiddleware, NextResponse } from "next/server"
|
import { type NextMiddleware, NextResponse } from "next/server"
|
||||||
|
|
||||||
import { MiddlewareMatcher } from "@/types/middleware"
|
import type { MiddlewareMatcher } from "@/types/middleware"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Middleware function to normalize date formats to support
|
Middleware function to normalize date formats to support
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
import createJiti from "jiti"
|
import createJiti from "jiti"
|
||||||
import { fileURLToPath } from "url"
|
import { fileURLToPath } from "url"
|
||||||
|
|
||||||
@@ -292,4 +293,23 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default nextConfig
|
export default Sentry.withSentryConfig(nextConfig, {
|
||||||
|
org: "scandic-hotels",
|
||||||
|
project: "scandic-web",
|
||||||
|
enabled: process.env.NODE_ENV !== "development",
|
||||||
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||||
|
|
||||||
|
// Only print logs for uploading source maps in CI
|
||||||
|
silent: !process.env.CI,
|
||||||
|
|
||||||
|
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
||||||
|
widenClientFileUpload: true,
|
||||||
|
|
||||||
|
// Automatically annotate React components to show their full name in breadcrumbs and session replay
|
||||||
|
reactComponentAnnotation: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
hideSourceMaps: true,
|
||||||
|
disableLogger: true,
|
||||||
|
})
|
||||||
|
|||||||
2860
package-lock.json
generated
2860
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -24,11 +24,11 @@
|
|||||||
"test:unit:watch": "jest --watch"
|
"test:unit:watch": "jest --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.24",
|
"@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.27",
|
||||||
"@contentstack/live-preview-utils": "^3.0.0",
|
"@contentstack/live-preview-utils": "^3.0.0",
|
||||||
"@hookform/error-message": "^2.0.1",
|
"@hookform/error-message": "^2.0.1",
|
||||||
"@hookform/resolvers": "^3.3.4",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
"@netlify/plugin-nextjs": "^5.1.1",
|
"@netlify/plugin-nextjs": "^5.9.0",
|
||||||
"@opentelemetry/api": "^1.9.0",
|
"@opentelemetry/api": "^1.9.0",
|
||||||
"@opentelemetry/sdk-metrics": "^1.25.1",
|
"@opentelemetry/sdk-metrics": "^1.25.1",
|
||||||
"@radix-ui/react-dialog": "^1.1.1",
|
"@radix-ui/react-dialog": "^1.1.1",
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
"@radix-ui/react-visually-hidden": "^1.1.0",
|
"@radix-ui/react-visually-hidden": "^1.1.0",
|
||||||
"@react-aria/ssr": "^3.9.5",
|
"@react-aria/ssr": "^3.9.5",
|
||||||
"@scandic-hotels/design-system": "git+https://x-token-auth:$DESIGN_SYSTEM_ACCESS_TOKEN@bitbucket.org/scandic-swap/design-system.git#v0.1.0-rc.9",
|
"@scandic-hotels/design-system": "git+https://x-token-auth:$DESIGN_SYSTEM_ACCESS_TOKEN@bitbucket.org/scandic-swap/design-system.git#v0.1.0-rc.9",
|
||||||
|
"@sentry/nextjs": "^8.41.0",
|
||||||
"@t3-oss/env-nextjs": "^0.9.2",
|
"@t3-oss/env-nextjs": "^0.9.2",
|
||||||
"@tanstack/react-query": "^5.28.6",
|
"@tanstack/react-query": "^5.28.6",
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
|
|||||||
17
sentry.client.config.ts
Normal file
17
sentry.client.config.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
|
||||||
|
import { env } from "./env/client"
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: "https://fe39c070b4154e2f9cc35f0e5de0aedb@o4508102497206272.ingest.de.sentry.io/4508102500286544",
|
||||||
|
environment: env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
|
||||||
|
enabled: env.NEXT_PUBLIC_SENTRY_ENVIRONMENT !== "development",
|
||||||
|
tracesSampleRate: env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
|
||||||
|
|
||||||
|
// Set profilesSampleRate to 1.0 to profile every transaction.
|
||||||
|
// Since profilesSampleRate is relative to tracesSampleRate,
|
||||||
|
// the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
|
||||||
|
// For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
|
||||||
|
// result in 25% of transactions being profiled (0.5*0.5=0.25)
|
||||||
|
profilesSampleRate: 0.01,
|
||||||
|
})
|
||||||
11
sentry.edge.config.ts
Normal file
11
sentry.edge.config.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
|
||||||
|
import { env } from "./env/server"
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: "https://fe39c070b4154e2f9cc35f0e5de0aedb@o4508102497206272.ingest.de.sentry.io/4508102500286544",
|
||||||
|
environment: env.SENTRY_ENVIRONMENT,
|
||||||
|
enabled: env.SENTRY_ENVIRONMENT !== "development",
|
||||||
|
|
||||||
|
tracesSampleRate: env.SENTRY_SERVER_SAMPLERATE,
|
||||||
|
})
|
||||||
10
sentry.server.config.ts
Normal file
10
sentry.server.config.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs"
|
||||||
|
|
||||||
|
import { env } from "./env/server"
|
||||||
|
|
||||||
|
Sentry.init({
|
||||||
|
dsn: "https://fe39c070b4154e2f9cc35f0e5de0aedb@o4508102497206272.ingest.de.sentry.io/4508102500286544",
|
||||||
|
environment: env.SENTRY_ENVIRONMENT,
|
||||||
|
enabled: env.SENTRY_ENVIRONMENT !== "development",
|
||||||
|
tracesSampleRate: env.SENTRY_SERVER_SAMPLERATE,
|
||||||
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { RoomData } from "@/types/hotel"
|
import type { RoomData } from "@/types/hotel"
|
||||||
import { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
export function getBookedHotelRoom(
|
export function getBookedHotelRoom(
|
||||||
rooms: RoomData[] | undefined,
|
rooms: RoomData[] | undefined,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { metrics } from "@opentelemetry/api"
|
import { metrics } from "@opentelemetry/api"
|
||||||
|
|
||||||
import { Lang } from "@/constants/languages"
|
|
||||||
import {
|
import {
|
||||||
GetAccountPage,
|
GetAccountPage,
|
||||||
GetAccountPageRefs,
|
GetAccountPageRefs,
|
||||||
@@ -26,6 +25,7 @@ import type {
|
|||||||
GetAccountPageRefsSchema,
|
GetAccountPageRefsSchema,
|
||||||
GetAccountPageSchema,
|
GetAccountPageSchema,
|
||||||
} from "@/types/trpc/routers/contentstack/accountPage"
|
} from "@/types/trpc/routers/contentstack/accountPage"
|
||||||
|
import type { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
const meter = metrics.getMeter("trpc.accountPage")
|
const meter = metrics.getMeter("trpc.accountPage")
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Lang } from "@/constants/languages"
|
|
||||||
import { batchRequest } from "@/lib/graphql/batchRequest"
|
import { batchRequest } from "@/lib/graphql/batchRequest"
|
||||||
import {
|
import {
|
||||||
GetContentPage,
|
GetContentPage,
|
||||||
@@ -19,6 +18,7 @@ import {
|
|||||||
type TrackingSDKPageData,
|
type TrackingSDKPageData,
|
||||||
} from "@/types/components/tracking"
|
} from "@/types/components/tracking"
|
||||||
import type { GetContentPageSchema } from "@/types/trpc/routers/contentstack/contentPage"
|
import type { GetContentPageSchema } from "@/types/trpc/routers/contentstack/contentPage"
|
||||||
|
import type { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
export const contentPageQueryRouter = router({
|
export const contentPageQueryRouter = router({
|
||||||
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { metrics } from "@opentelemetry/api"
|
import { metrics } from "@opentelemetry/api"
|
||||||
|
|
||||||
import { Lang } from "@/constants/languages"
|
|
||||||
import {
|
import {
|
||||||
GetLoyaltyPage,
|
GetLoyaltyPage,
|
||||||
GetLoyaltyPageRefs,
|
GetLoyaltyPageRefs,
|
||||||
@@ -20,12 +19,13 @@ import { getConnections } from "./utils"
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
TrackingChannelEnum,
|
TrackingChannelEnum,
|
||||||
TrackingSDKPageData,
|
type TrackingSDKPageData,
|
||||||
} from "@/types/components/tracking"
|
} from "@/types/components/tracking"
|
||||||
import type {
|
import type {
|
||||||
GetLoyaltyPageRefsSchema,
|
GetLoyaltyPageRefsSchema,
|
||||||
GetLoyaltyPageSchema,
|
GetLoyaltyPageSchema,
|
||||||
} from "@/types/trpc/routers/contentstack/loyaltyPage"
|
} from "@/types/trpc/routers/contentstack/loyaltyPage"
|
||||||
|
import type { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
const meter = metrics.getMeter("trpc.loyaltyPage")
|
const meter = metrics.getMeter("trpc.loyaltyPage")
|
||||||
// OpenTelemetry metrics: LoyaltyPage
|
// OpenTelemetry metrics: LoyaltyPage
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as Sentry from "@sentry/node"
|
||||||
import { initTRPC } from "@trpc/server"
|
import { initTRPC } from "@trpc/server"
|
||||||
import { experimental_nextAppDirCaller } from "@trpc/server/adapters/next-app-dir"
|
import { experimental_nextAppDirCaller } from "@trpc/server/adapters/next-app-dir"
|
||||||
import { ZodError } from "zod"
|
import { ZodError } from "zod"
|
||||||
@@ -36,9 +37,19 @@ const t = initTRPC
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const sentryMiddleware = t.middleware(
|
||||||
|
Sentry.trpcMiddleware({
|
||||||
|
attachRpcInput: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
export const { createCallerFactory, mergeRouters, router } = t
|
export const { createCallerFactory, mergeRouters, router } = t
|
||||||
export const publicProcedure = t.procedure
|
const baseProcedure = t.procedure.use(sentryMiddleware)
|
||||||
export const contentstackBaseProcedure = t.procedure.use(async function (opts) {
|
|
||||||
|
export const publicProcedure = baseProcedure
|
||||||
|
|
||||||
|
export const contentstackBaseProcedure = baseProcedure.use(
|
||||||
|
async function (opts) {
|
||||||
if (!opts.ctx.lang) {
|
if (!opts.ctx.lang) {
|
||||||
// When fetching data client side with TRPC we don't pass through middlewares and therefore do not get the lang through headers
|
// When fetching data client side with TRPC we don't pass through middlewares and therefore do not get the lang through headers
|
||||||
// We can then pass lang as an input in the request and set it to the context in the procedure
|
// We can then pass lang as an input in the request and set it to the context in the procedure
|
||||||
@@ -60,7 +71,8 @@ export const contentstackBaseProcedure = t.procedure.use(async function (opts) {
|
|||||||
lang: opts.ctx.lang,
|
lang: opts.ctx.lang,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
)
|
||||||
export const contentstackExtendedProcedureUID = contentstackBaseProcedure.use(
|
export const contentstackExtendedProcedureUID = contentstackBaseProcedure.use(
|
||||||
async function (opts) {
|
async function (opts) {
|
||||||
if (!opts.ctx.uid) {
|
if (!opts.ctx.uid) {
|
||||||
@@ -74,7 +86,7 @@ export const contentstackExtendedProcedureUID = contentstackBaseProcedure.use(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
export const protectedProcedure = t.procedure.use(async function (opts) {
|
export const protectedProcedure = baseProcedure.use(async function (opts) {
|
||||||
const authRequired = opts.meta?.authRequired ?? true
|
const authRequired = opts.meta?.authRequired ?? true
|
||||||
const session = await opts.ctx.auth()
|
const session = await opts.ctx.auth()
|
||||||
if (!authRequired && env.NODE_ENV === "development") {
|
if (!authRequired && env.NODE_ENV === "development") {
|
||||||
@@ -99,7 +111,7 @@ export const protectedProcedure = t.procedure.use(async function (opts) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
export const safeProtectedProcedure = t.procedure.use(async function (opts) {
|
export const safeProtectedProcedure = baseProcedure.use(async function (opts) {
|
||||||
const authRequired = opts.meta?.authRequired ?? true
|
const authRequired = opts.meta?.authRequired ?? true
|
||||||
|
|
||||||
let session: Session | null = await opts.ctx.auth()
|
let session: Session | null = await opts.ctx.auth()
|
||||||
@@ -121,7 +133,7 @@ export const safeProtectedProcedure = t.procedure.use(async function (opts) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
export const serviceProcedure = t.procedure.use(async function (opts) {
|
export const serviceProcedure = baseProcedure.use(async (opts) => {
|
||||||
const { access_token } = await getServiceToken()
|
const { access_token } = await getServiceToken()
|
||||||
if (!access_token) {
|
if (!access_token) {
|
||||||
throw internalServerError(`[serviceProcedure] No service token`)
|
throw internalServerError(`[serviceProcedure] No service token`)
|
||||||
@@ -133,7 +145,7 @@ export const serviceProcedure = t.procedure.use(async function (opts) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
export const serverActionProcedure = t.procedure.experimental_caller(
|
export const serverActionProcedure = baseProcedure.experimental_caller(
|
||||||
experimental_nextAppDirCaller({
|
experimental_nextAppDirCaller({
|
||||||
createContext,
|
createContext,
|
||||||
normalizeFormData: true,
|
normalizeFormData: true,
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { z } from "zod"
|
import type { z } from "zod"
|
||||||
|
|
||||||
import {
|
import type {
|
||||||
priceSchema,
|
priceSchema,
|
||||||
Product,
|
Product,
|
||||||
productTypePriceSchema,
|
productTypePriceSchema,
|
||||||
RoomConfiguration,
|
RoomConfiguration,
|
||||||
} from "@/server/routers/hotels/output"
|
} from "@/server/routers/hotels/output"
|
||||||
|
import type { RoomPackage } from "./roomFilter"
|
||||||
import { RoomPackage } from "./roomFilter"
|
|
||||||
|
|
||||||
import type { RateCode } from "./selectRate"
|
import type { RateCode } from "./selectRate"
|
||||||
|
|
||||||
type ProductPrice = z.output<typeof productTypePriceSchema>
|
type ProductPrice = z.output<typeof productTypePriceSchema>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Product, RoomConfiguration } from "@/server/routers/hotels/output"
|
import type { Product, RoomConfiguration } from "@/server/routers/hotels/output"
|
||||||
|
import type { ChildBedMapEnum } from "../../bookingWidget/enums"
|
||||||
import { ChildBedMapEnum } from "../../bookingWidget/enums"
|
|
||||||
|
|
||||||
export interface Child {
|
export interface Child {
|
||||||
bed: ChildBedMapEnum
|
bed: ChildBedMapEnum
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { sidePanelVariants } from "@/components/HotelReservation/SidePanel/variants"
|
|
||||||
|
|
||||||
import type { VariantProps } from "class-variance-authority"
|
import type { VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import type { sidePanelVariants } from "@/components/HotelReservation/SidePanel/variants"
|
||||||
|
|
||||||
export interface SidePanelProps
|
export interface SidePanelProps
|
||||||
extends VariantProps<typeof sidePanelVariants> {}
|
extends VariantProps<typeof sidePanelVariants> {}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { MembershipLevel } from "@/constants/membershipLevels"
|
|
||||||
|
|
||||||
import type { Lang } from "@/constants/languages"
|
import type { Lang } from "@/constants/languages"
|
||||||
|
import type { MembershipLevel } from "@/constants/membershipLevels"
|
||||||
|
|
||||||
export enum TrackingChannelEnum {
|
export enum TrackingChannelEnum {
|
||||||
"scandic-friends" = "scandic-friends",
|
"scandic-friends" = "scandic-friends",
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { z } from "zod"
|
import type { z } from "zod"
|
||||||
|
|
||||||
import { bookingConfirmationSchema } from "@/server/routers/booking/output"
|
import type { Hotel, RoomData } from "@/types/hotel"
|
||||||
|
import type { bookingConfirmationSchema } from "@/server/routers/booking/output"
|
||||||
import { Hotel, RoomData } from "@/types/hotel"
|
|
||||||
|
|
||||||
export interface BookingConfirmationSchema
|
export interface BookingConfirmationSchema
|
||||||
extends z.output<typeof bookingConfirmationSchema> {}
|
extends z.output<typeof bookingConfirmationSchema> {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TrackingPosition, TrackingSDKData } from "@/types/components/tracking"
|
import type { TrackingPosition, TrackingSDKData } from "@/types/components/tracking"
|
||||||
|
|
||||||
export function trackClick(name: string) {
|
export function trackClick(name: string) {
|
||||||
pushToDataLayer({
|
pushToDataLayer({
|
||||||
|
|||||||
Reference in New Issue
Block a user