cloudflare-next-intl 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/client/components/client_provider.js +2 -0
- package/dist/src/error_handling/index.d.ts +1 -0
- package/dist/src/error_handling/index.js +1 -0
- package/dist/src/error_handling/install_console_error_override.d.ts +23 -5
- package/dist/src/error_handling/install_console_error_override.js +29 -7
- package/dist/src/error_handling/install_global_error_override.d.ts +20 -0
- package/dist/src/error_handling/install_global_error_override.js +44 -0
- package/dist/src/error_handling/report_error.d.ts +26 -12
- package/dist/src/error_handling/report_error.js +60 -22
- package/dist/src/error_handling/stringify_unknown.js +9 -3
- package/dist/src/firebase_auth/client/auth_user_provider.js +1 -1
- package/dist/src/types/types.d.ts +40 -3
- package/package.json +5 -1
|
@@ -5,6 +5,7 @@ import { createContext, useMemo } from "react";
|
|
|
5
5
|
import dynamic from "next/dynamic";
|
|
6
6
|
import config from "@intl-config";
|
|
7
7
|
import installConsoleErrorOverride from "../../error_handling/install_console_error_override";
|
|
8
|
+
import installGlobalErrorOverride from "../../error_handling/install_global_error_override";
|
|
8
9
|
export const LocaleContext = createContext(undefined);
|
|
9
10
|
// Hoisted to module scope — calling `dynamic()` inside the component body
|
|
10
11
|
// creates a brand-new component identity every render, forcing React to
|
|
@@ -22,6 +23,7 @@ export default function LocationzationClientProvider({ language, messages, initi
|
|
|
22
23
|
setLocaleCache(language);
|
|
23
24
|
setMessageForLocaleCache(language, messages);
|
|
24
25
|
installConsoleErrorOverride(config, true);
|
|
26
|
+
installGlobalErrorOverride(config);
|
|
25
27
|
// `LocaleContext.Provider` stays the outermost element here — the
|
|
26
28
|
// client `AuthUserProvider` (and its descendants calling
|
|
27
29
|
// usePathname()/useLocale()) must render as a CHILD of it, not a
|
|
@@ -3,6 +3,7 @@ export type { WithErrorHandlingOptions } from './with_error_handling';
|
|
|
3
3
|
export { default as reportError } from './report_error';
|
|
4
4
|
export type { ReportErrorConfig } from './report_error';
|
|
5
5
|
export { default as installConsoleErrorOverride } from './install_console_error_override';
|
|
6
|
+
export { default as installGlobalErrorOverride } from './install_global_error_override';
|
|
6
7
|
export { default as stringifyUnknown } from './stringify_unknown';
|
|
7
8
|
export { default as formatErrorMessage } from './format_error_message';
|
|
8
9
|
export { defaultIgnoredConsoleErrors } from './default_ignored_console_errors';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as withErrorHandling } from './with_error_handling';
|
|
2
2
|
export { default as reportError } from './report_error';
|
|
3
3
|
export { default as installConsoleErrorOverride } from './install_console_error_override';
|
|
4
|
+
export { default as installGlobalErrorOverride } from './install_global_error_override';
|
|
4
5
|
export { default as stringifyUnknown } from './stringify_unknown';
|
|
5
6
|
export { default as formatErrorMessage } from './format_error_message';
|
|
6
7
|
export { defaultIgnoredConsoleErrors } from './default_ignored_console_errors';
|
|
@@ -2,11 +2,29 @@ import { type ReportErrorConfig } from './report_error';
|
|
|
2
2
|
/**
|
|
3
3
|
* Replaces the global `console.error` so every `console.error(...)` call is
|
|
4
4
|
* also routed through `config.errorHandling.onError`/`reportError` — the
|
|
5
|
-
* original `console.error` still runs afterwards, nothing is swallowed
|
|
6
|
-
* Safe to call more than once (a no-op after the first call in
|
|
7
|
-
* realm — call it separately on the server and on the client, each
|
|
8
|
-
* own `console`). Only takes effect when
|
|
9
|
-
* is `true`.
|
|
5
|
+
* original `console.error` still runs afterwards, nothing is swallowed by
|
|
6
|
+
* default. Safe to call more than once (a no-op after the first call in
|
|
7
|
+
* this JS realm — call it separately on the server and on the client, each
|
|
8
|
+
* has its own `console`). Only takes effect when
|
|
9
|
+
* `config.errorHandling.overrideConsoleError` is `true`.
|
|
10
|
+
*
|
|
11
|
+
* On the client ONLY (`isClient: true`), passing
|
|
12
|
+
* `config.errorHandling.suppressClientConsoleError: true` skips the
|
|
13
|
+
* browser's own `console.error` output entirely once a call has been
|
|
14
|
+
* routed to `onError`/`reportError` — the error is still reported, it just
|
|
15
|
+
* never shows up in browser devtools. Has no effect server-side.
|
|
16
|
+
*
|
|
17
|
+
* Sets `consoleOverrideState.active = true` in `report_error.ts` — once
|
|
18
|
+
* installed, THIS override becomes the sole place that ever calls the real
|
|
19
|
+
* console for a report (it already logs the raw message below, before
|
|
20
|
+
* calling `reportError`), and `reportError`'s own console-logging step
|
|
21
|
+
* stays out of the loop entirely. Without that, `reportError`'s own
|
|
22
|
+
* fallback log would call `console.error` again — landing right back on
|
|
23
|
+
* this override and recursing. (An "original console.error, captured once
|
|
24
|
+
* at module load" reference does NOT reliably dodge this: Next.js's own
|
|
25
|
+
* dev-mode console interception forwards through whatever `console.error`
|
|
26
|
+
* is CURRENT at call time, not the function it originally wrapped, so a
|
|
27
|
+
* stale capture can still loop back into a patched `console.error`.)
|
|
10
28
|
*
|
|
11
29
|
* A component stuck in a render-error loop calls `console.error` on every
|
|
12
30
|
* render — `reportError`'s own dedup/cap (on by default, see
|
|
@@ -1,14 +1,32 @@
|
|
|
1
|
-
import reportError from './report_error';
|
|
1
|
+
import reportError, { consoleOverrideState } from './report_error';
|
|
2
2
|
import stringifyUnknown from './stringify_unknown';
|
|
3
3
|
import { defaultIgnoredConsoleErrors } from './default_ignored_console_errors';
|
|
4
4
|
/**
|
|
5
5
|
* Replaces the global `console.error` so every `console.error(...)` call is
|
|
6
6
|
* also routed through `config.errorHandling.onError`/`reportError` — the
|
|
7
|
-
* original `console.error` still runs afterwards, nothing is swallowed
|
|
8
|
-
* Safe to call more than once (a no-op after the first call in
|
|
9
|
-
* realm — call it separately on the server and on the client, each
|
|
10
|
-
* own `console`). Only takes effect when
|
|
11
|
-
* is `true`.
|
|
7
|
+
* original `console.error` still runs afterwards, nothing is swallowed by
|
|
8
|
+
* default. Safe to call more than once (a no-op after the first call in
|
|
9
|
+
* this JS realm — call it separately on the server and on the client, each
|
|
10
|
+
* has its own `console`). Only takes effect when
|
|
11
|
+
* `config.errorHandling.overrideConsoleError` is `true`.
|
|
12
|
+
*
|
|
13
|
+
* On the client ONLY (`isClient: true`), passing
|
|
14
|
+
* `config.errorHandling.suppressClientConsoleError: true` skips the
|
|
15
|
+
* browser's own `console.error` output entirely once a call has been
|
|
16
|
+
* routed to `onError`/`reportError` — the error is still reported, it just
|
|
17
|
+
* never shows up in browser devtools. Has no effect server-side.
|
|
18
|
+
*
|
|
19
|
+
* Sets `consoleOverrideState.active = true` in `report_error.ts` — once
|
|
20
|
+
* installed, THIS override becomes the sole place that ever calls the real
|
|
21
|
+
* console for a report (it already logs the raw message below, before
|
|
22
|
+
* calling `reportError`), and `reportError`'s own console-logging step
|
|
23
|
+
* stays out of the loop entirely. Without that, `reportError`'s own
|
|
24
|
+
* fallback log would call `console.error` again — landing right back on
|
|
25
|
+
* this override and recursing. (An "original console.error, captured once
|
|
26
|
+
* at module load" reference does NOT reliably dodge this: Next.js's own
|
|
27
|
+
* dev-mode console interception forwards through whatever `console.error`
|
|
28
|
+
* is CURRENT at call time, not the function it originally wrapped, so a
|
|
29
|
+
* stale capture can still loop back into a patched `console.error`.)
|
|
12
30
|
*
|
|
13
31
|
* A component stuck in a render-error loop calls `console.error` on every
|
|
14
32
|
* render — `reportError`'s own dedup/cap (on by default, see
|
|
@@ -34,8 +52,12 @@ export default function installConsoleErrorOverride(config, isClient) {
|
|
|
34
52
|
if (console.error.__isErrorHandlingOverride)
|
|
35
53
|
return;
|
|
36
54
|
const originalConsoleError = console.error.bind(console);
|
|
55
|
+
consoleOverrideState.active = true;
|
|
56
|
+
const suppressOnClient = isClient === true && config.errorHandling?.suppressClientConsoleError === true;
|
|
37
57
|
const override = (message, ...optionalParams) => {
|
|
38
|
-
|
|
58
|
+
if (!suppressOnClient) {
|
|
59
|
+
originalConsoleError(message, ...optionalParams);
|
|
60
|
+
}
|
|
39
61
|
const stringified = stringifyUnknown(message, isClient);
|
|
40
62
|
const ignoreList = config.errorHandling?.ignoreConsoleErrors ?? defaultIgnoredConsoleErrors;
|
|
41
63
|
if (ignoreList.some((ignored) => stringified.includes(ignored)))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ReportErrorConfig } from './report_error';
|
|
2
|
+
/**
|
|
3
|
+
* Client-only: attaches `window.addEventListener('error'|'unhandledrejection', ...)`
|
|
4
|
+
* handlers that route through `config.errorHandling.onError`/`reportError` —
|
|
5
|
+
* catches uncaught exceptions and unhandled promise rejections that never go
|
|
6
|
+
* through `console.error` at all (unlike `installConsoleErrorOverride`),
|
|
7
|
+
* e.g. Next.js's own internal "Failed to fetch RSC payload" navigation
|
|
8
|
+
* fallback. Neither handler calls `event.preventDefault()` — the browser's
|
|
9
|
+
* own default handling (logging to the console) still happens, nothing is
|
|
10
|
+
* swallowed. Safe to call more than once (a no-op after the first call in
|
|
11
|
+
* this JS realm). Takes effect when `config.errorHandling.overrideWindowErrors`
|
|
12
|
+
* is `true`, or when it's omitted and `overrideConsoleError` is `true` (so
|
|
13
|
+
* enabling `overrideConsoleError` alone catches everything by default; pass
|
|
14
|
+
* `overrideWindowErrors: false` explicitly to opt out of just this part).
|
|
15
|
+
* No-op when `window` doesn't exist (server-side).
|
|
16
|
+
*
|
|
17
|
+
* @param config Pass the relevant slices of your `RoutingConfig` directly —
|
|
18
|
+
* `{ errorHandling: config.errorHandling, generate: config.generate }`.
|
|
19
|
+
*/
|
|
20
|
+
export default function installGlobalErrorOverride(config: ReportErrorConfig | undefined): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import reportError from './report_error';
|
|
2
|
+
import stringifyUnknown from './stringify_unknown';
|
|
3
|
+
/**
|
|
4
|
+
* Client-only: attaches `window.addEventListener('error'|'unhandledrejection', ...)`
|
|
5
|
+
* handlers that route through `config.errorHandling.onError`/`reportError` —
|
|
6
|
+
* catches uncaught exceptions and unhandled promise rejections that never go
|
|
7
|
+
* through `console.error` at all (unlike `installConsoleErrorOverride`),
|
|
8
|
+
* e.g. Next.js's own internal "Failed to fetch RSC payload" navigation
|
|
9
|
+
* fallback. Neither handler calls `event.preventDefault()` — the browser's
|
|
10
|
+
* own default handling (logging to the console) still happens, nothing is
|
|
11
|
+
* swallowed. Safe to call more than once (a no-op after the first call in
|
|
12
|
+
* this JS realm). Takes effect when `config.errorHandling.overrideWindowErrors`
|
|
13
|
+
* is `true`, or when it's omitted and `overrideConsoleError` is `true` (so
|
|
14
|
+
* enabling `overrideConsoleError` alone catches everything by default; pass
|
|
15
|
+
* `overrideWindowErrors: false` explicitly to opt out of just this part).
|
|
16
|
+
* No-op when `window` doesn't exist (server-side).
|
|
17
|
+
*
|
|
18
|
+
* @param config Pass the relevant slices of your `RoutingConfig` directly —
|
|
19
|
+
* `{ errorHandling: config.errorHandling, generate: config.generate }`.
|
|
20
|
+
*/
|
|
21
|
+
export default function installGlobalErrorOverride(config) {
|
|
22
|
+
const enabled = config?.errorHandling?.overrideWindowErrors ?? config?.errorHandling?.overrideConsoleError;
|
|
23
|
+
if (enabled !== true)
|
|
24
|
+
return;
|
|
25
|
+
if (typeof window === 'undefined')
|
|
26
|
+
return;
|
|
27
|
+
if (window.__isGlobalErrorOverrideInstalled)
|
|
28
|
+
return;
|
|
29
|
+
window.__isGlobalErrorOverrideInstalled = true;
|
|
30
|
+
window.addEventListener('error', (event) => {
|
|
31
|
+
void reportError(config, {
|
|
32
|
+
error: event.error ?? stringifyUnknown(event.message, true),
|
|
33
|
+
classOrMethodName: 'Global Window Error Handler',
|
|
34
|
+
isClient: true,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
38
|
+
void reportError(config, {
|
|
39
|
+
error: event.reason,
|
|
40
|
+
classOrMethodName: 'Global Unhandled Rejection Handler',
|
|
41
|
+
isClient: true,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -3,14 +3,23 @@ export interface ReportErrorConfig {
|
|
|
3
3
|
errorHandling?: ErrorHandlingRoutingConfig;
|
|
4
4
|
generate?: GenerateRoutingConfig;
|
|
5
5
|
}
|
|
6
|
+
export declare const consoleOverrideState: {
|
|
7
|
+
active: boolean;
|
|
8
|
+
};
|
|
6
9
|
/**
|
|
7
|
-
* Reports `params` via `
|
|
8
|
-
* `
|
|
10
|
+
* Reports `params`: logs `params.formattedMessage` via `console.error`
|
|
11
|
+
* (unless `config.errorHandling.logToConsole` is `false`, or
|
|
12
|
+
* `installConsoleErrorOverride` is active — in which case IT already did
|
|
13
|
+
* the console logging before calling this) AND calls
|
|
14
|
+
* `config.errorHandling.onError` when set — both run, not one instead of
|
|
15
|
+
* the other, so wiring `onError` (Sentry, Telegram, etc) never silently
|
|
16
|
+
* loses the console output. Skips reporting entirely when
|
|
9
17
|
* `config.errorHandling.enable === false`, `params.consent` is set and not
|
|
10
18
|
* `true` (reporting to a third party without cookie consent can itself be
|
|
11
19
|
* GDPR-relevant), or dedup throttles it (on by default — see
|
|
12
20
|
* `errorHandling.dedup`/`throttleMs`/`resetDedup`). Never throws — a broken
|
|
13
|
-
*
|
|
21
|
+
* `onError` must not mask the original error (falls back to logging via
|
|
22
|
+
* `console.error` instead, when the override isn't already handling that).
|
|
14
23
|
*
|
|
15
24
|
* Always overwrites `params.formattedMessage` with a fresh
|
|
16
25
|
* `formatErrorMessage(params)` before reporting — a human-readable one-line
|
|
@@ -18,15 +27,20 @@ export interface ReportErrorConfig {
|
|
|
18
27
|
* instead of the raw `error`/`params` object, for a default reporter (or a
|
|
19
28
|
* simple `onError`) to print directly.
|
|
20
29
|
*
|
|
21
|
-
* When `config.generate?.getCloudflareContext` is set
|
|
22
|
-
* SYNCHRONOUSLY, in the same tick, with
|
|
23
|
-
* Cloudflare Workers only extends the
|
|
24
|
-
* registered with `waitUntil` by the
|
|
25
|
-
* that call through an extra microtask
|
|
26
|
-
* risks the isolate tearing down the
|
|
27
|
-
* actually invoked, silently dropping
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
+
* When `config.generate?.getCloudflareContext` is set AND `params.isClient`
|
|
31
|
+
* is not `true`, `waitUntil` is called SYNCHRONOUSLY, in the same tick, with
|
|
32
|
+
* the `callOnError(...)` promise — Cloudflare Workers only extends the
|
|
33
|
+
* request's lifetime for work already registered with `waitUntil` by the
|
|
34
|
+
* time the handler returns; deferring that call through an extra microtask
|
|
35
|
+
* (e.g. `Promise.resolve().then(...)`) risks the isolate tearing down the
|
|
36
|
+
* request before `waitUntil` is ever actually invoked, silently dropping
|
|
37
|
+
* the report. `getCloudflareContext` is never called at all for a
|
|
38
|
+
* client-originated report (`params.isClient: true`) — it only exists
|
|
39
|
+
* server-side inside a Cloudflare Worker and throws synchronously (not a
|
|
40
|
+
* rejected promise) when called anywhere else, including the browser.
|
|
41
|
+
* Falls back to awaiting `onError` directly when `getCloudflareContext`/
|
|
42
|
+
* `ctx.waitUntil` is unset, unavailable (e.g. outside a Cloudflare Worker),
|
|
43
|
+
* or skipped for a client report.
|
|
30
44
|
*
|
|
31
45
|
* Passing `params.error` as `null`/`undefined` with `errorHandling.resetDedup: true`
|
|
32
46
|
* and nothing else is a valid "reset-only" call: the dedup state clears and
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import formatErrorMessage from './format_error_message';
|
|
2
2
|
import stringifyUnknown from './stringify_unknown';
|
|
3
3
|
const DEFAULT_THROTTLE_MS = 5000;
|
|
4
|
+
// Set by `installConsoleErrorOverride` once it patches `console.error`.
|
|
5
|
+
// When active, THAT override is the sole place that ever calls the real
|
|
6
|
+
// console for a report — it already logs the raw message itself, before
|
|
7
|
+
// calling `reportError` — so `callOnError`'s own console-logging step must
|
|
8
|
+
// stay OUT of the loop entirely rather than trying to detect and skip a
|
|
9
|
+
// recursive call after the fact. Attempting the latter (capturing "the
|
|
10
|
+
// original console.error" at module load, or tagging messages with a
|
|
11
|
+
// marker) is unreliable: Next.js's own dev-mode console interception
|
|
12
|
+
// forwards through whatever `console.error` is CURRENT at call time, not
|
|
13
|
+
// the function it originally wrapped, so any capture-then-call-through
|
|
14
|
+
// strategy can still loop back into a patched `console.error`. Removing
|
|
15
|
+
// the second caller removes the race entirely — not a per-module boolean
|
|
16
|
+
// (that would only cover one bundle chunk's module instance of this file;
|
|
17
|
+
// this constant is exported so `installConsoleErrorOverride` can mutate it
|
|
18
|
+
// via a live binding regardless of chunk).
|
|
19
|
+
export const consoleOverrideState = { active: false };
|
|
4
20
|
// Module-scope dedup state — safe by default only because a fresh JS realm
|
|
5
21
|
// (isolate/Worker instance) starts with it cleared. In a long-lived server
|
|
6
22
|
// process reused across many requests, pass `resetDedup: true` on the first
|
|
@@ -13,26 +29,39 @@ function buildDedupKey(params) {
|
|
|
13
29
|
}
|
|
14
30
|
async function callOnError(config, params) {
|
|
15
31
|
const paramsWithFormattedMessage = { ...params, formattedMessage: formatErrorMessage(params) };
|
|
16
|
-
|
|
17
|
-
|
|
32
|
+
// When `installConsoleErrorOverride` is active, it already logged the
|
|
33
|
+
// raw message to the real console BEFORE calling `reportError` — logging
|
|
34
|
+
// `formattedMessage` here too would be a second, redundant console
|
|
35
|
+
// write (differently formatted) for the exact same call, not a fix for
|
|
36
|
+
// a missing one.
|
|
37
|
+
if (config?.logToConsole !== false && !consoleOverrideState.active) {
|
|
38
|
+
console.error(paramsWithFormattedMessage.formattedMessage);
|
|
39
|
+
}
|
|
40
|
+
if (config?.onError) {
|
|
41
|
+
try {
|
|
18
42
|
await config.onError(paramsWithFormattedMessage);
|
|
19
43
|
}
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
catch {
|
|
45
|
+
if (!consoleOverrideState.active) {
|
|
46
|
+
console.error(paramsWithFormattedMessage.formattedMessage);
|
|
47
|
+
}
|
|
22
48
|
}
|
|
23
49
|
}
|
|
24
|
-
catch {
|
|
25
|
-
console.error(paramsWithFormattedMessage.formattedMessage);
|
|
26
|
-
}
|
|
27
50
|
}
|
|
28
51
|
/**
|
|
29
|
-
* Reports `params` via `
|
|
30
|
-
* `
|
|
52
|
+
* Reports `params`: logs `params.formattedMessage` via `console.error`
|
|
53
|
+
* (unless `config.errorHandling.logToConsole` is `false`, or
|
|
54
|
+
* `installConsoleErrorOverride` is active — in which case IT already did
|
|
55
|
+
* the console logging before calling this) AND calls
|
|
56
|
+
* `config.errorHandling.onError` when set — both run, not one instead of
|
|
57
|
+
* the other, so wiring `onError` (Sentry, Telegram, etc) never silently
|
|
58
|
+
* loses the console output. Skips reporting entirely when
|
|
31
59
|
* `config.errorHandling.enable === false`, `params.consent` is set and not
|
|
32
60
|
* `true` (reporting to a third party without cookie consent can itself be
|
|
33
61
|
* GDPR-relevant), or dedup throttles it (on by default — see
|
|
34
62
|
* `errorHandling.dedup`/`throttleMs`/`resetDedup`). Never throws — a broken
|
|
35
|
-
*
|
|
63
|
+
* `onError` must not mask the original error (falls back to logging via
|
|
64
|
+
* `console.error` instead, when the override isn't already handling that).
|
|
36
65
|
*
|
|
37
66
|
* Always overwrites `params.formattedMessage` with a fresh
|
|
38
67
|
* `formatErrorMessage(params)` before reporting — a human-readable one-line
|
|
@@ -40,15 +69,20 @@ async function callOnError(config, params) {
|
|
|
40
69
|
* instead of the raw `error`/`params` object, for a default reporter (or a
|
|
41
70
|
* simple `onError`) to print directly.
|
|
42
71
|
*
|
|
43
|
-
* When `config.generate?.getCloudflareContext` is set
|
|
44
|
-
* SYNCHRONOUSLY, in the same tick, with
|
|
45
|
-
* Cloudflare Workers only extends the
|
|
46
|
-
* registered with `waitUntil` by the
|
|
47
|
-
* that call through an extra microtask
|
|
48
|
-
* risks the isolate tearing down the
|
|
49
|
-
* actually invoked, silently dropping
|
|
50
|
-
*
|
|
51
|
-
*
|
|
72
|
+
* When `config.generate?.getCloudflareContext` is set AND `params.isClient`
|
|
73
|
+
* is not `true`, `waitUntil` is called SYNCHRONOUSLY, in the same tick, with
|
|
74
|
+
* the `callOnError(...)` promise — Cloudflare Workers only extends the
|
|
75
|
+
* request's lifetime for work already registered with `waitUntil` by the
|
|
76
|
+
* time the handler returns; deferring that call through an extra microtask
|
|
77
|
+
* (e.g. `Promise.resolve().then(...)`) risks the isolate tearing down the
|
|
78
|
+
* request before `waitUntil` is ever actually invoked, silently dropping
|
|
79
|
+
* the report. `getCloudflareContext` is never called at all for a
|
|
80
|
+
* client-originated report (`params.isClient: true`) — it only exists
|
|
81
|
+
* server-side inside a Cloudflare Worker and throws synchronously (not a
|
|
82
|
+
* rejected promise) when called anywhere else, including the browser.
|
|
83
|
+
* Falls back to awaiting `onError` directly when `getCloudflareContext`/
|
|
84
|
+
* `ctx.waitUntil` is unset, unavailable (e.g. outside a Cloudflare Worker),
|
|
85
|
+
* or skipped for a client report.
|
|
52
86
|
*
|
|
53
87
|
* Passing `params.error` as `null`/`undefined` with `errorHandling.resetDedup: true`
|
|
54
88
|
* and nothing else is a valid "reset-only" call: the dedup state clears and
|
|
@@ -80,9 +114,13 @@ export default async function reportError(config, params) {
|
|
|
80
114
|
lastDedupKey = dedupKey;
|
|
81
115
|
lastReportedAt = now;
|
|
82
116
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
117
|
+
// `getCloudflareContext` only exists server-side inside a Cloudflare
|
|
118
|
+
// Worker (with `initOpenNextCloudflareForDev` set up in dev) — calling
|
|
119
|
+
// it at all for a client-originated report throws synchronously, before
|
|
120
|
+
// any "is it available" check can run.
|
|
121
|
+
const ctx = params.isClient ? undefined : config?.generate?.getCloudflareContext?.({ async: false })?.ctx;
|
|
122
|
+
if (ctx?.waitUntil) {
|
|
123
|
+
ctx.waitUntil(callOnError(errorHandling, params));
|
|
86
124
|
return;
|
|
87
125
|
}
|
|
88
126
|
await callOnError(errorHandling, params);
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
const MAX_FUNCTION_RESOLUTION_ATTEMPTS = 5;
|
|
2
|
+
// eslint-disable-next-line no-control-regex
|
|
3
|
+
const ANSI_ESCAPE_CODE_PATTERN = /\x1b\[[0-9;]*m/g;
|
|
4
|
+
/** Strips ANSI color/style escape codes (e.g. from Next.js's own pretty-printed terminal errors) — unreadable once JSON-escaped into a report. */
|
|
5
|
+
function stripAnsiCodes(value) {
|
|
6
|
+
return value.replace(ANSI_ESCAPE_CODE_PATTERN, '');
|
|
7
|
+
}
|
|
2
8
|
function resolveFunctionError(value) {
|
|
3
9
|
let result = value;
|
|
4
10
|
try {
|
|
@@ -24,9 +30,9 @@ function resolveFunctionError(value) {
|
|
|
24
30
|
*/
|
|
25
31
|
export default function stringifyUnknown(value, isClient, isNested = false) {
|
|
26
32
|
if (typeof value === 'string')
|
|
27
|
-
return value;
|
|
33
|
+
return stripAnsiCodes(value);
|
|
28
34
|
if (value instanceof Error)
|
|
29
|
-
return `${value.name}: ${value.message}\n\n${value.stack ?? ''}
|
|
35
|
+
return stripAnsiCodes(`${value.name}: ${value.message}\n\n${value.stack ?? ''}`);
|
|
30
36
|
if (typeof value === 'function') {
|
|
31
37
|
if (isClient)
|
|
32
38
|
return '[Function]';
|
|
@@ -34,7 +40,7 @@ export default function stringifyUnknown(value, isClient, isNested = false) {
|
|
|
34
40
|
return typeof resolved !== 'function' ? stringifyUnknown(resolved, isClient) : '[Function]';
|
|
35
41
|
}
|
|
36
42
|
try {
|
|
37
|
-
return isNested ? JSON.stringify(value) : JSON.stringify(value, null, 2);
|
|
43
|
+
return stripAnsiCodes(isNested ? JSON.stringify(value) : JSON.stringify(value, null, 2));
|
|
38
44
|
}
|
|
39
45
|
catch {
|
|
40
46
|
return '[Unserializable value]';
|
|
@@ -183,7 +183,7 @@ export default function AuthUserProvider({ initialUser = null, children }) {
|
|
|
183
183
|
}
|
|
184
184
|
finally {
|
|
185
185
|
await clearSession(sessionCookieName, refreshTokenCookieName);
|
|
186
|
-
|
|
186
|
+
router.push(fa.redirectAuthPath);
|
|
187
187
|
}
|
|
188
188
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
189
189
|
}, [fa.redirectAuthPath, sessionCookieName, refreshTokenCookieName]);
|
|
@@ -167,11 +167,22 @@ export interface ErrorHandlingRoutingConfig {
|
|
|
167
167
|
*/
|
|
168
168
|
enable?: boolean;
|
|
169
169
|
/**
|
|
170
|
-
* Called with the caught error whenever one is reported
|
|
171
|
-
* `console.error
|
|
172
|
-
*
|
|
170
|
+
* Called with the caught error whenever one is reported, in ADDITION to
|
|
171
|
+
* the always-on `console.error(params.formattedMessage)` (see
|
|
172
|
+
* `logToConsole` to disable that). Use this to wire your own
|
|
173
|
+
* error-tracking/logging transport (Sentry, Telegram, etc) alongside the
|
|
174
|
+
* console log, not instead of it. Omit to just log to the console.
|
|
173
175
|
*/
|
|
174
176
|
onError?: (params: ErrorHandlingParams) => void | Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Whether `reportError` also logs `params.formattedMessage` via the
|
|
179
|
+
* real, unpatched `console.error` (captured at module load, before
|
|
180
|
+
* `installConsoleErrorOverride` can touch it — so this never loops back
|
|
181
|
+
* into `reportError` even when the override is installed). Defaults to
|
|
182
|
+
* `true`. Set `false` if `onError` is your only sink and you don't want
|
|
183
|
+
* console output at all.
|
|
184
|
+
*/
|
|
185
|
+
logToConsole?: boolean;
|
|
175
186
|
/**
|
|
176
187
|
* Whether `reportError`/`withErrorHandling` replace the global
|
|
177
188
|
* `console.error` so every `console.error(...)` call in your app is
|
|
@@ -183,6 +194,18 @@ export interface ErrorHandlingRoutingConfig {
|
|
|
183
194
|
* bigger behavior change than a plain function call.
|
|
184
195
|
*/
|
|
185
196
|
overrideConsoleError?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* On the CLIENT only (`installConsoleErrorOverride(config, true)`),
|
|
199
|
+
* suppresses the browser's own `console.error(...)` output for a call
|
|
200
|
+
* once it's been routed to `onError`/`reportError` — the error is still
|
|
201
|
+
* reported (server-side logging, Sentry, etc), it just never shows up
|
|
202
|
+
* in browser devtools. Has no effect server-side (the server override
|
|
203
|
+
* always keeps logging normally — there's no "hide it from the
|
|
204
|
+
* terminal" use case). Only consulted when `overrideConsoleError` is
|
|
205
|
+
* `true`. Defaults to `false` (nothing is swallowed anywhere, matching
|
|
206
|
+
* `overrideConsoleError`'s own doc).
|
|
207
|
+
*/
|
|
208
|
+
suppressClientConsoleError?: boolean;
|
|
186
209
|
/**
|
|
187
210
|
* Substrings matched against the stringified message of each
|
|
188
211
|
* `console.error(...)` call (only consulted when `overrideConsoleError`
|
|
@@ -201,6 +224,20 @@ export interface ErrorHandlingRoutingConfig {
|
|
|
201
224
|
* substring match.
|
|
202
225
|
*/
|
|
203
226
|
ignoreConsoleError?: (message: string) => boolean;
|
|
227
|
+
/**
|
|
228
|
+
* Whether the client `LocationzationClientProvider` also installs
|
|
229
|
+
* `window.addEventListener('error'|'unhandledrejection', ...)` handlers
|
|
230
|
+
* that route through `onError`/`reportError` the same way
|
|
231
|
+
* `overrideConsoleError` does for `console.error(...)` calls. Catches
|
|
232
|
+
* uncaught exceptions and unhandled promise rejections that never go
|
|
233
|
+
* through `console.error` at all — e.g. Next.js's own internal
|
|
234
|
+
* "Failed to fetch RSC payload" navigation-fallback error. Defaults to
|
|
235
|
+
* `overrideConsoleError`'s value (so setting just `overrideConsoleError:
|
|
236
|
+
* true` catches everything by default) — pass `false` explicitly to
|
|
237
|
+
* enable console overriding without the window listeners. No-op on the
|
|
238
|
+
* server (no `window` there).
|
|
239
|
+
*/
|
|
240
|
+
overrideWindowErrors?: boolean;
|
|
204
241
|
/**
|
|
205
242
|
* Dedup: `reportError` skips reporting an error whose key (`dedupKey`,
|
|
206
243
|
* or a built-in key derived from `classOrMethodName`/`error`/`params`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudflare-next-intl",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.7",
|
|
4
4
|
"description": "Optimized Next Intl Package Special for App Router and Cloudflare",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -148,6 +148,10 @@
|
|
|
148
148
|
"types": "./dist/src/error_handling/install_console_error_override.d.ts",
|
|
149
149
|
"import": "./dist/src/error_handling/install_console_error_override.js"
|
|
150
150
|
},
|
|
151
|
+
"./installGlobalErrorOverride": {
|
|
152
|
+
"types": "./dist/src/error_handling/install_global_error_override.d.ts",
|
|
153
|
+
"import": "./dist/src/error_handling/install_global_error_override.js"
|
|
154
|
+
},
|
|
151
155
|
"./stringifyUnknown": {
|
|
152
156
|
"types": "./dist/src/error_handling/stringify_unknown.d.ts",
|
|
153
157
|
"import": "./dist/src/error_handling/stringify_unknown.js"
|