@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 +2 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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({
|
|
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({
|
|
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>(...)` | |
|
package/dist/index.cjs.map
CHANGED
|
@@ -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,
|
|
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<
|
|
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,
|
|
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<
|
|
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.
|
|
4
|
-
"description": "React
|
|
5
|
-
"homepage": "https://
|
|
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.
|
|
54
|
+
"@inso_web/els-client": "^0.5.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@testing-library/react": "^14.1.2",
|