@drakkar.software/sunglasses-react 0.11.0 → 0.12.0

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/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ISunglassesClient, ScreenTrackingOptions, AutoCaptureErrorsOptions, ConsentStatus, CaptureExceptionOptions } from '@drakkar.software/sunglasses-core';
3
- export { AutoCaptureErrorsOptions, CaptureExceptionOptions, ConsentStatus, ConsoleCaptureOptions, ISunglassesClient, ScreenTrackingOptions, SunglassesConfig, SunglassesCore, SunglassesEvent, captureException, patchConsole } from '@drakkar.software/sunglasses-core';
3
+ export { AutoCaptureErrorsOptions, CaptureExceptionOptions, ConsentStatus, ConsoleCaptureOptions, GlobalErrorInfo, GlobalErrorListener, ISunglassesClient, ScreenTrackingOptions, SunglassesConfig, SunglassesCore, SunglassesEvent, captureException, patchConsole, publishGlobalError, subscribeGlobalError } from '@drakkar.software/sunglasses-core';
4
4
 
5
5
  interface SunglassesProviderProps {
6
6
  /** An initialized ISunglassesClient (from SunglassesCore.create()). */
@@ -13,9 +13,10 @@ interface SunglassesProviderProps {
13
13
  *
14
14
  * - `true` installs the global handlers for `window` `'error'` and
15
15
  * `'unhandledrejection'`.
16
- * - An options object additionally lets you toggle `globalHandlers` and opt
17
- * into `console` capture (`console.error` / `console.warn`), plus configure
18
- * truncation / stack inclusion / ignore patterns.
16
+ * - An options object additionally lets you toggle `globalHandlers` and
17
+ * `unhandledRejections`, opt into `console` capture (`console.error` /
18
+ * `console.warn`), plus configure truncation / stack inclusion / ignore
19
+ * patterns.
19
20
  *
20
21
  * Default: off.
21
22
  */
@@ -162,4 +163,49 @@ interface SunglassesErrorBoundaryProps {
162
163
  */
163
164
  declare function SunglassesErrorBoundary(props: SunglassesErrorBoundaryProps): React.ReactElement;
164
165
 
165
- export { SunglassesErrorBoundary, type SunglassesErrorBoundaryProps, SunglassesProvider, type SunglassesProviderProps, captureUtmParams, useCapture, useConsentStatus, useScreenTracking, useSunglasses };
166
+ interface SunglassesGlobalErrorBoundaryProps {
167
+ /**
168
+ * SunGlasses client. Optional — defaults to the client provided by the
169
+ * nearest `<SunglassesProvider>`.
170
+ */
171
+ client?: ISunglassesClient;
172
+ /** Rendered when an error is caught. Defaults to rendering nothing. */
173
+ fallback?: React.ReactNode;
174
+ /** Error capture configuration forwarded to `captureException`. */
175
+ config?: CaptureExceptionOptions;
176
+ /**
177
+ * Also render the fallback for non-fatal global errors (e.g. `ErrorUtils`
178
+ * errors reported as non-fatal). Default: `false`.
179
+ */
180
+ includeNonFatalGlobalErrors?: boolean;
181
+ /**
182
+ * Also render the fallback for unhandled promise rejections. Off by default
183
+ * because many apps prefer to surface rejections as toasts or inline errors
184
+ * rather than as a full-screen fallback. Default: `false`.
185
+ */
186
+ includeUnhandledRejections?: boolean;
187
+ children: React.ReactNode;
188
+ }
189
+ /**
190
+ * A superset of `SunglassesErrorBoundary` that renders a fallback UI for fatal
191
+ * non-render errors (uncaught errors and, optionally, unhandled rejections) in
192
+ * addition to the render-phase errors a normal error boundary catches.
193
+ *
194
+ * Render-phase errors are captured here as `$error` events
195
+ * (`$error_handled: true`). Global errors are captured by the provider's
196
+ * `autoCaptureErrors` handlers and merely surfaced here as a fallback — so the
197
+ * global fallback requires `autoCaptureErrors` to be enabled on the
198
+ * `<SunglassesProvider>`. No event is captured twice.
199
+ *
200
+ * @example
201
+ * ```tsx
202
+ * <SunglassesProvider client={client} autoCaptureErrors>
203
+ * <SunglassesGlobalErrorBoundary fallback={<ErrorScreen />}>
204
+ * <App />
205
+ * </SunglassesGlobalErrorBoundary>
206
+ * </SunglassesProvider>
207
+ * ```
208
+ */
209
+ declare function SunglassesGlobalErrorBoundary(props: SunglassesGlobalErrorBoundaryProps): React.ReactElement;
210
+
211
+ export { SunglassesErrorBoundary, type SunglassesErrorBoundaryProps, SunglassesGlobalErrorBoundary, type SunglassesGlobalErrorBoundaryProps, SunglassesProvider, type SunglassesProviderProps, captureUtmParams, useCapture, useConsentStatus, useScreenTracking, useSunglasses };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ISunglassesClient, ScreenTrackingOptions, AutoCaptureErrorsOptions, ConsentStatus, CaptureExceptionOptions } from '@drakkar.software/sunglasses-core';
3
- export { AutoCaptureErrorsOptions, CaptureExceptionOptions, ConsentStatus, ConsoleCaptureOptions, ISunglassesClient, ScreenTrackingOptions, SunglassesConfig, SunglassesCore, SunglassesEvent, captureException, patchConsole } from '@drakkar.software/sunglasses-core';
3
+ export { AutoCaptureErrorsOptions, CaptureExceptionOptions, ConsentStatus, ConsoleCaptureOptions, GlobalErrorInfo, GlobalErrorListener, ISunglassesClient, ScreenTrackingOptions, SunglassesConfig, SunglassesCore, SunglassesEvent, captureException, patchConsole, publishGlobalError, subscribeGlobalError } from '@drakkar.software/sunglasses-core';
4
4
 
5
5
  interface SunglassesProviderProps {
6
6
  /** An initialized ISunglassesClient (from SunglassesCore.create()). */
@@ -13,9 +13,10 @@ interface SunglassesProviderProps {
13
13
  *
14
14
  * - `true` installs the global handlers for `window` `'error'` and
15
15
  * `'unhandledrejection'`.
16
- * - An options object additionally lets you toggle `globalHandlers` and opt
17
- * into `console` capture (`console.error` / `console.warn`), plus configure
18
- * truncation / stack inclusion / ignore patterns.
16
+ * - An options object additionally lets you toggle `globalHandlers` and
17
+ * `unhandledRejections`, opt into `console` capture (`console.error` /
18
+ * `console.warn`), plus configure truncation / stack inclusion / ignore
19
+ * patterns.
19
20
  *
20
21
  * Default: off.
21
22
  */
@@ -162,4 +163,49 @@ interface SunglassesErrorBoundaryProps {
162
163
  */
163
164
  declare function SunglassesErrorBoundary(props: SunglassesErrorBoundaryProps): React.ReactElement;
164
165
 
165
- export { SunglassesErrorBoundary, type SunglassesErrorBoundaryProps, SunglassesProvider, type SunglassesProviderProps, captureUtmParams, useCapture, useConsentStatus, useScreenTracking, useSunglasses };
166
+ interface SunglassesGlobalErrorBoundaryProps {
167
+ /**
168
+ * SunGlasses client. Optional — defaults to the client provided by the
169
+ * nearest `<SunglassesProvider>`.
170
+ */
171
+ client?: ISunglassesClient;
172
+ /** Rendered when an error is caught. Defaults to rendering nothing. */
173
+ fallback?: React.ReactNode;
174
+ /** Error capture configuration forwarded to `captureException`. */
175
+ config?: CaptureExceptionOptions;
176
+ /**
177
+ * Also render the fallback for non-fatal global errors (e.g. `ErrorUtils`
178
+ * errors reported as non-fatal). Default: `false`.
179
+ */
180
+ includeNonFatalGlobalErrors?: boolean;
181
+ /**
182
+ * Also render the fallback for unhandled promise rejections. Off by default
183
+ * because many apps prefer to surface rejections as toasts or inline errors
184
+ * rather than as a full-screen fallback. Default: `false`.
185
+ */
186
+ includeUnhandledRejections?: boolean;
187
+ children: React.ReactNode;
188
+ }
189
+ /**
190
+ * A superset of `SunglassesErrorBoundary` that renders a fallback UI for fatal
191
+ * non-render errors (uncaught errors and, optionally, unhandled rejections) in
192
+ * addition to the render-phase errors a normal error boundary catches.
193
+ *
194
+ * Render-phase errors are captured here as `$error` events
195
+ * (`$error_handled: true`). Global errors are captured by the provider's
196
+ * `autoCaptureErrors` handlers and merely surfaced here as a fallback — so the
197
+ * global fallback requires `autoCaptureErrors` to be enabled on the
198
+ * `<SunglassesProvider>`. No event is captured twice.
199
+ *
200
+ * @example
201
+ * ```tsx
202
+ * <SunglassesProvider client={client} autoCaptureErrors>
203
+ * <SunglassesGlobalErrorBoundary fallback={<ErrorScreen />}>
204
+ * <App />
205
+ * </SunglassesGlobalErrorBoundary>
206
+ * </SunglassesProvider>
207
+ * ```
208
+ */
209
+ declare function SunglassesGlobalErrorBoundary(props: SunglassesGlobalErrorBoundaryProps): React.ReactElement;
210
+
211
+ export { SunglassesErrorBoundary, type SunglassesErrorBoundaryProps, SunglassesGlobalErrorBoundary, type SunglassesGlobalErrorBoundaryProps, SunglassesProvider, type SunglassesProviderProps, captureUtmParams, useCapture, useConsentStatus, useScreenTracking, useSunglasses };
package/dist/index.js CHANGED
@@ -30,12 +30,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- SunglassesCore: () => import_sunglasses_core3.SunglassesCore,
33
+ SunglassesCore: () => import_sunglasses_core4.SunglassesCore,
34
34
  SunglassesErrorBoundary: () => SunglassesErrorBoundary,
35
+ SunglassesGlobalErrorBoundary: () => SunglassesGlobalErrorBoundary,
35
36
  SunglassesProvider: () => SunglassesProvider,
36
- captureException: () => import_sunglasses_core3.captureException,
37
+ captureException: () => import_sunglasses_core4.captureException,
37
38
  captureUtmParams: () => captureUtmParams,
38
- patchConsole: () => import_sunglasses_core3.patchConsole,
39
+ patchConsole: () => import_sunglasses_core4.patchConsole,
40
+ publishGlobalError: () => import_sunglasses_core4.publishGlobalError,
41
+ subscribeGlobalError: () => import_sunglasses_core4.subscribeGlobalError,
39
42
  useCapture: () => useCapture,
40
43
  useConsentStatus: () => useConsentStatus,
41
44
  useScreenTracking: () => useScreenTracking,
@@ -135,19 +138,24 @@ function SunglassesProvider({
135
138
  if (!autoCaptureErrors) return;
136
139
  const options = typeof autoCaptureErrors === "object" ? autoCaptureErrors : {};
137
140
  const cleanups = [];
138
- if (options.globalHandlers !== false && typeof window !== "undefined") {
139
- const onError = (event) => {
140
- (0, import_sunglasses_core.captureException)(client, event.error ?? event.message, { handled: false, ...options });
141
- };
142
- const onRejection = (event) => {
143
- (0, import_sunglasses_core.captureException)(client, event.reason, { handled: false, ...options });
144
- };
145
- window.addEventListener("error", onError);
146
- window.addEventListener("unhandledrejection", onRejection);
147
- cleanups.push(() => {
148
- window.removeEventListener("error", onError);
149
- window.removeEventListener("unhandledrejection", onRejection);
150
- });
141
+ if (typeof window !== "undefined") {
142
+ if (options.globalHandlers !== false) {
143
+ const onError = (event) => {
144
+ const error = event.error ?? event.message;
145
+ (0, import_sunglasses_core.captureException)(client, error, { handled: false, ...options });
146
+ (0, import_sunglasses_core.publishGlobalError)({ error, fatal: true, kind: "error" });
147
+ };
148
+ window.addEventListener("error", onError);
149
+ cleanups.push(() => window.removeEventListener("error", onError));
150
+ }
151
+ if (options.unhandledRejections !== false) {
152
+ const onRejection = (event) => {
153
+ (0, import_sunglasses_core.captureException)(client, event.reason, { handled: false, ...options });
154
+ (0, import_sunglasses_core.publishGlobalError)({ error: event.reason, fatal: false, kind: "rejection" });
155
+ };
156
+ window.addEventListener("unhandledrejection", onRejection);
157
+ cleanups.push(() => window.removeEventListener("unhandledrejection", onRejection));
158
+ }
151
159
  }
152
160
  if (options.console) {
153
161
  const consoleOptions = typeof options.console === "object" ? options.console : {};
@@ -250,16 +258,68 @@ function SunglassesErrorBoundary(props) {
250
258
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ErrorBoundaryInner, { ...props, client });
251
259
  }
252
260
 
253
- // src/index.ts
261
+ // src/SunglassesGlobalErrorBoundary.tsx
262
+ var import_react6 = __toESM(require("react"));
254
263
  var import_sunglasses_core3 = require("@drakkar.software/sunglasses-core");
264
+ var import_jsx_runtime3 = require("react/jsx-runtime");
265
+ var GlobalErrorBoundaryInner = class extends import_react6.default.Component {
266
+ constructor() {
267
+ super(...arguments);
268
+ this.state = { hasError: false };
269
+ }
270
+ static getDerivedStateFromError() {
271
+ return { hasError: true };
272
+ }
273
+ componentDidMount() {
274
+ this.unsubscribe = (0, import_sunglasses_core3.subscribeGlobalError)((info) => this.handleGlobalError(info));
275
+ }
276
+ componentWillUnmount() {
277
+ this.unsubscribe?.();
278
+ }
279
+ componentDidCatch(error) {
280
+ const { client, config } = this.props;
281
+ (0, import_sunglasses_core3.captureException)(client, error, { handled: true, ...config });
282
+ }
283
+ /**
284
+ * React to a global error published by the provider's auto-capture handlers.
285
+ * The provider already captured it, so we only decide whether to show the
286
+ * fallback — we never re-capture here.
287
+ */
288
+ handleGlobalError(info) {
289
+ if (this.state.hasError) return;
290
+ const { includeNonFatalGlobalErrors, includeUnhandledRejections } = this.props;
291
+ const shouldShow = info.kind === "rejection" ? includeUnhandledRejections === true : info.fatal || includeNonFatalGlobalErrors === true;
292
+ if (shouldShow) this.setState({ hasError: true });
293
+ }
294
+ render() {
295
+ if (this.state.hasError) return this.props.fallback ?? null;
296
+ return this.props.children;
297
+ }
298
+ };
299
+ function SunglassesGlobalErrorBoundary(props) {
300
+ const contextClient = (0, import_react6.useContext)(SunglassesContext);
301
+ const client = props.client ?? contextClient;
302
+ if (client === null) {
303
+ throw new Error(
304
+ "[SunGlasses] <SunglassesGlobalErrorBoundary> must be inside a <SunglassesProvider> or receive a `client` prop."
305
+ );
306
+ }
307
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GlobalErrorBoundaryInner, { ...props, client });
308
+ }
309
+
310
+ // src/index.ts
311
+ var import_sunglasses_core4 = require("@drakkar.software/sunglasses-core");
255
312
  // Annotate the CommonJS export names for ESM import in node:
256
313
  0 && (module.exports = {
257
314
  SunglassesCore,
258
315
  SunglassesErrorBoundary,
316
+ SunglassesGlobalErrorBoundary,
259
317
  SunglassesProvider,
260
318
  captureException,
261
319
  captureUtmParams,
262
320
  patchConsole,
321
+ publishGlobalError,
322
+ subscribeGlobalError,
263
323
  useCapture,
264
324
  useConsentStatus,
265
325
  useScreenTracking,
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/SunglassesProvider.tsx
2
2
  import { useEffect as useEffect2 } from "react";
3
- import { captureException, patchConsole } from "@drakkar.software/sunglasses-core";
3
+ import { captureException, patchConsole, publishGlobalError } from "@drakkar.software/sunglasses-core";
4
4
 
5
5
  // src/context.ts
6
6
  import { createContext, useContext } from "react";
@@ -90,19 +90,24 @@ function SunglassesProvider({
90
90
  if (!autoCaptureErrors) return;
91
91
  const options = typeof autoCaptureErrors === "object" ? autoCaptureErrors : {};
92
92
  const cleanups = [];
93
- if (options.globalHandlers !== false && typeof window !== "undefined") {
94
- const onError = (event) => {
95
- captureException(client, event.error ?? event.message, { handled: false, ...options });
96
- };
97
- const onRejection = (event) => {
98
- captureException(client, event.reason, { handled: false, ...options });
99
- };
100
- window.addEventListener("error", onError);
101
- window.addEventListener("unhandledrejection", onRejection);
102
- cleanups.push(() => {
103
- window.removeEventListener("error", onError);
104
- window.removeEventListener("unhandledrejection", onRejection);
105
- });
93
+ if (typeof window !== "undefined") {
94
+ if (options.globalHandlers !== false) {
95
+ const onError = (event) => {
96
+ const error = event.error ?? event.message;
97
+ captureException(client, error, { handled: false, ...options });
98
+ publishGlobalError({ error, fatal: true, kind: "error" });
99
+ };
100
+ window.addEventListener("error", onError);
101
+ cleanups.push(() => window.removeEventListener("error", onError));
102
+ }
103
+ if (options.unhandledRejections !== false) {
104
+ const onRejection = (event) => {
105
+ captureException(client, event.reason, { handled: false, ...options });
106
+ publishGlobalError({ error: event.reason, fatal: false, kind: "rejection" });
107
+ };
108
+ window.addEventListener("unhandledrejection", onRejection);
109
+ cleanups.push(() => window.removeEventListener("unhandledrejection", onRejection));
110
+ }
106
111
  }
107
112
  if (options.console) {
108
113
  const consoleOptions = typeof options.console === "object" ? options.console : {};
@@ -205,15 +210,73 @@ function SunglassesErrorBoundary(props) {
205
210
  return /* @__PURE__ */ jsx2(ErrorBoundaryInner, { ...props, client });
206
211
  }
207
212
 
213
+ // src/SunglassesGlobalErrorBoundary.tsx
214
+ import React3, { useContext as useContext3 } from "react";
215
+ import { captureException as captureException3, subscribeGlobalError } from "@drakkar.software/sunglasses-core";
216
+ import { jsx as jsx3 } from "react/jsx-runtime";
217
+ var GlobalErrorBoundaryInner = class extends React3.Component {
218
+ constructor() {
219
+ super(...arguments);
220
+ this.state = { hasError: false };
221
+ }
222
+ static getDerivedStateFromError() {
223
+ return { hasError: true };
224
+ }
225
+ componentDidMount() {
226
+ this.unsubscribe = subscribeGlobalError((info) => this.handleGlobalError(info));
227
+ }
228
+ componentWillUnmount() {
229
+ this.unsubscribe?.();
230
+ }
231
+ componentDidCatch(error) {
232
+ const { client, config } = this.props;
233
+ captureException3(client, error, { handled: true, ...config });
234
+ }
235
+ /**
236
+ * React to a global error published by the provider's auto-capture handlers.
237
+ * The provider already captured it, so we only decide whether to show the
238
+ * fallback — we never re-capture here.
239
+ */
240
+ handleGlobalError(info) {
241
+ if (this.state.hasError) return;
242
+ const { includeNonFatalGlobalErrors, includeUnhandledRejections } = this.props;
243
+ const shouldShow = info.kind === "rejection" ? includeUnhandledRejections === true : info.fatal || includeNonFatalGlobalErrors === true;
244
+ if (shouldShow) this.setState({ hasError: true });
245
+ }
246
+ render() {
247
+ if (this.state.hasError) return this.props.fallback ?? null;
248
+ return this.props.children;
249
+ }
250
+ };
251
+ function SunglassesGlobalErrorBoundary(props) {
252
+ const contextClient = useContext3(SunglassesContext);
253
+ const client = props.client ?? contextClient;
254
+ if (client === null) {
255
+ throw new Error(
256
+ "[SunGlasses] <SunglassesGlobalErrorBoundary> must be inside a <SunglassesProvider> or receive a `client` prop."
257
+ );
258
+ }
259
+ return /* @__PURE__ */ jsx3(GlobalErrorBoundaryInner, { ...props, client });
260
+ }
261
+
208
262
  // src/index.ts
209
- import { SunglassesCore, captureException as captureException3, patchConsole as patchConsole2 } from "@drakkar.software/sunglasses-core";
263
+ import {
264
+ SunglassesCore,
265
+ captureException as captureException4,
266
+ patchConsole as patchConsole2,
267
+ publishGlobalError as publishGlobalError2,
268
+ subscribeGlobalError as subscribeGlobalError2
269
+ } from "@drakkar.software/sunglasses-core";
210
270
  export {
211
271
  SunglassesCore,
212
272
  SunglassesErrorBoundary,
273
+ SunglassesGlobalErrorBoundary,
213
274
  SunglassesProvider,
214
- captureException3 as captureException,
275
+ captureException4 as captureException,
215
276
  captureUtmParams,
216
277
  patchConsole2 as patchConsole,
278
+ publishGlobalError2 as publishGlobalError,
279
+ subscribeGlobalError2 as subscribeGlobalError,
217
280
  useCapture,
218
281
  useConsentStatus,
219
282
  useScreenTracking,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakkar.software/sunglasses-react",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "React (web) provider and hooks for SunGlasses event tracking",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -16,7 +16,7 @@
16
16
  "dist"
17
17
  ],
18
18
  "dependencies": {
19
- "@drakkar.software/sunglasses-core": "0.11.0"
19
+ "@drakkar.software/sunglasses-core": "0.12.0"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "react": ">=18.0.0"