Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/logger/src/index.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,36 @@ describe('Logger', () => {
})
})

describe('browser suppression in production', () => {
const realProcess = globalThis.process

afterEach(() => {
Reflect.deleteProperty(globalThis, 'window')
globalThis.process = realProcess
})

test('should keep logging when the server installs a DOM', () => {
globalThis.process = {
...realProcess,
env: { ...realProcess.env, NODE_ENV: 'production' },
} as typeof realProcess
Object.assign(globalThis, { window: { document: {} } })

createLogger('Test').error('server still logs')

expect(consoleErrorSpy).toHaveBeenCalled()
})

test('should stay silent in a real browser', () => {
globalThis.process = { env: { NODE_ENV: 'production' } } as unknown as typeof realProcess
Object.assign(globalThis, { window: { document: {} } })

createLogger('Test').error('browser stays quiet')

expect(consoleErrorSpy).not.toHaveBeenCalled()
})
})

describe('LogLevel enum', () => {
test('should have correct log levels', () => {
expect(LogLevel.DEBUG).toBe('DEBUG')
Expand Down
20 changes: 16 additions & 4 deletions packages/logger/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,21 @@ const getNodeEnv = (): string => {
return 'development'
}

/**
* True only in a real browser.
*
* Server code can legitimately install a DOM — `ensureDomForTipTap` in the
* collab-doc converter mounts a jsdom `window` so TipTap runs headless — so the
* presence of `window` alone does not mean the browser. Node always exposes
* `process.versions.node` and a browser never does, which keeps a server-side
* DOM from silencing the logger for the rest of the process's life.
*/
const isBrowserRuntime = (): boolean => {
if (typeof (globalThis as { window?: unknown }).window === 'undefined') return false
const runtime = (globalThis as { process?: { versions?: { node?: unknown } } }).process
return typeof runtime?.versions?.node !== 'string'
}

const getLogLevel = (): string | undefined => {
if (typeof process !== 'undefined' && process.env) {
return process.env.LOG_LEVEL
Expand DownExpand Up@@ -201,10 +216,7 @@ export class Logger {
private shouldLog(level: LogLevel): boolean {
if (!this.config.enabled) return false

if (
getNodeEnv() === 'production' &&
typeof (globalThis as { window?: unknown }).window !== 'undefined'
) {
if (getNodeEnv() === 'production' && isBrowserRuntime()) {
return false
}

Expand Down