Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 237bd46593 | |||
| 40ebdb31d9 | |||
| 8f39ec3d35 |
@@ -46,13 +46,13 @@ ENV PORT=3000
|
|||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
# Copy standalone output and static files
|
# Copy standalone output and static files
|
||||||
|
# Create directory as root first, then copy with chown
|
||||||
|
RUN mkdir -p /app/.next/cache && chown -R nextjs:nodejs /app/.next/cache
|
||||||
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
|
||||||
# Ensure the cache directory specifically is writeable (Mintel Standard #16)
|
|
||||||
RUN mkdir -p .next/cache && chown -R nextjs:nodejs .next/cache
|
|
||||||
|
|
||||||
USER nextjs
|
USER nextjs
|
||||||
|
|
||||||
CMD ["node", "server.js"]
|
CMD ["node", "server.js"]
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ export default async function RootLayout({
|
|||||||
const { headers } = await import("next/headers");
|
const { headers } = await import("next/headers");
|
||||||
const requestHeaders = await headers();
|
const requestHeaders = await headers();
|
||||||
|
|
||||||
if ("setServerContext" in serverServices.analytics) {
|
if (serverServices.analytics.setServerContext) {
|
||||||
(serverServices.analytics as any).setServerContext({
|
serverServices.analytics.setServerContext({
|
||||||
userAgent: requestHeaders.get("user-agent") || undefined,
|
userAgent: requestHeaders.get("user-agent") || undefined,
|
||||||
language:
|
language:
|
||||||
requestHeaders.get("accept-language")?.split(",")[0] || undefined,
|
requestHeaders.get("accept-language")?.split(",")[0] || undefined,
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export async function POST(req: Request) {
|
|||||||
|
|
||||||
// Set analytics context from request headers for high-fidelity server-side tracking
|
// Set analytics context from request headers for high-fidelity server-side tracking
|
||||||
// This fulfills the "server-side via nextjs proxy" requirement
|
// This fulfills the "server-side via nextjs proxy" requirement
|
||||||
if ("setServerContext" in services.analytics) {
|
if (services.analytics.setServerContext) {
|
||||||
(services.analytics as any).setServerContext({
|
services.analytics.setServerContext({
|
||||||
userAgent: req.headers.get("user-agent") || undefined,
|
userAgent: req.headers.get("user-agent") || undefined,
|
||||||
language: req.headers.get("accept-language")?.split(",")[0] || undefined,
|
language: req.headers.get("accept-language")?.split(",")[0] || undefined,
|
||||||
referrer: req.headers.get("referer") || undefined,
|
referrer: req.headers.get("referer") || undefined,
|
||||||
|
|||||||
@@ -73,4 +73,15 @@ export interface AnalyticsService {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
trackPageview(url?: string): void;
|
trackPageview(url?: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the server-side context for the current request.
|
||||||
|
* This is used for server-side tracking (e.g. from Next.js proxy).
|
||||||
|
*/
|
||||||
|
setServerContext?(context: {
|
||||||
|
userAgent?: string;
|
||||||
|
language?: string;
|
||||||
|
referrer?: string;
|
||||||
|
ip?: string;
|
||||||
|
}): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,4 +68,16 @@ export class NoopAnalyticsService implements AnalyticsService {
|
|||||||
trackPageview(_url?: string) {
|
trackPageview(_url?: string) {
|
||||||
// intentionally noop - analytics are disabled
|
// intentionally noop - analytics are disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op implementation of setServerContext.
|
||||||
|
*/
|
||||||
|
setServerContext(_context: {
|
||||||
|
userAgent?: string;
|
||||||
|
language?: string;
|
||||||
|
referrer?: string;
|
||||||
|
ip?: string;
|
||||||
|
}) {
|
||||||
|
// intentionally noop - analytics are disabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,11 @@ export class UmamiAnalyticsService implements AnalyticsService {
|
|||||||
const payload = {
|
const payload = {
|
||||||
website: this.websiteId,
|
website: this.websiteId,
|
||||||
hostname:
|
hostname:
|
||||||
typeof window !== "undefined" ? window.location.hostname : "server",
|
typeof window !== "undefined"
|
||||||
|
? window.location.hostname
|
||||||
|
: this.serverContext?.referrer
|
||||||
|
? new URL(this.serverContext.referrer).hostname
|
||||||
|
: "server",
|
||||||
screen:
|
screen:
|
||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
? `${window.screen.width}x${window.screen.height}`
|
? `${window.screen.width}x${window.screen.height}`
|
||||||
@@ -131,7 +135,9 @@ export class UmamiAnalyticsService implements AnalyticsService {
|
|||||||
url:
|
url:
|
||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
? window.location.pathname + window.location.search
|
? window.location.pathname + window.location.search
|
||||||
: undefined,
|
: this.serverContext?.referrer
|
||||||
|
? new URL(this.serverContext.referrer).pathname
|
||||||
|
: "/",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +150,9 @@ export class UmamiAnalyticsService implements AnalyticsService {
|
|||||||
url ||
|
url ||
|
||||||
(typeof window !== "undefined"
|
(typeof window !== "undefined"
|
||||||
? window.location.pathname + window.location.search
|
? window.location.pathname + window.location.search
|
||||||
: undefined),
|
: this.serverContext?.referrer
|
||||||
|
? new URL(this.serverContext.referrer).pathname
|
||||||
|
: "/"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,33 +31,51 @@ export class PinoLoggerService implements LoggerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace(msg: string, ...args: unknown[]) {
|
trace(msg: string, ...args: unknown[]) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
|
||||||
this.logger.trace(msg, ...(args as any));
|
(this.logger as any).trace(args[0] as object, msg, ...args.slice(1));
|
||||||
|
} else {
|
||||||
|
(this.logger as any).trace(msg, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(msg: string, ...args: unknown[]) {
|
debug(msg: string, ...args: unknown[]) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
|
||||||
this.logger.debug(msg, ...(args as any));
|
(this.logger as any).debug(args[0] as object, msg, ...args.slice(1));
|
||||||
|
} else {
|
||||||
|
(this.logger as any).debug(msg, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info(msg: string, ...args: unknown[]) {
|
info(msg: string, ...args: unknown[]) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
|
||||||
this.logger.info(msg, ...(args as any));
|
(this.logger as any).info(args[0] as object, msg, ...args.slice(1));
|
||||||
|
} else {
|
||||||
|
(this.logger as any).info(msg, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(msg: string, ...args: unknown[]) {
|
warn(msg: string, ...args: unknown[]) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
|
||||||
this.logger.warn(msg, ...(args as any));
|
(this.logger as any).warn(args[0] as object, msg, ...args.slice(1));
|
||||||
|
} else {
|
||||||
|
(this.logger as any).warn(msg, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error(msg: string, ...args: unknown[]) {
|
error(msg: string, ...args: unknown[]) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
|
||||||
this.logger.error(msg, ...(args as any));
|
(this.logger as any).error(args[0] as object, msg, ...args.slice(1));
|
||||||
|
} else {
|
||||||
|
(this.logger as any).error(msg, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fatal(msg: string, ...args: unknown[]) {
|
fatal(msg: string, ...args: unknown[]) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (args.length > 0 && typeof args[0] === "object" && args[0] !== null) {
|
||||||
this.logger.fatal(msg, ...(args as any));
|
(this.logger as any).fatal(args[0] as object, msg, ...args.slice(1));
|
||||||
|
} else {
|
||||||
|
(this.logger as any).fatal(msg, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
child(bindings: Record<string, unknown>): LoggerService {
|
child(bindings: Record<string, unknown>): LoggerService {
|
||||||
|
|||||||
13
sentry.client.config.ts
Normal file
13
sentry.client.config.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
import { config } from "./lib/config";
|
||||||
|
|
||||||
|
if (config.errors.glitchtip.enabled) {
|
||||||
|
Sentry.init({
|
||||||
|
dsn: config.errors.glitchtip.dsn,
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
debug: config.isDevelopment,
|
||||||
|
environment: config.target || "production",
|
||||||
|
// Use the proxy path defined in config
|
||||||
|
tunnel: config.errors.glitchtip.proxyPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
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 { config } from "./lib/config";
|
||||||
|
|
||||||
|
if (config.errors.glitchtip.enabled) {
|
||||||
|
Sentry.init({
|
||||||
|
dsn: config.errors.glitchtip.dsn,
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
debug: config.isDevelopment,
|
||||||
|
environment: config.target || "production",
|
||||||
|
});
|
||||||
|
}
|
||||||
11
sentry.server.config.ts
Normal file
11
sentry.server.config.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
import { config } from "./lib/config";
|
||||||
|
|
||||||
|
if (config.errors.glitchtip.enabled) {
|
||||||
|
Sentry.init({
|
||||||
|
dsn: config.errors.glitchtip.dsn,
|
||||||
|
tracesSampleRate: 1.0,
|
||||||
|
debug: config.isDevelopment,
|
||||||
|
environment: config.target || "production",
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user