@docx-editor.dev/telemetry 0.0.1 → 2.29.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 +85 -7
- package/THIRD_PARTY_NOTICES.md +22 -0
- package/dist/chunk-73YEPWY5.js +1 -0
- package/dist/chunk-7ZXJ6HP2.cjs +1 -0
- package/dist/chunk-DT2KMPUJ.js +1 -0
- package/dist/chunk-DTEVX2XS.js +1 -0
- package/dist/chunk-LFQSY2TD.cjs +1 -0
- package/dist/chunk-LFX65QJG.js +4 -0
- package/dist/chunk-LGNT4I5W.cjs +1 -0
- package/dist/chunk-MJX3ECH3.cjs +4 -0
- package/dist/chunk-NUN46EXH.js +2 -0
- package/dist/chunk-RRYW7EAV.js +1 -0
- package/dist/chunk-S7KBMROA.js +1 -0
- package/dist/chunk-U6ERFNUM.cjs +1 -0
- package/dist/chunk-UK2MNJCG.cjs +2 -0
- package/dist/chunk-WGWKNKUT.cjs +1 -0
- package/dist/hocuspocus/index.cjs +1 -0
- package/dist/hocuspocus/index.d.cts +118 -0
- package/dist/hocuspocus/index.d.ts +118 -0
- package/dist/hocuspocus/index.js +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +332 -0
- package/dist/index.d.ts +332 -0
- package/dist/index.js +1 -0
- package/dist/ingest/index.cjs +1 -0
- package/dist/ingest/index.d.cts +107 -0
- package/dist/ingest/index.d.ts +107 -0
- package/dist/ingest/index.js +1 -0
- package/dist/otel/index.cjs +1 -0
- package/dist/otel/index.d.cts +57 -0
- package/dist/otel/index.d.ts +57 -0
- package/dist/otel/index.js +1 -0
- package/dist/pipeline-DbVW7S-K.d.cts +223 -0
- package/dist/pipeline-DbVW7S-K.d.ts +223 -0
- package/dist/prometheus/index.cjs +1 -0
- package/dist/prometheus/index.d.cts +88 -0
- package/dist/prometheus/index.d.ts +88 -0
- package/dist/prometheus/index.js +1 -0
- package/dist/sentry/index.cjs +1 -0
- package/dist/sentry/index.d.cts +134 -0
- package/dist/sentry/index.d.ts +134 -0
- package/dist/sentry/index.js +1 -0
- package/dist/server/index.cjs +1 -0
- package/dist/server/index.d.cts +156 -0
- package/dist/server/index.d.ts +156 -0
- package/dist/server/index.js +1 -0
- package/package.json +100 -16
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymous diagnostics, metrics, and error reporting for editors and collaboration servers.
|
|
3
|
+
*
|
|
4
|
+
* - `@docx-editor.dev/telemetry`: {@link createTelemetry} for editors, the console, callback,
|
|
5
|
+
* memory, and HTTP exporters, and {@link browserPrivacySignals}.
|
|
6
|
+
* - `@docx-editor.dev/telemetry/ingest`: a route that receives telemetry from `httpExporter`
|
|
7
|
+
* and forwards it to a log service.
|
|
8
|
+
* - `@docx-editor.dev/telemetry/otel`: OpenTelemetry metrics and traces through your SDK.
|
|
9
|
+
* - `@docx-editor.dev/telemetry/sentry`: Sentry issues and breadcrumbs.
|
|
10
|
+
* - `@docx-editor.dev/telemetry/prometheus`: a `/metrics` endpoint.
|
|
11
|
+
* - `@docx-editor.dev/telemetry/server`: room telemetry for any Yjs server.
|
|
12
|
+
* - `@docx-editor.dev/telemetry/hocuspocus`: room telemetry for Hocuspocus in one call.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
import { EditorModule, EditorDiagnostic } from '@docx-editor.dev/core';
|
|
17
|
+
export { ByteSizeBucket, CollaborationDiagnosticCode, CollaborationParticipantsDiagnostic, CollaborationStatusDiagnostic, CountBucket, CustomNodeDiagnosticCode, CustomNodeDiagnosticEvent, DiagnosticBase, DiagnosticCode, DiagnosticErrorName, DiagnosticExplanation, DiagnosticFailureDetail, DocumentOpenDiagnostic, DocumentOpenDiagnosticCode, DocumentPartKind, DocumentShape, EditDiagnosticCode, EditRejectedDiagnostic, EditRejectionOrigin, EditorDiagnostic, EditorDiagnosticKind, FailureStage, FontDiagnosticCode, FontFailedDiagnostic, FormattingChangeKind, HistoryDiagnosticCode, HistoryDiagnosticEvent, PerformanceDiagnostic, PerformanceDiagnosticCode, ReviewChangeKind, ReviewDiagnosticCode, ReviewOperation, ReviewSkippedDiagnostic, TimingSummary, explainDiagnostic } from '@docx-editor.dev/core';
|
|
18
|
+
import { A as Attributes, T as TelemetryPipelineOptions, a as TelemetryEvent, b as TelemetryExporter, M as MetricRecord } from './pipeline-DbVW7S-K.cjs';
|
|
19
|
+
export { c as AttributeValue, E as ENGINE_VERSION, d as MAX_METRIC_LABEL_VALUES, e as METRICS, f as MetricDefinition, g as MetricId, h as MetricKind, i as TelemetryEventContext, j as TelemetryExporterContext, p as prometheusName } from './pipeline-DbVW7S-K.cjs';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The areas you can switch on. Each one selects diagnostic kinds:
|
|
23
|
+
*
|
|
24
|
+
* - `documentOpen`: documents opened and refused (`document.open`).
|
|
25
|
+
* - `editing`: edits and commands refused while changes are not tracked (`edit.rejected`).
|
|
26
|
+
* - `trackedChanges`: refusals while suggesting, refusals about tracking itself, and skipped
|
|
27
|
+
* tracked changes
|
|
28
|
+
* (`edit.rejected` with `tracked: true`, `review.skipped`).
|
|
29
|
+
* - `fonts`: fonts that failed and were substituted (`font.failed`).
|
|
30
|
+
* - `history`: undo steps that did not group as the gesture intended (`history`).
|
|
31
|
+
* - `customNodes`: custom node payloads that could not be read (`custom-node`).
|
|
32
|
+
* - `collaborationClient`: collaboration status changes and room size (`collab.*`).
|
|
33
|
+
* - `performance`: how fast the editor responds: key presses and clicks to the next frame,
|
|
34
|
+
* and engine layout and paint times, as one summary per minute of use (`performance`).
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
type TelemetryArea = 'documentOpen' | 'editing' | 'trackedChanges' | 'fonts' | 'history' | 'customNodes' | 'collaborationClient' | 'performance';
|
|
39
|
+
/** Options for one area. @public */
|
|
40
|
+
interface TelemetryAreaOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Share of events to send, from 0 to 1. Metrics count every event, except that a
|
|
43
|
+
* `performance` rate of 0 turns performance off, metrics included. Defaults to 1.
|
|
44
|
+
* Each event is sampled on its own, except in `performance`: there the choice is made once
|
|
45
|
+
* for each editor, which sends all of its summaries or none.
|
|
46
|
+
*/
|
|
47
|
+
readonly sampleRate?: number;
|
|
48
|
+
}
|
|
49
|
+
/** Which areas to record. An area that is absent or `false` records nothing. @public */
|
|
50
|
+
type TelemetryInclude = {
|
|
51
|
+
readonly [A in TelemetryArea]?: boolean | TelemetryAreaOptions;
|
|
52
|
+
};
|
|
53
|
+
/** Options for {@link createTelemetry}. @public */
|
|
54
|
+
interface TelemetryOptions extends TelemetryPipelineOptions {
|
|
55
|
+
/**
|
|
56
|
+
* The areas to record. Omitted, every area is on.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* include: { documentOpen: true, trackedChanges: true, editing: { sampleRate: 0.2 } }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
readonly include?: TelemetryInclude;
|
|
64
|
+
/**
|
|
65
|
+
* Identical refusals inside this window are sent once, then summarized with `repeated`.
|
|
66
|
+
* Holding Backspace on a locked drawing is one event, not hundreds. Defaults to 10 000 ms.
|
|
67
|
+
* Set 0 to send every event.
|
|
68
|
+
*/
|
|
69
|
+
readonly dedupeWindowMs?: number;
|
|
70
|
+
/**
|
|
71
|
+
* How much of an opened document's shape to send. `'basic'`, the default, sends the size and
|
|
72
|
+
* page buckets. `'detailed'` also sends part, paragraph, review item, and embedded font
|
|
73
|
+
* buckets: useful to group open times, but several counts together describe a document more
|
|
74
|
+
* closely, so ask for it only when you need it.
|
|
75
|
+
*/
|
|
76
|
+
readonly documentShape?: 'basic' | 'detailed';
|
|
77
|
+
/**
|
|
78
|
+
* Your identifiers on every event, such as a tenant or a pseudonymous user id. A function is
|
|
79
|
+
* read at each event, so it can follow sign-in and tenant switches. Events only: to label
|
|
80
|
+
* metrics with a key, list it in `metricLabels`. For values that belong to one editor, such as
|
|
81
|
+
* its room or document, use {@link Telemetry.moduleFor}.
|
|
82
|
+
*
|
|
83
|
+
* These values are yours and go only to your exporters. Keys follow attribute rules: letters,
|
|
84
|
+
* digits, `_`, `.`, and `-`, up to 64 characters. Values are strings, numbers, or booleans;
|
|
85
|
+
* strings are cut at 256 characters.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* attributes: () => ({ 'tenant.id': session.tenantId, 'user.id': session.pseudonymousId })
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
readonly attributes?: Attributes | (() => Attributes);
|
|
93
|
+
/**
|
|
94
|
+
* Which events go to your exporters, after the privacy check and sampling. Metrics still count
|
|
95
|
+
* every event. A filter that throws drops the event.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* // Failures and performance summaries only: no event for an open that succeeded.
|
|
100
|
+
* filter: (event) => isFailure(event) || event.kind === 'performance'
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
readonly filter?: (event: TelemetryEvent) => boolean;
|
|
104
|
+
}
|
|
105
|
+
/** A configured telemetry client. Create it once, outside any component. @public */
|
|
106
|
+
interface Telemetry {
|
|
107
|
+
/**
|
|
108
|
+
* Register this in the editor's `modules`. It observes every editor created with it, from
|
|
109
|
+
* the first open on.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* const MODULES = [reviewModule(), telemetry.module];
|
|
114
|
+
* <DocxEditor document={bytes} modules={MODULES} />;
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
readonly module: EditorModule;
|
|
118
|
+
/**
|
|
119
|
+
* A module for one editor, whose events also carry `attributes`, such as its collaboration
|
|
120
|
+
* room, document, or workspace. Create one for each editor, and keep it stable across renders.
|
|
121
|
+
* Use it in place of `module`, not next to it.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```tsx
|
|
125
|
+
* const modules = useMemo(
|
|
126
|
+
* () => [reviewModule(), telemetry.moduleFor({ 'room.id': roomId, 'document.id': documentId })],
|
|
127
|
+
* [roomId, documentId]
|
|
128
|
+
* );
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
moduleFor(attributes: Attributes): EditorModule;
|
|
132
|
+
/**
|
|
133
|
+
* Record one diagnostic yourself, for example from a runtime you created without `module`.
|
|
134
|
+
* Use `module` or `record`, not both, or every event is recorded twice. `attributes` are added
|
|
135
|
+
* to this event, as `moduleFor` adds them.
|
|
136
|
+
*/
|
|
137
|
+
record(event: EditorDiagnostic, attributes?: Attributes): void;
|
|
138
|
+
/** Send summaries of open deduplication windows, then flush every exporter. */
|
|
139
|
+
flush(): Promise<void>;
|
|
140
|
+
/** Flush, then stop. Later events are dropped. */
|
|
141
|
+
shutdown(): Promise<void>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create a telemetry client for editors.
|
|
145
|
+
*
|
|
146
|
+
* Nothing is sent unless you pass an exporter. With `consent`, nothing is sent while it is
|
|
147
|
+
* false; without it, events are sent. Every event is anonymous: codes, enums, and bucketed
|
|
148
|
+
* numbers only.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { createTelemetry, consoleExporter } from '@docx-editor.dev/telemetry';
|
|
153
|
+
*
|
|
154
|
+
* export const telemetry = createTelemetry({
|
|
155
|
+
* exporters: [consoleExporter()],
|
|
156
|
+
* include: { documentOpen: true, trackedChanges: true },
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @public
|
|
161
|
+
*/
|
|
162
|
+
declare function createTelemetry(options: TelemetryOptions): Telemetry;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Sending telemetry to your own HTTP endpoint from a browser, and reading the browser's privacy
|
|
166
|
+
* signals. No dependency: `fetch`, `sendBeacon`, and `localStorage` only.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/** Options for {@link httpExporter}. @public */
|
|
170
|
+
interface HttpExporterOptions {
|
|
171
|
+
/**
|
|
172
|
+
* Where to POST. Use a route on your own origin, which then forwards to your log service, so
|
|
173
|
+
* the service's token never reaches the browser. See `@docx-editor.dev/telemetry/ingest`.
|
|
174
|
+
*/
|
|
175
|
+
readonly url: string;
|
|
176
|
+
/**
|
|
177
|
+
* Events per request, from 1 to 50. Defaults to 20. A full batch is sent at once. The limit
|
|
178
|
+
* matches the default `maxEvents` of `telemetryRoute`, which refuses a longer list.
|
|
179
|
+
*/
|
|
180
|
+
readonly batchSize?: number;
|
|
181
|
+
/** How long an event waits for its batch to fill, in milliseconds. Defaults to 10 000. */
|
|
182
|
+
readonly flushIntervalMs?: number;
|
|
183
|
+
/**
|
|
184
|
+
* Extra request headers. A browser cannot set headers on `sendBeacon`, so with headers, the
|
|
185
|
+
* batches sent while the page closes use `fetch` with `keepalive` instead.
|
|
186
|
+
*/
|
|
187
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
188
|
+
/**
|
|
189
|
+
* Called when a request fails, or when batches are dropped because the page closed with more
|
|
190
|
+
* than the browser lets it send. Telemetry never throws into your app.
|
|
191
|
+
*/
|
|
192
|
+
readonly onError?: (error: unknown) => void;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Batch events and POST them as a JSON array to your own endpoint.
|
|
196
|
+
*
|
|
197
|
+
* While the page is open, events wait up to `flushIntervalMs` for a batch of `batchSize`, and
|
|
198
|
+
* each batch goes out with an ordinary `fetch`; so does a `telemetry.flush()` you call. When the
|
|
199
|
+
* page is hidden or closes, everything waiting goes out with `sendBeacon`. A closing page may
|
|
200
|
+
* send only about 64 KiB in all, so delivery while closing is best effort: batches beyond that
|
|
201
|
+
* are dropped and reported to `onError`. If consent is withdrawn, events still waiting are
|
|
202
|
+
* discarded.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* import { createTelemetry, httpExporter } from '@docx-editor.dev/telemetry';
|
|
207
|
+
*
|
|
208
|
+
* export const telemetry = createTelemetry({
|
|
209
|
+
* exporters: [httpExporter({ url: '/api/telemetry' })],
|
|
210
|
+
* include: { documentOpen: true, editing: true, trackedChanges: true, performance: true },
|
|
211
|
+
* });
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @public
|
|
215
|
+
*/
|
|
216
|
+
declare function httpExporter(options: HttpExporterOptions): TelemetryExporter;
|
|
217
|
+
/** Options for {@link browserPrivacySignals}. @public */
|
|
218
|
+
interface BrowserPrivacySignalsOptions {
|
|
219
|
+
/**
|
|
220
|
+
* A `localStorage` key that opts the visitor out when its value is `off`, such as one your
|
|
221
|
+
* privacy settings page writes. Omit it to read only the browser signals.
|
|
222
|
+
*/
|
|
223
|
+
readonly optOutKey?: string;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A `consent` function that follows the browser's privacy signals: it returns `false` when the
|
|
227
|
+
* visitor sends Global Privacy Control or Do Not Track, or when `optOutKey` is set to `off`.
|
|
228
|
+
* Outside a browser page, such as during server rendering, it returns `false`. Combine it with
|
|
229
|
+
* your consent manager when you have one.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* import { browserPrivacySignals, createTelemetry } from '@docx-editor.dev/telemetry';
|
|
234
|
+
*
|
|
235
|
+
* const privacy = browserPrivacySignals({ optOutKey: 'my-app:telemetry' });
|
|
236
|
+
* export const telemetry = createTelemetry({
|
|
237
|
+
* exporters: [],
|
|
238
|
+
* consent: () => privacy() && consentManager.analytics,
|
|
239
|
+
* });
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
declare function browserPrivacySignals(options?: BrowserPrivacySignalsOptions): () => boolean;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Send each event to your own function: Datadog RUM, PostHog, a logger, or an API route.
|
|
248
|
+
*
|
|
249
|
+
* `onMetric` receives every measurement. A performance summary arrives as one histogram sample
|
|
250
|
+
* for each timing in it, at the middle of the timing's band, so the bucket counts are exact.
|
|
251
|
+
* To chart percentiles, read `p50Ms` and `p95Ms` from the `performance` event instead.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* callbackExporter((event) =>
|
|
256
|
+
* isFailure(event)
|
|
257
|
+
* ? datadogRum.addError(new Error(event.kind), event)
|
|
258
|
+
* : datadogRum.addAction(event.kind, event)
|
|
259
|
+
* );
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* @public
|
|
263
|
+
*/
|
|
264
|
+
declare function callbackExporter(onEvent: (event: TelemetryEvent) => void, onMetric?: (record: MetricRecord) => void): TelemetryExporter;
|
|
265
|
+
/** Options for {@link consoleExporter}. @public */
|
|
266
|
+
interface ConsoleExporterOptions {
|
|
267
|
+
/** Also print every metric measurement. Defaults to `false`. */
|
|
268
|
+
readonly metrics?: boolean;
|
|
269
|
+
/** Where to print. Defaults to the global `console`. */
|
|
270
|
+
readonly console?: Pick<Console, 'info' | 'warn'>;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Whether an event is a failure: a refused open, a refused edit other than an expected one
|
|
274
|
+
* (a stale range, a read-only document, protected content, a session or refresh not ready
|
|
275
|
+
* yet), an unreadable payload, a font that did not load, or a collaboration error. A missing
|
|
276
|
+
* font that was substituted and a tracked change someone else already reviewed are not. Use it
|
|
277
|
+
* in a callback to send failures as errors and the rest as actions or logs.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* callbackExporter((event) => {
|
|
282
|
+
* const code = 'code' in event ? event.code : undefined;
|
|
283
|
+
* if (isFailure(event)) myLogger.error(event.kind, { code, hint: event.hint });
|
|
284
|
+
* else myLogger.info(event.kind);
|
|
285
|
+
* });
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
declare function isFailure(event: TelemetryEvent): boolean;
|
|
291
|
+
/**
|
|
292
|
+
* Print each event with its hint and docs link. Use it during development to see why a
|
|
293
|
+
* document did not open or why a tracked change was refused.
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```ts
|
|
297
|
+
* createTelemetry({ exporters: [consoleExporter()] });
|
|
298
|
+
* // An agent deletes a picture while changes are tracked:
|
|
299
|
+
* // [docx-editor] edit refused: edit.tracked-operation-unsupported (automation, tracked)
|
|
300
|
+
* // This editing API operation cannot be recorded as a tracked change, so nothing was ...
|
|
301
|
+
* // https://docx-editor.dev/docs/2.x/guides/diagnostics#edit-tracked-operation-unsupported
|
|
302
|
+
* ```
|
|
303
|
+
*
|
|
304
|
+
* @public
|
|
305
|
+
*/
|
|
306
|
+
declare function consoleExporter(options?: ConsoleExporterOptions): TelemetryExporter;
|
|
307
|
+
/** An exporter that keeps what it receives. Returned by {@link memoryExporter}. @public */
|
|
308
|
+
interface MemoryExporter extends TelemetryExporter {
|
|
309
|
+
readonly events: readonly TelemetryEvent[];
|
|
310
|
+
readonly metrics: readonly MetricRecord[];
|
|
311
|
+
/** Forget everything received so far. */
|
|
312
|
+
clear(): void;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Keep events and metrics in memory, for tests in your own suite.
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```ts
|
|
319
|
+
* const memory = memoryExporter();
|
|
320
|
+
* const telemetry = createTelemetry({ exporters: [memory] });
|
|
321
|
+
* // ...open a file that fails...
|
|
322
|
+
* expect(memory.events).toContainEqual(
|
|
323
|
+
* expect.objectContaining({ code: 'open.missing-main-document' })
|
|
324
|
+
* );
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @public
|
|
328
|
+
*/
|
|
329
|
+
declare function memoryExporter(): MemoryExporter;
|
|
330
|
+
|
|
331
|
+
export { Attributes, MetricRecord, TelemetryEvent, TelemetryExporter, TelemetryPipelineOptions, browserPrivacySignals, callbackExporter, consoleExporter, createTelemetry, httpExporter, isFailure, memoryExporter };
|
|
332
|
+
export type { BrowserPrivacySignalsOptions, ConsoleExporterOptions, HttpExporterOptions, MemoryExporter, Telemetry, TelemetryArea, TelemetryAreaOptions, TelemetryInclude, TelemetryOptions };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymous diagnostics, metrics, and error reporting for editors and collaboration servers.
|
|
3
|
+
*
|
|
4
|
+
* - `@docx-editor.dev/telemetry`: {@link createTelemetry} for editors, the console, callback,
|
|
5
|
+
* memory, and HTTP exporters, and {@link browserPrivacySignals}.
|
|
6
|
+
* - `@docx-editor.dev/telemetry/ingest`: a route that receives telemetry from `httpExporter`
|
|
7
|
+
* and forwards it to a log service.
|
|
8
|
+
* - `@docx-editor.dev/telemetry/otel`: OpenTelemetry metrics and traces through your SDK.
|
|
9
|
+
* - `@docx-editor.dev/telemetry/sentry`: Sentry issues and breadcrumbs.
|
|
10
|
+
* - `@docx-editor.dev/telemetry/prometheus`: a `/metrics` endpoint.
|
|
11
|
+
* - `@docx-editor.dev/telemetry/server`: room telemetry for any Yjs server.
|
|
12
|
+
* - `@docx-editor.dev/telemetry/hocuspocus`: room telemetry for Hocuspocus in one call.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
import { EditorModule, EditorDiagnostic } from '@docx-editor.dev/core';
|
|
17
|
+
export { ByteSizeBucket, CollaborationDiagnosticCode, CollaborationParticipantsDiagnostic, CollaborationStatusDiagnostic, CountBucket, CustomNodeDiagnosticCode, CustomNodeDiagnosticEvent, DiagnosticBase, DiagnosticCode, DiagnosticErrorName, DiagnosticExplanation, DiagnosticFailureDetail, DocumentOpenDiagnostic, DocumentOpenDiagnosticCode, DocumentPartKind, DocumentShape, EditDiagnosticCode, EditRejectedDiagnostic, EditRejectionOrigin, EditorDiagnostic, EditorDiagnosticKind, FailureStage, FontDiagnosticCode, FontFailedDiagnostic, FormattingChangeKind, HistoryDiagnosticCode, HistoryDiagnosticEvent, PerformanceDiagnostic, PerformanceDiagnosticCode, ReviewChangeKind, ReviewDiagnosticCode, ReviewOperation, ReviewSkippedDiagnostic, TimingSummary, explainDiagnostic } from '@docx-editor.dev/core';
|
|
18
|
+
import { A as Attributes, T as TelemetryPipelineOptions, a as TelemetryEvent, b as TelemetryExporter, M as MetricRecord } from './pipeline-DbVW7S-K.js';
|
|
19
|
+
export { c as AttributeValue, E as ENGINE_VERSION, d as MAX_METRIC_LABEL_VALUES, e as METRICS, f as MetricDefinition, g as MetricId, h as MetricKind, i as TelemetryEventContext, j as TelemetryExporterContext, p as prometheusName } from './pipeline-DbVW7S-K.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The areas you can switch on. Each one selects diagnostic kinds:
|
|
23
|
+
*
|
|
24
|
+
* - `documentOpen`: documents opened and refused (`document.open`).
|
|
25
|
+
* - `editing`: edits and commands refused while changes are not tracked (`edit.rejected`).
|
|
26
|
+
* - `trackedChanges`: refusals while suggesting, refusals about tracking itself, and skipped
|
|
27
|
+
* tracked changes
|
|
28
|
+
* (`edit.rejected` with `tracked: true`, `review.skipped`).
|
|
29
|
+
* - `fonts`: fonts that failed and were substituted (`font.failed`).
|
|
30
|
+
* - `history`: undo steps that did not group as the gesture intended (`history`).
|
|
31
|
+
* - `customNodes`: custom node payloads that could not be read (`custom-node`).
|
|
32
|
+
* - `collaborationClient`: collaboration status changes and room size (`collab.*`).
|
|
33
|
+
* - `performance`: how fast the editor responds: key presses and clicks to the next frame,
|
|
34
|
+
* and engine layout and paint times, as one summary per minute of use (`performance`).
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
type TelemetryArea = 'documentOpen' | 'editing' | 'trackedChanges' | 'fonts' | 'history' | 'customNodes' | 'collaborationClient' | 'performance';
|
|
39
|
+
/** Options for one area. @public */
|
|
40
|
+
interface TelemetryAreaOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Share of events to send, from 0 to 1. Metrics count every event, except that a
|
|
43
|
+
* `performance` rate of 0 turns performance off, metrics included. Defaults to 1.
|
|
44
|
+
* Each event is sampled on its own, except in `performance`: there the choice is made once
|
|
45
|
+
* for each editor, which sends all of its summaries or none.
|
|
46
|
+
*/
|
|
47
|
+
readonly sampleRate?: number;
|
|
48
|
+
}
|
|
49
|
+
/** Which areas to record. An area that is absent or `false` records nothing. @public */
|
|
50
|
+
type TelemetryInclude = {
|
|
51
|
+
readonly [A in TelemetryArea]?: boolean | TelemetryAreaOptions;
|
|
52
|
+
};
|
|
53
|
+
/** Options for {@link createTelemetry}. @public */
|
|
54
|
+
interface TelemetryOptions extends TelemetryPipelineOptions {
|
|
55
|
+
/**
|
|
56
|
+
* The areas to record. Omitted, every area is on.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* include: { documentOpen: true, trackedChanges: true, editing: { sampleRate: 0.2 } }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
readonly include?: TelemetryInclude;
|
|
64
|
+
/**
|
|
65
|
+
* Identical refusals inside this window are sent once, then summarized with `repeated`.
|
|
66
|
+
* Holding Backspace on a locked drawing is one event, not hundreds. Defaults to 10 000 ms.
|
|
67
|
+
* Set 0 to send every event.
|
|
68
|
+
*/
|
|
69
|
+
readonly dedupeWindowMs?: number;
|
|
70
|
+
/**
|
|
71
|
+
* How much of an opened document's shape to send. `'basic'`, the default, sends the size and
|
|
72
|
+
* page buckets. `'detailed'` also sends part, paragraph, review item, and embedded font
|
|
73
|
+
* buckets: useful to group open times, but several counts together describe a document more
|
|
74
|
+
* closely, so ask for it only when you need it.
|
|
75
|
+
*/
|
|
76
|
+
readonly documentShape?: 'basic' | 'detailed';
|
|
77
|
+
/**
|
|
78
|
+
* Your identifiers on every event, such as a tenant or a pseudonymous user id. A function is
|
|
79
|
+
* read at each event, so it can follow sign-in and tenant switches. Events only: to label
|
|
80
|
+
* metrics with a key, list it in `metricLabels`. For values that belong to one editor, such as
|
|
81
|
+
* its room or document, use {@link Telemetry.moduleFor}.
|
|
82
|
+
*
|
|
83
|
+
* These values are yours and go only to your exporters. Keys follow attribute rules: letters,
|
|
84
|
+
* digits, `_`, `.`, and `-`, up to 64 characters. Values are strings, numbers, or booleans;
|
|
85
|
+
* strings are cut at 256 characters.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* attributes: () => ({ 'tenant.id': session.tenantId, 'user.id': session.pseudonymousId })
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
readonly attributes?: Attributes | (() => Attributes);
|
|
93
|
+
/**
|
|
94
|
+
* Which events go to your exporters, after the privacy check and sampling. Metrics still count
|
|
95
|
+
* every event. A filter that throws drops the event.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* // Failures and performance summaries only: no event for an open that succeeded.
|
|
100
|
+
* filter: (event) => isFailure(event) || event.kind === 'performance'
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
readonly filter?: (event: TelemetryEvent) => boolean;
|
|
104
|
+
}
|
|
105
|
+
/** A configured telemetry client. Create it once, outside any component. @public */
|
|
106
|
+
interface Telemetry {
|
|
107
|
+
/**
|
|
108
|
+
* Register this in the editor's `modules`. It observes every editor created with it, from
|
|
109
|
+
* the first open on.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* const MODULES = [reviewModule(), telemetry.module];
|
|
114
|
+
* <DocxEditor document={bytes} modules={MODULES} />;
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
readonly module: EditorModule;
|
|
118
|
+
/**
|
|
119
|
+
* A module for one editor, whose events also carry `attributes`, such as its collaboration
|
|
120
|
+
* room, document, or workspace. Create one for each editor, and keep it stable across renders.
|
|
121
|
+
* Use it in place of `module`, not next to it.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```tsx
|
|
125
|
+
* const modules = useMemo(
|
|
126
|
+
* () => [reviewModule(), telemetry.moduleFor({ 'room.id': roomId, 'document.id': documentId })],
|
|
127
|
+
* [roomId, documentId]
|
|
128
|
+
* );
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
moduleFor(attributes: Attributes): EditorModule;
|
|
132
|
+
/**
|
|
133
|
+
* Record one diagnostic yourself, for example from a runtime you created without `module`.
|
|
134
|
+
* Use `module` or `record`, not both, or every event is recorded twice. `attributes` are added
|
|
135
|
+
* to this event, as `moduleFor` adds them.
|
|
136
|
+
*/
|
|
137
|
+
record(event: EditorDiagnostic, attributes?: Attributes): void;
|
|
138
|
+
/** Send summaries of open deduplication windows, then flush every exporter. */
|
|
139
|
+
flush(): Promise<void>;
|
|
140
|
+
/** Flush, then stop. Later events are dropped. */
|
|
141
|
+
shutdown(): Promise<void>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create a telemetry client for editors.
|
|
145
|
+
*
|
|
146
|
+
* Nothing is sent unless you pass an exporter. With `consent`, nothing is sent while it is
|
|
147
|
+
* false; without it, events are sent. Every event is anonymous: codes, enums, and bucketed
|
|
148
|
+
* numbers only.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { createTelemetry, consoleExporter } from '@docx-editor.dev/telemetry';
|
|
153
|
+
*
|
|
154
|
+
* export const telemetry = createTelemetry({
|
|
155
|
+
* exporters: [consoleExporter()],
|
|
156
|
+
* include: { documentOpen: true, trackedChanges: true },
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @public
|
|
161
|
+
*/
|
|
162
|
+
declare function createTelemetry(options: TelemetryOptions): Telemetry;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Sending telemetry to your own HTTP endpoint from a browser, and reading the browser's privacy
|
|
166
|
+
* signals. No dependency: `fetch`, `sendBeacon`, and `localStorage` only.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/** Options for {@link httpExporter}. @public */
|
|
170
|
+
interface HttpExporterOptions {
|
|
171
|
+
/**
|
|
172
|
+
* Where to POST. Use a route on your own origin, which then forwards to your log service, so
|
|
173
|
+
* the service's token never reaches the browser. See `@docx-editor.dev/telemetry/ingest`.
|
|
174
|
+
*/
|
|
175
|
+
readonly url: string;
|
|
176
|
+
/**
|
|
177
|
+
* Events per request, from 1 to 50. Defaults to 20. A full batch is sent at once. The limit
|
|
178
|
+
* matches the default `maxEvents` of `telemetryRoute`, which refuses a longer list.
|
|
179
|
+
*/
|
|
180
|
+
readonly batchSize?: number;
|
|
181
|
+
/** How long an event waits for its batch to fill, in milliseconds. Defaults to 10 000. */
|
|
182
|
+
readonly flushIntervalMs?: number;
|
|
183
|
+
/**
|
|
184
|
+
* Extra request headers. A browser cannot set headers on `sendBeacon`, so with headers, the
|
|
185
|
+
* batches sent while the page closes use `fetch` with `keepalive` instead.
|
|
186
|
+
*/
|
|
187
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
188
|
+
/**
|
|
189
|
+
* Called when a request fails, or when batches are dropped because the page closed with more
|
|
190
|
+
* than the browser lets it send. Telemetry never throws into your app.
|
|
191
|
+
*/
|
|
192
|
+
readonly onError?: (error: unknown) => void;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Batch events and POST them as a JSON array to your own endpoint.
|
|
196
|
+
*
|
|
197
|
+
* While the page is open, events wait up to `flushIntervalMs` for a batch of `batchSize`, and
|
|
198
|
+
* each batch goes out with an ordinary `fetch`; so does a `telemetry.flush()` you call. When the
|
|
199
|
+
* page is hidden or closes, everything waiting goes out with `sendBeacon`. A closing page may
|
|
200
|
+
* send only about 64 KiB in all, so delivery while closing is best effort: batches beyond that
|
|
201
|
+
* are dropped and reported to `onError`. If consent is withdrawn, events still waiting are
|
|
202
|
+
* discarded.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* import { createTelemetry, httpExporter } from '@docx-editor.dev/telemetry';
|
|
207
|
+
*
|
|
208
|
+
* export const telemetry = createTelemetry({
|
|
209
|
+
* exporters: [httpExporter({ url: '/api/telemetry' })],
|
|
210
|
+
* include: { documentOpen: true, editing: true, trackedChanges: true, performance: true },
|
|
211
|
+
* });
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @public
|
|
215
|
+
*/
|
|
216
|
+
declare function httpExporter(options: HttpExporterOptions): TelemetryExporter;
|
|
217
|
+
/** Options for {@link browserPrivacySignals}. @public */
|
|
218
|
+
interface BrowserPrivacySignalsOptions {
|
|
219
|
+
/**
|
|
220
|
+
* A `localStorage` key that opts the visitor out when its value is `off`, such as one your
|
|
221
|
+
* privacy settings page writes. Omit it to read only the browser signals.
|
|
222
|
+
*/
|
|
223
|
+
readonly optOutKey?: string;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A `consent` function that follows the browser's privacy signals: it returns `false` when the
|
|
227
|
+
* visitor sends Global Privacy Control or Do Not Track, or when `optOutKey` is set to `off`.
|
|
228
|
+
* Outside a browser page, such as during server rendering, it returns `false`. Combine it with
|
|
229
|
+
* your consent manager when you have one.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* import { browserPrivacySignals, createTelemetry } from '@docx-editor.dev/telemetry';
|
|
234
|
+
*
|
|
235
|
+
* const privacy = browserPrivacySignals({ optOutKey: 'my-app:telemetry' });
|
|
236
|
+
* export const telemetry = createTelemetry({
|
|
237
|
+
* exporters: [],
|
|
238
|
+
* consent: () => privacy() && consentManager.analytics,
|
|
239
|
+
* });
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
declare function browserPrivacySignals(options?: BrowserPrivacySignalsOptions): () => boolean;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Send each event to your own function: Datadog RUM, PostHog, a logger, or an API route.
|
|
248
|
+
*
|
|
249
|
+
* `onMetric` receives every measurement. A performance summary arrives as one histogram sample
|
|
250
|
+
* for each timing in it, at the middle of the timing's band, so the bucket counts are exact.
|
|
251
|
+
* To chart percentiles, read `p50Ms` and `p95Ms` from the `performance` event instead.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* callbackExporter((event) =>
|
|
256
|
+
* isFailure(event)
|
|
257
|
+
* ? datadogRum.addError(new Error(event.kind), event)
|
|
258
|
+
* : datadogRum.addAction(event.kind, event)
|
|
259
|
+
* );
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* @public
|
|
263
|
+
*/
|
|
264
|
+
declare function callbackExporter(onEvent: (event: TelemetryEvent) => void, onMetric?: (record: MetricRecord) => void): TelemetryExporter;
|
|
265
|
+
/** Options for {@link consoleExporter}. @public */
|
|
266
|
+
interface ConsoleExporterOptions {
|
|
267
|
+
/** Also print every metric measurement. Defaults to `false`. */
|
|
268
|
+
readonly metrics?: boolean;
|
|
269
|
+
/** Where to print. Defaults to the global `console`. */
|
|
270
|
+
readonly console?: Pick<Console, 'info' | 'warn'>;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Whether an event is a failure: a refused open, a refused edit other than an expected one
|
|
274
|
+
* (a stale range, a read-only document, protected content, a session or refresh not ready
|
|
275
|
+
* yet), an unreadable payload, a font that did not load, or a collaboration error. A missing
|
|
276
|
+
* font that was substituted and a tracked change someone else already reviewed are not. Use it
|
|
277
|
+
* in a callback to send failures as errors and the rest as actions or logs.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* callbackExporter((event) => {
|
|
282
|
+
* const code = 'code' in event ? event.code : undefined;
|
|
283
|
+
* if (isFailure(event)) myLogger.error(event.kind, { code, hint: event.hint });
|
|
284
|
+
* else myLogger.info(event.kind);
|
|
285
|
+
* });
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
declare function isFailure(event: TelemetryEvent): boolean;
|
|
291
|
+
/**
|
|
292
|
+
* Print each event with its hint and docs link. Use it during development to see why a
|
|
293
|
+
* document did not open or why a tracked change was refused.
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```ts
|
|
297
|
+
* createTelemetry({ exporters: [consoleExporter()] });
|
|
298
|
+
* // An agent deletes a picture while changes are tracked:
|
|
299
|
+
* // [docx-editor] edit refused: edit.tracked-operation-unsupported (automation, tracked)
|
|
300
|
+
* // This editing API operation cannot be recorded as a tracked change, so nothing was ...
|
|
301
|
+
* // https://docx-editor.dev/docs/2.x/guides/diagnostics#edit-tracked-operation-unsupported
|
|
302
|
+
* ```
|
|
303
|
+
*
|
|
304
|
+
* @public
|
|
305
|
+
*/
|
|
306
|
+
declare function consoleExporter(options?: ConsoleExporterOptions): TelemetryExporter;
|
|
307
|
+
/** An exporter that keeps what it receives. Returned by {@link memoryExporter}. @public */
|
|
308
|
+
interface MemoryExporter extends TelemetryExporter {
|
|
309
|
+
readonly events: readonly TelemetryEvent[];
|
|
310
|
+
readonly metrics: readonly MetricRecord[];
|
|
311
|
+
/** Forget everything received so far. */
|
|
312
|
+
clear(): void;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Keep events and metrics in memory, for tests in your own suite.
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```ts
|
|
319
|
+
* const memory = memoryExporter();
|
|
320
|
+
* const telemetry = createTelemetry({ exporters: [memory] });
|
|
321
|
+
* // ...open a file that fails...
|
|
322
|
+
* expect(memory.events).toContainEqual(
|
|
323
|
+
* expect.objectContaining({ code: 'open.missing-main-document' })
|
|
324
|
+
* );
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @public
|
|
328
|
+
*/
|
|
329
|
+
declare function memoryExporter(): MemoryExporter;
|
|
330
|
+
|
|
331
|
+
export { Attributes, MetricRecord, TelemetryEvent, TelemetryExporter, TelemetryPipelineOptions, browserPrivacySignals, callbackExporter, consoleExporter, createTelemetry, httpExporter, isFailure, memoryExporter };
|
|
332
|
+
export type { BrowserPrivacySignalsOptions, ConsoleExporterOptions, HttpExporterOptions, MemoryExporter, Telemetry, TelemetryArea, TelemetryAreaOptions, TelemetryInclude, TelemetryOptions };
|