@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.
Files changed (47) hide show
  1. package/README.md +85 -7
  2. package/THIRD_PARTY_NOTICES.md +22 -0
  3. package/dist/chunk-73YEPWY5.js +1 -0
  4. package/dist/chunk-7ZXJ6HP2.cjs +1 -0
  5. package/dist/chunk-DT2KMPUJ.js +1 -0
  6. package/dist/chunk-DTEVX2XS.js +1 -0
  7. package/dist/chunk-LFQSY2TD.cjs +1 -0
  8. package/dist/chunk-LFX65QJG.js +4 -0
  9. package/dist/chunk-LGNT4I5W.cjs +1 -0
  10. package/dist/chunk-MJX3ECH3.cjs +4 -0
  11. package/dist/chunk-NUN46EXH.js +2 -0
  12. package/dist/chunk-RRYW7EAV.js +1 -0
  13. package/dist/chunk-S7KBMROA.js +1 -0
  14. package/dist/chunk-U6ERFNUM.cjs +1 -0
  15. package/dist/chunk-UK2MNJCG.cjs +2 -0
  16. package/dist/chunk-WGWKNKUT.cjs +1 -0
  17. package/dist/hocuspocus/index.cjs +1 -0
  18. package/dist/hocuspocus/index.d.cts +118 -0
  19. package/dist/hocuspocus/index.d.ts +118 -0
  20. package/dist/hocuspocus/index.js +1 -0
  21. package/dist/index.cjs +1 -0
  22. package/dist/index.d.cts +332 -0
  23. package/dist/index.d.ts +332 -0
  24. package/dist/index.js +1 -0
  25. package/dist/ingest/index.cjs +1 -0
  26. package/dist/ingest/index.d.cts +107 -0
  27. package/dist/ingest/index.d.ts +107 -0
  28. package/dist/ingest/index.js +1 -0
  29. package/dist/otel/index.cjs +1 -0
  30. package/dist/otel/index.d.cts +57 -0
  31. package/dist/otel/index.d.ts +57 -0
  32. package/dist/otel/index.js +1 -0
  33. package/dist/pipeline-DbVW7S-K.d.cts +223 -0
  34. package/dist/pipeline-DbVW7S-K.d.ts +223 -0
  35. package/dist/prometheus/index.cjs +1 -0
  36. package/dist/prometheus/index.d.cts +88 -0
  37. package/dist/prometheus/index.d.ts +88 -0
  38. package/dist/prometheus/index.js +1 -0
  39. package/dist/sentry/index.cjs +1 -0
  40. package/dist/sentry/index.d.cts +134 -0
  41. package/dist/sentry/index.d.ts +134 -0
  42. package/dist/sentry/index.js +1 -0
  43. package/dist/server/index.cjs +1 -0
  44. package/dist/server/index.d.cts +156 -0
  45. package/dist/server/index.d.ts +156 -0
  46. package/dist/server/index.js +1 -0
  47. package/package.json +100 -16
@@ -0,0 +1,223 @@
1
+ import { EditorDiagnostic } from '@docx-editor.dev/core';
2
+
3
+ /**
4
+ * The metric catalog: one definition per metric, in OpenTelemetry terms. Prometheus names are
5
+ * derived from it mechanically by {@link prometheusName}, so the two outputs cannot drift.
6
+ *
7
+ * Every label is a bounded enum. No metric carries a room name, a user, or a document.
8
+ */
9
+ /** How a metric aggregates. @public */
10
+ type MetricKind = 'counter' | 'gauge' | 'histogram';
11
+ /** One metric in the catalog. @public */
12
+ interface MetricDefinition {
13
+ /** OpenTelemetry name, such as `docx_editor.collab.room.load.duration`. */
14
+ readonly name: string;
15
+ readonly kind: MetricKind;
16
+ /** UCUM unit as OpenTelemetry writes it: `s`, `By`, `1`, or a `{annotation}`. */
17
+ readonly unit: string;
18
+ readonly description: string;
19
+ /** The label keys this metric may carry. Each value is a bounded enum. */
20
+ readonly labels: readonly string[];
21
+ /** Histogram bucket upper bounds, in the metric's unit. */
22
+ readonly buckets?: readonly number[];
23
+ }
24
+ /**
25
+ * Every metric the package records.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { METRICS, prometheusName } from '@docx-editor.dev/telemetry';
30
+ * prometheusName(METRICS.roomLoadDuration); // 'docx_editor_collab_room_load_duration_seconds'
31
+ * ```
32
+ *
33
+ * @public
34
+ */
35
+ declare const METRICS: Readonly<{
36
+ documentOpens: MetricDefinition;
37
+ documentOpenDuration: MetricDefinition;
38
+ editRejections: MetricDefinition;
39
+ reviewSkipped: MetricDefinition;
40
+ fontFailures: MetricDefinition;
41
+ historyDiagnostics: MetricDefinition;
42
+ customNodeDiagnostics: MetricDefinition;
43
+ collabClientStatusTransitions: MetricDefinition;
44
+ collabClientConnectDuration: MetricDefinition;
45
+ collabClientParticipants: MetricDefinition;
46
+ editorInteractionDuration: MetricDefinition;
47
+ editorLayoutDuration: MetricDefinition;
48
+ editorPaintDuration: MetricDefinition;
49
+ droppedEvents: MetricDefinition;
50
+ roomsActive: MetricDefinition;
51
+ connectionsActive: MetricDefinition;
52
+ participantsActive: MetricDefinition;
53
+ roomParticipants: MetricDefinition;
54
+ roomParticipantsMax: MetricDefinition;
55
+ roomMemory: MetricDefinition;
56
+ roomsMemory: MetricDefinition;
57
+ roomNodes: MetricDefinition;
58
+ roomResourceUsage: MetricDefinition;
59
+ roomAge: MetricDefinition;
60
+ roomIdle: MetricDefinition;
61
+ roomLoadDuration: MetricDefinition;
62
+ roomStoreDuration: MetricDefinition;
63
+ admissionRejections: MetricDefinition;
64
+ messageRefusals: MetricDefinition;
65
+ updates: MetricDefinition;
66
+ updateBytes: MetricDefinition;
67
+ roomParticipantsByRoom: MetricDefinition;
68
+ roomMemoryByRoom: MetricDefinition;
69
+ migrations: MetricDefinition;
70
+ }>;
71
+ /** A key of {@link METRICS}. @public */
72
+ type MetricId = keyof typeof METRICS;
73
+ /**
74
+ * The Prometheus name of a metric: dots become underscores, the unit becomes a suffix, and a
75
+ * counter ends in `_total`, as the OpenTelemetry Prometheus exporter writes it.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * prometheusName(METRICS.editRejections); // 'docx_editor_edit_rejections_total'
80
+ * prometheusName(METRICS.editorInteractionDuration); // 'docx_editor_editor_interaction_duration_seconds'
81
+ * ```
82
+ *
83
+ * @public
84
+ */
85
+ declare function prometheusName(definition: MetricDefinition): string;
86
+
87
+ /**
88
+ * The shared delivery path: consent, the anonymity guard, and exporters that can never throw
89
+ * into the code they observe. The editor client and the room server both send through it.
90
+ */
91
+
92
+ /** A metric attribute or a resource value. @public */
93
+ type AttributeValue = string | number | boolean;
94
+ /** Attributes or resource values, keyed by name. @public */
95
+ type Attributes = Readonly<Record<string, AttributeValue>>;
96
+ /** Context the package adds to every diagnostic before it reaches an exporter. @public */
97
+ interface TelemetryEventContext {
98
+ /** The fixed hint for the event's code. A constant, never document content. */
99
+ readonly hint?: string;
100
+ /** The documentation section for the event's code. */
101
+ readonly docs?: string;
102
+ /** The version of the editor packages. Core and this package release together. */
103
+ readonly engineVersion: string;
104
+ /**
105
+ * Present only on a summary: the event that closes a deduplication window repeats the first
106
+ * one, with the number of identical events folded into it beyond the first. Count it, do not
107
+ * treat it as a new failure. Its `time` is the first event's. The Sentry exporter records
108
+ * summaries as breadcrumbs.
109
+ */
110
+ readonly repeated?: number;
111
+ /**
112
+ * The host's own values from `createTelemetry({ resource })`, such as `service.name`. The
113
+ * host decides what goes here, and every event carries it.
114
+ */
115
+ readonly resource: Attributes;
116
+ /**
117
+ * Your identifiers for this event: the client's `attributes`, then the values of the
118
+ * `moduleFor` module of the editor that sent it, such as a room, a document, or a user.
119
+ * Empty when you set none. The engine never adds a value here.
120
+ */
121
+ readonly attributes: Attributes;
122
+ }
123
+ /** A diagnostic as an exporter receives it. Switch on `kind` to narrow it. @public */
124
+ type TelemetryEvent = EditorDiagnostic & TelemetryEventContext;
125
+ /** One metric measurement. @public */
126
+ interface MetricRecord {
127
+ readonly definition: MetricDefinition;
128
+ /** A counter increment, a gauge value, or a histogram sample, in the metric's unit. */
129
+ readonly value: number;
130
+ readonly attributes: Attributes;
131
+ }
132
+ /**
133
+ * Where telemetry goes. Implement `event`, `metric`, or both.
134
+ *
135
+ * An exporter never throws into the editor or the server: a failure is caught and reported
136
+ * once through `onExporterError`.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const toMyLogger: TelemetryExporter = {
141
+ * name: 'my-logger',
142
+ * event: (event) => myLogger.warn(event.kind, { code: 'code' in event ? event.code : undefined }),
143
+ * };
144
+ * ```
145
+ *
146
+ * @public
147
+ */
148
+ interface TelemetryExporter {
149
+ /** Shown in `onExporterError` reports. */
150
+ readonly name: string;
151
+ event?(event: TelemetryEvent): void;
152
+ metric?(record: MetricRecord): void;
153
+ /**
154
+ * Drop a series that no longer exists, such as a closed room's per-room gauge. Optional:
155
+ * an exporter without it keeps the series until it expires on its own.
156
+ */
157
+ forget?(definition: MetricDefinition, attributes: Attributes): void;
158
+ /**
159
+ * Start a series at zero before its first measurement. A scraper that sees a counter first
160
+ * at 1 cannot count that first increase, so the room server declares its known series when
161
+ * it starts. Optional: an exporter without it creates each series at its first measurement.
162
+ */
163
+ declare?(definition: MetricDefinition, attributes: Attributes): void;
164
+ /** Send anything buffered. Called by `flush()` and when a page is hidden. */
165
+ flush?(): void | Promise<void>;
166
+ /** Flush and release resources. Called by `shutdown()`. */
167
+ shutdown?(): void | Promise<void>;
168
+ /**
169
+ * Called once when a telemetry client or room server takes the exporter. An exporter that
170
+ * holds events, such as a batching one, reads `consented()` before it sends, so events queued
171
+ * before consent was withdrawn are discarded, not sent.
172
+ */
173
+ attach?(context: TelemetryExporterContext): void;
174
+ }
175
+ /** What a telemetry client tells an exporter it takes. @public */
176
+ interface TelemetryExporterContext {
177
+ /** Whether the host's consent is given, read now. */
178
+ consented(): boolean;
179
+ /**
180
+ * Whether the page is hidden or closing, read now. While it is, a browser exporter sends with
181
+ * `sendBeacon` or `keepalive`, which still deliver after the page goes away.
182
+ */
183
+ pageClosing(): boolean;
184
+ }
185
+ /** Options shared by the editor client and the room server. @public */
186
+ interface TelemetryPipelineOptions {
187
+ /** Where telemetry goes. Nothing is recorded or sent without at least one exporter. */
188
+ readonly exporters: readonly TelemetryExporter[];
189
+ /**
190
+ * Whether the viewer agreed to telemetry. Read before each event and metric, so a consent
191
+ * banner can change it at any time. Events before consent are dropped, not buffered.
192
+ * Defaults to `true`: without this option, events are sent. Pass it whenever your app asks
193
+ * for consent.
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * consent: () => window.cookieConsent?.analytics === true
198
+ * ```
199
+ */
200
+ readonly consent?: boolean | (() => boolean);
201
+ /**
202
+ * Values added to every event, such as `{ 'service.name': 'contracts-app' }`. Metrics do not
203
+ * carry them: set resource attributes on your OpenTelemetry SDK or Prometheus target instead.
204
+ * You own these values: do not put a user, a document, or a room name here.
205
+ */
206
+ readonly resource?: Attributes;
207
+ /** Told once per exporter when it throws. Defaults to one `console.warn`. */
208
+ readonly onExporterError?: (error: unknown, exporter: string) => void;
209
+ /**
210
+ * Keys of your own attributes that may also label metrics, such as `tenant.tier` or
211
+ * `app.region`. Only for values with few distinct values: each value makes a new series.
212
+ * After {@link MAX_METRIC_LABEL_VALUES} distinct values of one key, later values become
213
+ * `other`. Never list a user, document, or room id here; put those on events instead.
214
+ */
215
+ readonly metricLabels?: readonly string[];
216
+ }
217
+ /** Distinct values one of your metric labels may take before later values become `other`. @public */
218
+ declare const MAX_METRIC_LABEL_VALUES = 50;
219
+ /** The version of the editor packages, or `'development'` when running from source. @public */
220
+ declare const ENGINE_VERSION: string;
221
+
222
+ export { ENGINE_VERSION as E, MAX_METRIC_LABEL_VALUES as d, METRICS as e, prometheusName as p };
223
+ export type { Attributes as A, MetricRecord as M, TelemetryPipelineOptions as T, TelemetryEvent as a, TelemetryExporter as b, AttributeValue as c, MetricDefinition as f, MetricId as g, MetricKind as h, TelemetryEventContext as i, TelemetryExporterContext as j };
@@ -0,0 +1 @@
1
+ 'use strict';var chunkMJX3ECH3_cjs=require('../chunk-MJX3ECH3.cjs');require('../chunk-LGNT4I5W.cjs');Object.defineProperty(exports,"PROMETHEUS_CONTENT_TYPE",{enumerable:true,get:function(){return chunkMJX3ECH3_cjs.a}});Object.defineProperty(exports,"fetchMetricsHandler",{enumerable:true,get:function(){return chunkMJX3ECH3_cjs.d}});Object.defineProperty(exports,"metricsHandler",{enumerable:true,get:function(){return chunkMJX3ECH3_cjs.c}});Object.defineProperty(exports,"prometheusRegistry",{enumerable:true,get:function(){return chunkMJX3ECH3_cjs.b}});
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Prometheus: an in-process registry in the text exposition format, and `/metrics` handlers for
3
+ * Node-style servers ({@link metricsHandler}) and Fetch-style servers
4
+ * ({@link fetchMetricsHandler}). No dependency on `prom-client`; a `prom-client` registry
5
+ * merges into the same endpoint.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { b as TelemetryExporter } from '../pipeline-DbVW7S-K.cjs';
10
+ import '@docx-editor.dev/core';
11
+
12
+ /** The Prometheus text exposition content type. @public */
13
+ declare const PROMETHEUS_CONTENT_TYPE = "text/plain; version=0.0.4; charset=utf-8";
14
+ /** Anything that renders Prometheus text, such as a `prom-client` `Registry`. @public */
15
+ interface PrometheusTextSource {
16
+ metrics(): string | Promise<string>;
17
+ }
18
+ /** The exporter returned by {@link prometheusRegistry}. @public */
19
+ interface PrometheusRegistry extends TelemetryExporter, PrometheusTextSource {
20
+ /** Every recorded metric in the Prometheus text format. */
21
+ metrics(): string;
22
+ /** Forget every recorded value. */
23
+ reset(): void;
24
+ }
25
+ /**
26
+ * Collect metrics in memory and render them for Prometheus to scrape.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { prometheusRegistry, metricsHandler } from '@docx-editor.dev/telemetry/prometheus';
31
+ *
32
+ * const metrics = prometheusRegistry();
33
+ * // Pass `metrics` as an exporter, then serve it:
34
+ * app.get('/metrics', metricsHandler(metrics));
35
+ * ```
36
+ *
37
+ * @public
38
+ */
39
+ declare function prometheusRegistry(): PrometheusRegistry;
40
+ /** The part of a Node `ServerResponse` the handler writes to. @public */
41
+ interface NodeResponseLike {
42
+ setHeader(name: string, value: string): unknown;
43
+ end(body: string): unknown;
44
+ statusCode?: number;
45
+ }
46
+ /** Options for {@link metricsHandler} and {@link fetchMetricsHandler}. @public */
47
+ interface MetricsHandlerOptions {
48
+ /**
49
+ * More sources rendered into the same response, such as your `prom-client` registry:
50
+ * `merge: [register]`.
51
+ */
52
+ readonly merge?: readonly PrometheusTextSource[];
53
+ }
54
+ /**
55
+ * A Node-style handler, `(request, response)`, for Node `http`, Express, and Koa
56
+ * (`ctx.res`). For Fastify, hijack the reply and pass `reply.raw`. For Fetch-style servers,
57
+ * use {@link fetchMetricsHandler}. Protect the route as you protect other operational
58
+ * endpoints.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * app.get('/metrics', metricsHandler(metrics, { merge: [promClient.register] })); // Express
63
+ *
64
+ * fastify.get('/metrics', (request, reply) => {
65
+ * reply.hijack();
66
+ * return metricsHandler(metrics)(request.raw, reply.raw);
67
+ * });
68
+ * ```
69
+ *
70
+ * @public
71
+ */
72
+ declare function metricsHandler(registry: PrometheusTextSource, options?: MetricsHandlerOptions): (request: unknown, response: NodeResponseLike) => Promise<void>;
73
+ /**
74
+ * A Fetch-style handler that returns a `Response`, for Next.js route handlers, Hono, Bun,
75
+ * Deno, and workers. It ignores its argument, so a Hono context works as well as a `Request`.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // app/metrics/route.ts
80
+ * export const GET = fetchMetricsHandler(metrics);
81
+ * ```
82
+ *
83
+ * @public
84
+ */
85
+ declare function fetchMetricsHandler(registry: PrometheusTextSource, options?: MetricsHandlerOptions): (request?: unknown) => Promise<Response>;
86
+
87
+ export { PROMETHEUS_CONTENT_TYPE, TelemetryExporter, fetchMetricsHandler, metricsHandler, prometheusRegistry };
88
+ export type { MetricsHandlerOptions, NodeResponseLike, PrometheusRegistry, PrometheusTextSource };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Prometheus: an in-process registry in the text exposition format, and `/metrics` handlers for
3
+ * Node-style servers ({@link metricsHandler}) and Fetch-style servers
4
+ * ({@link fetchMetricsHandler}). No dependency on `prom-client`; a `prom-client` registry
5
+ * merges into the same endpoint.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { b as TelemetryExporter } from '../pipeline-DbVW7S-K.js';
10
+ import '@docx-editor.dev/core';
11
+
12
+ /** The Prometheus text exposition content type. @public */
13
+ declare const PROMETHEUS_CONTENT_TYPE = "text/plain; version=0.0.4; charset=utf-8";
14
+ /** Anything that renders Prometheus text, such as a `prom-client` `Registry`. @public */
15
+ interface PrometheusTextSource {
16
+ metrics(): string | Promise<string>;
17
+ }
18
+ /** The exporter returned by {@link prometheusRegistry}. @public */
19
+ interface PrometheusRegistry extends TelemetryExporter, PrometheusTextSource {
20
+ /** Every recorded metric in the Prometheus text format. */
21
+ metrics(): string;
22
+ /** Forget every recorded value. */
23
+ reset(): void;
24
+ }
25
+ /**
26
+ * Collect metrics in memory and render them for Prometheus to scrape.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { prometheusRegistry, metricsHandler } from '@docx-editor.dev/telemetry/prometheus';
31
+ *
32
+ * const metrics = prometheusRegistry();
33
+ * // Pass `metrics` as an exporter, then serve it:
34
+ * app.get('/metrics', metricsHandler(metrics));
35
+ * ```
36
+ *
37
+ * @public
38
+ */
39
+ declare function prometheusRegistry(): PrometheusRegistry;
40
+ /** The part of a Node `ServerResponse` the handler writes to. @public */
41
+ interface NodeResponseLike {
42
+ setHeader(name: string, value: string): unknown;
43
+ end(body: string): unknown;
44
+ statusCode?: number;
45
+ }
46
+ /** Options for {@link metricsHandler} and {@link fetchMetricsHandler}. @public */
47
+ interface MetricsHandlerOptions {
48
+ /**
49
+ * More sources rendered into the same response, such as your `prom-client` registry:
50
+ * `merge: [register]`.
51
+ */
52
+ readonly merge?: readonly PrometheusTextSource[];
53
+ }
54
+ /**
55
+ * A Node-style handler, `(request, response)`, for Node `http`, Express, and Koa
56
+ * (`ctx.res`). For Fastify, hijack the reply and pass `reply.raw`. For Fetch-style servers,
57
+ * use {@link fetchMetricsHandler}. Protect the route as you protect other operational
58
+ * endpoints.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * app.get('/metrics', metricsHandler(metrics, { merge: [promClient.register] })); // Express
63
+ *
64
+ * fastify.get('/metrics', (request, reply) => {
65
+ * reply.hijack();
66
+ * return metricsHandler(metrics)(request.raw, reply.raw);
67
+ * });
68
+ * ```
69
+ *
70
+ * @public
71
+ */
72
+ declare function metricsHandler(registry: PrometheusTextSource, options?: MetricsHandlerOptions): (request: unknown, response: NodeResponseLike) => Promise<void>;
73
+ /**
74
+ * A Fetch-style handler that returns a `Response`, for Next.js route handlers, Hono, Bun,
75
+ * Deno, and workers. It ignores its argument, so a Hono context works as well as a `Request`.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // app/metrics/route.ts
80
+ * export const GET = fetchMetricsHandler(metrics);
81
+ * ```
82
+ *
83
+ * @public
84
+ */
85
+ declare function fetchMetricsHandler(registry: PrometheusTextSource, options?: MetricsHandlerOptions): (request?: unknown) => Promise<Response>;
86
+
87
+ export { PROMETHEUS_CONTENT_TYPE, TelemetryExporter, fetchMetricsHandler, metricsHandler, prometheusRegistry };
88
+ export type { MetricsHandlerOptions, NodeResponseLike, PrometheusRegistry, PrometheusTextSource };
@@ -0,0 +1 @@
1
+ export{a as PROMETHEUS_CONTENT_TYPE,d as fetchMetricsHandler,c as metricsHandler,b as prometheusRegistry}from'../chunk-LFX65QJG.js';import'../chunk-73YEPWY5.js';
@@ -0,0 +1 @@
1
+ 'use strict';var chunkUK2MNJCG_cjs=require('../chunk-UK2MNJCG.cjs');var i=class extends Error{name="DocxEditorDiagnosticError";code;constructor(r,t){super(t?`${r}: ${t}`:r),this.code=r;}},u=new Set(["collab.authentication-failed","collab.room-generation-changed"]),l=new Set(["open.failed","open.unsupported-source","open.invalid-limits"]),f=Object.freeze([".docx-editor",".docx-pages"]);function x(e,r){return e.category?.startsWith("ui.")&&g(r?.event?.target)?null:e}function g(e){try{let r=e;return r&&typeof r.closest!="function"&&(r=r.parentElement),!r||typeof r.closest!="function"?!0:r.closest(f.join(", "))!=null}catch{return true}}function p(e){switch(e.kind){case "document.open":return e.outcome==="rejected"&&l.has(e.code);case "edit.rejected":return e.code==="edit.internal-invariant";case "review.skipped":return e.code==="review.revision-unsupported"||e.code==="review.retained-structure";case "font.failed":return e.code==="font.shaper-unavailable";case "collab.status":return e.status==="error"&&!e.recovering&&!u.has(e.code??"");default:return false}}function m(e){return e.kind==="document.open"?e.outcome==="opened":e.kind==="performance"&&e.code===void 0}function c(e){return "code"in e&&e.code?e.code:e.kind}function y(e){let r=e,t={"docx_editor.kind":e.kind,"docx_editor.code":c(e),"docx_editor.version":e.engineVersion,"docx_editor.editor_session":e.editorSessionId};for(let[o,n]of [["origin","origin"],["tracked","tracked"],["status","status"],["outcome","outcome"],["command","command"],["cause","cause"],["part","part"],["errorName","error_name"],["stage","stage"],["operation","operation"],["changeKind","change_kind"],["formattingKind","formatting_kind"]])r[o]!==void 0&&(t[`docx_editor.${n}`]=String(r[o]));for(let[o,n]of Object.entries(e.attributes??{}))t[o]=String(n);return t}function k(e,r){let t=e,o=["cause","errorName","stage","changeKind","formattingKind"].map(n=>t[n]).filter(n=>typeof n=="string");return ["docx-editor",e.kind,r,...o]}function d(e){let{resource:r,...t}=e;return {...t,...Object.keys(r).length?{resource:r}:{}}}function b(e,r={}){let t=r.issue??p,o=r.breadcrumbs??true;return {name:"sentry",event(n){let s=c(n);if(n.repeated===void 0&&t(n)){e.captureException(new i(s,n.hint),{fingerprint:k(n,s),level:n.kind==="font.failed"||n.kind==="review.skipped"?"warning":"error",tags:y(n),contexts:{docx_editor:d(n)}});return}o&&e.addBreadcrumb({category:"docx-editor",message:chunkUK2MNJCG_cjs.b(n),level:m(n)?"info":"warning",data:d(n)});},async flush(){await e.flush?.(2e3);}}}exports.DocxEditorDiagnosticError=i;exports.EDITOR_SELECTORS=f;exports.dropEditorBreadcrumbs=x;exports.isSentryIssue=p;exports.sentryExporter=b;
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Sentry: actionable failures become issues grouped by code; everything else becomes a
3
+ * breadcrumb, so it appears beside your own errors without using your event quota.
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ import { a as TelemetryEvent, b as TelemetryExporter } from '../pipeline-DbVW7S-K.cjs';
8
+ import '@docx-editor.dev/core';
9
+
10
+ /** Sentry severity, as the Sentry SDKs spell it. @public */
11
+ type SentrySeverity = 'fatal' | 'error' | 'warning' | 'info' | 'debug';
12
+ /**
13
+ * The part of a Sentry SDK the exporter uses. `@sentry/browser`, `@sentry/react`,
14
+ * `@sentry/vue`, `@sentry/nextjs`, and `@sentry/node` all fit: pass the module itself.
15
+ *
16
+ * @public
17
+ */
18
+ interface SentryLike {
19
+ captureException(exception: unknown, context?: {
20
+ readonly fingerprint?: string[];
21
+ readonly level?: SentrySeverity;
22
+ readonly tags?: Record<string, string>;
23
+ readonly contexts?: Record<string, Record<string, unknown>>;
24
+ }): unknown;
25
+ addBreadcrumb(breadcrumb: {
26
+ readonly category?: string;
27
+ readonly message?: string;
28
+ readonly level?: SentrySeverity;
29
+ readonly data?: Record<string, unknown>;
30
+ }): void;
31
+ /** Send queued events. Called when the page is hidden. */
32
+ flush?(timeout?: number): PromiseLike<boolean>;
33
+ }
34
+ /** Options for {@link sentryExporter}. @public */
35
+ interface SentryExporterOptions {
36
+ /**
37
+ * Which events become Sentry issues. The rest become breadcrumbs. The default sends an issue
38
+ * when the app can act: an open refused because the app passed something wrong or for an
39
+ * unknown reason, a collaboration error that will not heal, a text shaper that did not load,
40
+ * and an engine invariant. A corrupt or oversized file and a refused keystroke are
41
+ * breadcrumbs.
42
+ */
43
+ readonly issue?: (event: TelemetryEvent) => boolean;
44
+ /** Record breadcrumbs for the other events. Defaults to `true`. */
45
+ readonly breadcrumbs?: boolean;
46
+ }
47
+ /**
48
+ * The error a Sentry issue is made from. The message is the code, so issues group by cause,
49
+ * and the stack trace contains no document data.
50
+ *
51
+ * @public
52
+ */
53
+ declare class DocxEditorDiagnosticError extends Error {
54
+ readonly name = "DocxEditorDiagnosticError";
55
+ readonly code: string;
56
+ constructor(code: string, hint?: string);
57
+ }
58
+ /**
59
+ * CSS selectors for everything that shows the document: the editor shell and the painted pages.
60
+ * Pass them to Session Replay's `block` option, which replaces the editor with a placeholder, so
61
+ * `mask` is not needed as well.
62
+ *
63
+ * @public
64
+ */
65
+ declare const EDITOR_SELECTORS: readonly string[];
66
+ /** A Sentry breadcrumb, as `beforeBreadcrumb` receives it. @public */
67
+ interface SentryBreadcrumbLike {
68
+ readonly category?: string;
69
+ }
70
+ /** The hint Sentry passes with a breadcrumb. For a click or key press, `event` is the DOM event. @public */
71
+ interface SentryBreadcrumbHintLike {
72
+ readonly event?: unknown;
73
+ }
74
+ /**
75
+ * A `beforeBreadcrumb` filter that drops Sentry's click and key press breadcrumbs from inside the
76
+ * editor. Sentry describes the element a person clicked with its `alt`, `title`, and
77
+ * `aria-label` values. Inside the editor, those values come from the document: picture
78
+ * descriptions, link tooltips, and content control names. A `ui` breadcrumb whose element is
79
+ * unknown is dropped too. Other breadcrumbs pass unchanged.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * Sentry.init({ dsn, beforeBreadcrumb: dropEditorBreadcrumbs });
84
+ * // With a filter of your own:
85
+ * Sentry.init({
86
+ * dsn,
87
+ * beforeBreadcrumb: (crumb, hint) => {
88
+ * const kept = dropEditorBreadcrumbs(crumb, hint);
89
+ * return kept && myFilter(kept, hint); // dropped breadcrumbs never reach your filter
90
+ * },
91
+ * });
92
+ * ```
93
+ *
94
+ * @public
95
+ */
96
+ declare function dropEditorBreadcrumbs<B extends SentryBreadcrumbLike>(breadcrumb: B, hint?: SentryBreadcrumbHintLike): B | null;
97
+ /**
98
+ * The default issue rule: an open the app caused, an internal error, a shaper that never
99
+ * loaded, and a collaboration error that will not heal become issues. Wrap it to add your own.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * sentryExporter(Sentry, {
104
+ * issue: (event) =>
105
+ * isSentryIssue(event) || ('code' in event && event.code === 'font.load-failed'),
106
+ * });
107
+ * ```
108
+ *
109
+ * @public
110
+ */
111
+ declare function isSentryIssue(event: TelemetryEvent): boolean;
112
+ /**
113
+ * Send diagnostics to Sentry.
114
+ *
115
+ * Sentry Session Replay records the page, and the page shows the document. Block the editor in
116
+ * Replay, so neither its text nor its pictures are recorded, and drop the click breadcrumbs that
117
+ * describe its elements: `Sentry.replayIntegration({ block: [...EDITOR_SELECTORS] })` and
118
+ * `beforeBreadcrumb: dropEditorBreadcrumbs`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import * as Sentry from '@sentry/react';
123
+ * import { createTelemetry } from '@docx-editor.dev/telemetry';
124
+ * import { sentryExporter } from '@docx-editor.dev/telemetry/sentry';
125
+ *
126
+ * export const telemetry = createTelemetry({ exporters: [sentryExporter(Sentry)] });
127
+ * ```
128
+ *
129
+ * @public
130
+ */
131
+ declare function sentryExporter(sentry: SentryLike, options?: SentryExporterOptions): TelemetryExporter;
132
+
133
+ export { DocxEditorDiagnosticError, EDITOR_SELECTORS, TelemetryEvent, TelemetryExporter, dropEditorBreadcrumbs, isSentryIssue, sentryExporter };
134
+ export type { SentryBreadcrumbHintLike, SentryBreadcrumbLike, SentryExporterOptions, SentryLike, SentrySeverity };
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Sentry: actionable failures become issues grouped by code; everything else becomes a
3
+ * breadcrumb, so it appears beside your own errors without using your event quota.
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ import { a as TelemetryEvent, b as TelemetryExporter } from '../pipeline-DbVW7S-K.js';
8
+ import '@docx-editor.dev/core';
9
+
10
+ /** Sentry severity, as the Sentry SDKs spell it. @public */
11
+ type SentrySeverity = 'fatal' | 'error' | 'warning' | 'info' | 'debug';
12
+ /**
13
+ * The part of a Sentry SDK the exporter uses. `@sentry/browser`, `@sentry/react`,
14
+ * `@sentry/vue`, `@sentry/nextjs`, and `@sentry/node` all fit: pass the module itself.
15
+ *
16
+ * @public
17
+ */
18
+ interface SentryLike {
19
+ captureException(exception: unknown, context?: {
20
+ readonly fingerprint?: string[];
21
+ readonly level?: SentrySeverity;
22
+ readonly tags?: Record<string, string>;
23
+ readonly contexts?: Record<string, Record<string, unknown>>;
24
+ }): unknown;
25
+ addBreadcrumb(breadcrumb: {
26
+ readonly category?: string;
27
+ readonly message?: string;
28
+ readonly level?: SentrySeverity;
29
+ readonly data?: Record<string, unknown>;
30
+ }): void;
31
+ /** Send queued events. Called when the page is hidden. */
32
+ flush?(timeout?: number): PromiseLike<boolean>;
33
+ }
34
+ /** Options for {@link sentryExporter}. @public */
35
+ interface SentryExporterOptions {
36
+ /**
37
+ * Which events become Sentry issues. The rest become breadcrumbs. The default sends an issue
38
+ * when the app can act: an open refused because the app passed something wrong or for an
39
+ * unknown reason, a collaboration error that will not heal, a text shaper that did not load,
40
+ * and an engine invariant. A corrupt or oversized file and a refused keystroke are
41
+ * breadcrumbs.
42
+ */
43
+ readonly issue?: (event: TelemetryEvent) => boolean;
44
+ /** Record breadcrumbs for the other events. Defaults to `true`. */
45
+ readonly breadcrumbs?: boolean;
46
+ }
47
+ /**
48
+ * The error a Sentry issue is made from. The message is the code, so issues group by cause,
49
+ * and the stack trace contains no document data.
50
+ *
51
+ * @public
52
+ */
53
+ declare class DocxEditorDiagnosticError extends Error {
54
+ readonly name = "DocxEditorDiagnosticError";
55
+ readonly code: string;
56
+ constructor(code: string, hint?: string);
57
+ }
58
+ /**
59
+ * CSS selectors for everything that shows the document: the editor shell and the painted pages.
60
+ * Pass them to Session Replay's `block` option, which replaces the editor with a placeholder, so
61
+ * `mask` is not needed as well.
62
+ *
63
+ * @public
64
+ */
65
+ declare const EDITOR_SELECTORS: readonly string[];
66
+ /** A Sentry breadcrumb, as `beforeBreadcrumb` receives it. @public */
67
+ interface SentryBreadcrumbLike {
68
+ readonly category?: string;
69
+ }
70
+ /** The hint Sentry passes with a breadcrumb. For a click or key press, `event` is the DOM event. @public */
71
+ interface SentryBreadcrumbHintLike {
72
+ readonly event?: unknown;
73
+ }
74
+ /**
75
+ * A `beforeBreadcrumb` filter that drops Sentry's click and key press breadcrumbs from inside the
76
+ * editor. Sentry describes the element a person clicked with its `alt`, `title`, and
77
+ * `aria-label` values. Inside the editor, those values come from the document: picture
78
+ * descriptions, link tooltips, and content control names. A `ui` breadcrumb whose element is
79
+ * unknown is dropped too. Other breadcrumbs pass unchanged.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * Sentry.init({ dsn, beforeBreadcrumb: dropEditorBreadcrumbs });
84
+ * // With a filter of your own:
85
+ * Sentry.init({
86
+ * dsn,
87
+ * beforeBreadcrumb: (crumb, hint) => {
88
+ * const kept = dropEditorBreadcrumbs(crumb, hint);
89
+ * return kept && myFilter(kept, hint); // dropped breadcrumbs never reach your filter
90
+ * },
91
+ * });
92
+ * ```
93
+ *
94
+ * @public
95
+ */
96
+ declare function dropEditorBreadcrumbs<B extends SentryBreadcrumbLike>(breadcrumb: B, hint?: SentryBreadcrumbHintLike): B | null;
97
+ /**
98
+ * The default issue rule: an open the app caused, an internal error, a shaper that never
99
+ * loaded, and a collaboration error that will not heal become issues. Wrap it to add your own.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * sentryExporter(Sentry, {
104
+ * issue: (event) =>
105
+ * isSentryIssue(event) || ('code' in event && event.code === 'font.load-failed'),
106
+ * });
107
+ * ```
108
+ *
109
+ * @public
110
+ */
111
+ declare function isSentryIssue(event: TelemetryEvent): boolean;
112
+ /**
113
+ * Send diagnostics to Sentry.
114
+ *
115
+ * Sentry Session Replay records the page, and the page shows the document. Block the editor in
116
+ * Replay, so neither its text nor its pictures are recorded, and drop the click breadcrumbs that
117
+ * describe its elements: `Sentry.replayIntegration({ block: [...EDITOR_SELECTORS] })` and
118
+ * `beforeBreadcrumb: dropEditorBreadcrumbs`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * import * as Sentry from '@sentry/react';
123
+ * import { createTelemetry } from '@docx-editor.dev/telemetry';
124
+ * import { sentryExporter } from '@docx-editor.dev/telemetry/sentry';
125
+ *
126
+ * export const telemetry = createTelemetry({ exporters: [sentryExporter(Sentry)] });
127
+ * ```
128
+ *
129
+ * @public
130
+ */
131
+ declare function sentryExporter(sentry: SentryLike, options?: SentryExporterOptions): TelemetryExporter;
132
+
133
+ export { DocxEditorDiagnosticError, EDITOR_SELECTORS, TelemetryEvent, TelemetryExporter, dropEditorBreadcrumbs, isSentryIssue, sentryExporter };
134
+ export type { SentryBreadcrumbHintLike, SentryBreadcrumbLike, SentryExporterOptions, SentryLike, SentrySeverity };