@inso_web/els-react 0.5.0 → 0.5.2

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/README.md CHANGED
@@ -68,7 +68,6 @@ import { ELSProvider } from '@inso_web/els-react';
68
68
  import { App } from './App';
69
69
 
70
70
  const client = new ELSClient({
71
- endpoint: import.meta.env.VITE_ELS_URL,
72
71
  apiKey: import.meta.env.VITE_ELS_API_KEY,
73
72
  appSlug: 'my-react-app',
74
73
  serviceName: 'web',
@@ -173,7 +172,6 @@ userLog.info('viewed profile');
173
172
 
174
173
  | Option | Description |
175
174
  |---|---|
176
- | `endpoint` | ELS URL (required) |
177
175
  | `apiKey` | API key (required) |
178
176
  | `appSlug` | App slug (required) |
179
177
  | `serviceName` | Service / module name |
@@ -223,7 +221,6 @@ import { ELSClient } from '@inso_web/els-client';
223
221
  import { ELSProvider, ELSErrorBoundary, useELS } from '@inso_web/els-react';
224
222
 
225
223
  const client = new ELSClient({
226
- endpoint: import.meta.env.VITE_ELS_URL,
227
224
  apiKey: import.meta.env.VITE_ELS_API_KEY,
228
225
  appSlug: 'my-react-app',
229
226
  deploymentEnv: import.meta.env.PROD ? 'PRODUCTION' : 'DEV',
@@ -251,7 +248,7 @@ function MyButton() {
251
248
 
252
249
  | Sentry | ELS | Notes |
253
250
  |---|---|---|
254
- | `Sentry.init({ dsn })` | `new ELSClient({ endpoint, apiKey, appSlug })` | Three explicit fields |
251
+ | `Sentry.init({ dsn })` | `new ELSClient({ apiKey, appSlug })` | Three explicit fields |
255
252
  | `<Sentry.ErrorBoundary>` | `<ELSErrorBoundary>` | Same role, same API |
256
253
  | `Sentry.captureException(err)` | `log.error(err)` | Via `useELS()` |
257
254
  | `Sentry.captureMessage(msg, level)` | `log.<level>(msg)` | |
@@ -291,7 +288,6 @@ import { ELSClient } from '@inso_web/els-client';
291
288
  import { ELSProvider, ELSErrorBoundary, useELS } from '@inso_web/els-react';
292
289
 
293
290
  const client = new ELSClient({
294
- endpoint: import.meta.env.VITE_ELS_URL,
295
291
  apiKey: import.meta.env.VITE_ELS_API_KEY,
296
292
  appSlug: 'my-react-app',
297
293
  });
@@ -304,7 +300,7 @@ log.error(new Error('boom'));
304
300
 
305
301
  | LogRocket | ELS | Notes |
306
302
  |---|---|---|
307
- | `LogRocket.init('app/123')` | `new ELSClient({ endpoint, apiKey, appSlug })` | Three explicit fields |
303
+ | `LogRocket.init('app/123')` | `new ELSClient({ apiKey, appSlug })` | Three explicit fields |
308
304
  | `LogRocket.identify(id, meta)` | `log.child({ user: { id, ...meta } })` | Bindings travel with the logger |
309
305
  | `LogRocket.captureException(err)` | `log.error(err)` | |
310
306
  | `LogRocket.log/info/warn/error` | `log.<level>(...)` | |
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/ELSProvider.tsx","../src/useELS.ts","../src/useErrorReporter.ts","../src/ELSErrorBoundary.tsx","../src/withErrorReporting.tsx"],"sourcesContent":["export { ELSProvider, ELSContext } from \"./ELSProvider.js\";\nexport { useELS } from \"./useELS.js\";\nexport { useErrorReporter } from \"./useErrorReporter.js\";\nexport { ELSErrorBoundary } from \"./ELSErrorBoundary.js\";\nexport { withErrorReporting } from \"./withErrorReporting.js\";\nexport type { ELSProviderProps } from \"./ELSProvider.js\";\n","import * as React from \"react\";\nimport { ELSClient, ELSQueue } from \"@inso_web/els-client\";\nimport type { ELSConfig } from \"@inso_web/els-client\";\n\n/** Value provided by {@link ELSProvider} and read via {@link useELS}. */\nexport interface ELSContextValue {\n /** The shared ELS client. */\n client: ELSClient;\n /** The batching queue, or `null` when `useQueue` is disabled. */\n queue: ELSQueue | null;\n}\n\n/** React context holding the ELS client/queue. Prefer the {@link useELS} hook. */\nexport const ELSContext = React.createContext<ELSContextValue | null>(null);\n\n/** Props for {@link ELSProvider}. */\nexport interface ELSProviderProps {\n /** ELS client configuration (only `apiKey` + `appSlug` are required). */\n config: ELSConfig;\n /** Use a batching queue. Default: `true`. */\n useQueue?: boolean;\n /** Queue auto-flush interval, in ms. */\n flushIntervalMs?: number;\n /** Max entries buffered before an early flush. */\n maxBatchSize?: number;\n /** Auto-subscribe to `window.onerror` and `unhandledrejection`. Default: `true`. */\n captureGlobalErrors?: boolean;\n children?: React.ReactNode;\n}\n\n/**\n * Provides a single ELS client (and optional queue) to the React tree and, by\n * default, captures uncaught errors and unhandled promise rejections. Wrap your\n * app once near the root.\n *\n * @example\n * <ELSProvider config={{ apiKey: \"els_live_…\", appSlug: \"web\" }}>\n * <App />\n * </ELSProvider>\n */\nexport const ELSProvider: React.FC<ELSProviderProps> = ({\n config,\n useQueue = true,\n flushIntervalMs,\n maxBatchSize,\n captureGlobalErrors = true,\n children,\n}) => {\n const value = React.useMemo<ELSContextValue>(() => {\n const client = new ELSClient(config);\n const queue = useQueue\n ? new ELSQueue(client, { flushIntervalMs, maxBatchSize })\n : null;\n return { client, queue };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n React.useEffect(() => {\n if (!captureGlobalErrors || typeof window === \"undefined\") return;\n\n const onError = (event: ErrorEvent) => {\n const entry = {\n message: event.message || \"window.onerror\",\n stack: event.error?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const entry = {\n message: String(reason?.message ?? reason ?? \"unhandledrejection\"),\n stack: reason?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n }, [captureGlobalErrors, value]);\n\n React.useEffect(() => {\n return () => {\n value.queue?.stop();\n };\n }, [value]);\n\n return <ELSContext.Provider value={value}>{children}</ELSContext.Provider>;\n};\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\nimport type { ELSContextValue } from \"./ELSProvider.js\";\n\n/**\n * Returns the ELS `client` and `queue` from the nearest {@link ELSProvider}.\n * Throws if no provider is present.\n *\n * @example\n * const { client } = useELS();\n * client.info(\"dashboard opened\");\n */\nexport function useELS(): ELSContextValue {\n const ctx = React.useContext(ELSContext);\n if (!ctx) {\n throw new Error(\n \"useELS: no ELSProvider found. Wrap your app in <ELSProvider>.\",\n );\n }\n return ctx;\n}\n","import * as React from \"react\";\nimport type { ErrorEntry } from \"@inso_web/els-client\";\nimport { useELS } from \"./useELS.js\";\n\n/**\n * Returns a stable `report(error, extra?)` callback that sends an error to ELS\n * (through the provider's queue when enabled). Use it for handled/caught errors.\n *\n * @example\n * const report = useErrorReporter();\n * try { await save(); } catch (e) { report(e, { url: \"/save\" }); }\n */\nexport function useErrorReporter() {\n const { client, queue } = useELS();\n\n return React.useCallback(\n (err: unknown, extra?: Partial<ErrorEntry>) => {\n const e = err as Error | undefined;\n const entry: ErrorEntry = {\n message: e?.message ?? String(err),\n stack: e?.stack,\n level: \"error\",\n ...extra,\n };\n if (queue) queue.enqueue(entry);\n else void client.sendError(entry);\n },\n [client, queue],\n );\n}\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\n\n/** Props for {@link ELSErrorBoundary}. */\nexport interface ELSErrorBoundaryProps {\n /** Rendered when a child throws. A function receives the caught error. */\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n /** Called in addition to reporting, e.g. for custom logging. */\n onError?: (error: Error, info: React.ErrorInfo) => void;\n children?: React.ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Error boundary that reports render errors (with component stack) to ELS via\n * the surrounding {@link ELSProvider} and shows an optional `fallback`.\n *\n * @example\n * <ELSErrorBoundary fallback={<p>Something went wrong</p>}>\n * <Dashboard />\n * </ELSErrorBoundary>\n */\nexport class ELSErrorBoundary extends React.Component<\n ELSErrorBoundaryProps,\n State\n> {\n static contextType = ELSContext;\n declare context: React.ContextType<typeof ELSContext>;\n\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: React.ErrorInfo) {\n this.props.onError?.(error, info);\n const ctx = this.context;\n if (!ctx) return;\n const entry = {\n message: error.message,\n stack: error.stack,\n componentStack: info.componentStack ?? undefined,\n level: \"error\" as const,\n };\n if (ctx.queue) ctx.queue.enqueue(entry);\n else void ctx.client.sendError(entry);\n }\n\n render() {\n if (this.state.error) {\n const { fallback } = this.props;\n if (typeof fallback === \"function\") return fallback(this.state.error);\n return fallback ?? null;\n }\n return this.props.children;\n }\n}\n","import * as React from \"react\";\nimport { ELSErrorBoundary } from \"./ELSErrorBoundary.js\";\nimport type { ELSErrorBoundaryProps } from \"./ELSErrorBoundary.js\";\n\n/**\n * HOC that wraps a component in an {@link ELSErrorBoundary}.\n *\n * @example\n * export default withErrorReporting(Dashboard, { fallback: <ErrorPage /> });\n */\nexport function withErrorReporting<P extends object>(\n Component: React.ComponentType<P>,\n boundaryProps?: Omit<ELSErrorBoundaryProps, \"children\">,\n): React.FC<P> {\n const Wrapped: React.FC<P> = (props) => (\n <ELSErrorBoundary {...boundaryProps}>\n <Component {...props} />\n </ELSErrorBoundary>\n );\n Wrapped.displayName = `withErrorReporting(${\n Component.displayName ?? Component.name ?? \"Component\"\n })`;\n return Wrapped;\n}\n"],"mappings":"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","names":["React","React","React","import_jsx_runtime","Component"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/ELSProvider.tsx","../src/useELS.ts","../src/useErrorReporter.ts","../src/ELSErrorBoundary.tsx","../src/withErrorReporting.tsx"],"sourcesContent":["export { ELSProvider, ELSContext } from \"./ELSProvider.js\";\nexport { useELS } from \"./useELS.js\";\nexport { useErrorReporter } from \"./useErrorReporter.js\";\nexport { ELSErrorBoundary } from \"./ELSErrorBoundary.js\";\nexport { withErrorReporting } from \"./withErrorReporting.js\";\nexport type { ELSProviderProps } from \"./ELSProvider.js\";\n","import * as React from \"react\";\nimport { ELSClient, ELSQueue } from \"@inso_web/els-client\";\nimport type { ELSConfig } from \"@inso_web/els-client\";\n\n/** Value provided by {@link ELSProvider} and read via {@link useELS}. */\nexport interface ELSContextValue {\n /** The shared ELS client. */\n client: ELSClient;\n /** The batching queue, or `null` when `useQueue` is disabled. */\n queue: ELSQueue | null;\n}\n\n/** React context holding the ELS client/queue. Prefer the {@link useELS} hook. */\nexport const ELSContext = React.createContext<ELSContextValue | null>(null);\n\n/** Props for {@link ELSProvider}. */\nexport interface ELSProviderProps {\n /** ELS client configuration (only `apiKey` + `appSlug` are required). */\n config: ELSConfig;\n /** Use a batching queue. Default: `true`. */\n useQueue?: boolean;\n /** Queue auto-flush interval, in ms. */\n flushIntervalMs?: number;\n /** Max entries buffered before an early flush. */\n maxBatchSize?: number;\n /** Auto-subscribe to `window.onerror` and `unhandledrejection`. Default: `true`. */\n captureGlobalErrors?: boolean;\n children?: React.ReactNode;\n}\n\n/**\n * Provides a single ELS client (and optional queue) to the React tree and, by\n * default, captures uncaught errors and unhandled promise rejections. Wrap your\n * app once near the root.\n *\n * @example\n * <ELSProvider config={{ apiKey: \"els_live_…\", appSlug: \"web\" }}>\n * <App />\n * </ELSProvider>\n */\nexport const ELSProvider: React.FC<ELSProviderProps> = ({\n config,\n useQueue = true,\n flushIntervalMs,\n maxBatchSize,\n captureGlobalErrors = true,\n children,\n}) => {\n const value = React.useMemo<ELSContextValue>(() => {\n const client = new ELSClient(config);\n const queue = useQueue\n ? new ELSQueue(client, { flushIntervalMs, maxBatchSize })\n : null;\n return { client, queue };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n React.useEffect(() => {\n if (!captureGlobalErrors || typeof window === \"undefined\") return;\n\n const onError = (event: ErrorEvent) => {\n const entry = {\n message: event.message || \"window.onerror\",\n stack: event.error?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const entry = {\n message: String(reason?.message ?? reason ?? \"unhandledrejection\"),\n stack: reason?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n }, [captureGlobalErrors, value]);\n\n React.useEffect(() => {\n return () => {\n value.queue?.stop();\n };\n }, [value]);\n\n return <ELSContext.Provider value={value}>{children}</ELSContext.Provider>;\n};\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\nimport type { ELSContextValue } from \"./ELSProvider.js\";\n\n/**\n * Returns the ELS `client` and `queue` from the nearest {@link ELSProvider}.\n * Throws if no provider is present.\n *\n * @example\n * const { client } = useELS();\n * client.info(\"dashboard opened\");\n */\nexport function useELS(): ELSContextValue {\n const ctx = React.useContext(ELSContext);\n if (!ctx) {\n throw new Error(\n \"useELS: no ELSProvider found. Wrap your app in <ELSProvider>.\",\n );\n }\n return ctx;\n}\n","import * as React from \"react\";\nimport type { ErrorEntry, WritableErrorEntry } from \"@inso_web/els-client\";\nimport { useELS } from \"./useELS.js\";\n\n/**\n * Returns a stable `report(error, extra?)` callback that sends an error to ELS\n * (through the provider's queue when enabled). Use it for handled/caught errors.\n *\n * @example\n * const report = useErrorReporter();\n * try { await save(); } catch (e) { report(e, { url: \"/save\" }); }\n */\nexport function useErrorReporter() {\n const { client, queue } = useELS();\n\n return React.useCallback(\n (err: unknown, extra?: Partial<WritableErrorEntry>) => {\n const e = err as Error | undefined;\n const entry: WritableErrorEntry = {\n message: e?.message ?? String(err),\n stack: e?.stack,\n level: \"error\",\n ...extra,\n };\n // Browser-side: source/url are resolved by the client (location.href).\n if (queue) queue.enqueue(entry as ErrorEntry);\n else void client.sendError(entry as ErrorEntry);\n },\n [client, queue],\n );\n}\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\n\n/** Props for {@link ELSErrorBoundary}. */\nexport interface ELSErrorBoundaryProps {\n /** Rendered when a child throws. A function receives the caught error. */\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n /** Called in addition to reporting, e.g. for custom logging. */\n onError?: (error: Error, info: React.ErrorInfo) => void;\n children?: React.ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Error boundary that reports render errors (with component stack) to ELS via\n * the surrounding {@link ELSProvider} and shows an optional `fallback`.\n *\n * @example\n * <ELSErrorBoundary fallback={<p>Something went wrong</p>}>\n * <Dashboard />\n * </ELSErrorBoundary>\n */\nexport class ELSErrorBoundary extends React.Component<\n ELSErrorBoundaryProps,\n State\n> {\n static contextType = ELSContext;\n declare context: React.ContextType<typeof ELSContext>;\n\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: React.ErrorInfo) {\n this.props.onError?.(error, info);\n const ctx = this.context;\n if (!ctx) return;\n const entry = {\n message: error.message,\n stack: error.stack,\n componentStack: info.componentStack ?? undefined,\n level: \"error\" as const,\n };\n if (ctx.queue) ctx.queue.enqueue(entry);\n else void ctx.client.sendError(entry);\n }\n\n render() {\n if (this.state.error) {\n const { fallback } = this.props;\n if (typeof fallback === \"function\") return fallback(this.state.error);\n return fallback ?? null;\n }\n return this.props.children;\n }\n}\n","import * as React from \"react\";\nimport { ELSErrorBoundary } from \"./ELSErrorBoundary.js\";\nimport type { ELSErrorBoundaryProps } from \"./ELSErrorBoundary.js\";\n\n/**\n * HOC that wraps a component in an {@link ELSErrorBoundary}.\n *\n * @example\n * export default withErrorReporting(Dashboard, { fallback: <ErrorPage /> });\n */\nexport function withErrorReporting<P extends object>(\n Component: React.ComponentType<P>,\n boundaryProps?: Omit<ELSErrorBoundaryProps, \"children\">,\n): React.FC<P> {\n const Wrapped: React.FC<P> = (props) => (\n <ELSErrorBoundary {...boundaryProps}>\n <Component {...props} />\n </ELSErrorBoundary>\n );\n Wrapped.displayName = `withErrorReporting(${\n Component.displayName ?? Component.name ?? \"Component\"\n })`;\n return Wrapped;\n}\n"],"mappings":"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","names":["React","React","React","import_jsx_runtime","Component"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { ELSClient, ELSQueue, ELSConfig, ErrorEntry } from '@inso_web/els-client';
2
+ import { ELSClient, ELSQueue, ELSConfig, WritableErrorEntry } from '@inso_web/els-client';
3
3
 
4
4
  /** Value provided by {@link ELSProvider} and read via {@link useELS}. */
5
5
  interface ELSContextValue {
@@ -54,7 +54,7 @@ declare function useELS(): ELSContextValue;
54
54
  * const report = useErrorReporter();
55
55
  * try { await save(); } catch (e) { report(e, { url: "/save" }); }
56
56
  */
57
- declare function useErrorReporter(): (err: unknown, extra?: Partial<ErrorEntry>) => void;
57
+ declare function useErrorReporter(): (err: unknown, extra?: Partial<WritableErrorEntry>) => void;
58
58
 
59
59
  /** Props for {@link ELSErrorBoundary}. */
60
60
  interface ELSErrorBoundaryProps {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { ELSClient, ELSQueue, ELSConfig, ErrorEntry } from '@inso_web/els-client';
2
+ import { ELSClient, ELSQueue, ELSConfig, WritableErrorEntry } from '@inso_web/els-client';
3
3
 
4
4
  /** Value provided by {@link ELSProvider} and read via {@link useELS}. */
5
5
  interface ELSContextValue {
@@ -54,7 +54,7 @@ declare function useELS(): ELSContextValue;
54
54
  * const report = useErrorReporter();
55
55
  * try { await save(); } catch (e) { report(e, { url: "/save" }); }
56
56
  */
57
- declare function useErrorReporter(): (err: unknown, extra?: Partial<ErrorEntry>) => void;
57
+ declare function useErrorReporter(): (err: unknown, extra?: Partial<WritableErrorEntry>) => void;
58
58
 
59
59
  /** Props for {@link ELSErrorBoundary}. */
60
60
  interface ELSErrorBoundaryProps {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ELSProvider.tsx","../src/useELS.ts","../src/useErrorReporter.ts","../src/ELSErrorBoundary.tsx","../src/withErrorReporting.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { ELSClient, ELSQueue } from \"@inso_web/els-client\";\nimport type { ELSConfig } from \"@inso_web/els-client\";\n\n/** Value provided by {@link ELSProvider} and read via {@link useELS}. */\nexport interface ELSContextValue {\n /** The shared ELS client. */\n client: ELSClient;\n /** The batching queue, or `null` when `useQueue` is disabled. */\n queue: ELSQueue | null;\n}\n\n/** React context holding the ELS client/queue. Prefer the {@link useELS} hook. */\nexport const ELSContext = React.createContext<ELSContextValue | null>(null);\n\n/** Props for {@link ELSProvider}. */\nexport interface ELSProviderProps {\n /** ELS client configuration (only `apiKey` + `appSlug` are required). */\n config: ELSConfig;\n /** Use a batching queue. Default: `true`. */\n useQueue?: boolean;\n /** Queue auto-flush interval, in ms. */\n flushIntervalMs?: number;\n /** Max entries buffered before an early flush. */\n maxBatchSize?: number;\n /** Auto-subscribe to `window.onerror` and `unhandledrejection`. Default: `true`. */\n captureGlobalErrors?: boolean;\n children?: React.ReactNode;\n}\n\n/**\n * Provides a single ELS client (and optional queue) to the React tree and, by\n * default, captures uncaught errors and unhandled promise rejections. Wrap your\n * app once near the root.\n *\n * @example\n * <ELSProvider config={{ apiKey: \"els_live_…\", appSlug: \"web\" }}>\n * <App />\n * </ELSProvider>\n */\nexport const ELSProvider: React.FC<ELSProviderProps> = ({\n config,\n useQueue = true,\n flushIntervalMs,\n maxBatchSize,\n captureGlobalErrors = true,\n children,\n}) => {\n const value = React.useMemo<ELSContextValue>(() => {\n const client = new ELSClient(config);\n const queue = useQueue\n ? new ELSQueue(client, { flushIntervalMs, maxBatchSize })\n : null;\n return { client, queue };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n React.useEffect(() => {\n if (!captureGlobalErrors || typeof window === \"undefined\") return;\n\n const onError = (event: ErrorEvent) => {\n const entry = {\n message: event.message || \"window.onerror\",\n stack: event.error?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const entry = {\n message: String(reason?.message ?? reason ?? \"unhandledrejection\"),\n stack: reason?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n }, [captureGlobalErrors, value]);\n\n React.useEffect(() => {\n return () => {\n value.queue?.stop();\n };\n }, [value]);\n\n return <ELSContext.Provider value={value}>{children}</ELSContext.Provider>;\n};\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\nimport type { ELSContextValue } from \"./ELSProvider.js\";\n\n/**\n * Returns the ELS `client` and `queue` from the nearest {@link ELSProvider}.\n * Throws if no provider is present.\n *\n * @example\n * const { client } = useELS();\n * client.info(\"dashboard opened\");\n */\nexport function useELS(): ELSContextValue {\n const ctx = React.useContext(ELSContext);\n if (!ctx) {\n throw new Error(\n \"useELS: no ELSProvider found. Wrap your app in <ELSProvider>.\",\n );\n }\n return ctx;\n}\n","import * as React from \"react\";\nimport type { ErrorEntry } from \"@inso_web/els-client\";\nimport { useELS } from \"./useELS.js\";\n\n/**\n * Returns a stable `report(error, extra?)` callback that sends an error to ELS\n * (through the provider's queue when enabled). Use it for handled/caught errors.\n *\n * @example\n * const report = useErrorReporter();\n * try { await save(); } catch (e) { report(e, { url: \"/save\" }); }\n */\nexport function useErrorReporter() {\n const { client, queue } = useELS();\n\n return React.useCallback(\n (err: unknown, extra?: Partial<ErrorEntry>) => {\n const e = err as Error | undefined;\n const entry: ErrorEntry = {\n message: e?.message ?? String(err),\n stack: e?.stack,\n level: \"error\",\n ...extra,\n };\n if (queue) queue.enqueue(entry);\n else void client.sendError(entry);\n },\n [client, queue],\n );\n}\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\n\n/** Props for {@link ELSErrorBoundary}. */\nexport interface ELSErrorBoundaryProps {\n /** Rendered when a child throws. A function receives the caught error. */\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n /** Called in addition to reporting, e.g. for custom logging. */\n onError?: (error: Error, info: React.ErrorInfo) => void;\n children?: React.ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Error boundary that reports render errors (with component stack) to ELS via\n * the surrounding {@link ELSProvider} and shows an optional `fallback`.\n *\n * @example\n * <ELSErrorBoundary fallback={<p>Something went wrong</p>}>\n * <Dashboard />\n * </ELSErrorBoundary>\n */\nexport class ELSErrorBoundary extends React.Component<\n ELSErrorBoundaryProps,\n State\n> {\n static contextType = ELSContext;\n declare context: React.ContextType<typeof ELSContext>;\n\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: React.ErrorInfo) {\n this.props.onError?.(error, info);\n const ctx = this.context;\n if (!ctx) return;\n const entry = {\n message: error.message,\n stack: error.stack,\n componentStack: info.componentStack ?? undefined,\n level: \"error\" as const,\n };\n if (ctx.queue) ctx.queue.enqueue(entry);\n else void ctx.client.sendError(entry);\n }\n\n render() {\n if (this.state.error) {\n const { fallback } = this.props;\n if (typeof fallback === \"function\") return fallback(this.state.error);\n return fallback ?? null;\n }\n return this.props.children;\n }\n}\n","import * as React from \"react\";\nimport { ELSErrorBoundary } from \"./ELSErrorBoundary.js\";\nimport type { ELSErrorBoundaryProps } from \"./ELSErrorBoundary.js\";\n\n/**\n * HOC that wraps a component in an {@link ELSErrorBoundary}.\n *\n * @example\n * export default withErrorReporting(Dashboard, { fallback: <ErrorPage /> });\n */\nexport function withErrorReporting<P extends object>(\n Component: React.ComponentType<P>,\n boundaryProps?: Omit<ELSErrorBoundaryProps, \"children\">,\n): React.FC<P> {\n const Wrapped: React.FC<P> = (props) => (\n <ELSErrorBoundary {...boundaryProps}>\n <Component {...props} />\n </ELSErrorBoundary>\n );\n Wrapped.displayName = `withErrorReporting(${\n Component.displayName ?? Component.name ?? \"Component\"\n })`;\n return Wrapped;\n}\n"],"mappings":"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","names":["React","React","React","jsx","Component"]}
1
+ {"version":3,"sources":["../src/ELSProvider.tsx","../src/useELS.ts","../src/useErrorReporter.ts","../src/ELSErrorBoundary.tsx","../src/withErrorReporting.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { ELSClient, ELSQueue } from \"@inso_web/els-client\";\nimport type { ELSConfig } from \"@inso_web/els-client\";\n\n/** Value provided by {@link ELSProvider} and read via {@link useELS}. */\nexport interface ELSContextValue {\n /** The shared ELS client. */\n client: ELSClient;\n /** The batching queue, or `null` when `useQueue` is disabled. */\n queue: ELSQueue | null;\n}\n\n/** React context holding the ELS client/queue. Prefer the {@link useELS} hook. */\nexport const ELSContext = React.createContext<ELSContextValue | null>(null);\n\n/** Props for {@link ELSProvider}. */\nexport interface ELSProviderProps {\n /** ELS client configuration (only `apiKey` + `appSlug` are required). */\n config: ELSConfig;\n /** Use a batching queue. Default: `true`. */\n useQueue?: boolean;\n /** Queue auto-flush interval, in ms. */\n flushIntervalMs?: number;\n /** Max entries buffered before an early flush. */\n maxBatchSize?: number;\n /** Auto-subscribe to `window.onerror` and `unhandledrejection`. Default: `true`. */\n captureGlobalErrors?: boolean;\n children?: React.ReactNode;\n}\n\n/**\n * Provides a single ELS client (and optional queue) to the React tree and, by\n * default, captures uncaught errors and unhandled promise rejections. Wrap your\n * app once near the root.\n *\n * @example\n * <ELSProvider config={{ apiKey: \"els_live_…\", appSlug: \"web\" }}>\n * <App />\n * </ELSProvider>\n */\nexport const ELSProvider: React.FC<ELSProviderProps> = ({\n config,\n useQueue = true,\n flushIntervalMs,\n maxBatchSize,\n captureGlobalErrors = true,\n children,\n}) => {\n const value = React.useMemo<ELSContextValue>(() => {\n const client = new ELSClient(config);\n const queue = useQueue\n ? new ELSQueue(client, { flushIntervalMs, maxBatchSize })\n : null;\n return { client, queue };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n React.useEffect(() => {\n if (!captureGlobalErrors || typeof window === \"undefined\") return;\n\n const onError = (event: ErrorEvent) => {\n const entry = {\n message: event.message || \"window.onerror\",\n stack: event.error?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const entry = {\n message: String(reason?.message ?? reason ?? \"unhandledrejection\"),\n stack: reason?.stack,\n level: \"error\" as const,\n };\n if (value.queue) value.queue.enqueue(entry);\n else void value.client.sendError(entry);\n };\n\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n return () => {\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n };\n }, [captureGlobalErrors, value]);\n\n React.useEffect(() => {\n return () => {\n value.queue?.stop();\n };\n }, [value]);\n\n return <ELSContext.Provider value={value}>{children}</ELSContext.Provider>;\n};\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\nimport type { ELSContextValue } from \"./ELSProvider.js\";\n\n/**\n * Returns the ELS `client` and `queue` from the nearest {@link ELSProvider}.\n * Throws if no provider is present.\n *\n * @example\n * const { client } = useELS();\n * client.info(\"dashboard opened\");\n */\nexport function useELS(): ELSContextValue {\n const ctx = React.useContext(ELSContext);\n if (!ctx) {\n throw new Error(\n \"useELS: no ELSProvider found. Wrap your app in <ELSProvider>.\",\n );\n }\n return ctx;\n}\n","import * as React from \"react\";\nimport type { ErrorEntry, WritableErrorEntry } from \"@inso_web/els-client\";\nimport { useELS } from \"./useELS.js\";\n\n/**\n * Returns a stable `report(error, extra?)` callback that sends an error to ELS\n * (through the provider's queue when enabled). Use it for handled/caught errors.\n *\n * @example\n * const report = useErrorReporter();\n * try { await save(); } catch (e) { report(e, { url: \"/save\" }); }\n */\nexport function useErrorReporter() {\n const { client, queue } = useELS();\n\n return React.useCallback(\n (err: unknown, extra?: Partial<WritableErrorEntry>) => {\n const e = err as Error | undefined;\n const entry: WritableErrorEntry = {\n message: e?.message ?? String(err),\n stack: e?.stack,\n level: \"error\",\n ...extra,\n };\n // Browser-side: source/url are resolved by the client (location.href).\n if (queue) queue.enqueue(entry as ErrorEntry);\n else void client.sendError(entry as ErrorEntry);\n },\n [client, queue],\n );\n}\n","import * as React from \"react\";\nimport { ELSContext } from \"./ELSProvider.js\";\n\n/** Props for {@link ELSErrorBoundary}. */\nexport interface ELSErrorBoundaryProps {\n /** Rendered when a child throws. A function receives the caught error. */\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n /** Called in addition to reporting, e.g. for custom logging. */\n onError?: (error: Error, info: React.ErrorInfo) => void;\n children?: React.ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Error boundary that reports render errors (with component stack) to ELS via\n * the surrounding {@link ELSProvider} and shows an optional `fallback`.\n *\n * @example\n * <ELSErrorBoundary fallback={<p>Something went wrong</p>}>\n * <Dashboard />\n * </ELSErrorBoundary>\n */\nexport class ELSErrorBoundary extends React.Component<\n ELSErrorBoundaryProps,\n State\n> {\n static contextType = ELSContext;\n declare context: React.ContextType<typeof ELSContext>;\n\n state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n componentDidCatch(error: Error, info: React.ErrorInfo) {\n this.props.onError?.(error, info);\n const ctx = this.context;\n if (!ctx) return;\n const entry = {\n message: error.message,\n stack: error.stack,\n componentStack: info.componentStack ?? undefined,\n level: \"error\" as const,\n };\n if (ctx.queue) ctx.queue.enqueue(entry);\n else void ctx.client.sendError(entry);\n }\n\n render() {\n if (this.state.error) {\n const { fallback } = this.props;\n if (typeof fallback === \"function\") return fallback(this.state.error);\n return fallback ?? null;\n }\n return this.props.children;\n }\n}\n","import * as React from \"react\";\nimport { ELSErrorBoundary } from \"./ELSErrorBoundary.js\";\nimport type { ELSErrorBoundaryProps } from \"./ELSErrorBoundary.js\";\n\n/**\n * HOC that wraps a component in an {@link ELSErrorBoundary}.\n *\n * @example\n * export default withErrorReporting(Dashboard, { fallback: <ErrorPage /> });\n */\nexport function withErrorReporting<P extends object>(\n Component: React.ComponentType<P>,\n boundaryProps?: Omit<ELSErrorBoundaryProps, \"children\">,\n): React.FC<P> {\n const Wrapped: React.FC<P> = (props) => (\n <ELSErrorBoundary {...boundaryProps}>\n <Component {...props} />\n </ELSErrorBoundary>\n );\n Wrapped.displayName = `withErrorReporting(${\n Component.displayName ?? Component.name ?? \"Component\"\n })`;\n return Wrapped;\n}\n"],"mappings":"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","names":["React","React","React","jsx","Component"]}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@inso_web/els-react",
3
- "version": "0.5.0",
4
- "description": "React‑обёртка для Error Logs Service (ELS): Provider, hooks, ErrorBoundary и HOC для автоматического репорта ошибок компонентов.",
5
- "homepage": "https://api.insoweb.ru/els",
3
+ "version": "0.5.2",
4
+ "description": "React bindings for the Error Logs Service (ELS): Provider, hooks, ErrorBoundary and a HOC for automatic component error reporting.",
5
+ "homepage": "https://els.insoweb.ru",
6
6
  "author": "INSOWEB",
7
7
  "type": "module",
8
8
  "main": "./dist/index.cjs",
@@ -51,7 +51,7 @@
51
51
  "react": ">=17.0.0"
52
52
  },
53
53
  "dependencies": {
54
- "@inso_web/els-client": "^0.5.0"
54
+ "@inso_web/els-client": "^0.5.2"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@testing-library/react": "^14.1.2",