From bef85988a16433c6ae7166ded5fdf7e4a2055521 Mon Sep 17 00:00:00 2001 From: Guy Ben-Aharon Date: Sat, 21 Feb 2026 21:00:00 +0200 Subject: [PATCH] fix: json logs for prod --- .github/workflows/publish.yml | 2 + apps/watcher/Dockerfile | 7 +- apps/watcher/package.json | 3 +- apps/watcher/src/config.spec.ts | 24 ++++-- apps/watcher/src/config.ts | 6 +- apps/watcher/src/index.ts | 69 +++++++-------- apps/watcher/src/logger.ts | 6 ++ apps/web/Dockerfile | 36 ++++---- apps/web/package.json | 2 + apps/web/src/instrumentation.ts | 20 +++++ apps/web/src/lib/auth/nextauth-config.ts | 1 + pnpm-lock.yaml | 103 ++++++++++++++++++++++- turbo.json | 4 +- 13 files changed, 212 insertions(+), 71 deletions(-) create mode 100644 apps/watcher/src/logger.ts create mode 100644 apps/web/src/instrumentation.ts diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 480f139..1f08f6f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -22,6 +22,7 @@ jobs: - image: web dockerfile: apps/web/Dockerfile pre-build: false + build-args: NEXT_PUBLIC_AUTH_PROVIDER=nextauth - image: watcher dockerfile: apps/watcher/Dockerfile pre-build: true @@ -86,5 +87,6 @@ jobs: platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + build-args: ${{ matrix.build-args || '' }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/apps/watcher/Dockerfile b/apps/watcher/Dockerfile index c281d40..2c15c9c 100644 --- a/apps/watcher/Dockerfile +++ b/apps/watcher/Dockerfile @@ -24,8 +24,13 @@ RUN pnpm --filter=@clawe/watcher --prod deploy deploy # Production runner FROM node:22-slim WORKDIR /app + ENV NODE_ENV=production +ENV NO_COLOR=1 +ENV FORCE_COLOR=0 + +COPY --from=builder --chown=node:node /app/deploy . -COPY --from=builder /app/deploy . +USER node CMD ["node", "dist/index.js"] diff --git a/apps/watcher/package.json b/apps/watcher/package.json index 8efb2e9..03e7685 100644 --- a/apps/watcher/package.json +++ b/apps/watcher/package.json @@ -19,7 +19,8 @@ "dependencies": { "@clawe/backend": "workspace:*", "@clawe/shared": "workspace:*", - "convex": "^1.21.0" + "convex": "^1.21.0", + "pino": "^10.3.1" }, "devDependencies": { "@clawe/eslint-config": "workspace:*", diff --git a/apps/watcher/src/config.spec.ts b/apps/watcher/src/config.spec.ts index 6de6a0e..b8016ce 100644 --- a/apps/watcher/src/config.spec.ts +++ b/apps/watcher/src/config.spec.ts @@ -1,10 +1,16 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +const mockFatal = vi.fn(); +vi.mock("./logger.js", () => ({ + logger: { fatal: mockFatal }, +})); + describe("config", () => { const originalEnv = process.env; beforeEach(() => { vi.resetModules(); + mockFatal.mockClear(); process.env = { ...originalEnv }; }); @@ -20,18 +26,19 @@ describe("config", () => { const mockExit = vi .spyOn(process, "exit") .mockImplementation(() => undefined as never); - const mockError = vi.spyOn(console, "error").mockImplementation(() => {}); const { validateEnv } = await import("./config.js"); validateEnv(); - expect(mockError).toHaveBeenCalledWith( - expect.stringContaining("CONVEX_URL"), + expect(mockFatal).toHaveBeenCalledWith( + expect.objectContaining({ + missing: expect.arrayContaining(["CONVEX_URL"]), + }), + expect.any(String), ); expect(mockExit).toHaveBeenCalledWith(1); mockExit.mockRestore(); - mockError.mockRestore(); }); it("exits when WATCHER_TOKEN is missing", async () => { @@ -41,18 +48,19 @@ describe("config", () => { const mockExit = vi .spyOn(process, "exit") .mockImplementation(() => undefined as never); - const mockError = vi.spyOn(console, "error").mockImplementation(() => {}); const { validateEnv } = await import("./config.js"); validateEnv(); - expect(mockError).toHaveBeenCalledWith( - expect.stringContaining("WATCHER_TOKEN"), + expect(mockFatal).toHaveBeenCalledWith( + expect.objectContaining({ + missing: expect.arrayContaining(["WATCHER_TOKEN"]), + }), + expect.any(String), ); expect(mockExit).toHaveBeenCalledWith(1); mockExit.mockRestore(); - mockError.mockRestore(); }); it("does not exit when all required vars are set", async () => { diff --git a/apps/watcher/src/config.ts b/apps/watcher/src/config.ts index 59b65cf..e930175 100644 --- a/apps/watcher/src/config.ts +++ b/apps/watcher/src/config.ts @@ -1,5 +1,7 @@ // Watcher configuration +import { logger } from "./logger.js"; + export const POLL_INTERVAL_MS = 2000; // Check every 2 seconds // Environment validation @@ -8,9 +10,7 @@ export function validateEnv(): void { const missing = required.filter((key) => !process.env[key]); if (missing.length > 0) { - console.error( - `Missing required environment variables: ${missing.join(", ")}`, - ); + logger.fatal({ missing }, "Missing required environment variables"); process.exit(1); } } diff --git a/apps/watcher/src/index.ts b/apps/watcher/src/index.ts index 022dcdb..5b1ec66 100644 --- a/apps/watcher/src/index.ts +++ b/apps/watcher/src/index.ts @@ -20,6 +20,7 @@ import { api } from "@clawe/backend"; import { sessionsSend, type SquadhubConnection } from "@clawe/shared/squadhub"; import { getTimeInZone, DEFAULT_TIMEZONE } from "@clawe/shared/timezone"; import { validateEnv, config, POLL_INTERVAL_MS } from "./config.js"; +import { logger } from "./logger.js"; // Validate environment on startup validateEnv(); @@ -98,13 +99,11 @@ async function checkRoutinesForTenant(machineToken: string): Promise { machineToken, routineId: routine._id, }); - console.log( - `[watcher] ✓ Triggered routine "${routine.title}" → task ${taskId}`, - ); + logger.info({ routine: routine.title, taskId }, "Triggered routine"); } catch (err) { - console.error( - `[watcher] Failed to trigger routine "${routine.title}":`, - err instanceof Error ? err.message : err, + logger.error( + { routine: routine.title, err }, + "Failed to trigger routine", ); } } @@ -120,9 +119,9 @@ async function checkRoutines(): Promise { try { await checkRoutinesForTenant(tenant.connection.squadhubToken); } catch (err) { - console.error( - `[watcher] Error checking routines for tenant ${tenant.id}:`, - err instanceof Error ? err.message : err, + logger.error( + { tenantId: tenant.id, err }, + "Error checking routines for tenant", ); } } @@ -175,8 +174,9 @@ async function deliverToAgent( return; } - console.log( - `[watcher] 📬 ${sessionKey} has ${notifications.length} pending notification(s)`, + logger.info( + { sessionKey, count: notifications.length }, + "Pending notifications", ); for (const notification of notifications) { @@ -194,27 +194,24 @@ async function deliverToAgent( notificationIds: [notification._id], }); - console.log( - `[watcher] ✅ Delivered to ${sessionKey}: ${notification.content.slice(0, 50)}...`, + logger.info( + { sessionKey, preview: notification.content.slice(0, 50) }, + "Delivered notification", ); } else { // Agent might be asleep or session unavailable - console.log( - `[watcher] 💤 ${sessionKey} unavailable: ${result.error?.message ?? "unknown error"}`, + logger.warn( + { sessionKey, error: result.error?.message ?? "unknown error" }, + "Agent unavailable", ); } } catch (err) { // Network error or agent asleep - console.log( - `[watcher] 💤 ${sessionKey} error: ${err instanceof Error ? err.message : "unknown"}`, - ); + logger.warn({ sessionKey, err }, "Agent delivery error"); } } } catch (err) { - console.error( - `[watcher] Error checking ${sessionKey}:`, - err instanceof Error ? err.message : err, - ); + logger.error({ sessionKey, err }, "Error checking agent notifications"); } } @@ -246,10 +243,7 @@ function startRoutineCheckLoop(): void { try { await checkRoutines(); } catch (err) { - console.error( - "[watcher] Routine check error:", - err instanceof Error ? err.message : err, - ); + logger.error({ err }, "Routine check error"); } }; @@ -266,10 +260,7 @@ async function startDeliveryLoop(): Promise { try { await deliveryLoop(); } catch (err) { - console.error( - "[watcher] Delivery loop error:", - err instanceof Error ? err.message : err, - ); + logger.error({ err }, "Delivery loop error"); } await sleep(POLL_INTERVAL_MS); @@ -280,14 +271,16 @@ async function startDeliveryLoop(): Promise { * Main entry point */ async function main(): Promise { - console.log("[watcher] 🦞 Clawe Watcher starting..."); - console.log(`[watcher] Convex: ${config.convexUrl}`); - console.log(`[watcher] Notification poll interval: ${POLL_INTERVAL_MS}ms`); - console.log( - `[watcher] Routine check interval: ${ROUTINE_CHECK_INTERVAL_MS}ms\n`, + logger.info("Clawe Watcher starting..."); + logger.info({ convexUrl: config.convexUrl }, "Convex connected"); + logger.info( + { + pollIntervalMs: POLL_INTERVAL_MS, + routineCheckIntervalMs: ROUTINE_CHECK_INTERVAL_MS, + }, + "Intervals configured", ); - - console.log("[watcher] Starting loops...\n"); + logger.info("Starting loops..."); // Start routine check loop (every 10 seconds) startRoutineCheckLoop(); @@ -298,6 +291,6 @@ async function main(): Promise { // Start the watcher main().catch((err) => { - console.error("[watcher] Fatal error:", err); + logger.fatal({ err }, "Fatal error"); process.exit(1); }); diff --git a/apps/watcher/src/logger.ts b/apps/watcher/src/logger.ts new file mode 100644 index 0000000..a505c78 --- /dev/null +++ b/apps/watcher/src/logger.ts @@ -0,0 +1,6 @@ +import pino from "pino"; + +export const logger = pino({ + level: process.env.LOG_LEVEL || "info", + name: "watcher", +}); diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index f69409e..8c275d1 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -14,31 +14,35 @@ RUN pnpm install --frozen-lockfile # Build the app FROM base AS builder +ENV NEXT_TELEMETRY_DISABLED=1 + +ARG NEXT_PUBLIC_AUTH_PROVIDER +ENV NEXT_PUBLIC_AUTH_PROVIDER=${NEXT_PUBLIC_AUTH_PROVIDER} + COPY --from=deps /app/ . COPY --from=pruner /app/out/full/ . - -# No build-time env vars needed - Convex URL is configured at runtime RUN pnpm build --filter=@clawe/web # Production runner -FROM base AS runner -ENV NODE_ENV=production +FROM node:22-alpine AS runner +WORKDIR /app -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV NO_COLOR=1 +ENV FORCE_COLOR=0 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" +ENV CLAWE_DATA_DIR=/data/clawe -# Create data directory for config storage -RUN mkdir -p /data/clawe && chown nextjs:nodejs /data/clawe +# Create data directory with built-in node user (UID 1000) +RUN mkdir -p /data/clawe && chown node:node /data/clawe -COPY --from=builder /app/apps/web/.next/standalone ./ -COPY --from=builder /app/apps/web/.next/static ./apps/web/.next/static -COPY --from=builder /app/apps/web/public ./apps/web/public +COPY --from=builder --chown=node:node /app/apps/web/.next/standalone ./ +COPY --from=builder --chown=node:node /app/apps/web/.next/static ./apps/web/.next/static +COPY --from=builder --chown=node:node /app/apps/web/public ./apps/web/public -USER nextjs +USER node EXPOSE 3000 -ENV PORT=3000 -ENV HOSTNAME="0.0.0.0" -ENV CLAWE_DATA_DIR=/data/clawe - CMD ["node", "apps/web/server.js"] diff --git a/apps/web/package.json b/apps/web/package.json index 9dcff70..0515365 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -47,10 +47,12 @@ "next": "16.1.0", "next-auth": "5.0.0-beta.30", "next-themes": "^0.4.6", + "pino": "^10.3.1", "react": "^19.2.0", "react-dom": "^19.2.0", "react-markdown": "^10.1.0", "rehype-raw": "^7.0.0", + "sharp": "^0.34.5", "remark-gfm": "^4.0.1", "sonner": "^2.0.7", "tippy.js": "^6.3.7", diff --git a/apps/web/src/instrumentation.ts b/apps/web/src/instrumentation.ts new file mode 100644 index 0000000..f667e3a --- /dev/null +++ b/apps/web/src/instrumentation.ts @@ -0,0 +1,20 @@ +export async function register() { + if ( + process.env.NODE_ENV === "production" && + process.env.NEXT_RUNTIME === "nodejs" + ) { + const pino = (await import("pino")).default; + const logger = pino({ level: process.env.LOG_LEVEL || "info" }); + + globalThis.console.log = (...args: unknown[]) => + logger.info(args.length === 1 ? args[0] : args); + globalThis.console.info = (...args: unknown[]) => + logger.info(args.length === 1 ? args[0] : args); + globalThis.console.warn = (...args: unknown[]) => + logger.warn(args.length === 1 ? args[0] : args); + globalThis.console.error = (...args: unknown[]) => + logger.error(args.length === 1 ? args[0] : args); + globalThis.console.debug = (...args: unknown[]) => + logger.debug(args.length === 1 ? args[0] : args); + } +} diff --git a/apps/web/src/lib/auth/nextauth-config.ts b/apps/web/src/lib/auth/nextauth-config.ts index 9f728ed..b745869 100644 --- a/apps/web/src/lib/auth/nextauth-config.ts +++ b/apps/web/src/lib/auth/nextauth-config.ts @@ -54,6 +54,7 @@ if (process.env.AUTO_LOGIN_EMAIL) { } const nextAuth = NextAuth({ + trustHost: true, providers, session: { strategy: "jwt" }, jwt: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f39cd8e..6e117b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: convex: specifier: ^1.21.0 version: 1.31.7(react@19.2.0) + pino: + specifier: ^10.3.1 + version: 10.3.1 devDependencies: '@clawe/eslint-config': specifier: workspace:* @@ -150,6 +153,9 @@ importers: next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + pino: + specifier: ^10.3.1 + version: 10.3.1 react: specifier: ^19.2.0 version: 19.2.0 @@ -165,6 +171,9 @@ importers: remark-gfm: specifier: ^4.0.1 version: 4.0.1 + sharp: + specifier: ^0.34.5 + version: 0.34.5 sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -1331,6 +1340,9 @@ packages: '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} @@ -3062,6 +3074,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -4432,6 +4448,10 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4489,6 +4509,16 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true + pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -4601,6 +4631,9 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -4679,6 +4712,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + radix-ui@1.4.3: resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} peerDependencies: @@ -4757,6 +4793,10 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -4835,6 +4875,10 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -4893,6 +4937,9 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: @@ -4910,6 +4957,10 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -5013,6 +5064,10 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thread-stream@4.0.0: + resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} + engines: {node: '>=20'} + throttleit@2.1.0: resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} engines: {node: '>=18'} @@ -6401,8 +6456,7 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@img/colour@1.0.0': - optional: true + '@img/colour@1.0.0': {} '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: @@ -6563,6 +6617,8 @@ snapshots: '@panva/hkdf@1.2.1': {} + '@pinojs/redact@0.4.0': {} + '@popperjs/core@2.11.8': {} '@radix-ui/number@1.1.1': {} @@ -8501,6 +8557,8 @@ snapshots: asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -10202,6 +10260,8 @@ snapshots: obug@2.1.1: {} + on-exit-leak-free@2.1.2: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -10263,6 +10323,26 @@ snapshots: picomatch@4.0.3: {} + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.1.0: {} + + pino@10.3.1: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.0.0 + pirates@4.0.7: {} pkg-types@1.3.1: @@ -10313,6 +10393,8 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + process-warning@5.0.0: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -10432,6 +10514,8 @@ snapshots: queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} + radix-ui@1.4.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@radix-ui/primitive': 1.1.3 @@ -10560,6 +10644,8 @@ snapshots: readdirp@4.1.2: {} + real-require@0.2.0: {} + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -10703,6 +10789,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safe-stable-stringify@2.5.0: {} + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -10765,7 +10853,6 @@ snapshots: '@img/sharp-win32-arm64': 0.34.5 '@img/sharp-win32-ia32': 0.34.5 '@img/sharp-win32-x64': 0.34.5 - optional: true shebang-command@2.0.0: dependencies: @@ -10803,6 +10890,10 @@ snapshots: siginfo@2.0.0: {} + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 @@ -10814,6 +10905,8 @@ snapshots: space-separated-tokens@2.0.2: {} + split2@4.2.0: {} + stackback@0.0.2: {} std-env@3.10.0: {} @@ -10935,6 +11028,10 @@ snapshots: dependencies: any-promise: 1.3.0 + thread-stream@4.0.0: + dependencies: + real-require: 0.2.0 + throttleit@2.1.0: {} tinybench@2.9.0: {} diff --git a/turbo.json b/turbo.json index 79ee0ef..6cbe6dc 100644 --- a/turbo.json +++ b/turbo.json @@ -15,7 +15,9 @@ "AUTO_LOGIN_EMAIL", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", - "WATCHER_TOKEN" + "WATCHER_TOKEN", + "LOG_LEVEL", + "NEXT_RUNTIME" ], "tasks": { "build": {