@inso_web/els-react 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +320 -59
- package/dist/index.cjs +4 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -4
- package/dist/index.d.ts +54 -4
- package/dist/index.js +4 -12
- package/dist/index.js.map +1 -1
- package/examples/vite-react/src/main.tsx +0 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,73 +5,62 @@
|
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
|
-
React
|
|
8
|
+
React bindings for the **Inso Error Logs Service (ELS)** — a managed SaaS for centralised event logging (debug → fatal) with AI-assisted error triage. Ships `<ELSProvider>` for DI, `useELS()` hook, a ready-made `<ELSErrorBoundary>` that auto-reports render-phase errors, and a `useGlobalErrorHandlers()` hook for `window` listeners. React 17+.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- `<ELSProvider client={...}>` — кладёт клиент в контекст.
|
|
13
|
-
- `useELS()` — hook возвращает logger.
|
|
14
|
-
- `<ELSErrorBoundary>` — error boundary который ловит render-ошибки и шлёт в ELS со stack trace + componentStack.
|
|
15
|
-
- `useGlobalErrorHandlers()` — hook для подписки на `window.error` и `unhandledrejection`.
|
|
10
|
+
> 🇷🇺 [Русская версия → README_RU.md](README_RU.md)
|
|
16
11
|
|
|
17
12
|
---
|
|
18
13
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
14
|
+
## Table of contents
|
|
15
|
+
|
|
16
|
+
- [What you get](#what-you-get)
|
|
17
|
+
- [Install](#install)
|
|
18
|
+
- [Quick Start](#quick-start)
|
|
19
|
+
- [When to use what](#when-to-use-what)
|
|
20
|
+
- [Core concepts](#core-concepts)
|
|
21
|
+
- [Configuration](#configuration)
|
|
22
|
+
- [Migration](#migration)
|
|
23
|
+
- [From @sentry/react](#from-sentryreact)
|
|
24
|
+
- [From LogRocket React SDK](#from-logrocket-react-sdk)
|
|
25
|
+
- [Versioning](#versioning)
|
|
26
|
+
- [Quick reference](#quick-reference)
|
|
27
|
+
- [Why ELS](#why-els)
|
|
28
|
+
- [API](#api)
|
|
29
|
+
- [FAQ](#faq)
|
|
30
|
+
- [Other ELS SDKs](#other-els-sdks)
|
|
31
|
+
- [Pricing](#pricing)
|
|
32
|
+
- [License](#license)
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Stack trace с распарсенными фреймами + AI-анализ что именно сломалось и как чинить. Для React-ошибок дополнительно сохраняется `componentStack`.
|
|
40
|
-
|
|
41
|
-
### Аналитика и регрессии по версиям
|
|
42
|
-
|
|
43
|
-

|
|
44
|
-
|
|
45
|
-
Total / critical+errors / warnings / error rate. AI-обзор слева, timeline в центре, donut'ы по приложению/источнику/уровню. **Виджет «Регрессии»**: какие fingerprint'ы появились впервые в свежей версии и какие пропали.
|
|
46
|
-
|
|
47
|
-
### Управление API-ключами
|
|
48
|
-
|
|
49
|
-

|
|
50
|
-

|
|
51
|
-
|
|
52
|
-
Scoped-ключи (write/read/read-any), live/test environments, ротация без даунтайма.
|
|
34
|
+
---
|
|
53
35
|
|
|
54
|
-
|
|
36
|
+
## What you get
|
|
55
37
|
|
|
56
|
-
|
|
38
|
+
ELS ships with a built-in admin dashboard. Every event captured by this SDK lands there with full-text search, faceted filtering, AI-assisted diagnosis, and version-aware regression detection. React render-phase errors carry `componentStack` alongside the regular stack trace.
|
|
57
39
|
|
|
58
|
-
|
|
40
|
+
| | |
|
|
41
|
+
|---|---|
|
|
42
|
+
|  |  |
|
|
43
|
+
| Virtual table with facet sidebar (app, env, **version**, source, level, browser, IP, category). Live mode auto-refreshes every 5s. | Full event metadata: timestamps, geo, env, **app version**, fingerprint, session, repetition cards, in-session correlation. |
|
|
44
|
+
|  |  |
|
|
45
|
+
| Parsed stack trace + AI-assisted diagnosis: what broke, where, how to fix. | Timeline, donuts, top URLs/IPs, hourly heatmap, **version-regression widget**. |
|
|
59
46
|
|
|
60
47
|
---
|
|
61
48
|
|
|
62
|
-
##
|
|
49
|
+
## Install
|
|
63
50
|
|
|
64
51
|
```bash
|
|
65
52
|
npm install @inso_web/els-client @inso_web/els-react
|
|
66
53
|
```
|
|
67
54
|
|
|
55
|
+
**Requirements:** React 17+, Node.js 18+ at build time. Works with Vite, CRA, Webpack, Parcel.
|
|
56
|
+
|
|
68
57
|
---
|
|
69
58
|
|
|
70
59
|
## Quick Start
|
|
71
60
|
|
|
72
|
-
### 1.
|
|
61
|
+
### 1. Wrap your app in `<ELSProvider>`
|
|
73
62
|
|
|
74
|
-
`main.tsx` (Vite)
|
|
63
|
+
`main.tsx` (Vite) or `index.tsx` (CRA):
|
|
75
64
|
|
|
76
65
|
```tsx
|
|
77
66
|
import { ELSClient } from '@inso_web/els-client';
|
|
@@ -95,7 +84,9 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
95
84
|
);
|
|
96
85
|
```
|
|
97
86
|
|
|
98
|
-
|
|
87
|
+
Don't have an API key yet? **[Sign up at lk.insoweb.ru](https://lk.insoweb.ru)** — takes under a minute.
|
|
88
|
+
|
|
89
|
+
### 2. Log via `useELS()`
|
|
99
90
|
|
|
100
91
|
```tsx
|
|
101
92
|
import { useELS } from '@inso_web/els-react';
|
|
@@ -114,19 +105,19 @@ export function CheckoutButton() {
|
|
|
114
105
|
}
|
|
115
106
|
```
|
|
116
107
|
|
|
117
|
-
### 3.
|
|
108
|
+
### 3. Wrap the root in `<ELSErrorBoundary>`
|
|
118
109
|
|
|
119
110
|
```tsx
|
|
120
111
|
import { ELSErrorBoundary } from '@inso_web/els-react';
|
|
121
112
|
|
|
122
|
-
<ELSErrorBoundary fallback={<div
|
|
113
|
+
<ELSErrorBoundary fallback={<div>Something went wrong</div>}>
|
|
123
114
|
<App />
|
|
124
115
|
</ELSErrorBoundary>
|
|
125
116
|
```
|
|
126
117
|
|
|
127
|
-
Render
|
|
118
|
+
Render-phase errors are captured automatically with stack trace + `componentStack`.
|
|
128
119
|
|
|
129
|
-
### 4.
|
|
120
|
+
### 4. Global handlers (optional)
|
|
130
121
|
|
|
131
122
|
```tsx
|
|
132
123
|
import { useGlobalErrorHandlers } from '@inso_web/els-react';
|
|
@@ -137,11 +128,200 @@ export function ErrorReporter() {
|
|
|
137
128
|
}
|
|
138
129
|
```
|
|
139
130
|
|
|
131
|
+
Mount `<ErrorReporter />` once inside the provider.
|
|
132
|
+
|
|
140
133
|
---
|
|
141
134
|
|
|
142
|
-
##
|
|
135
|
+
## When to use what
|
|
136
|
+
|
|
137
|
+
| Scenario | Use |
|
|
138
|
+
|---|---|
|
|
139
|
+
| Catch render-phase errors | Wrap a subtree in `<ELSErrorBoundary>` |
|
|
140
|
+
| Handle async errors in event handlers | `useELS()` + `try/catch` |
|
|
141
|
+
| Background `window.error` / `unhandledrejection` | Mount `<ErrorReporter />` with `useGlobalErrorHandlers()` |
|
|
142
|
+
| Multiple sub-apps with different configs | Multiple `<ELSProvider>` instances (innermost wins) |
|
|
143
|
+
| Outside React (utility module) | Import the `ELSClient` directly |
|
|
144
|
+
| SSR (Next.js) | Use [`@inso_web/els-next`](https://github.com/official-inso/els-next) instead |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Core concepts
|
|
149
|
+
|
|
150
|
+
### `<ELSErrorBoundary>`
|
|
151
|
+
|
|
152
|
+
A regular React error boundary that calls `client.error(err, ..., { meta: { componentStack } })` in `componentDidCatch`. Render-phase exceptions are captured; event-handler errors are not (React itself doesn't surface them to boundaries — wrap with `try/catch`).
|
|
143
153
|
|
|
144
|
-
|
|
154
|
+
### `useELS()`
|
|
155
|
+
|
|
156
|
+
Returns the same `Logger` interface as the base client: `info`, `warn`, `error`, `debug`, `trace`, `fatal`, `child`, `flush`. The reference is stable across renders.
|
|
157
|
+
|
|
158
|
+
### Bindings & child loggers
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
const log = useELS();
|
|
162
|
+
const userLog = log.child({ userId: 42, role: 'admin' });
|
|
163
|
+
userLog.info('viewed profile');
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`child` is cheap — create one per user, per workflow, per route as needed.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Configuration
|
|
171
|
+
|
|
172
|
+
`ELSConfig` matches the base client — see [@inso_web/els-client](https://github.com/official-inso/els-client). Key fields:
|
|
173
|
+
|
|
174
|
+
| Option | Description |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `endpoint` | ELS URL (required) |
|
|
177
|
+
| `apiKey` | API key (required) |
|
|
178
|
+
| `appSlug` | App slug (required) |
|
|
179
|
+
| `serviceName` | Service / module name |
|
|
180
|
+
| `deploymentEnv` | `DEV` / `STAGING` / `PRODUCTION` |
|
|
181
|
+
| `appVersion` | Version (≤128 chars) |
|
|
182
|
+
| `minLevel` | Minimum level to send |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Migration
|
|
187
|
+
|
|
188
|
+
### From @sentry/react
|
|
189
|
+
|
|
190
|
+
**Before:**
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import * as Sentry from '@sentry/react';
|
|
194
|
+
|
|
195
|
+
Sentry.init({
|
|
196
|
+
dsn: 'https://public@sentry.example.com/1',
|
|
197
|
+
environment: process.env.NODE_ENV,
|
|
198
|
+
release: import.meta.env.VITE_BUILD_VERSION,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const SentryRoute = Sentry.withSentryReactRouterV6Routing(Route);
|
|
202
|
+
|
|
203
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
204
|
+
<Sentry.ErrorBoundary fallback={<p>Crashed</p>}>
|
|
205
|
+
<App />
|
|
206
|
+
</Sentry.ErrorBoundary>,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
function MyButton() {
|
|
210
|
+
return (
|
|
211
|
+
<button onClick={() => {
|
|
212
|
+
Sentry.captureMessage('clicked');
|
|
213
|
+
doStuff().catch(Sentry.captureException);
|
|
214
|
+
}}>Click</button>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**After:**
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { ELSClient } from '@inso_web/els-client';
|
|
223
|
+
import { ELSProvider, ELSErrorBoundary, useELS } from '@inso_web/els-react';
|
|
224
|
+
|
|
225
|
+
const client = new ELSClient({
|
|
226
|
+
endpoint: import.meta.env.VITE_ELS_URL,
|
|
227
|
+
apiKey: import.meta.env.VITE_ELS_API_KEY,
|
|
228
|
+
appSlug: 'my-react-app',
|
|
229
|
+
deploymentEnv: import.meta.env.PROD ? 'PRODUCTION' : 'DEV',
|
|
230
|
+
appVersion: import.meta.env.VITE_BUILD_VERSION,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
234
|
+
<ELSProvider client={client}>
|
|
235
|
+
<ELSErrorBoundary fallback={<p>Crashed</p>}>
|
|
236
|
+
<App />
|
|
237
|
+
</ELSErrorBoundary>
|
|
238
|
+
</ELSProvider>,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
function MyButton() {
|
|
242
|
+
const log = useELS();
|
|
243
|
+
return (
|
|
244
|
+
<button onClick={() => {
|
|
245
|
+
log.info('clicked');
|
|
246
|
+
doStuff().catch((err) => log.error(err, 'click failed'));
|
|
247
|
+
}}>Click</button>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
| Sentry | ELS | Notes |
|
|
253
|
+
|---|---|---|
|
|
254
|
+
| `Sentry.init({ dsn })` | `new ELSClient({ endpoint, apiKey, appSlug })` | Three explicit fields |
|
|
255
|
+
| `<Sentry.ErrorBoundary>` | `<ELSErrorBoundary>` | Same role, same API |
|
|
256
|
+
| `Sentry.captureException(err)` | `log.error(err)` | Via `useELS()` |
|
|
257
|
+
| `Sentry.captureMessage(msg, level)` | `log.<level>(msg)` | |
|
|
258
|
+
| `Sentry.setUser({ id })` | `log.child({ user: { id } })` | Or via `loggerDefaults` |
|
|
259
|
+
| `release` | `appVersion` | Any string ≤128 chars |
|
|
260
|
+
| `environment` | `deploymentEnv` | Fixed enum |
|
|
261
|
+
| `Sentry.withSentryReactRouterV6Routing` | Not provided | Routing telemetry stays in Sentry if needed |
|
|
262
|
+
| Source maps upload | Not provided | Pair with another tool if critical |
|
|
263
|
+
| Session replay | Not provided | LogRocket / Sentry Replay if needed |
|
|
264
|
+
|
|
265
|
+
**Gotchas:**
|
|
266
|
+
|
|
267
|
+
- React event-handler errors are not caught by error boundaries — wrap async logic in `try/catch` and call `log.error(...)` explicitly.
|
|
268
|
+
- Sentry's `breadcrumbs` have no direct equivalent — use `log.child({ ... })` to carry context.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
### From LogRocket React SDK
|
|
273
|
+
|
|
274
|
+
**Before:**
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import LogRocket from 'logrocket';
|
|
278
|
+
import setupLogRocketReact from 'logrocket-react';
|
|
279
|
+
|
|
280
|
+
LogRocket.init('app/123');
|
|
281
|
+
setupLogRocketReact(LogRocket);
|
|
282
|
+
|
|
283
|
+
LogRocket.identify('user-42', { email: 'a@b.com' });
|
|
284
|
+
LogRocket.captureException(new Error('boom'));
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**After:**
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
import { ELSClient } from '@inso_web/els-client';
|
|
291
|
+
import { ELSProvider, ELSErrorBoundary, useELS } from '@inso_web/els-react';
|
|
292
|
+
|
|
293
|
+
const client = new ELSClient({
|
|
294
|
+
endpoint: import.meta.env.VITE_ELS_URL,
|
|
295
|
+
apiKey: import.meta.env.VITE_ELS_API_KEY,
|
|
296
|
+
appSlug: 'my-react-app',
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// usage
|
|
300
|
+
const log = useELS();
|
|
301
|
+
log.child({ user: { id: 'user-42', email: 'a@b.com' } }).info('identified');
|
|
302
|
+
log.error(new Error('boom'));
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
| LogRocket | ELS | Notes |
|
|
306
|
+
|---|---|---|
|
|
307
|
+
| `LogRocket.init('app/123')` | `new ELSClient({ endpoint, apiKey, appSlug })` | Three explicit fields |
|
|
308
|
+
| `LogRocket.identify(id, meta)` | `log.child({ user: { id, ...meta } })` | Bindings travel with the logger |
|
|
309
|
+
| `LogRocket.captureException(err)` | `log.error(err)` | |
|
|
310
|
+
| `LogRocket.log/info/warn/error` | `log.<level>(...)` | |
|
|
311
|
+
| Session replay | Not provided | Stay on LogRocket if replay is critical |
|
|
312
|
+
| Network request capture | Not provided | Log explicit `log.info({ url, status })` instead |
|
|
313
|
+
| Redux integration | Not provided | Call `log.info(action.type, ...)` in middleware |
|
|
314
|
+
|
|
315
|
+
**Gotchas:**
|
|
316
|
+
|
|
317
|
+
- LogRocket records full DOM sessions; ELS only stores discrete events. If session replay is the reason you chose LogRocket, keep it.
|
|
318
|
+
- LogRocket's request/response interception is opaque — replicate with explicit log calls in your fetch wrapper.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Versioning
|
|
323
|
+
|
|
324
|
+
Pass via build-time env. For Vite — `VITE_BUILD_VERSION` (Vite inlines at `npm run build`):
|
|
145
325
|
|
|
146
326
|
```Dockerfile
|
|
147
327
|
ARG VITE_BUILD_VERSION=dev
|
|
@@ -159,7 +339,59 @@ RUN npm run build
|
|
|
159
339
|
new ELSClient({ ..., appVersion: import.meta.env.VITE_BUILD_VERSION });
|
|
160
340
|
```
|
|
161
341
|
|
|
162
|
-
ELS
|
|
342
|
+
ELS accepts any format ≤128 chars: semver, CalVer, date-compact, git SHA, opaque. The server auto-detects the format and sorts timelines.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Quick reference
|
|
347
|
+
|
|
348
|
+
| Need | Use |
|
|
349
|
+
|---|---|
|
|
350
|
+
| Logger in components | `const log = useELS()` |
|
|
351
|
+
| Catch render crashes | `<ELSErrorBoundary>` |
|
|
352
|
+
| Catch event-handler errors | `try/catch` + `log.error(err)` |
|
|
353
|
+
| Global browser errors | Mount `<ErrorReporter />` with `useGlobalErrorHandlers()` |
|
|
354
|
+
| Identify user | `log.child({ user: { id, email } })` |
|
|
355
|
+
| Per-route context | `log.child({ route })` in a layout component |
|
|
356
|
+
| Suppress noisy levels | `minLevel: 'warn'` |
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Why ELS
|
|
361
|
+
|
|
362
|
+
ELS for Node.js is a focused logging SaaS, not a full observability suite. It optimises for capture speed, AI-driven triage, and a low integration cost.
|
|
363
|
+
|
|
364
|
+
- **Lower weight.** ~3 KB gzip in the browser, no transitive deps.
|
|
365
|
+
- **Zero external API calls.** Only `POST /errors[/batch]` and `GET /health`.
|
|
366
|
+
- **AI-assisted diagnosis** on every stack trace — `componentStack` included for React render errors.
|
|
367
|
+
- **5-minute integration.** Provider + boundary + hook, done.
|
|
368
|
+
- **Predictable price.** Tariffs in the dashboard.
|
|
369
|
+
|
|
370
|
+
### Detailed comparison
|
|
371
|
+
|
|
372
|
+
| Category | ELS | Sentry | Datadog / New Relic | Grafana Loki | LogRocket / Logtail / BetterStack |
|
|
373
|
+
|---|---|---|---|---|---|
|
|
374
|
+
| Hosting model | Managed SaaS | SaaS or self-hosted | SaaS only | Self-hosted / Grafana Cloud | SaaS |
|
|
375
|
+
| SDK runtime deps | Zero | Medium (sub-SDKs, integrations) | Heavy (agent + tracing) | Promtail / agent | Medium |
|
|
376
|
+
| Typical integration time | ~5 min | 10–20 min | 30–60 min | Hours to days | 10–20 min |
|
|
377
|
+
| AI-assisted triage | Built-in | Paid add-on | Paid add-on | None | None |
|
|
378
|
+
| Error grouping / fingerprint | Yes | Yes | Yes | Manual via LogQL | Partial |
|
|
379
|
+
| Source-map upload | No | Yes | Yes | n/a | Partial |
|
|
380
|
+
| Session replay (frontend) | No | Paid | Paid | n/a | Yes (core) |
|
|
381
|
+
| Distributed tracing / APM | No | Partial | Yes (core) | Yes with Tempo | No |
|
|
382
|
+
| Infrastructure metrics | No | No | Yes (core) | Yes with Mimir | No |
|
|
383
|
+
| Free tier log retention | 24 hours | 30 days (limited volume) | Trial only | Self-cost | 3–30 days |
|
|
384
|
+
| Russian-language support / docs | Native | Community | Limited | Community | None |
|
|
385
|
+
|
|
386
|
+
### When ELS is the wrong choice
|
|
387
|
+
|
|
388
|
+
- You need a single vendor for **APM + logs + metrics** under one bill — go Datadog or New Relic.
|
|
389
|
+
- Your frontend bug triage relies on **DOM session replay** — go LogRocket or Sentry Replay.
|
|
390
|
+
- You ship a **public mobile app** and need crash symbolication + ANR detection — Firebase Crashlytics or Sentry Mobile.
|
|
391
|
+
|
|
392
|
+
For everything else — backend errors, frontend JS errors, request logs, structured app events with version-aware analytics — ELS is built to be the cheapest path to a working dashboard.
|
|
393
|
+
|
|
394
|
+
→ **Sign up at [lk.insoweb.ru](https://lk.insoweb.ru)** to grab an API key.
|
|
163
395
|
|
|
164
396
|
---
|
|
165
397
|
|
|
@@ -179,23 +411,52 @@ class ELSErrorBoundary extends React.Component<{
|
|
|
179
411
|
function useGlobalErrorHandlers(opts?: { errors?: boolean; rejections?: boolean }): void;
|
|
180
412
|
```
|
|
181
413
|
|
|
414
|
+
Full `ELSConfig` reference — see [@inso_web/els-client](https://github.com/official-inso/els-client).
|
|
415
|
+
|
|
182
416
|
---
|
|
183
417
|
|
|
184
418
|
## FAQ
|
|
185
419
|
|
|
186
|
-
|
|
420
|
+
**React 18 / 19?** Yes. Supported on React 17+.
|
|
187
421
|
|
|
188
|
-
|
|
422
|
+
**Is the API key safe in the client bundle?** Yes. ELS keys are scoped — a write key cannot read events. Same model as Sentry public DSN. If you still want to hide it, run an internal `/api/log` proxy.
|
|
189
423
|
|
|
190
|
-
|
|
424
|
+
**What if `apiKey` is empty?** `new ELSClient({ ..., apiKey: '' })` throws. Guard in the entry file:
|
|
191
425
|
|
|
192
426
|
```ts
|
|
193
427
|
const client = apiKey
|
|
194
428
|
? new ELSClient({ ..., apiKey })
|
|
195
|
-
: { info: () => {}, warn: () => {}, error: () => {}, /* ... */ };
|
|
429
|
+
: ({ info: () => {}, warn: () => {}, error: () => {}, /* ... */ } as any);
|
|
196
430
|
```
|
|
197
431
|
|
|
198
|
-
|
|
432
|
+
Or use [`@inso_web/els-next`](https://github.com/official-inso/els-next) which has the silent-no-op guard built-in.
|
|
433
|
+
|
|
434
|
+
**SSR with Next.js?** Use [`@inso_web/els-next`](https://github.com/official-inso/els-next) — single config for server + client + edge.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Other ELS SDKs
|
|
439
|
+
|
|
440
|
+
Same wire format, same dashboard — pick by stack.
|
|
441
|
+
|
|
442
|
+
**Node.js family**
|
|
443
|
+
- [`@inso_web/els-client`](https://github.com/official-inso/els-client) — base TS / Node / browser client
|
|
444
|
+
- [`@inso_web/els-express`](https://github.com/official-inso/els-express) — Express middleware
|
|
445
|
+
- [`@inso_web/els-next`](https://github.com/official-inso/els-next) — Next.js helpers (App + Pages router)
|
|
446
|
+
- [`@inso_web/els-nest`](https://github.com/official-inso/els-nest) — NestJS module
|
|
447
|
+
- [`@inso_web/els-react`](https://github.com/official-inso/els-react) — React Provider, hooks, ErrorBoundary (this repo)
|
|
448
|
+
- [`@inso_web/els-vue`](https://github.com/official-inso/els-vue) — Vue 3 plugin
|
|
449
|
+
|
|
450
|
+
**Other stacks**
|
|
451
|
+
- [`Inso.Els`](https://github.com/official-inso/els-csharp) — .NET (Core + ASP.NET Core + ILogger)
|
|
452
|
+
- [`io.github.official-inso:els-core`](https://github.com/official-inso/els-java) — Java + Spring Boot starter + SLF4J
|
|
453
|
+
- [`github.com/official-inso/els-go`](https://github.com/official-inso/els-go) — Go
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Pricing
|
|
458
|
+
|
|
459
|
+
Free tier — **24-hour log retention**. See **[lk.insoweb.ru](https://lk.insoweb.ru)** for the full tariff matrix.
|
|
199
460
|
|
|
200
461
|
---
|
|
201
462
|
|
package/dist/index.cjs
CHANGED
|
@@ -62,10 +62,8 @@ var ELSProvider = ({
|
|
|
62
62
|
const onError = (event) => {
|
|
63
63
|
const entry = {
|
|
64
64
|
message: event.message || "window.onerror",
|
|
65
|
-
url: typeof location !== "undefined" ? location.href : "",
|
|
66
65
|
stack: event.error?.stack,
|
|
67
|
-
level: "error"
|
|
68
|
-
source: "client"
|
|
66
|
+
level: "error"
|
|
69
67
|
};
|
|
70
68
|
if (value.queue) value.queue.enqueue(entry);
|
|
71
69
|
else void value.client.sendError(entry);
|
|
@@ -74,10 +72,8 @@ var ELSProvider = ({
|
|
|
74
72
|
const reason = event.reason;
|
|
75
73
|
const entry = {
|
|
76
74
|
message: String(reason?.message ?? reason ?? "unhandledrejection"),
|
|
77
|
-
url: typeof location !== "undefined" ? location.href : "",
|
|
78
75
|
stack: reason?.stack,
|
|
79
|
-
level: "error"
|
|
80
|
-
source: "client"
|
|
76
|
+
level: "error"
|
|
81
77
|
};
|
|
82
78
|
if (value.queue) value.queue.enqueue(entry);
|
|
83
79
|
else void value.client.sendError(entry);
|
|
@@ -103,7 +99,7 @@ function useELS() {
|
|
|
103
99
|
const ctx = React2.useContext(ELSContext);
|
|
104
100
|
if (!ctx) {
|
|
105
101
|
throw new Error(
|
|
106
|
-
"useELS: ELSProvider
|
|
102
|
+
"useELS: no ELSProvider found. Wrap your app in <ELSProvider>."
|
|
107
103
|
);
|
|
108
104
|
}
|
|
109
105
|
return ctx;
|
|
@@ -119,9 +115,7 @@ function useErrorReporter() {
|
|
|
119
115
|
const entry = {
|
|
120
116
|
message: e?.message ?? String(err),
|
|
121
117
|
stack: e?.stack,
|
|
122
|
-
url: typeof location !== "undefined" ? location.href : extra?.url ?? "",
|
|
123
118
|
level: "error",
|
|
124
|
-
source: "client",
|
|
125
119
|
...extra
|
|
126
120
|
};
|
|
127
121
|
if (queue) queue.enqueue(entry);
|
|
@@ -149,9 +143,7 @@ var ELSErrorBoundary = class extends React4.Component {
|
|
|
149
143
|
message: error.message,
|
|
150
144
|
stack: error.stack,
|
|
151
145
|
componentStack: info.componentStack ?? void 0,
|
|
152
|
-
|
|
153
|
-
level: "error",
|
|
154
|
-
source: "client"
|
|
146
|
+
level: "error"
|
|
155
147
|
};
|
|
156
148
|
if (ctx.queue) ctx.queue.enqueue(entry);
|
|
157
149
|
else void ctx.client.sendError(entry);
|
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\nexport interface ELSContextValue {\n client: ELSClient;\n queue: ELSQueue | null;\n}\n\nexport const ELSContext = React.createContext<ELSContextValue | null>(null);\n\nexport interface ELSProviderProps {\n config: ELSConfig;\n /** Включить очередь с батчингом. По умолчанию true. */\n useQueue?: boolean;\n /** Интервал авто‑флаша очереди в мс. */\n flushIntervalMs?: number;\n /** Максимальный размер батча. */\n maxBatchSize?: number;\n /** Авто‑подписка на window.onerror и unhandledrejection. По умолчанию true. */\n captureGlobalErrors?: boolean;\n children?: React.ReactNode;\n}\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 url: typeof location !== \"undefined\" ? location.href : \"\",\n stack: event.error?.stack,\n level: \"error\" as const,\n source: \"client\" 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 url: typeof location !== \"undefined\" ? location.href : \"\",\n stack: reason?.stack,\n level: \"error\" as const,\n source: \"client\" 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\nexport function useELS(): ELSContextValue {\n const ctx = React.useContext(ELSContext);\n if (!ctx) {\n throw new Error(\n \"useELS: ELSProvider не найден. Оберните приложение в <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\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 url:\n typeof location !== \"undefined\" ? location.href : extra?.url ?? \"\",\n level: \"error\",\n source: \"client\",\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\nexport interface ELSErrorBoundaryProps {\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n onError?: (error: Error, info: React.ErrorInfo) => void;\n children?: React.ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\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 url: typeof location !== \"undefined\" ? location.href : \"\",\n level: \"error\" as const,\n source: \"client\" 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\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 } 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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,37 +1,81 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ELSClient, ELSQueue, ELSConfig, ErrorEntry } from '@inso_web/els-client';
|
|
3
3
|
|
|
4
|
+
/** Value provided by {@link ELSProvider} and read via {@link useELS}. */
|
|
4
5
|
interface ELSContextValue {
|
|
6
|
+
/** The shared ELS client. */
|
|
5
7
|
client: ELSClient;
|
|
8
|
+
/** The batching queue, or `null` when `useQueue` is disabled. */
|
|
6
9
|
queue: ELSQueue | null;
|
|
7
10
|
}
|
|
11
|
+
/** React context holding the ELS client/queue. Prefer the {@link useELS} hook. */
|
|
8
12
|
declare const ELSContext: React.Context<ELSContextValue | null>;
|
|
13
|
+
/** Props for {@link ELSProvider}. */
|
|
9
14
|
interface ELSProviderProps {
|
|
15
|
+
/** ELS client configuration (only `apiKey` + `appSlug` are required). */
|
|
10
16
|
config: ELSConfig;
|
|
11
|
-
/**
|
|
17
|
+
/** Use a batching queue. Default: `true`. */
|
|
12
18
|
useQueue?: boolean;
|
|
13
|
-
/**
|
|
19
|
+
/** Queue auto-flush interval, in ms. */
|
|
14
20
|
flushIntervalMs?: number;
|
|
15
|
-
/**
|
|
21
|
+
/** Max entries buffered before an early flush. */
|
|
16
22
|
maxBatchSize?: number;
|
|
17
|
-
/**
|
|
23
|
+
/** Auto-subscribe to `window.onerror` and `unhandledrejection`. Default: `true`. */
|
|
18
24
|
captureGlobalErrors?: boolean;
|
|
19
25
|
children?: React.ReactNode;
|
|
20
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Provides a single ELS client (and optional queue) to the React tree and, by
|
|
29
|
+
* default, captures uncaught errors and unhandled promise rejections. Wrap your
|
|
30
|
+
* app once near the root.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <ELSProvider config={{ apiKey: "els_live_…", appSlug: "web" }}>
|
|
34
|
+
* <App />
|
|
35
|
+
* </ELSProvider>
|
|
36
|
+
*/
|
|
21
37
|
declare const ELSProvider: React.FC<ELSProviderProps>;
|
|
22
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Returns the ELS `client` and `queue` from the nearest {@link ELSProvider}.
|
|
41
|
+
* Throws if no provider is present.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const { client } = useELS();
|
|
45
|
+
* client.info("dashboard opened");
|
|
46
|
+
*/
|
|
23
47
|
declare function useELS(): ELSContextValue;
|
|
24
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Returns a stable `report(error, extra?)` callback that sends an error to ELS
|
|
51
|
+
* (through the provider's queue when enabled). Use it for handled/caught errors.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const report = useErrorReporter();
|
|
55
|
+
* try { await save(); } catch (e) { report(e, { url: "/save" }); }
|
|
56
|
+
*/
|
|
25
57
|
declare function useErrorReporter(): (err: unknown, extra?: Partial<ErrorEntry>) => void;
|
|
26
58
|
|
|
59
|
+
/** Props for {@link ELSErrorBoundary}. */
|
|
27
60
|
interface ELSErrorBoundaryProps {
|
|
61
|
+
/** Rendered when a child throws. A function receives the caught error. */
|
|
28
62
|
fallback?: React.ReactNode | ((error: Error) => React.ReactNode);
|
|
63
|
+
/** Called in addition to reporting, e.g. for custom logging. */
|
|
29
64
|
onError?: (error: Error, info: React.ErrorInfo) => void;
|
|
30
65
|
children?: React.ReactNode;
|
|
31
66
|
}
|
|
32
67
|
interface State {
|
|
33
68
|
error: Error | null;
|
|
34
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Error boundary that reports render errors (with component stack) to ELS via
|
|
72
|
+
* the surrounding {@link ELSProvider} and shows an optional `fallback`.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* <ELSErrorBoundary fallback={<p>Something went wrong</p>}>
|
|
76
|
+
* <Dashboard />
|
|
77
|
+
* </ELSErrorBoundary>
|
|
78
|
+
*/
|
|
35
79
|
declare class ELSErrorBoundary extends React.Component<ELSErrorBoundaryProps, State> {
|
|
36
80
|
static contextType: React.Context<ELSContextValue | null>;
|
|
37
81
|
context: React.ContextType<typeof ELSContext>;
|
|
@@ -41,6 +85,12 @@ declare class ELSErrorBoundary extends React.Component<ELSErrorBoundaryProps, St
|
|
|
41
85
|
render(): React.ReactNode;
|
|
42
86
|
}
|
|
43
87
|
|
|
88
|
+
/**
|
|
89
|
+
* HOC that wraps a component in an {@link ELSErrorBoundary}.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* export default withErrorReporting(Dashboard, { fallback: <ErrorPage /> });
|
|
93
|
+
*/
|
|
44
94
|
declare function withErrorReporting<P extends object>(Component: React.ComponentType<P>, boundaryProps?: Omit<ELSErrorBoundaryProps, "children">): React.FC<P>;
|
|
45
95
|
|
|
46
96
|
export { ELSContext, ELSErrorBoundary, ELSProvider, type ELSProviderProps, useELS, useErrorReporter, withErrorReporting };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,37 +1,81 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ELSClient, ELSQueue, ELSConfig, ErrorEntry } from '@inso_web/els-client';
|
|
3
3
|
|
|
4
|
+
/** Value provided by {@link ELSProvider} and read via {@link useELS}. */
|
|
4
5
|
interface ELSContextValue {
|
|
6
|
+
/** The shared ELS client. */
|
|
5
7
|
client: ELSClient;
|
|
8
|
+
/** The batching queue, or `null` when `useQueue` is disabled. */
|
|
6
9
|
queue: ELSQueue | null;
|
|
7
10
|
}
|
|
11
|
+
/** React context holding the ELS client/queue. Prefer the {@link useELS} hook. */
|
|
8
12
|
declare const ELSContext: React.Context<ELSContextValue | null>;
|
|
13
|
+
/** Props for {@link ELSProvider}. */
|
|
9
14
|
interface ELSProviderProps {
|
|
15
|
+
/** ELS client configuration (only `apiKey` + `appSlug` are required). */
|
|
10
16
|
config: ELSConfig;
|
|
11
|
-
/**
|
|
17
|
+
/** Use a batching queue. Default: `true`. */
|
|
12
18
|
useQueue?: boolean;
|
|
13
|
-
/**
|
|
19
|
+
/** Queue auto-flush interval, in ms. */
|
|
14
20
|
flushIntervalMs?: number;
|
|
15
|
-
/**
|
|
21
|
+
/** Max entries buffered before an early flush. */
|
|
16
22
|
maxBatchSize?: number;
|
|
17
|
-
/**
|
|
23
|
+
/** Auto-subscribe to `window.onerror` and `unhandledrejection`. Default: `true`. */
|
|
18
24
|
captureGlobalErrors?: boolean;
|
|
19
25
|
children?: React.ReactNode;
|
|
20
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Provides a single ELS client (and optional queue) to the React tree and, by
|
|
29
|
+
* default, captures uncaught errors and unhandled promise rejections. Wrap your
|
|
30
|
+
* app once near the root.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <ELSProvider config={{ apiKey: "els_live_…", appSlug: "web" }}>
|
|
34
|
+
* <App />
|
|
35
|
+
* </ELSProvider>
|
|
36
|
+
*/
|
|
21
37
|
declare const ELSProvider: React.FC<ELSProviderProps>;
|
|
22
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Returns the ELS `client` and `queue` from the nearest {@link ELSProvider}.
|
|
41
|
+
* Throws if no provider is present.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const { client } = useELS();
|
|
45
|
+
* client.info("dashboard opened");
|
|
46
|
+
*/
|
|
23
47
|
declare function useELS(): ELSContextValue;
|
|
24
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Returns a stable `report(error, extra?)` callback that sends an error to ELS
|
|
51
|
+
* (through the provider's queue when enabled). Use it for handled/caught errors.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const report = useErrorReporter();
|
|
55
|
+
* try { await save(); } catch (e) { report(e, { url: "/save" }); }
|
|
56
|
+
*/
|
|
25
57
|
declare function useErrorReporter(): (err: unknown, extra?: Partial<ErrorEntry>) => void;
|
|
26
58
|
|
|
59
|
+
/** Props for {@link ELSErrorBoundary}. */
|
|
27
60
|
interface ELSErrorBoundaryProps {
|
|
61
|
+
/** Rendered when a child throws. A function receives the caught error. */
|
|
28
62
|
fallback?: React.ReactNode | ((error: Error) => React.ReactNode);
|
|
63
|
+
/** Called in addition to reporting, e.g. for custom logging. */
|
|
29
64
|
onError?: (error: Error, info: React.ErrorInfo) => void;
|
|
30
65
|
children?: React.ReactNode;
|
|
31
66
|
}
|
|
32
67
|
interface State {
|
|
33
68
|
error: Error | null;
|
|
34
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Error boundary that reports render errors (with component stack) to ELS via
|
|
72
|
+
* the surrounding {@link ELSProvider} and shows an optional `fallback`.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* <ELSErrorBoundary fallback={<p>Something went wrong</p>}>
|
|
76
|
+
* <Dashboard />
|
|
77
|
+
* </ELSErrorBoundary>
|
|
78
|
+
*/
|
|
35
79
|
declare class ELSErrorBoundary extends React.Component<ELSErrorBoundaryProps, State> {
|
|
36
80
|
static contextType: React.Context<ELSContextValue | null>;
|
|
37
81
|
context: React.ContextType<typeof ELSContext>;
|
|
@@ -41,6 +85,12 @@ declare class ELSErrorBoundary extends React.Component<ELSErrorBoundaryProps, St
|
|
|
41
85
|
render(): React.ReactNode;
|
|
42
86
|
}
|
|
43
87
|
|
|
88
|
+
/**
|
|
89
|
+
* HOC that wraps a component in an {@link ELSErrorBoundary}.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* export default withErrorReporting(Dashboard, { fallback: <ErrorPage /> });
|
|
93
|
+
*/
|
|
44
94
|
declare function withErrorReporting<P extends object>(Component: React.ComponentType<P>, boundaryProps?: Omit<ELSErrorBoundaryProps, "children">): React.FC<P>;
|
|
45
95
|
|
|
46
96
|
export { ELSContext, ELSErrorBoundary, ELSProvider, type ELSProviderProps, useELS, useErrorReporter, withErrorReporting };
|
package/dist/index.js
CHANGED
|
@@ -21,10 +21,8 @@ var ELSProvider = ({
|
|
|
21
21
|
const onError = (event) => {
|
|
22
22
|
const entry = {
|
|
23
23
|
message: event.message || "window.onerror",
|
|
24
|
-
url: typeof location !== "undefined" ? location.href : "",
|
|
25
24
|
stack: event.error?.stack,
|
|
26
|
-
level: "error"
|
|
27
|
-
source: "client"
|
|
25
|
+
level: "error"
|
|
28
26
|
};
|
|
29
27
|
if (value.queue) value.queue.enqueue(entry);
|
|
30
28
|
else void value.client.sendError(entry);
|
|
@@ -33,10 +31,8 @@ var ELSProvider = ({
|
|
|
33
31
|
const reason = event.reason;
|
|
34
32
|
const entry = {
|
|
35
33
|
message: String(reason?.message ?? reason ?? "unhandledrejection"),
|
|
36
|
-
url: typeof location !== "undefined" ? location.href : "",
|
|
37
34
|
stack: reason?.stack,
|
|
38
|
-
level: "error"
|
|
39
|
-
source: "client"
|
|
35
|
+
level: "error"
|
|
40
36
|
};
|
|
41
37
|
if (value.queue) value.queue.enqueue(entry);
|
|
42
38
|
else void value.client.sendError(entry);
|
|
@@ -62,7 +58,7 @@ function useELS() {
|
|
|
62
58
|
const ctx = React2.useContext(ELSContext);
|
|
63
59
|
if (!ctx) {
|
|
64
60
|
throw new Error(
|
|
65
|
-
"useELS: ELSProvider
|
|
61
|
+
"useELS: no ELSProvider found. Wrap your app in <ELSProvider>."
|
|
66
62
|
);
|
|
67
63
|
}
|
|
68
64
|
return ctx;
|
|
@@ -78,9 +74,7 @@ function useErrorReporter() {
|
|
|
78
74
|
const entry = {
|
|
79
75
|
message: e?.message ?? String(err),
|
|
80
76
|
stack: e?.stack,
|
|
81
|
-
url: typeof location !== "undefined" ? location.href : extra?.url ?? "",
|
|
82
77
|
level: "error",
|
|
83
|
-
source: "client",
|
|
84
78
|
...extra
|
|
85
79
|
};
|
|
86
80
|
if (queue) queue.enqueue(entry);
|
|
@@ -108,9 +102,7 @@ var ELSErrorBoundary = class extends React4.Component {
|
|
|
108
102
|
message: error.message,
|
|
109
103
|
stack: error.stack,
|
|
110
104
|
componentStack: info.componentStack ?? void 0,
|
|
111
|
-
|
|
112
|
-
level: "error",
|
|
113
|
-
source: "client"
|
|
105
|
+
level: "error"
|
|
114
106
|
};
|
|
115
107
|
if (ctx.queue) ctx.queue.enqueue(entry);
|
|
116
108
|
else void ctx.client.sendError(entry);
|
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\nexport interface ELSContextValue {\n client: ELSClient;\n queue: ELSQueue | null;\n}\n\nexport const ELSContext = React.createContext<ELSContextValue | null>(null);\n\nexport interface ELSProviderProps {\n config: ELSConfig;\n /** Включить очередь с батчингом. По умолчанию true. */\n useQueue?: boolean;\n /** Интервал авто‑флаша очереди в мс. */\n flushIntervalMs?: number;\n /** Максимальный размер батча. */\n maxBatchSize?: number;\n /** Авто‑подписка на window.onerror и unhandledrejection. По умолчанию true. */\n captureGlobalErrors?: boolean;\n children?: React.ReactNode;\n}\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 url: typeof location !== \"undefined\" ? location.href : \"\",\n stack: event.error?.stack,\n level: \"error\" as const,\n source: \"client\" 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 url: typeof location !== \"undefined\" ? location.href : \"\",\n stack: reason?.stack,\n level: \"error\" as const,\n source: \"client\" 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\nexport function useELS(): ELSContextValue {\n const ctx = React.useContext(ELSContext);\n if (!ctx) {\n throw new Error(\n \"useELS: ELSProvider не найден. Оберните приложение в <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\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 url:\n typeof location !== \"undefined\" ? location.href : extra?.url ?? \"\",\n level: \"error\",\n source: \"client\",\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\nexport interface ELSErrorBoundaryProps {\n fallback?: React.ReactNode | ((error: Error) => React.ReactNode);\n onError?: (error: Error, info: React.ErrorInfo) => void;\n children?: React.ReactNode;\n}\n\ninterface State {\n error: Error | null;\n}\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 url: typeof location !== \"undefined\" ? location.href : \"\",\n level: \"error\" as const,\n source: \"client\" 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\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 } 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":";AAAA,YAAY,WAAW;AACvB,SAAS,WAAW,gBAAgB;AA8F3B;AAlFF,IAAM,aAAmB,oBAAsC,IAAI;AA2BnE,IAAM,cAA0C,CAAC;AAAA,EACtD;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB;AACF,MAAM;AACJ,QAAM,QAAc,cAAyB,MAAM;AACjD,UAAM,SAAS,IAAI,UAAU,MAAM;AACnC,UAAM,QAAQ,WACV,IAAI,SAAS,QAAQ,EAAE,iBAAiB,aAAa,CAAC,IACtD;AACJ,WAAO,EAAE,QAAQ,MAAM;AAAA,EAEzB,GAAG,CAAC,CAAC;AAEL,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,uBAAuB,OAAO,WAAW,YAAa;AAE3D,UAAM,UAAU,CAAC,UAAsB;AACrC,YAAM,QAAQ;AAAA,QACZ,SAAS,MAAM,WAAW;AAAA,QAC1B,OAAO,MAAM,OAAO;AAAA,QACpB,OAAO;AAAA,MACT;AACA,UAAI,MAAM,MAAO,OAAM,MAAM,QAAQ,KAAK;AAAA,UACrC,MAAK,MAAM,OAAO,UAAU,KAAK;AAAA,IACxC;AAEA,UAAM,cAAc,CAAC,UAAiC;AACpD,YAAM,SAAS,MAAM;AACrB,YAAM,QAAQ;AAAA,QACZ,SAAS,OAAO,QAAQ,WAAW,UAAU,oBAAoB;AAAA,QACjE,OAAO,QAAQ;AAAA,QACf,OAAO;AAAA,MACT;AACA,UAAI,MAAM,MAAO,OAAM,MAAM,QAAQ,KAAK;AAAA,UACrC,MAAK,MAAM,OAAO,UAAU,KAAK;AAAA,IACxC;AAEA,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,sBAAsB,WAAW;AACzD,WAAO,MAAM;AACX,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,sBAAsB,WAAW;AAAA,IAC9D;AAAA,EACF,GAAG,CAAC,qBAAqB,KAAK,CAAC;AAE/B,EAAM,gBAAU,MAAM;AACpB,WAAO,MAAM;AACX,YAAM,OAAO,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO,oBAAC,WAAW,UAAX,EAAoB,OAAe,UAAS;AACtD;;;AChGA,YAAYA,YAAW;AAYhB,SAAS,SAA0B;AACxC,QAAM,MAAY,kBAAW,UAAU;AACvC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;ACpBA,YAAYC,YAAW;AAYhB,SAAS,mBAAmB;AACjC,QAAM,EAAE,QAAQ,MAAM,IAAI,OAAO;AAEjC,SAAa;AAAA,IACX,CAAC,KAAc,UAAgC;AAC7C,YAAM,IAAI;AACV,YAAM,QAAoB;AAAA,QACxB,SAAS,GAAG,WAAW,OAAO,GAAG;AAAA,QACjC,OAAO,GAAG;AAAA,QACV,OAAO;AAAA,QACP,GAAG;AAAA,MACL;AACA,UAAI,MAAO,OAAM,QAAQ,KAAK;AAAA,UACzB,MAAK,OAAO,UAAU,KAAK;AAAA,IAClC;AAAA,IACA,CAAC,QAAQ,KAAK;AAAA,EAChB;AACF;;;AC7BA,YAAYC,YAAW;AAyBhB,IAAM,mBAAN,cAAqC,iBAG1C;AAAA,EAHK;AAAA;AAOL,iBAAe,EAAE,OAAO,KAAK;AAAA;AAAA,EAE7B,OAAO,yBAAyB,OAAqB;AACnD,WAAO,EAAE,MAAM;AAAA,EACjB;AAAA,EAEA,kBAAkB,OAAc,MAAuB;AACrD,SAAK,MAAM,UAAU,OAAO,IAAI;AAChC,UAAM,MAAM,KAAK;AACjB,QAAI,CAAC,IAAK;AACV,UAAM,QAAQ;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb,gBAAgB,KAAK,kBAAkB;AAAA,MACvC,OAAO;AAAA,IACT;AACA,QAAI,IAAI,MAAO,KAAI,MAAM,QAAQ,KAAK;AAAA,QACjC,MAAK,IAAI,OAAO,UAAU,KAAK;AAAA,EACtC;AAAA,EAEA,SAAS;AACP,QAAI,KAAK,MAAM,OAAO;AACpB,YAAM,EAAE,SAAS,IAAI,KAAK;AAC1B,UAAI,OAAO,aAAa,WAAY,QAAO,SAAS,KAAK,MAAM,KAAK;AACpE,aAAO,YAAY;AAAA,IACrB;AACA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAnCa,iBAIJ,cAAc;;;ACbjB,gBAAAC,YAAA;AANC,SAAS,mBACdC,YACA,eACa;AACb,QAAM,UAAuB,CAAC,UAC5B,gBAAAD,KAAC,oBAAkB,GAAG,eACpB,0BAAAA,KAACC,YAAA,EAAW,GAAG,OAAO,GACxB;AAEF,UAAQ,cAAc,sBACpBA,WAAU,eAAeA,WAAU,QAAQ,WAC7C;AACA,SAAO;AACT;","names":["React","React","React","jsx","Component"]}
|
|
@@ -8,7 +8,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
8
8
|
<React.StrictMode>
|
|
9
9
|
<ELSProvider
|
|
10
10
|
config={{
|
|
11
|
-
endpoint: import.meta.env.VITE_ELS_URL || 'https://api.insoweb.ru/els',
|
|
12
11
|
apiKey: import.meta.env.VITE_ELS_API_KEY || 'els_live_xxxxxxxx',
|
|
13
12
|
appSlug: 'examples',
|
|
14
13
|
deploymentEnv: 'DEV',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inso_web/els-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "React‑обёртка для Error Logs Service (ELS): Provider, hooks, ErrorBoundary и HOC для автоматического репорта ошибок компонентов.",
|
|
5
5
|
"homepage": "https://api.insoweb.ru/els",
|
|
6
6
|
"author": "INSOWEB",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"react": ">=17.0.0"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@inso_web/els-client": "^0.
|
|
54
|
+
"@inso_web/els-client": "^0.5.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@testing-library/react": "^14.1.2",
|