@drakkar.software/sunglasses-react 0.11.0 → 0.12.1

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,69 @@ 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
+ if (typeof import_sunglasses_core3.subscribeGlobalError !== "function") return;
275
+ this.unsubscribe = (0, import_sunglasses_core3.subscribeGlobalError)((info) => this.handleGlobalError(info));
276
+ }
277
+ componentWillUnmount() {
278
+ this.unsubscribe?.();
279
+ }
280
+ componentDidCatch(error) {
281
+ const { client, config } = this.props;
282
+ (0, import_sunglasses_core3.captureException)(client, error, { handled: true, ...config });
283
+ }
284
+ /**
285
+ * React to a global error published by the provider's auto-capture handlers.
286
+ * The provider already captured it, so we only decide whether to show the
287
+ * fallback — we never re-capture here.
288
+ */
289
+ handleGlobalError(info) {
290
+ if (this.state.hasError) return;
291
+ const { includeNonFatalGlobalErrors, includeUnhandledRejections } = this.props;
292
+ const shouldShow = info.kind === "rejection" ? includeUnhandledRejections === true : info.fatal || includeNonFatalGlobalErrors === true;
293
+ if (shouldShow) this.setState({ hasError: true });
294
+ }
295
+ render() {
296
+ if (this.state.hasError) return this.props.fallback ?? null;
297
+ return this.props.children;
298
+ }
299
+ };
300
+ function SunglassesGlobalErrorBoundary(props) {
301
+ const contextClient = (0, import_react6.useContext)(SunglassesContext);
302
+ const client = props.client ?? contextClient;
303
+ if (client === null) {
304
+ throw new Error(
305
+ "[SunGlasses] <SunglassesGlobalErrorBoundary> must be inside a <SunglassesProvider> or receive a `client` prop."
306
+ );
307
+ }
308
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GlobalErrorBoundaryInner, { ...props, client });
309
+ }
310
+
311
+ // src/index.ts
312
+ var import_sunglasses_core4 = require("@drakkar.software/sunglasses-core");
255
313
  // Annotate the CommonJS export names for ESM import in node:
256
314
  0 && (module.exports = {
257
315
  SunglassesCore,
258
316
  SunglassesErrorBoundary,
317
+ SunglassesGlobalErrorBoundary,
259
318
  SunglassesProvider,
260
319
  captureException,
261
320
  captureUtmParams,
262
321
  patchConsole,
322
+ publishGlobalError,
323
+ subscribeGlobalError,
263
324
  useCapture,
264
325
  useConsentStatus,
265
326
  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,74 @@ 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
+ if (typeof subscribeGlobalError !== "function") return;
227
+ this.unsubscribe = subscribeGlobalError((info) => this.handleGlobalError(info));
228
+ }
229
+ componentWillUnmount() {
230
+ this.unsubscribe?.();
231
+ }
232
+ componentDidCatch(error) {
233
+ const { client, config } = this.props;
234
+ captureException3(client, error, { handled: true, ...config });
235
+ }
236
+ /**
237
+ * React to a global error published by the provider's auto-capture handlers.
238
+ * The provider already captured it, so we only decide whether to show the
239
+ * fallback — we never re-capture here.
240
+ */
241
+ handleGlobalError(info) {
242
+ if (this.state.hasError) return;
243
+ const { includeNonFatalGlobalErrors, includeUnhandledRejections } = this.props;
244
+ const shouldShow = info.kind === "rejection" ? includeUnhandledRejections === true : info.fatal || includeNonFatalGlobalErrors === true;
245
+ if (shouldShow) this.setState({ hasError: true });
246
+ }
247
+ render() {
248
+ if (this.state.hasError) return this.props.fallback ?? null;
249
+ return this.props.children;
250
+ }
251
+ };
252
+ function SunglassesGlobalErrorBoundary(props) {
253
+ const contextClient = useContext3(SunglassesContext);
254
+ const client = props.client ?? contextClient;
255
+ if (client === null) {
256
+ throw new Error(
257
+ "[SunGlasses] <SunglassesGlobalErrorBoundary> must be inside a <SunglassesProvider> or receive a `client` prop."
258
+ );
259
+ }
260
+ return /* @__PURE__ */ jsx3(GlobalErrorBoundaryInner, { ...props, client });
261
+ }
262
+
208
263
  // src/index.ts
209
- import { SunglassesCore, captureException as captureException3, patchConsole as patchConsole2 } from "@drakkar.software/sunglasses-core";
264
+ import {
265
+ SunglassesCore,
266
+ captureException as captureException4,
267
+ patchConsole as patchConsole2,
268
+ publishGlobalError as publishGlobalError2,
269
+ subscribeGlobalError as subscribeGlobalError2
270
+ } from "@drakkar.software/sunglasses-core";
210
271
  export {
211
272
  SunglassesCore,
212
273
  SunglassesErrorBoundary,
274
+ SunglassesGlobalErrorBoundary,
213
275
  SunglassesProvider,
214
- captureException3 as captureException,
276
+ captureException4 as captureException,
215
277
  captureUtmParams,
216
278
  patchConsole2 as patchConsole,
279
+ publishGlobalError2 as publishGlobalError,
280
+ subscribeGlobalError2 as subscribeGlobalError,
217
281
  useCapture,
218
282
  useConsentStatus,
219
283
  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.1",
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"